Chrome extension that collects web stories and recipes into EPUB ebooks. One story or recipe = one chapter. Built with React, Vite, TypeScript, Tailwind, and shadcn/ui.
npm install
npm run buildLoad the dist folder as an unpacked extension: chrome://extensions → Developer mode → Load unpacked → select dist.
- Current book is shown (title and chapter count).
- Add this page as chapter — main button adds the current page to the current book and closes the popup.
- Dropdown (▼) — choose another book to add the page to without changing the current book; popup stays open.
- My book — edit, export, manage — opens the options page.
Two tabs:
- Current book — Edit title/author, reorder or remove chapters, Preview, Export EPUB, Start new book. Use Manage another book → to switch to My books.
- My books — List of all saved books. For each book you can:
- Manage — Expand to edit title/author, reorder or remove chapters, Preview, Export, Set as current, or Delete. No need to set a book as current just to edit it.
- Quick actions: Preview (eye), Set as current (book icon), Export, Delete.
If a chapter’s title was wrong when you added it (e.g. before you set a custom headline), click the refresh icon (↻) next to the chapter title in the chapter list. The extension opens the page in the background, re-reads the title using your current headline rules, and updates the chapter.
On any site, right‑click the element that should be the story title (e.g. the main heading) → Set as headline for this site. That selector is saved per host and used when adding or re-fetching titles.
On food blogs, the extension detects Recipe (JSON-LD or microdata) and extracts ingredients and instructions. Recipe units are converted to metric (cups → ml, tbsp/tsp → ml, oz/lb → g, °F → °C) for the saved chapter.
From the options page, Preview or the eye icon on a book opens the built-in reader: sidebar with chapters and “View original” per chapter.
- Extension: Manifest V3, React 18, Vite, TypeScript
- UI: Tailwind CSS v4, shadcn-style components (Button, Card, Input, Label, Tabs, DropdownMenu, etc.)
- Extraction: @mozilla/readability in the content script; Recipe detection via JSON-LD/microdata
- EPUB: Generated in the browser with JSZip (OPF, NCX, XHTML chapters)
| Path | Purpose |
|---|---|
popup.html / src/popup/ |
Popup UI (add chapter, current book, book dropdown, link to options) |
options.html / src/options/ |
Options: Current book + My books (edit, reorder, remove, export, preview, re-fetch title) |
reader.html / src/reader/ |
In-extension book reader (sidebar + chapter content) |
src/background/ |
Service worker: context menu “Set as headline”, relay EXTRACT/GET_PAGE_TITLE, REFETCH_CHAPTER_TITLE (open tab, get title, close) |
src/content/ |
Readability + Recipe extraction, headline selector, metric conversion, message handlers |
src/lib/storage.ts |
Books and chapters in chrome.storage.local |
src/lib/epub.ts |
EPUB build and download |
src/lib/host-selectors.ts |
Per-host headline selectors (right-click “Set as headline”) |
src/components/ui/ |
Shared UI components |
public/manifest.json |
Extension manifest (copied to dist) |
npx shadcn@latest add <component-name>Example: npx shadcn@latest add scroll-area --yes. Config: components.json.