mirror of
https://github.com/svemagie/indiekit-endpoint-microsub.git
synced 2026-04-02 15:35:00 +02:00
feat: add bookmark to timeline, mark-read to item view
- Add bookmark button to item-card.njk (timeline view) - Add mark-read button to item.njk (full item view) - Add JavaScript handler for mark-read on item page - Pass channel info to item template for mark-read API call Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -314,9 +314,17 @@ export async function item(request, response) {
|
|||||||
return response.status(404).render("404");
|
return response.status(404).render("404");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the channel for this item (needed for mark-read)
|
||||||
|
let channel = null;
|
||||||
|
if (itemDocument.channelId) {
|
||||||
|
const channelsCollection = application.collections.get("microsub_channels");
|
||||||
|
channel = await channelsCollection.findOne({ _id: itemDocument.channelId });
|
||||||
|
}
|
||||||
|
|
||||||
response.render("item", {
|
response.render("item", {
|
||||||
title: itemDocument.name || "Item",
|
title: itemDocument.name || "Item",
|
||||||
item: itemDocument,
|
item: itemDocument,
|
||||||
|
channel,
|
||||||
baseUrl: request.baseUrl,
|
baseUrl: request.baseUrl,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rmdes/indiekit-endpoint-microsub",
|
"name": "@rmdes/indiekit-endpoint-microsub",
|
||||||
"version": "1.0.18",
|
"version": "1.0.19",
|
||||||
"description": "Microsub endpoint for Indiekit. Enables subscribing to feeds and reading content using the Microsub protocol.",
|
"description": "Microsub endpoint for Indiekit. Enables subscribing to feeds and reading content using the Microsub protocol.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"indiekit",
|
"indiekit",
|
||||||
|
|||||||
@@ -146,6 +146,61 @@
|
|||||||
<a href="{{ baseUrl }}/compose?bookmark={{ item.url | urlencode }}" class="button button--secondary button--small">
|
<a href="{{ baseUrl }}/compose?bookmark={{ item.url | urlencode }}" class="button button--secondary button--small">
|
||||||
{{ icon("bookmark") }} {{ __("microsub.item.bookmark") }}
|
{{ icon("bookmark") }} {{ __("microsub.item.bookmark") }}
|
||||||
</a>
|
</a>
|
||||||
|
{% if not item._is_read %}
|
||||||
|
<button type="button"
|
||||||
|
class="button button--secondary button--small item__mark-read"
|
||||||
|
data-item-id="{{ item._id }}"
|
||||||
|
data-channel="{{ channel.uid }}">
|
||||||
|
{{ icon("checkboxChecked") }} {{ __("microsub.timeline.markRead") }}
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
</footer>
|
</footer>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
// Handle mark-read button
|
||||||
|
const markReadBtn = document.querySelector('.item__mark-read');
|
||||||
|
if (markReadBtn) {
|
||||||
|
markReadBtn.addEventListener('click', async () => {
|
||||||
|
const itemId = markReadBtn.dataset.itemId;
|
||||||
|
const channelUid = markReadBtn.dataset.channel;
|
||||||
|
const microsubApiUrl = '{{ baseUrl }}'.replace(/\/reader.*$/, '');
|
||||||
|
|
||||||
|
markReadBtn.disabled = true;
|
||||||
|
markReadBtn.textContent = 'Marking...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const formData = new URLSearchParams();
|
||||||
|
formData.append('action', 'timeline');
|
||||||
|
formData.append('method', 'mark_read');
|
||||||
|
formData.append('channel', channelUid);
|
||||||
|
formData.append('entry', itemId);
|
||||||
|
|
||||||
|
const response = await fetch(microsubApiUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
body: formData.toString(),
|
||||||
|
credentials: 'same-origin'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
markReadBtn.textContent = 'Marked as read';
|
||||||
|
markReadBtn.classList.add('button--success');
|
||||||
|
setTimeout(() => {
|
||||||
|
markReadBtn.remove();
|
||||||
|
}, 1500);
|
||||||
|
} else {
|
||||||
|
markReadBtn.textContent = 'Failed';
|
||||||
|
markReadBtn.disabled = false;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
markReadBtn.textContent = 'Error';
|
||||||
|
markReadBtn.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -165,6 +165,10 @@
|
|||||||
{{ icon("repost") }}
|
{{ icon("repost") }}
|
||||||
<span class="visually-hidden">Repost</span>
|
<span class="visually-hidden">Repost</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ baseUrl }}/compose?bookmark={{ item.url | urlencode }}" class="item-actions__button" title="Bookmark">
|
||||||
|
{{ icon("bookmark") }}
|
||||||
|
<span class="visually-hidden">Bookmark</span>
|
||||||
|
</a>
|
||||||
{% if not item._is_read %}
|
{% if not item._is_read %}
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="item-actions__button item-actions__mark-read"
|
class="item-actions__button item-actions__mark-read"
|
||||||
|
|||||||
Reference in New Issue
Block a user