Ignore:
Timestamp:
06/30/2026 01:31:49 PM (2 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
8b700ad
Parents:
d5aa7c8
Message:

feat(circle): filter the Circle feed by member (clickable chips + Following "Show" link)

The member chips on the Circle page are now clickable filters: clicking one shows only that
account's posts, with an "Everyone" chip to clear and an active highlight. The Following page
gets a "Show" link per featured account that lands on the filtered Circle view. So Featured =
"include in my Circle", and Show lets you view just that one person here.

  • src/services/ActivityPubService.js — getCirkelPosts(slug, limit, actorUri) filter; members expose actor_uri
  • src/routes/circle.js — honour ?actor=<uri> (validated against the member list) + active flags
  • src/views/pages/circle-feed.ejs — chips + modal as filter links + Everyone + active state
  • src/views/pages/following.ejs — Show link for featured accounts
  • src/services/i18n.js — cfeed.all, tl.show (nl/en/de)

Co-Authored-By: Claude <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    rd5aa7c8 r462a931  
    14171417
    14181418// ── Cirkel = posts from the accounts you auto-boost ("feature an artist") ──
    1419 let _abCount, _cirkelPosts, _cirkelMembers;
     1419let _abCount, _cirkelPosts, _cirkelPostsActor, _cirkelMembers;
    14201420export function autoBoostCount(slug) {
    14211421  try { if (!_abCount) _abCount = db.prepare('SELECT COUNT(*) AS n FROM ap_following WHERE slug = ? AND auto_boost = 1'); return _abCount.get(slug).n; } catch { return 0; }
    14221422}
    1423 export function getCirkelPosts(slug, limit) {
     1423export function getCirkelPosts(slug, limit, actorUri) {
    14241424  try {
    14251425    // Cirkel = posts from featured (auto_boost) accounts + posts you boosted
    14261426    // (t.boosted), mixed by date. One row per note in ap_timeline → no duplicates.
     1427    // Optional actorUri → only that member's posts (the "Show this person" filter).
     1428    if (actorUri) {
     1429      if (!_cirkelPostsActor) _cirkelPostsActor = db.prepare(`
     1430        SELECT t.id, t.author_uri, t.author_name, t.author_handle, t.author_icon, t.author_url,
     1431               t.content, t.url, t.published, t.media_json, t.boosted, t.nsfw, t.cw
     1432        FROM ap_timeline t
     1433        LEFT JOIN ap_following f ON f.slug = t.slug AND f.actor_uri = t.author_uri
     1434        WHERE t.slug = ? AND t.author_uri = ? AND (f.auto_boost = 1 OR t.boosted = 1)
     1435        ORDER BY COALESCE(t.published, t.created_at) DESC, t.rowid DESC
     1436        LIMIT ?`);
     1437      return _cirkelPostsActor.all(slug, actorUri, limit || 60);
     1438    }
    14271439    if (!_cirkelPosts) _cirkelPosts = db.prepare(`
    14281440      SELECT t.id, t.author_uri, t.author_name, t.author_handle, t.author_icon, t.author_url,
     
    14371449}
    14381450export function getCirkelMembers(slug) {
    1439   try { if (!_cirkelMembers) _cirkelMembers = db.prepare('SELECT name, url, icon FROM ap_following WHERE slug = ? AND auto_boost = 1 ORDER BY name'); return _cirkelMembers.all(slug); } catch { return []; }
     1451  try { if (!_cirkelMembers) _cirkelMembers = db.prepare('SELECT actor_uri, name, url, icon FROM ap_following WHERE slug = ? AND auto_boost = 1 ORDER BY name'); return _cirkelMembers.all(slug); } catch { return []; }
    14401452}
    14411453// Mark a timeline post as boosted so it shows in the Cirkel (mixed by date).
Note: See TracChangeset for help on using the changeset viewer.