mirror of
https://github.com/svemagie/indiekit-endpoint-microsub.git
synced 2026-04-02 15:35:00 +02:00
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:
@@ -21,6 +21,7 @@ import {
|
||||
getTimelineItems,
|
||||
getItemById,
|
||||
markItemsRead,
|
||||
countReadItems,
|
||||
} from "../storage/items.js";
|
||||
import { getUserId } from "../utils/auth.js";
|
||||
import {
|
||||
@@ -95,24 +96,37 @@ export async function channel(request, response) {
|
||||
const { application } = request.app.locals;
|
||||
const userId = getUserId(request);
|
||||
const { uid } = request.params;
|
||||
const { before, after } = request.query;
|
||||
const { before, after, showRead } = request.query;
|
||||
|
||||
const channelDocument = await getChannel(application, uid, userId);
|
||||
if (!channelDocument) {
|
||||
return response.status(404).render("404");
|
||||
}
|
||||
|
||||
// Check if showing read items
|
||||
const showReadItems = showRead === "true";
|
||||
|
||||
const timeline = await getTimelineItems(application, channelDocument._id, {
|
||||
before,
|
||||
after,
|
||||
userId,
|
||||
showRead: showReadItems,
|
||||
});
|
||||
|
||||
// Count read items to show "View read items" button
|
||||
const readCount = await countReadItems(
|
||||
application,
|
||||
channelDocument._id,
|
||||
userId,
|
||||
);
|
||||
|
||||
response.render("channel", {
|
||||
title: channelDocument.name,
|
||||
channel: channelDocument,
|
||||
items: timeline.items,
|
||||
paging: timeline.paging,
|
||||
readCount,
|
||||
showRead: showReadItems,
|
||||
baseUrl: request.baseUrl,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user