{"id":49384463,"url":"https://github.com/cxro/astro-whono","last_synced_at":"2026-05-03T06:13:02.944Z","repository":{"id":344170750,"uuid":"1135832672","full_name":"cxro/astro-whono","owner":"cxro","description":"一个极简双栏 Astro 主题，用于个人写作与轻量内容发布。","archived":false,"fork":false,"pushed_at":"2026-04-28T07:13:11.000Z","size":16752,"stargazers_count":105,"open_issues_count":1,"forks_count":33,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-28T08:32:47.175Z","etag":null,"topics":["astro","astro-theme","blog","markdown","minimal","personal-website","static-site","theme","typography"],"latest_commit_sha":null,"homepage":"https://astro.whono.me","language":"TypeScript","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/cxro.png","metadata":{"files":{"readme":"README.en.md","changelog":"CHANGELOG.md","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-01-16T16:51:58.000Z","updated_at":"2026-04-28T07:05:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cxro/astro-whono","commit_stats":null,"previous_names":["cxro/astro-whono"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/cxro/astro-whono","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cxro%2Fastro-whono","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cxro%2Fastro-whono/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cxro%2Fastro-whono/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cxro%2Fastro-whono/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cxro","download_url":"https://codeload.github.com/cxro/astro-whono/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cxro%2Fastro-whono/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32559731,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T03:21:47.309Z","status":"ssl_error","status_checked_at":"2026-05-03T03:21:43.884Z","response_time":103,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["astro","astro-theme","blog","markdown","minimal","personal-website","static-site","theme","typography"],"created_at":"2026-04-28T08:07:40.201Z","updated_at":"2026-05-03T06:13:02.895Z","avatar_url":"https://github.com/cxro.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# astro-whono\n\n[中文](README.md) | [English](README.en.md)\n\n[![CI](https://img.shields.io/github/actions/workflow/status/cxro/astro-whono/ci.yml?style=flat\u0026label=CI\u0026labelColor=2E3440\u0026color=A3BE8C\u0026logo=githubactions\u0026logoColor=ECEFF4)](https://github.com/cxro/astro-whono/actions/workflows/ci.yml)  [![Node](https://img.shields.io/badge/Node-%3E%3D22.12.0-81A1C1?style=flat\u0026labelColor=2E3440\u0026logo=nodedotjs\u0026logoColor=ECEFF4)](README.en.md#requirements)  [![Astro](https://img.shields.io/github/package-json/dependency-version/cxro/astro-whono/astro?branch=main\u0026style=flat\u0026label=Astro\u0026labelColor=2E3440\u0026color=BC52EE\u0026logo=astro\u0026logoColor=ECEFF4)](https://docs.astro.build/)  [![License](https://img.shields.io/badge/License-MIT-4C566A?style=flat\u0026labelColor=2E3440\u0026logo=opensourceinitiative\u0026logoColor=ECEFF4)](LICENSE)\n\n**✨ astro-whono is now upgraded to Astro v6**\n\nA minimal two-column Astro theme for personal writing and lightweight publishing.\n\n## Links\n\n- Live demo: \u003chttps://astro.whono.me\u003e\n- Repository: \u003chttps://github.com/cxro/astro-whono\u003e\n\n\n## Preview\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"public/preview-light.png\" width=\"49%\" alt=\"Light preview\" /\u003e\n  \u003cimg src=\"public/preview-dark.png\" width=\"49%\" alt=\"Dark preview\" /\u003e\n\u003c/p\u003e\n\n\n## Features\n\n- Two-column layout (sidebar navigation + content area)\n- Responsive design for mobile devices\n- Content collections: essay / bits / memo (archive is generated from essay)\n- Built-in local Admin Console (`/admin`): use Theme / Images / Checks / Data Console in development to manage site settings and assets, and take over the theme after forking or cloning\n- Bits draft generator on `/bits/`: one-click Markdown output (copy/download), with multi-image support and automatic image dimension detection\n- RSS: default archive feed + section feeds\n- Light / dark theme + reading mode\n\n\n## Getting Started\n\n### Requirements\n\n- Node.js 22.12+ (`.nvmrc` recommended)\n\n\n### Quick Start\n\n```bash\nnpm i\n# Repeatable install (recommended for CI/troubleshooting)\n# npm ci\nnpm run dev\nnpm run build \u0026\u0026 npm run preview\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eWindows (PowerShell) note\u003c/summary\u003e\n\nIf execution policy blocks `npm.ps1`, use one of the following:\n\n- `cmd /c npm run ...`\n- Or use Git Bash / WSL\n\u003c/details\u003e\n\n\n### Common Commands\n\n  - npm run dev\n  - npm run build\n  - npm run ci\n  - npm run new:bit\n\n\u003cdetails\u003e\n  \u003csummary\u003eCheck and regression commands\u003c/summary\u003e\n\nUse them depending on the situation:\n\n```bash\n# Default regression entry (GitHub Actions)\nnpm run ci\n\n# Manual release verification for absolute links / sitemap / RSS (requires the final production domain)\nSITE_URL=https://your-domain npm run build\nSITE_URL=https://your-domain npm run check:prod-artifacts\n\n# Only when changing Admin Console subroutes, /api/admin/** static boundaries, or dev/prod read-only boundaries\nnpm run check:preview-admin\n```\n\n- `npm test` mainly covers tag utilities, shared Theme Console validation rules, and core pure-logic regressions around theme settings `revision`.\n- `npm run ci` is the default regression entry; `npm run ci:core` is only for faster local incremental checks.\n- `npm run build` still works without `SITE_URL`, but SEO-related outputs will be incomplete.\n- Before release, if you need to verify absolute-link artifacts, set a real `SITE_URL` and run `npm run check:prod-artifacts`.\n\u003c/details\u003e\n\n\n## Deployment\n\n### One-click Deploy\n\n[![Deploy to Vercel](https://img.shields.io/badge/Deploy-Vercel-000000?style=flat\u0026logo=vercel\u0026logoColor=white)](https://vercel.com/new/clone?repository-url=https://github.com/cxro/astro-whono)\u0026nbsp;\u0026nbsp;[![Deploy to Netlify](https://img.shields.io/badge/Deploy-Netlify-00C7B7?style=flat\u0026logo=netlify\u0026logoColor=white)](https://app.netlify.com/start/deploy?repository=https://github.com/cxro/astro-whono)\u0026nbsp;\u0026nbsp;[![Deploy to Cloudflare Pages](https://img.shields.io/badge/Deploy-Cloudflare%20Pages-F38020?style=flat\u0026logo=cloudflare\u0026logoColor=white)](https://dash.cloudflare.com/?to=/:account/workers-and-pages)\n\n\u003e For production, set: `SITE_URL=https://your-domain` (without a trailing slash).\n\u003e If not set, the site can still run, but link metadata for sharing/indexing may be incomplete.\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eCloudflare Pages deployment (manual repository import)\u003c/strong\u003e\u003c/summary\u003e\n\n**Build settings**\n- Framework preset: `Astro`\n- Build command: `npm run build`\n- Output directory: `dist`\n\n**Node.js version (usually not required)**\n- This project includes `.nvmrc`, and Cloudflare Pages reads it automatically.\n- If you need to set it manually, add `NODE_VERSION=22.22.0` in environment variables.\n\n**Environment variables (strongly recommended for production)**\n- In Pages project -\u003e Settings -\u003e Environment variables, add: `SITE_URL=https://your-domain` (for example `https://astro.whono.me`, without a trailing `/`).\n\n**Why set `SITE_URL`?**\n- Astro uses it to generate canonical, Open Graph `og:url`, RSS links, sitemap, and other fields that require absolute URLs. Without `SITE_URL`, deployment still works, but these links may fall back to relative paths or placeholder domains, which can hurt share previews and search indexing.\n\n**About sitemap / robots**\n- `sitemap` is generated only when `SITE_URL` is set, and `/robots.txt` includes a `Sitemap:` line only in that case (to avoid pointing to the wrong domain).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003ePost-deploy checklist\u003c/strong\u003e\u003c/summary\u003e\n\n- Home page / list pages / detail pages are accessible\n- RSS endpoints are accessible (`/rss.xml` and section feeds)\n- With `SITE_URL` set: canonical / `og:url` point to your domain\n- No network requests to demo-domain resources\n\n\u003c/details\u003e\n\n\n## Configuration and Entry Points\n\n### Project Entry Points\n\n- Site config: `site.config.mjs`\n- Content collections: `src/content.config.ts`\n- Shared style entry: `src/styles/global.css`\n- Page / scene style entries: `src/styles/home.css`, `src/styles/about.css`, `src/styles/memo.css`, `src/styles/article.css`, `src/styles/bits-page.css`\n- Admin style entry: `src/styles/components/admin-shell.css` + route-specific Admin styles; the full `admin.css` aggregate is no longer provided\n\n### Admin Console (`/admin`)\n\nastro-whono includes a local Admin Console as the development entry point for viewing the site overview, adjusting theme settings, and importing/exporting settings snapshots.\n\n#### Admin Entry Points\n\nAdmin Console is intended for **local development** by default.\n\nStart the dev server:\n\n```bash\nnpm install\nnpm run dev\n```\n\nThen open `http://localhost:4321/admin/` in your browser.\n(If you changed the dev server port, replace `4321` with your actual port.)\n\n| Entry | Status | Purpose |\n| :---: | :---: | :--- |\n| `/admin/` | Available | Stable Admin entry and Site Overview |\n| `/admin/theme/` | Available | Theme Console for editing site information, sidebar, home page, inner-page copy, and more |\n| `/admin/images/` | Available | Image resource browser and path helper |\n| `/admin/checks/` | Available | Structured diagnostics and pre-release checks |\n| `/admin/data/` | Available | Settings snapshot export / dry-run import / confirmed write |\n| `/admin/content/` | In progress | Placeholder for content management and visual writing |\n\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e🖼️ Theme Console Overview \u003c/strong\u003e\u003c/summary\u003e\n\nastro-whono provides a local Theme Console for centralized theme-level configuration in development.\u003cbr\u003e\n\n#### Current Theme Console Support\n\nTheme Console mainly covers **site-level** and **page-level** settings, including:\n\n- Site title, description, brand name, and other basic metadata\n- `/admin/` Overview public visibility and hidden-state copy\n- Home intro copy and Hero image settings\n- Sidebar navigation labels, visibility, and ordering\n- Social links and custom social items\n- Footer copyright line / basic footer copy\n- Main title and subtitle for fixed inner pages\n- Article metadata display rules\n- Default author for the `/bits/` page\n\nFor more details, see the [Theme Console configuration guide](https://astro.whono.me/archive/theme-console-guide/).\n\n\u003cbr\u003e\n\u003c/details\u003e\n\n#### Production behavior\n\n- Theme Console / Data Console provide write capabilities only in local development; Content Console is still a placeholder.\n- `/admin/content/` and `/admin/content/:collection/` currently only show the work-in-progress notice; collection overview, details, and frontmatter editing are not exposed.\n- Production builds remain static output. `/admin/` can show a read-only public Overview or a hidden-state message based on Theme settings; production does not show Admin tabs, and other Admin subroutes only keep a local-development notice.\n- `/api/admin/settings/` is for local development only and should not be treated as a production API\n- `/api/admin/content/entry/` is for local development frontmatter writes only and should not be treated as a production API\n- `/api/admin/data/settings/` is for local development settings export only and should not be treated as a production API\n\n#### Compatibility for existing forks\n\n- If `src/data/settings/*.json` does not exist yet, the frontend still reads config via `settings \u003e legacy \u003e default`\n- The JSON files are generated only after the first save in `/admin/theme/`, so no manual migration script is required\n\n\n## Content and Writing\n\n### Collections and Routes\n\nContent Collections:\n- Essay: `src/content/essay`\n- Bits: `src/content/bits`\n- Memo: `src/content/memo/index.md`\n- Archive: generated from essay entries via the `archive` field\n\nMain routes:\n- List pages: `/archive/`, `/essay/`, `/bits/`, `/memo/`, `/about/`\n- Canonical detail route: `/archive/[slug]` (`/essay/[slug]` remains as a compatibility redirect)\n\n### Image Assets\n\n- Images inside article content: prefer `src/content/**` or `src/assets/**`, so Astro can process and optimize them during build\n- `/bits/` images: place them under `public/bits/**` and use the actual file path, for example `bits/demo-01.jpg`\n- Default avatar for `/bits/`: place it under `public/author/**` and use the actual file path, for example `author/your-avatar.png`\n- Home Hero: supports `src/assets/**`, `public/**`, and `https://` image URLs\n- If you need a public direct URL, or do not want Astro to process the asset, place it under `public/**`\n\n\n### Core Frontmatter Fields\n\nEssay:\n```yaml\ntitle: My Post\ndate: 2026-01-01\ndraft: false        # Draft: hidden from list/RSS in production (visible in local preview; default false, optional)\narchive: true       # Archive switch: false excludes it from /archive and /archive/rss.xml (default true; detail page and /essay remain available)\nslug: optional      # Custom URL slug (defaults to the flattened content path, e.g. 2024/my-post -\u003e 2024-my-post)\nbadge: optional     # List badge; if omitted, list shows \"Essay\"\n```\n\nBits:\n```yaml\ndate: 2026-01-01T12:00:00+08:00 # Example; generator outputs local timezone\ntags:                           # Optional tags (defaults to empty array)\n  - loc:Shenzhen                # Location tag format: loc:\u003cplace\u003e; only the first one is displayed\n  - reading\nimages:                         # Optional: multi-image list (dimensions reduce CLS)\n  - src: bits/demo-01.webp      # Supports relative path bits/... or absolute URL https://...\n    width: 800\n    height: 800\n# draft: true   # Optional draft; visible in `dev`, hidden by default in `build/preview` and production\n```\n\n`/bits/` does not currently generate detail routes from `slug`, nor does it render it as visible UI text; unless you are extending the theme, you usually do not need to set it.\n\nAuthor info (on `/bits/` only):\n\n- Default author and avatar are read from Theme Console via `page.bits.defaultAuthor`; if `src/data/settings/page.json` does not exist yet, they fall back to `site.author` / `site.authorAvatar` in `site.config.mjs`\n- `authorAvatar` should be a relative image path only (no `public/`, no leading `/`), for example: `author/avatar.webp`; the file must actually exist under `public/**`\n- Per-bit overrides are supported via `author` in frontmatter:\n\n```yaml\nauthor:\n  name: Alice\n  avatar: author/alice.webp\n```\n- Per-bit `author.avatar` follows the same rule as the default avatar: it must be a relative image path pointing to an existing file under `public/**`\n\n- If the avatar is missing or fails to load, it automatically falls back to an initial-based avatar.\n\n\n### Excerpt and Description (`description`)\n\n- List excerpt is generated from content by default (sanitized and truncated)\n- Use `\u003c!-- more --\u003e` to define excerpt split point\n- `description` is used for SEO/OG (meta description) only and does not affect list excerpts\n\n\n### Writing Conventions (Content Blocks)\n\n- Callout: recommended directive syntax `:::note[title] ... :::` (`note` / `tip` / `info` / `warning`); in HTML form use `.callout-title`, and use `data-icon=\"none\"` to hide icon\n- Figure: `figure \u003e (img|picture) + figcaption?`\n- Gallery: `ul.gallery \u003e li \u003e figure \u003e (img|picture) + figcaption?` (optional `cols-2` / `cols-3`)\n- Quote: standard `blockquote`, optional `cite` for source\n- Pullquote: `blockquote.pullquote`\n- Code Block: toolbar / copy button / line numbers are enhanced at build time (no extra author-side syntax needed)\n\nCallout example:\n\n```md\n:::note[Note]\nBody text goes here...\n:::\n```\n\nHTML example:\n\n```html\n\u003cdiv class=\"callout note\"\u003e\n  \u003cp class=\"callout-title\" data-icon=\"none\"\u003eNote\u003c/p\u003e\n  \u003cp\u003eBody text goes here...\u003c/p\u003e\n\u003c/div\u003e\n```\n\n\n## Fonts and Licensing\n\nThis theme uses two typeface families (self-hosted + subsetted):\n- Noto Serif SC (400 / 600)\n- LXGW WenKai Lite (Regular)\n\nThe repository includes subsetted WOFF2 files (`latin` / `cjk-common` / `cjk-ext`, loaded on demand via `unicode-range`), so you can use the project immediately after cloning.\nSubset charset is generated from repository text plus `tools/charset-base.txt` (3,500 common characters) to reduce missing-glyph cases.\n\nTo regenerate font subsets:\n1. Install Python 3, then run `python -m pip install fonttools brotli zopfli`\n2. Make sure `pyftsubset --help` works; if it does not, add the Python Scripts directory to `PATH`\n3. Put the source fonts in `tools/fonts-src/`\n4. Run `npm run font:build`\n5. If glyphs are missing, add the characters to `tools/charset-base.txt` and rerun `npm run font:build`\n6. `tools/charset-common.txt` is regenerated by `npm run font:charset`; do not edit it unless you only want to rerun `npm run font:subset`\n\n\u003cdetails\u003e\n  \u003csummary\u003eFont file list (subsets + source files)\u003c/summary\u003e\n\nSubset files (tracked in repository):\n- `public/fonts/lxgw-wenkai-lite-latin.woff2`\n- `public/fonts/lxgw-wenkai-lite-cjk-common.woff2`\n- `public/fonts/lxgw-wenkai-lite-cjk-ext.woff2`\n- `public/fonts/noto-serif-sc-400-latin.woff2`\n- `public/fonts/noto-serif-sc-400-cjk-common.woff2`\n- `public/fonts/noto-serif-sc-400-cjk-ext.woff2`\n- `public/fonts/noto-serif-sc-600-latin.woff2`\n- `public/fonts/noto-serif-sc-600-cjk-common.woff2`\n- `public/fonts/noto-serif-sc-600-cjk-ext.woff2`\n\nSource files (not tracked in repository):\n- `tools/fonts-src/LXGWWenKaiLite-Regular.woff2`\n- `tools/fonts-src/NotoSerifSC-Regular.ttf`\n- `tools/fonts-src/NotoSerifSC-SemiBold.ttf`\n\u003c/details\u003e\n\nFont license: SIL Open Font License 1.1 (see `public/fonts/OFL-LXGW-WenKai-Lite.txt` and `public/fonts/OFL-NotoSerifSC.txt`).\n\n\n## RSS\n\n- `/rss.xml` (default feed; uses the same archive items as `/archive/rss.xml`)\n- `/archive/rss.xml` (archive feed)\n- `/essay/rss.xml`\n\nSetting `SITE_URL` is recommended for deployment (affects absolute links in RSS/OG/canonical).\n\n\n## Contributing\n\nIssues are welcome for bug reports and ideas.\nPull requests are welcome; using a `feature/*` branch is recommended.\n\n### Sync Upstream in a Fork\n\n```bash\ngit remote add upstream https://github.com/cxro/astro-whono.git\ngit fetch upstream --tags\ngit checkout main\ngit merge upstream/main\ngit push origin main --tags\n```\n\n\n## Acknowledgements\n\n- Thanks to [elizen/elizen-blog](https://github.com/elizen/elizen-blog), the starting point of this theme design, which is inspired by the Hugo theme [yihui/hugo-ivy](https://github.com/yihui/hugo-ivy)\n\n\n## License\n\nLicense: MIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcxro%2Fastro-whono","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcxro%2Fastro-whono","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcxro%2Fastro-whono/lists"}