Skip to content

News heading as menus: Sources (switch + Manage), Calendar, Filter - #226

Merged
ra3orblade merged 2 commits into
mainfrom
feat/news-heading-menus
Oct 26, 2026
Merged

ra3orblade merged 2 commits into
mainfrom
feat/news-heading-menus

Conversation

@ra3orblade

@ra3orblade ra3orblade commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

What

The News view's controls move into the heading as one row of buttons that open popups, the way the portal's Security › News does:

  • Sources ▾: a menu of every source read, grouped by kind, with an eye icon per row. Clicking a row switches that source on or off. The setting is saved in the daemon, not just hidden in the page: POST /v1/news/feeds/switch → store.setFeedOn writes feeds_off to ~/.swarm/settings.toml and reconciles news_feeds immediately. A source switched back on is read right away. The switch is refused, with the file named, when config.toml or the policy already sets feeds_off. The button label counts the sources that are off.

  • Manage sources… is pinned as the menu's footer (the list scrolls above it). It opens the old Sources table in a modal, now with Turn on / Turn off per row next to Check, plus the add-a-feed check.

  • Calendar ▾: the month calendar opens in the same popup. Picking a day narrows the items, closes the popup, and the button then shows the day (26 Oct).

  • Filter ▾: kinds, Unread only and All items in one menu that stays open while you toggle.

  • Paper / Table: two heading buttons with the chosen one lit.

  • Site icons: every source in the menu and in the Manage table shows its site's favicon, and switched-off rows are drawn faint. The daemon fetches each icon itself via GET /v1/favicons/<host>: it takes the icon the home page names (never an SVG, at most 256 KB), else /favicon.ico, fetched about once a week and kept in ~/.swarm/favicons/. It only fetches for hosts that one of your sources names, never under SWARM_OFFLINE, and not with [security] pictures = false. Each source's site is the host of its newest article, so a feedburner feed gets the publisher's icon. The privacy page in the guide now says so.

  • The end of a long menu can be reached again: fancy-menus caps .fm-list at 60vh whatever height the menu is allowed. A menu held shorter than that (by its maxHeight, a short window, or a footer) hid its last rows with nothing to scroll to. .fm-body is now a flex column that gives the list the height that is left.

The chip row, the inline Sources panel and the calendar sidebar column are gone.

How

  • Menus island (src/menus.tsx): MenuSpec.refresh redraws a stay-open menu after an item runs, MenuSpec.footer pins an action under a scrolling list, and openPanel(anchor, render) puts free content in the same popup.
  • core/src/newsfeeds.ts feedsOffWith (unit test). NewsFeedsReport.kinds lets the menu leave out built-ins whose kind is not read.
  • New icons: calendar, eye-slash, funnel.
  • core/src/newsfeed.ts iconLinks + siteHost (tested); SecurityService.favicon keeps a cache in memory and on disk, and retries a failed site after 30 minutes.

Verified

lint, typecheck, test (1110 pass), smoke, check:classes, docs:check. The daemon tests cover switching off, switching on, a refusal over config.toml, a 400 and a 404. The favicon test uses a stub fetch and checks that the icon is fetched once, kept on disk and served by a fresh daemon without fetching again, and that an unnamed host gets a 404. I also drove a scratch daemon in headless Chrome: the six heading buttons are all 22px tall, toggling a source updates the menu and its label, Manage opens the modal, and the calendar popup is 260px wide and narrows to a day.

🤖 Generated with Claude Code

ra3orblade and others added 2 commits October 26, 2026 14:24
The News view's controls were a row of chips under the heading, an inline
Sources table and a calendar in a sidebar column. They are now buttons in
the heading, drawn alike, each opening a popup the way the menus do:

- Sources: a menu of every source read, by kind, with an eye per row; a
  click switches the source on or off. It is real, not a view filter:
  POST /v1/news/feeds/switch writes feeds_off to ~/.swarm/settings.toml
  (store.setFeedOn, refused when config.toml or the policy sets the list),
  reconciles the rows at once, and reads a source back on immediately.
- Manage sources… is pinned under the list (the list scrolls above it) and
  opens the sources table in a modal, now with Turn on / off per row.
- Calendar: the month calendar in the same popup; a day narrows the items,
  closes it, and the button then names the day.
- Filter: kinds, Unread only, All items in one menu that stays open.
- Paper / Table: two heading buttons, the chosen one lit.

The menus island gains a refresh for stay-open menus, a pinned footer
action, and a panel for free content. core: feedsOffWith + test; the
feeds report carries [security] kinds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… to its last row

Favicons: the daemon asks each source's site for its icon (the one its
home page names, near 32 px, never an SVG, else /favicon.ico), once a
week, only for a host a source names, never offline or with
[security] pictures = false, and keeps it in ~/.swarm/favicons/. Served
at GET /v1/favicons/<host>; the feeds report carries each source's site
(the host of its newest article, so a feedburner feed gets the
publisher's icon). The menu rows show it with the eye moved to the end,
a switched-off row faint; the Manage table shows it beside the name.
core: iconLinks + siteHost, tested; daemon test with a stub fetch.

Scrolling: fancy-menus caps .fm-list at 60vh whatever the menu may be,
so a menu held shorter (its maxHeight, a short window, a footer) hid its
last rows below the body with nothing left to scroll. The body is now a
flex column that hands the list the height that is left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ra3orblade
ra3orblade merged commit 323964a into main Oct 26, 2026
2 checks passed
@ra3orblade
ra3orblade deleted the feat/news-heading-menus branch October 26, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant