feat: add show/hide read items and fix individual mark-read

- Add countReadItems function to storage/items.js
- Update getTimelineItems to filter out read items by default
- Add showRead query param support to channel controller
- Update channel.njk with show/hide read toggle buttons
- Add "All caught up!" state when all items are read
- Add JavaScript handler for individual mark-read buttons
- Mark-read now hides the item with smooth animation
- Add locale strings: showRead, hideRead, allRead

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Ricardo
2026-02-06 21:24:33 +01:00
parent 8d373dca5f
commit c830ad5df6
5 changed files with 120 additions and 4 deletions

View File

@@ -78,6 +78,7 @@ export async function addItem(application, { channelId, feedId, uid, item }) {
* @param {string} [options.after] - After cursor
* @param {number} [options.limit] - Items per page
* @param {string} [options.userId] - User ID for read state
* @param {boolean} [options.showRead] - Whether to show read items (default: false)
* @returns {Promise<object>} Timeline with items and paging
*/
export async function getTimelineItems(application, channelId, options = {}) {
@@ -86,7 +87,12 @@ export async function getTimelineItems(application, channelId, options = {}) {
typeof channelId === "string" ? new ObjectId(channelId) : channelId;
const limit = parseLimit(options.limit);
// Base query - filter out read items unless showRead is true
const baseQuery = { channelId: objectId };
if (options.userId && !options.showRead) {
baseQuery.readBy = { $ne: options.userId };
}
const query = buildPaginationQuery({
before: options.before,
after: options.after,
@@ -256,6 +262,24 @@ export async function getItemsByUids(application, uids, userId) {
return items.map((item) => transformToJf2(item, userId));
}
/**
* Count read items in a channel
* @param {object} application - Indiekit application
* @param {ObjectId|string} channelId - Channel ObjectId
* @param {string} userId - User ID
* @returns {Promise<number>} Number of read items
*/
export async function countReadItems(application, channelId, userId) {
const collection = getCollection(application);
const objectId =
typeof channelId === "string" ? new ObjectId(channelId) : channelId;
return collection.countDocuments({
channelId: objectId,
readBy: userId,
});
}
/**
* Mark items as read
* @param {object} application - Indiekit application