[READ-ONLY] Mirror of https://github.com/thang-qt/ThreadLine. Alternative frontend for HackerNews and Lobsters threadline.thangqt.com/
0

Configure Feed

Select the types of activity you want to include in your feed.

Add README screenshots

Quang Thang (Jul 11, 2026, 8:06 PM +0700) fca53e3c 8b298dec

+29 -49
+29 -49
README.md
··· 1 1 # Threadline 2 2 3 - Threadline is a static-first, local-preference reader for community news sources. It currently combines Hacker News and Lobsters, with source metadata and feed contracts organized so additional sources can be added later. The app is a React single-page app with routes for `/` (feed), `/story/:source/:id` (discussion), and `/settings` (preferences). 3 + Threadline is a compact, static-first reader for community news. It combines Hacker News and Lobsters into one local, customizable front page with fast feed loading, source filters, discussion reading, and an optional inline article reader on larger screens. 4 + 5 + Preferences live in `localStorage`; no account or backend database is required. 6 + 7 + ## Screenshots 8 + 9 + ### List layout 10 + 11 + ![Threadline list layout](docs/screenshots/frontpage-list.png) 12 + 13 + ### Grid layout, sepia theme 14 + 15 + ![Threadline grid layout in sepia theme](docs/screenshots/frontpage-grid-sepia.png) 16 + 17 + ### Inline reader and discussion 18 + 19 + ![Threadline read-here split reader](docs/screenshots/read-here.png) 20 + 21 + ## Features 4 22 5 - Preferences are stored only in `localStorage`. The storage key remains `hnster.preferences.v1` intentionally for compatibility with older builds. 23 + - Combined Hacker News and Lobsters feed 24 + - List and newspaper-style grid layouts 25 + - Light, dark, and sepia themes 26 + - Local source, ranking, domain, and Lobsters tag preferences 27 + - Nested discussion view with collapse and comment navigation 28 + - Inline article reader on desktop/tablet 29 + - Static React app deployable on Cloudflare Pages 30 + - Cloudflare Pages Functions for feed aggregation and Lobsters CORS proxy 6 31 7 32 ## Development 8 33 9 - This repository uses pnpm and includes a Nix development shell: 10 - 11 34 ```bash 12 - nix develop # supplies Node 22 and pnpm 35 + nix develop 13 36 pnpm install 14 37 pnpm dev 15 38 ``` 16 39 17 - The Vite server mirrors the Cloudflare API surface in development: 18 - 19 - - `/api/feed` fetches and normalizes the combined front page. 20 - - `/api/lobsters/*` proxies Lobsters JSON discussion/feed endpoints for CORS-safe comment loading. 40 + Checks: 21 41 22 42 ```bash 23 43 pnpm typecheck ··· 25 45 pnpm build 26 46 ``` 27 47 28 - ## Feed architecture 29 - 30 - The browser first requests a same-origin aggregated feed: 31 - 32 - ```text 33 - GET /api/feed?hn=top&lobsters=hottest 34 - ``` 35 - 36 - The Cloudflare Pages Function fetches Hacker News and Lobsters HTML front pages, parses the visible story metadata, and returns a normalized `FeedResult`. If scraping fails or returns suspiciously few stories, it falls back to the public APIs: 37 - 38 - - Hacker News Firebase item API 39 - - Lobsters JSON feed API 40 - 41 - Partial failures return the successful source plus a per-source error so the UI can still render available stories. 42 - 43 - For purely static hosts without the feed aggregation function, the browser falls back to public feed APIs directly. Hacker News can work in that mode, but Lobsters discussions still require a CORS-safe proxy (`VITE_API_PROXY_URL`) unless the app is deployed with the included Cloudflare Pages Function. 44 - 45 - ## Lobsters proxy and deployment 46 - 47 - Lobsters does not reliably permit browser cross-origin requests for discussions. The client therefore calls a proxy base, not Lobsters directly: 48 - 49 - - Default: same-origin `/api/lobsters`, implemented by `functions/api/lobsters/[[path]].ts` on Cloudflare Pages. 50 - - External: set `VITE_API_PROXY_URL` at **build time** to a full proxy base, for example `https://reader-proxy.example.workers.dev/api/lobsters`. Do not include a trailing feed path. 51 - 52 - The proxy only forwards safe endpoint forms: 53 - 54 - - `hottest.json` 55 - - `newest.json` 56 - - `s/<id>.json` 57 - 58 - ## Optional environment variables 59 - 60 - - `VITE_FEED_API_URL`: full URL for an external compatible `/api/feed` endpoint. 61 - - `VITE_API_PROXY_URL`: full URL for an external compatible `/api/lobsters` endpoint. 62 - 63 - Leave both unset on Cloudflare Pages when using the included same-origin functions. 64 - 65 - ## Cloudflare Pages 66 - 67 - Use build command `pnpm build` and output directory `dist`. The repo includes `public/_redirects`, copied into `dist`, to serve `index.html` for non-asset routes so direct visits to `/settings` and `/story/...` work. Cloudflare Pages Functions under `/api/*` are handled separately from this static SPA fallback.
docs/screenshots/frontpage-grid-sepia.png

This is a binary file and will not be displayed.

docs/screenshots/frontpage-list.png

This is a binary file and will not be displayed.

docs/screenshots/read-here.png

This is a binary file and will not be displayed.