AstroBlog

blog (puellamogica) — Astro Blog Template

By puellamogica

An Astro-based Japanese blog theme for Project SEKAI and the character Akiyama Mizuki, featuring public articles and a password-protected vault as two content collections, deployed as a Cloudflare Worker.

Explore the design

Compare the page layouts and mobile experience. Open any screenshot for a closer look.

3 previews
Desktop homepage1 / 3
Desktop captureTop of page

Actual screenshot captured by the server browser.

All pages & views 3

Screenshots show visual appearance; interactive behavior may differ.

Recorded 2026-09-30View source

What stands out

A quick read of the recorded project description.

01

Two content collections: public article and password-protected vault, both plain Markdown (GFM) with schema-validated frontmatter

02

Vault uses a per-article argon2id hash, a Cloudflare Turnstile unlock challenge, D1 unlock sessions with TTL, and per-IP and per-slug rate limits

03

Markdown pipeline supports GFM footnotes/tables/task lists, KaTeX math, reading time, sanitized raw HTML, and eager images

04

Code blocks use Expressive Code with Kanagawa light and dark color schemes, supporting collapsible sections and line numbers

05

Progressive enhancement: Plyr media player, PhotoSwipe lightbox, and Swiper galleries are dynamically imported only on pages that use them

06

Built-in RSS, sitemap, robots.txt, Open Graph / Twitter cards, and instant light/dark theme switching

Template Details

This template is the public repository of puellamogica/blog, positioned as a Japanese blog theme centered on Project SEKAI and the character Akiyama Mizuki. It is built with Astro, and content is written in plain Markdown (GFM, no MDX) across two content collections: public article and password-protected vault. Each vault post uses an argon2id hash, the unlock form includes a Cloudflare Turnstile challenge, unlock sessions are stored in D1 with a TTL, and there are per-IP and per-slug rate limits. The Markdown pipeline supports GFM footnotes, tables, task lists, KaTeX math, reading time, sanitized raw HTML, and eager images; code blocks use Expressive Code with Kanagawa light and dark color schemes, supporting collapsible sections and line numbers. The site also includes client-side category/year filtering (still usable without JavaScript), weather snapshots from a separate crawler Worker (displayed in JST), on-demand dynamic imports of Plyr, PhotoSwipe, and Swiper, plus RSS, sitemap, robots.txt, and Open Graph / Twitter cards. Except for login/[slug], vault/[slug], and api/auth, which are server-rendered, all routes are prerendered. Content lives in a git submodule, article bodies use only h2–h6, and the page h1 is handled by the layout. Drafts are excluded from lists, RSS, sitemap, and generated routes.

AstroBlog

Is it right for your project?

Use Cases

  • Building a Japanese blog themed around Project SEKAI and the character Akiyama Mizuki
  • Writing scenarios where some articles need password protection and the unlock flow should include challenges and rate limits
  • Blogs that want to write in Markdown and automatically get KaTeX formulas, GFM extensions, and code highlighting
  • Projects deployed to Cloudflare Workers using Workers Assets, Cloudflare Images, KV, and D1

Suitable For

  • Developers familiar with Astro, TypeScript, and Cloudflare Workers
  • Personal bloggers who need both public articles and password-protected content
  • Users who accept content managed as a git submodule and are willing to configure bindings per wrangler.jsonc
  • Sites that need basic SEO output such as RSS, sitemap, and social cards

Getting started & customization

Use these recorded setup notes alongside the repository instructions for your chosen version.

  1. 1

    Install dependencies with pnpm install, and initialize the content submodule with git submodule update --init

  2. 2

    Content lives in src/content/article/<slug>.md (public) and src/content/vault/<slug>.md (password-protected); bodies use only h2–h6

  3. 3

    The passwordHash for vault articles must be generated with pnpm hash:vault and must match VAULT_ARGON2_OPTIONS

  4. 4

    Bindings, routes, and rate limits are declared in wrangler.jsonc; secrets are read from the Cloudflare secrets store, and TURNSTILE_SITEKEY is a public variable

  5. 5

    Deploy with pnpm deploy; the Worker is bound to the custom domain 20190716.xyz; related repositories include ../cron (weather crawler) and ../argon2 (password verification service)

Read repository instructions

License & source material

Usage conditions & limitations

Free to use · keep license notice

This listing covers the free version in the public repository under the Apache-2.0 license; the free scope is that version's code and does not mean external services or third-party assets are free.

Must comply with when using

  • Free use, modification, commercial use, and distribution are permitted; when distributing, include the Apache-2.0 license.
  • Modified files must be prominently marked as changed, and relevant copyright, patent, trademark, and attribution notices must be retained.
  • If the original project includes a NOTICE file, applicable attribution notices in it must be retained when distributing derivative works.
  • The license includes an applicable contributor patent grant; initiating patent litigation as described in the license terminates that patent grant, and no trademark rights are granted.
  • The code is provided as-is; warranties and limitations of liability are governed by the original license and applicable law.

Additional costs & items to verify

  • Using this template requires deployment to Cloudflare Workers and depends on paid/account-required Cloudflare services such as Workers Assets, Cloudflare Images, KV, and D1; it is not purely static hosting.
  • The vault unlock form depends on a Cloudflare Turnstile challenge and requires configuring a Turnstile site key and secret, which is an external service dependency.
  • Running it requires configuring secrets such as ARGON2_ENDPOINT, ARGON2_HMAC_SECRET, VERCEL_PROTECTION_BYPASS, and TURNSTILE_SECRET in the Cloudflare secrets store, and requires a self-hosted argon2 verification service.
  • Vault password verification depends on a separate ../argon2 HTTP service, which is not in this repository and must be deployed separately.
  • The weather component depends on a separate ../cron Worker that scrapes OpenWeatherMap to generate weather.json; it must be deployed additionally and may involve an OpenWeatherMap account/API fees.
  • Content is managed as a git submodule, so the submodule must be initialized additionally to obtain article content.
  • The vendored HTML sanitizer in the repository comes from satteri-sanitize (MIT, © Ashish Vaghela); that part of the code is under the MIT license rather than Apache-2.0, and its copyright and license notices must be retained when redistributing.
  • Demo images, fonts, icons, and other third-party assets must be checked against their respective licenses; the code's Apache-2.0 license alone cannot be used to judge them.
  • External services such as domains, hosting, databases, payments, or AI may incur additional charges.
View Original Text Basis

no-charge, royalty-free, irrevocable copyright license

Original License Text

Runtime:** Cloudflare Workers — Workers Assets, Cloudflare Images, KV (sessions), D1 (vault unlocks)

Original README

a Cloudflare Turnstile challenge on the unlock form

Original README

Secrets (`ARGON2_ENDPOINT`, `ARGON2_HMAC_SECRET`, `VERCEL_PROTECTION_BYPASS`, `TURNSTILE_SECRET`) are read from the Cloudflare secrets store

Original README

**`../argon2`** — the HTTP service that verifies vault passwords.

Original README

**`../cron`** — a Worker that crawls OpenWeatherMap and writes the `weather.json` snapshot the weather widget reads.

Original README

git submodule update --init # content lives in a submodule

Original README

The HTML sanitizer in `src/hast/sanitize/` is vendored from [`satteri-sanitize`](https://github.com/Ashish-CodeJourney/satteri-plugins/tree/main/packages/satteri-sanitize) (MIT, © Ashish Vaghela)

Original README
https://github.com/puellamogica/blog/blob/master/LICENSEhttps://github.com/puellamogica/blog/blob/master/README.md

Compiled by DeepSeek based on repository license and README ·2026-10-01. Results only cover the materials read; dependencies, images, fonts, and subsequent term changes are subject to their respective original texts.

Project checks & description sources

Template Information

Source platforms
GitHub
Documentation and maintenance reference score
Partly documented · 72 / 100
Technologies
Astro
Website type
Blog
How this score is calculated

Our heuristic uses license records (up to 30), a demo link (12), a preview (10), stars (15), recorded maintenance (15), description completeness (8), feature records (5) and classification data (5). It is not a code, security or performance test, or a Google score. A link does not establish tested functionality.

What to verify for this project

Repository update recorded
2026-09-29
Screenshot last checked
2026-10-01

A demo link is listed. Check it with your own content and viewport sizes; its presence does not confirm that forms, authentication or payments work.

The catalog identifies Astro as the primary stack. Check the actual dependency manifest and lockfile for versions and hosting requirements. These notes use recorded metadata, not a code audit or a deployment test.

Use a selection guide →

How this description was prepared

AI-assisted description based on catalog records and repository material. Repository authors are not automatically the reviewers of this description.

Automatically checked against source and license rules; no manual editorial review.

Inspect the recorded source material

SHA-256: 16a5d64083954fb3120896e7345bc69b9614c56c8a2fbbf510d30ca2eed01cde

2026-10-01T14:54:34.942Z

Source file / repository
# puellamogica/blog

An astro framework blog theme

A Japanese-language blog about _Project SEKAI_ and the character 暁山 瑞希, built with Astro and deployed as a Cloudflare Worker.

- **Site:** https://20190716.xyz
- **Stack:** Astro 7, TypeScript, Tailwind CSS v4, daisyUI 5
- **Runtime:** Cloudflare Workers — Workers Assets, Cloudflare Images, KV (sessions), D1 (vault unlocks)

## Features

- **Two content collections** — `article` (public) and `vault` (password-gated), both plain Markdown (GFM, no MDX) with schema-validated frontmatter.
- **Password-gated vault** — per-post argon2id hash, a Cloudflare Turnstile challenge on the unlock form, D1-backed unlock sessions with a TTL, and per-IP / per-slug rate limits.
- **Markdown pipeline** — GFM (footnotes, tables, task lists), KaTeX math, reading time, sanitized raw HTML, and eager images, all through one shared Sätteri processor.
- **Syntax-highlighted code** — Expressive Code with the Kanagawa light/dark pair, collapsible sections, and line numbers.
- **Post filter** — client-side category/year filtering that still works without JavaScript.
- **Weather widget** — a snapshot from a separate crawler Worker, normalized defensively and shown in JST.
- **Progressive enhancements** — Plyr media players, a PhotoSwipe lightbox, and a Swiper gallery, each dynamically imported only on pages that use them.
- **Feeds and metadata** — RSS, sitemap, `robots.txt`, and Open Graph / Twitter cards.
- **Light and dark themes** with an instant toggle.

## Project structure

```
├── migrations/            # D1 migrations (unlock table)
├── public/                # self-hosted static assets (icons, _headers)
├── scripts/               # authoring scripts (vault password hashing)
├── src/
│   ├── components/        # .astro components
│   ├── content/           # git submodule: article/, vault/, assets/
│   ├── data/              # categories and the character profile
│   ├── hast/              # HAST plugins + vendored HTML sanitizer
│   ├── layouts/           # BaseLayout and BlogPost
│   ├── mdast/             # MDAST plugins (KaTeX, reading time, question)
│   ├── pages/             # routes
│   ├── scripts/           # client-side enhancements
│   ├── styles/            # Tailwind entry and theme tokens
│   └── utils/             # pure, unit-tested helpers
├── test/                  # Vitest unit tests
├── astro.config.mjs
└── wrangler.jsonc
```

Path aliases: `@components/*`, `@layouts/*`, `@utils/*`, `@assets/*`.

Routes are prerendered except the gated ones: `login/[slug]`, `vault/[slug]`, and `api/auth` are server-rendered.

## Getting started

```sh
pnpm install
git submodule update --init   # content lives in a submodule
pnpm dev                      # http://localhost:4321
```

## Commands

| Command           | Action                                                        |
| :---------------- | :------------------------------------------------------------ |
| `pnpm dev`        | Start the dev server at `localhost:4321`                      |
| `pnpm build`      | Run `astro check` and build to `dist/`                        |
| `pnpm preview`    | Build, then preview the built Worker                          |
| `pnpm test`       | Run the Vitest suite (`vitestconfig.ts`)                      |
| `pnpm cf-typegen` | Regenerate `worker-configuration.d.ts` from `wrangler.jsonc`  |
| `pnpm hash:vault` | Interactively generate an argon2id hash for vault frontmatter |
| `pnpm deploy`     | Build and `wrangler deploy`                                   |

Lint TypeScript/JS with `pnpm exec eslint <files>` and CSS with `pnpm exec stylelint <files>`; Husky + lint-staged run both (plus Prettier) on commit.

## Writing content

Posts live in the content submodule under `src/content/article/<slug>.md` (public) or `src/content/vault/<slug>.md` (password-gated). Body content is GFM and uses `h2`–`h6` only — the layout owns the page `h1`. Per-post images sit next to the post in `src/content/assets/<collection>/<slug>/`.

Frontmatter fields, in addition to `slug`, `category` (`tech` / `life` / `notes`), `title`, `description`, `pubDate`, `updatedDate?`, `heroImage?`, `pinned`, and `draft`:

| Collection | Field          | Notes                                                                                         |
| :--------- | :------------- | :-------------------------------------------------------------------------------------------- |
| vault      | `question`     | Prompt shown on the unlock page (defaults to パスワードは何ですか?)                          |
| vault      | `passwordHash` | Required argon2id hash; must match `VAULT_ARGON2_OPTIONS`. Generate it with `pnpm hash:vault` |

Drafts are excluded everywhere — listings, RSS, sitemap, and generated routes.

## Configuration

Bindings, routes, and rate limits are declared in `wrangler.jsonc`:

- **Assets** (`ASSETS`) serve the built `dist/` output; **`IMAGES`** backs Cloudflare Images.
- **KV** (`SESSION`) stores sessions; **D1** (`DB`) stores vault unlocks (see `migrations/`).
- Secrets (`ARGON2_ENDPOINT`, `ARGON2_HMAC_SECRET`, `VERCEL_PROTECTION_BYPASS`, `TURNSTILE_SECRET`) are read from the Cloudflare secrets store, never from plaintext vars. `TURNSTILE_SITEKEY` is a public var.
- `ARGON2_PEPPER` is not a Worker binding: only the argon2 service holds the pepper, so nothing in the Worker reads it. It is read from the local shell by `pnpm hash:vault`, which must hash with the same pepper the endpoint verifies with.

Vault passwords are never verified in the Worker: the request is HMAC-signed and sent to a separate argon2 service, so no hashing code is bundled.

## Deployment

```sh
pnpm deploy
```

The Worker is bound to the `20190716.xyz` custom domain.

## Related repositories

- **`../cron`** — a Worker that crawls OpenWeatherMap and writes the `weather.json` snapshot the weather widget reads.
- **`../argon2`** — the HTTP service that verifies vault passwords.

## Credits

- Scaffolded from the [Astro blog starter](https://github.com/withastro/astro/tree/main/examples/blog), itself based on [Bear Blog](https://github.com/HermanMartinus/bearblog/).
- The HTML sanitizer in `src/hast/sanitize/` is vendored from [`satteri-sanitize`](https://github.com/Ashish-CodeJourney/satteri-plugins/tree/main/packages/satteri-sanitize) (MIT, © Ashish Vaghela); the KaTeX rendering under `src/mdast/` was extracted into this source the same way, from `satteri-katex`.

## License

Licensed under the Apache License, Version 2.0 — see [LICENSE](LICENSE).
Report a correction

Explore similar templates

Compare previews and descriptions within the same stack and category.