RSS Reader

Browser-based RSS/Atom feed reader. Subscribe to feeds, browse articles, and track read/unread state — all in a single HTML file with no server required.

Layout

Two-panel layout: feed sidebar (left) · article list (right). Each article row links out to the original; no in-app reading pane.

UI Approach

Prefer DaisyUI components wherever there is a natural fit (e.g. badge, menu, input, btn, collapse). Fall back to Tailwind utilities only when no DaisyUI component fits.

Theme follows the OS prefers-color-scheme (dark/light). Set via an inline <script> before any stylesheets load: reads window.matchMedia('(prefers-color-scheme: dark)') and writes data-theme on <html>, with a change listener to keep it in sync if the user switches OS theme at runtime.

UI Components

Feed Sidebar

DaisyUI tabs (tabs tabs-border tabs-sm) under the header switch the grouping dimension: author · platform · topics. The list below shows the distinct values of the active dimension (alphabetical), derived from the slider-filtered feed set. A value can span multiple feeds (e.g. author Greg Hurrell = blog + YouTube; platform youtube = all channels). Topics are tags: a feed carries one or more and appears under each of them.

Single-select: clicking a value filters articles to feeds matching it; clicking again deselects. "All" entry at top is active when nothing is selected (filter() === null). Switching tabs clears the selection back to All. Each value row has a ↻ button that refreshes every feed in that category.

Below the feed list: a search box, then a range slider with a mode label. The label toggles between age and velocity modes on click. Slider steps and labels depend on mode:

Article List

Feed Configuration

Hardcoded array of feed objects at the top of the script: {url, author, platform, topics}. Author, platform, and topics are set manually in this table — never derived from the feed. topics is a list of tags (one or more per feed). The table below is the authoritative list; the FEEDS array in the HTML mirrors it row by row. FEED_META (Map<url, feed-object>) is derived from FEEDS for per-item lookups.

Platform values: blog · substack · youtube

Topic tags (process-mode taxonomy à la Bonnitta Roy): craft · technosphere · ways-of-knowing · process-metaphysics · interiority · soma · cosmos · planetary

URL Author Platform Topics
https://blog.codinghorror.com/feed/ Jeff Atwood blog craft
https://mariozechner.at/ Mario Zechner blog craft
https://lucumr.pocoo.org/ Armin Ronacher blog craft
https://overreacted.io/rss.xml Dan Abramov blog craft
https://www.joshwcomeau.com/rss.xml Josh Comeau blog craft
https://mathiasbynens.be/notes.rss Mathias Bynens blog craft
https://kentcdodds.com/blog/rss.xml Kent C. Dodds blog craft
https://wincent.dev/blog.rss Greg Hurrell blog craft
https://dayvster.com/rss.xml Dayvster blog craft
https://simonwillison.net/atom/everything/ Simon Willison blog technosphere, craft
https://meaningness.substack.com/feed David Chapman substack ways-of-knowing
https://bonnittaroy.substack.com/feed Bonnitta Roy substack process-metaphysics
https://davidbessis.substack.com/feed David Bessis substack ways-of-knowing
https://riverkenna.substack.com/feed River Kenna substack ways-of-knowing
https://morphenius.substack.com/feed Michael Smith substack interiority
https://michaelashcroft.com/notes/index.xml Michael Ashcroft blog interiority
https://footnotes2plato.substack.com/feed Matthew Segall substack process-metaphysics
https://gsnv.substack.com/feed Bonnitta Roy substack process-metaphysics, technosphere
https://www.youtube.com/feeds/videos.xml?channel_id=UCHnyfMqiRRG1u-2MsSQLbXA Veritasium youtube cosmos
https://www.youtube.com/feeds/videos.xml?channel_id=UCXPHFM88IlFn68OmLwtPmZA Greg Hurrell youtube craft
https://www.youtube.com/feeds/videos.xml?channel_id=UCInsOr-TZKJg-SQNc3ITjFA Seth Dellinger youtube interiority
https://www.youtube.com/feeds/videos.xml?channel_id=UCs7nPQIEba0T3tGOWWsZpJQ Like Stories of Old youtube interiority, process-metaphysics
https://www.youtube.com/feeds/videos.xml?channel_id=UCtagZg14RFF2pWZcUSt28rA Matthew Segall youtube process-metaphysics
https://www.youtube.com/feeds/videos.xml?channel_id=UC6zHDj4D323xJkblnPTvY3Q O.G. Rose youtube process-metaphysics
https://www.youtube.com/feeds/videos.xml?channel_id=UCoajvyVAjKEib4wHlIxmG_A Mike Hellwig youtube interiority
https://www.youtube.com/feeds/videos.xml?channel_id=UCPCiBMarvDiTx-lknzt934g Ido Portal youtube soma
https://www.youtube.com/feeds/videos.xml?channel_id=UC1yNl2E66ZzKApQdRuTQ4tw Sabine Hossenfelder youtube cosmos
https://www.youtube.com/feeds/videos.xml?channel_id=UC_ruB7qtdk4KufASPRuWhZA GMB Fitness youtube soma
https://aicoding.leaflet.pub/rss Chad Fowler blog craft, technosphere
https://charitydotwtf.substack.com/feed Charity Majors substack technosphere, craft
https://www.computerenhance.com/feed Casey Muratori substack craft
https://www.youtube.com/feeds/videos.xml?channel_id=UCuWsua1_gQ0inbBTqxmYuIQ Frank Yang youtube soma, interiority
https://www.youtube.com/feeds/videos.xml?channel_id=UCORX3Cl7ByidjEgzSCgv9Yw Anastasi In Tech youtube technosphere
https://www.youtube.com/feeds/videos.xml?channel_id=UCpcvPcHJVOkO9Qp79BOagTg Brad Stanfield youtube soma
https://www.youtube.com/feeds/videos.xml?channel_id=UCPR4DV8qMQVs_YBa-CQZQBQ Jake Van Clief youtube technosphere, craft
https://www.youtube.com/feeds/videos.xml?channel_id=UC2r6quRlj_KdT7QBPjB3GsA The Machian youtube cosmos
https://www.youtube.com/feeds/videos.xml?channel_id=UCz7Gx6wLCiPw3F-AmXUvH8w The Well youtube cosmos, process-metaphysics
https://www.youtube.com/feeds/videos.xml?channel_id=UChGMgfuwNjUwoCsfH38ZeNQ Mars Chroniken youtube cosmos, technosphere
https://www.youtube.com/feeds/videos.xml?channel_id=UCDsQqlrzoc-K32DE-Wh-roA Johannes Niederhauser youtube process-metaphysics
https://www.youtube.com/feeds/videos.xml?channel_id=UC1FD7JbC1p6PvlL0NBIiDtQ Spencer Greenberg youtube interiority, ways-of-knowing
https://www.youtube.com/feeds/videos.xml?channel_id=UCQgu_52prnkww28lCIgZEPA Jack Thompson youtube soma
https://www.youtube.com/feeds/videos.xml?channel_id=UClN5MMZ-uzoWEN8ZhH-1NiQ Nil Teisner youtube soma
https://www.youtube.com/feeds/videos.xml?channel_id=UCpVvjcOjp6uTN9AsgIDGlcA Hak youtube technosphere, craft
https://www.youtube.com/feeds/videos.xml?channel_id=UCKeq9IUfzw-QvDKP7N9K8rw Voicecraft youtube process-metaphysics
https://www.youtube.com/feeds/videos.xml?channel_id=UC27eC_usQzXTj9dK8JLDLwQ Science Petr youtube cosmos
https://www.youtube.com/feeds/videos.xml?channel_id=UC2AHH7osxgapbN-8hdjK20w Michael Eckert youtube soma
https://www.youtube.com/feeds/videos.xml?channel_id=UCU0DZhN-8KFLYO6beSaYljg Tom Merrick youtube soma
https://www.youtube.com/feeds/videos.xml?channel_id=UC2Zs9v2hL2qZZ7vsAENsg4w Justin Sung youtube ways-of-knowing
https://www.youtube.com/feeds/videos.xml?channel_id=UCWJOjGOpN8oSVr_OoJLzk9g Nate Hagens youtube planetary
https://www.youtube.com/feeds/videos.xml?channel_id=UCocSoHuhqV07Vsju_mXm-yg Rich Blundell youtube planetary
https://tvachaw.substack.com/feed Vacha substack soma, ways-of-knowing
https://bricolage.io/rss.xml Kyle Mathews blog technosphere
https://vaughntan.org/ Vaughn Tan blog technosphere, craft, ways-of-knowing

Dependencies

Library Version Purpose
daisyui 5 UI components via CDN link tag
@tailwindcss/browser 4 Utility CSS via CDN script tag
solid-js latest Reactive signals, memos, effects, For/Show components
solid-js/web latest DOM rendering via render()
solid-js/html latest No-build tagged template literal UI (html\...``)

State (localStorage)

Key Type Description
rss-feeds JSON string of [url, feed][] Cached feed data
rss-search string Current search query
rss-tab "author" | "platform" | "topics" Active sidebar tab; defaults to "author"
rss-filter string or absent Selected value in the active tab's dimension; absent = no filter (All)
rss-age number (ms) or absent Age limit; absent = ∞
rss-velocity number (posts/week) or absent Velocity limit; absent = ∞
rss-slider-mode "age" | "velocity" Active slider mode; defaults to "age"

State (SolidJS)

Signals via createSignal, derived values via createMemo, side effects via createEffect.

Name Type Description
feeds Signal<Map<url, {title, items[]}>> All cached feed data
search Signal<string> Current search query
tab Signal<"author"|"platform"|"topics"> Active sidebar tab dimension
filter Signal<string|null> Selected value in the active dimension; null = show all
ageLimit Signal<number|null> Max item age in ms; null = ∞
velocityLimit Signal<number|null> Max posts/week; null = ∞
sliderMode Signal<"age"|"velocity"> Which slider mode is active
feedList Memo<[url, feed][]> All feeds as array
activeFeedList Memo<[url, feed][]> Feeds filtered by current slider mode/value
categoryValues Memo<string[]> Distinct values of the active dimension across activeFeedList (topic lists flattened), alphabetical
allItems Memo<Item[]> All items across all feeds, sorted newest-first
ageLimitedItems Memo<Item[]> allItems filtered by age or velocity mode
visibleItems Memo<Item[]> ageLimitedItems filtered by filter (via FEED_META on the active dimension; topics match any tag) and search
last24hCount Memo<number> Count of items published in the last 24h

Key Functions

fetchFeed(url)

Fetches XML via https://proxy.namjul.deno.net/?url=<encoded>, returns parsed {title, items[]}.

parseFeed(xml, url)parseRSS / parseAtom

Detects RSS vs Atom by root element tag (rss/rdf:rdf → RSS, feed → Atom). Per-item fields: id, title, link, author, topics, pubDate, snippet, wordCount. Atom uses only <published> for pubDate (not <updated>).

refreshFeed(url)

Fetches a single feed and merges new/updated items into the feeds signal, preserving existing items not in the fresh response.

refreshAll()

Calls refreshFeed for every URL in FEEDS concurrently.

refreshCategory(value)

Calls refreshFeed for every feed whose active-dimension category matches value (for topics: any tag matches).

User Interactions

  1. On load: render from localStorage immediately, then refresh all feeds in the background — UI updates as each feed resolves
  2. Filter by category: pick a tab (author/platform/topics), click a value row → single-select; click again or "All" to clear; switching tabs clears the selection
  3. Filter by age/velocity: drag slider; click slider label to toggle mode
  4. Read: click article row → link opens in new tab, item marked read
  5. Search: type in search box → filters by title/author in real time
  6. Refresh: click ↻ on a value row → re-fetch every feed in that category