{"id":50682988,"url":"https://github.com/techjewel/mdread","last_synced_at":"2026-06-08T20:30:25.385Z","repository":{"id":360716673,"uuid":"1251406007","full_name":"techjewel/mdread","owner":"techjewel","description":"A quiet reading room for your markdown — local-first, privacy-first reader. Drop a file or folder, read, edit, download. No backend. Live: https://mdread.app","archived":false,"fork":false,"pushed_at":"2026-05-27T14:46:33.000Z","size":876,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-27T16:25:11.378Z","etag":null,"topics":["cloudflare-workers","local-first","markdown","markdown-editor","markdown-reader","offline-first","privacy","pwa"],"latest_commit_sha":null,"homepage":"https://mdread.app","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/techjewel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-27T14:45:17.000Z","updated_at":"2026-05-27T16:09:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/techjewel/mdread","commit_stats":null,"previous_names":["techjewel/mdread"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/techjewel/mdread","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techjewel%2Fmdread","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techjewel%2Fmdread/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techjewel%2Fmdread/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techjewel%2Fmdread/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/techjewel","download_url":"https://codeload.github.com/techjewel/mdread/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techjewel%2Fmdread/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34080025,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudflare-workers","local-first","markdown","markdown-editor","markdown-reader","offline-first","privacy","pwa"],"created_at":"2026-06-08T20:30:23.497Z","updated_at":"2026-06-08T20:30:25.376Z","avatar_url":"https://github.com/techjewel.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mdread\n\n**A quiet reading room for your markdown.** Drop a file or a whole folder, read it\nbeautifully, edit it in place, and download it — all in the browser. Local-first:\nyour files never leave your device. Deploys to Cloudflare in one command.\n\n🔗 **Live: [mdread.app](https://mdread.app)** · MIT licensed · no backend · no tracking\n\n[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/techjewel/mdread)\n\n![mdread](public/og-image.png)\n\n## What it does\n\n- 📂 **Open a folder or files** — via the native file picker, or just **drag \u0026 drop**\n  anything onto the page (a single `.md`, a stack of files, or an entire folder tree).\n- 📖 **Read** — typography tuned for hours of long-form reading, using your OS's\n  native reading serif (New York on Apple, Georgia elsewhere — no web fonts to\n  download): comfortable measure and leading, oldstyle figures, a table of contents\n  with scroll-spy, and a reading-progress bar.\n- ✍️ **Edit** — Read / Split / Edit views. On Chrome \u0026 Edge, **Save writes straight\n  back to the original file on disk** (File System Access API). Elsewhere it downloads.\n- ⬇️ **Download** any document as a clean `.md`.\n- 🎨 **Day / Sepia / Night** themes, adjustable text size, line width, typeface, and\n  an optional drop cap.\n- 🔌 **Offline** — installable PWA; the app shell is cached, so it works with no network.\n- 🧠 **Remembers** your last folder, your last document, your reading position, and your\n  preferences across visits.\n\nEverything runs client-side with three small markdown libraries\n([marked](https://marked.js.org), [DOMPurify](https://github.com/cure53/DOMPurify),\n[highlight.js](https://highlightjs.org)) bundled and self-hosted, and **system fonts\nonly** — no external requests at runtime.\n\n## Develop locally\n\n```bash\nnpm install\nnpm run dev          # Vite dev server with hot reload → http://localhost:5173\n```\n\nEdit anything under `src/` and the page reloads. To check a production build the\nway it's actually deployed:\n\n```bash\nnpm run build        # bundles + compiles SCSS into ./dist\nnpm run preview      # serves ./dist → http://localhost:4173\n```\n\n\u003e **Note on editing:** live \"save to disk\" needs the File System Access API\n\u003e (Chrome/Edge, and over `http://localhost` or HTTPS). In other browsers files open\n\u003e read-only and edits download as new files. Reading works everywhere.\n\n## Deploy to Cloudflare\n\n### One-click (no CLI)\n\n[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/techjewel/mdread)\n\nCloudflare clones this repo into your own GitHub, runs `npm run build`, and deploys\nto a free `*.workers.dev` URL on your account. Every push to your copy then\nauto-builds and deploys via Workers Builds. (The `mdread.app` custom domain lives in\nthe `production` environment, which the button doesn't use — you get your own URL.)\n\n### From the CLI\n\nBoth paths below build first, then publish `./dist`.\n\n#### Workers (recommended, uses `wrangler.jsonc`)\n\n```bash\nnpm install\nnpx wrangler login   # or set CLOUDFLARE_ACCOUNT_ID for non-interactive / CI deploys\nnpm run deploy       # → a free *.workers.dev URL (what a fork gets out of the box)\nnpm run deploy:prod  # → your custom domain (uses the `production` env in wrangler.jsonc)\n```\n\n`wrangler.jsonc` doesn't hardcode an account or domain: the account comes from\n`wrangler login` (or `CLOUDFLARE_ACCOUNT_ID`). The base config publishes to\n`*.workers.dev`; the `env.production` block carries the custom domain, so\n`deploy:prod` is the one that goes live on a real domain. To use your own domain,\nchange `name` and the `pattern` under `env.production.routes`.\n\n#### Cloudflare Pages\n\n```bash\nnpm run build\nnpx wrangler pages deploy dist --project-name markread\n# or: npm run deploy:pages\n```\n\n…or in the Cloudflare dashboard: **Pages → Create → Connect/Direct upload**. Build\ncommand `npm run build`, output directory `dist`.\n\n## Keyboard shortcuts\n\n| Key | Action |\n| --- | --- |\n| `⌘/Ctrl + O` | Open folder |\n| `⌘/Ctrl + S` | Save (to disk, or download) |\n| `⌘/Ctrl + E` | Toggle edit |\n| `⌘/Ctrl + \\` | Toggle sidebar |\n| `t` | Toggle table of contents |\n| `f` | Focus mode |\n| `/` | Search files |\n| `Esc` | Exit focus / close popover |\n\n## Project layout\n\n```\nindex.html            app shell (Vite entry)\nsrc/\n  main.js             entry: imports styles, wires the UI, boots the app\n  modules/            one concern per file — files, tree, document, editor,\n                      save, markdown, recents, scroll, view, ui, keyboard, …\n  styles/             SCSS partials assembled by main.scss (themes, typography, layout)\npublic/               static assets copied verbatim: icons, manifest, og-image\nvite.config.js        build + PWA service-worker config\nwrangler.jsonc        Cloudflare Workers Assets config (serves ./dist)\n```\n\nNo framework — plain ES modules and SCSS. The service worker is generated by\n`vite-plugin-pwa`. See [`CLAUDE.md`](CLAUDE.md) for an architecture tour and\n[`CONTRIBUTING.md`](CONTRIBUTING.md) to get started.\n\n## Privacy\n\nThere is no server, no analytics, and **no external requests at runtime** — not\neven web fonts (the app uses your operating system's native fonts). Files are read\nin your browser; the only persistence is local (IndexedDB stores folder handles so\nthey can be reopened; `localStorage` stores preferences and reading positions).\n\n## Contributing\n\nIssues and PRs welcome — see [`CONTRIBUTING.md`](CONTRIBUTING.md) and the\n[`Code of Conduct`](CODE_OF_CONDUCT.md). The app is plain ES modules in `src/modules/`\nand SCSS in `src/styles/`, so it's quick to find your way around.\n\n## License\n\n[MIT](LICENSE) © techjewel\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftechjewel%2Fmdread","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftechjewel%2Fmdread","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftechjewel%2Fmdread/lists"}