From c2a1ddbb9542234fc8356a4c82a8700be72dae87 Mon Sep 17 00:00:00 2001 From: Kevin Deng Date: Mon, 24 Aug 2026 04:13:23 +0900 Subject: [PATCH] Add Hanji branding and build-time OG images --- .codex/environments/environment.toml | 2 +- .github/assets/home-og.png | Bin 0 -> 39966 bytes .github/workflows/deploy.yml | 13 + .prettierignore | 4 + AGENTS.md | 2 + CLAUDE.md | 1 + DESIGN.md | 13 +- README.ja-JP.md | 14 +- README.md | 14 +- app/components/AppHeader.vue | 12 +- app/components/BrandMenu.vue | 293 ++++++ app/components/HanjiLogo.vue | 24 + app/components/HanjiMark.vue | 78 ++ app/components/HeroOverprint.vue | 2 +- app/components/OverprintChar.vue | 2 +- app/error.vue | 13 +- app/locales/ja-jp.ts | 17 +- app/locales/ko-kr.ts | 17 +- app/locales/zh-cn.ts | 20 +- app/locales/zh-hk.ts | 17 +- app/locales/zh-tw.ts | 17 +- app/pages/about.vue | 58 ++ app/pages/char/[key].vue | 32 +- app/pages/index.vue | 25 +- app/router.options.ts | 10 + app/styles/overprint.css | 2 +- data/sources.lock.json | 5 + nuxt.config.ts | 37 +- package.json | 9 +- pnpm-lock.yaml | 592 +++++++++++ pnpm-workspace.yaml | 5 + public/apple-touch-icon.png | Bin 0 -> 18328 bytes public/favicon-32x32.png | Bin 0 -> 2263 bytes public/favicon.ico | Bin 0 -> 15086 bytes public/favicon.svg | 1 + public/logo-seal.svg | 1 + public/logo.svg | 1 + scripts/build-data.ts | 22 +- scripts/build-og-images.ts | 1196 ++++++++++++++++++++++ scripts/cmap.ts | 16 +- codex-setup.sh => scripts/codex-setup.sh | 2 +- scripts/sources.ts | 5 + scripts/tests/chars.test.ts | 6 +- scripts/tests/columns.test.ts | 22 - scripts/tests/fonts.test.ts | 7 +- scripts/tests/frequency.test.ts | 21 +- scripts/tests/i18n.test.ts | 52 +- scripts/tests/listings.test.ts | 19 +- scripts/tests/og-images.test.ts | 43 + scripts/tests/patterns.test.ts | 19 +- scripts/tests/preference-restore.test.ts | 9 - scripts/tests/prerender.test.ts | 30 - scripts/tests/router-options.test.ts | 44 + scripts/tests/sitemap.test.ts | 60 -- scripts/tests/sources.test.ts | 21 - scripts/tests/stroke-data.test.ts | 4 +- scripts/tests/strokes.test.ts | 8 - scripts/tests/theme.test.ts | 12 - scripts/tests/worker.test.ts | 72 -- scripts/update-sources.ts | 3 +- shared/brand.ts | 15 + {app/utils => shared}/overprint.ts | 27 +- svgo.config.mjs | 18 + 63 files changed, 2679 insertions(+), 427 deletions(-) create mode 100644 .github/assets/home-og.png create mode 100644 CLAUDE.md create mode 100644 app/components/BrandMenu.vue create mode 100644 app/components/HanjiLogo.vue create mode 100644 app/components/HanjiMark.vue create mode 100644 public/apple-touch-icon.png create mode 100644 public/favicon-32x32.png create mode 100644 public/favicon.ico create mode 100644 public/favicon.svg create mode 100644 public/logo-seal.svg create mode 100644 public/logo.svg create mode 100644 scripts/build-og-images.ts rename codex-setup.sh => scripts/codex-setup.sh (98%) create mode 100644 scripts/tests/og-images.test.ts delete mode 100644 scripts/tests/prerender.test.ts create mode 100644 scripts/tests/router-options.test.ts delete mode 100644 scripts/tests/sitemap.test.ts delete mode 100644 scripts/tests/sources.test.ts delete mode 100644 scripts/tests/theme.test.ts delete mode 100644 scripts/tests/worker.test.ts create mode 100644 shared/brand.ts rename {app/utils => shared}/overprint.ts (52%) create mode 100644 svgo.config.mjs diff --git a/.codex/environments/environment.toml b/.codex/environments/environment.toml index 552f85c..68d2bb7 100644 --- a/.codex/environments/environment.toml +++ b/.codex/environments/environment.toml @@ -3,4 +3,4 @@ version = 1 name = "hanji" [setup] -script = "./codex-setup.sh" +script = "./scripts/codex-setup.sh" diff --git a/.github/assets/home-og.png b/.github/assets/home-og.png new file mode 100644 index 0000000000000000000000000000000000000000..b739d5895b5e60272f571338753e98c90cb90ac8 GIT binary patch literal 39966 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 xaEM4UZg5ZtNMSj^)aWpg3KAE>7cKhFKiTi+4Q`. Follow the existing two-space, single-quote, no-semicolon style and let Prettier resolve formatting. Name Vue components in PascalCase (`CharTable.vue`), composables with a `use` prefix (`useQueryState`), and utility files in kebab-case. Prefer shared types over duplicated shapes, UnoCSS utilities for component styling, and locale entries in `app/locales/` for user-facing text. +Always write the project's English name as `Hanji` in user-facing copy and visual assets. Never style it as `HANJI` or `hanji`; lowercase `hanji` is reserved for technical identifiers such as package names, URLs, CSS classes, filenames, and storage keys. + ## README Localizations `README.md` is the Simplified Chinese source and `README.ja-JP.md` is its Japanese translation. Whenever either file changes, update the other in the same change. Keep their structure, facts, commands, links, and data-source tables synchronized. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/DESIGN.md b/DESIGN.md index bc4c7d9..18b32d7 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -381,10 +381,21 @@ outline. The hero's character entry is the deliberate exception: a real input is visually hidden behind the overprint, with a drawn caret showing where the next character lands. +### Brand Mark + +The Hanji mark places the simplified `汉` and traditional `漢` in one square, +split along an anti-diagonal from upper right to lower left. The simplified +form occupies the Paper upper-left plate, while the traditional form occupies +the Proof Red lower-right plate. A fine seam and two registration ticks make +the construction read as a comparison proof rather than a decorative split. +The outlined Noto Serif CJK forms are fixed brand artwork and do not change +with the reader's interface-style preference. + ### Navigation The header is a flat sticky Paper band with no separating shadow. Navigation -starts muted, becomes Ink on hover or exact-route activation, and uses compact +begins with the mark and a compact localized-title / Hanji lockup. Other links +start muted, become Ink on hover or exact-route activation, and use compact icon controls for preferences. Floating menus use the only substantial shadow in the system and return focus to their trigger when closed by keyboard. diff --git a/README.ja-JP.md b/README.ja-JP.md index 6f17b0b..42b7b46 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -1,9 +1,15 @@ -# 漢智 · hanji +![Hanji ホームOG](.github/assets/home-og.png) + +# 漢智 · Hanji [简体中文](README.md) | 日本語 +> 一字のあいだに、五地域の字形が見える + +一つの漢字を並べて重ね、中国大陸、香港、台湾、日本、韓国のあいだにある、細やかで確かな字形の違いを映し出します。 + 中国大陸・香港・台湾・日本・韓国の5地域で一般的に使われる漢字をまとめた字表です。本アプリでは、一般的なゴシック体と明朝体における印刷字形を比較します。同じ字でも、地域によって異なる字形で表示されることがあります。5地域の字形を横に並べ、既定ではUIの言語に対応する地域の文字頻度順で表示します。画数順やコードポイント順への並べ替え、差異パターンによる絞り込みも可能です。韓国には文字頻度データがないため、韓国列は既定で非表示ですが、表示オプションから有効にできます。 字形は一つの側面にすぎません。収録範囲は5地域の常用字表の和集合であり、**字形が完全に同じ字も収録しています**。これは5地域の漢字に関する資料表であり、差異だけを並べた一覧ではありません。 @@ -69,7 +75,8 @@ pnpm build:data # 字表とフォントサブセットを生成。初回は約 pnpm update:sources # サードパーティデータの更新を確認して固定。変更があればダウンロードして再生成 pnpm dev pnpm test -pnpm generate # 静的Webアプリ +pnpm generate # 静的Webアプリ(OG画像は生成しない) +pnpm build:og # 任意。完全なOG画像を生成 ``` 各行のURLには行名を使います(`/char/着`)。5地域の表示字形、`aka`、`alternatives` もURLとして利用でき、クライアント側で対応する行へ移動します。たとえば `/char/国`、`/char/郞`、`/char/缐` です。ページの `rel=canonical` は行名のURLを指します。未確認関係はURL別名にはなりません。 @@ -105,10 +112,13 @@ Cloudflareの **Settings → Domains & Routes** でproductionドメインを接 ```bash pnpm build:data pnpm generate +pnpm build:og # 任意。完全なソーシャル共有用アセットが必要な場合に実行 pnpm preview:worker # http://localhost:8787 pnpm deploy ``` +`pnpm generate` はサイト本体だけを生成し、OG画像はローカルの開発やデプロイを妨げません。ローカルで完全なソーシャル共有用アセットを確認する場合は、静的生成後に `pnpm build:og` を個別に実行してください。本番のGitHub Actionsでは、生成スクリプト、字形とフォントの入力、ブランド文言、Logo、依存関係のlockfileから厳密なハッシュを計算します。ヒット時はOGディレクトリ全体を復元し、ミス時のみ全量生成します。 + ## データ出典 diff --git a/README.md b/README.md index 7b0d4e7..5c4be2f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,15 @@ -# 汉智 · hanji +![Hanji 首页 OG](.github/assets/home-og.png) + +# 汉智 · Hanji 简体中文 | [日本語](README.ja-JP.md) +> 一字之间,照见五地字形 + +把同一个汉字并排、叠印,照见中国大陆、香港、台湾、日本与韩国之间细微而真实的字形差异。 + 中国大陆、香港、台湾、日本、韩国五地常用汉字的字表。本应用对照的是通用黑体与宋体中的印刷字形:同一个字,在各地可能呈现不同字形。这里把五地字形并排列出,默认按界面语言对应地区的字频排序,也可按笔画或码点排序,并按差异模式筛选。韩国没有字频数据,韩国列默认关闭,可在显示选项中启用。 字形只是其中一个维度。收录范围是五地常用字表的并集,**字形完全相同的字同样收录**:这是一份五地汉字的资料表,不是一份差异清单。 @@ -69,7 +75,8 @@ pnpm build:data # 生成字表与字体子集,首次会下载约 302 MiB 原 pnpm update:sources # 检查并锁定新版第三方数据;有变化时下载并重新生成 pnpm dev pnpm test -pnpm generate # 静态应用 +pnpm generate # 静态应用(不生成 OG 图片) +pnpm build:og # 可选;生成完整 OG 图片 ``` 每一行的地址是它的行名(`/char/着`)。五地展示形、`aka` 和 `alternatives` 也可作为地址,由客户端跳到所属的行——例如 `/char/国`、`/char/郞`、`/char/缐`,页面用 `rel=canonical` 指回行名地址;未确认关系不是地址别名。 @@ -105,10 +112,13 @@ Cloudflare Worker 名称须为 `hanji`,与 `wrangler.json` 中的 `name` 一 ```bash pnpm build:data pnpm generate +pnpm build:og # 可选;需要完整社交分享资源时运行 pnpm preview:worker # http://localhost:8787 pnpm deploy ``` +`pnpm generate` 只生成站点主体,OG 图片不会阻断本地开发或部署。需要在本地检查完整社交分享资源时,请在静态生成后单独运行 `pnpm build:og`。线上 GitHub Actions 会根据生成脚本、字形与字体输入、品牌文案、Logo 和依赖锁计算精确哈希;命中时恢复完整 OG 目录,未命中时才执行全量生成。 + ## 数据来源 diff --git a/app/components/AppHeader.vue b/app/components/AppHeader.vue index 95c60c2..3831b17 100644 --- a/app/components/AppHeader.vue +++ b/app/components/AppHeader.vue @@ -14,17 +14,7 @@ const { t } = useT()
- -

- {{ t('meta.title') }} -

- -
+ + + + + diff --git a/app/components/HeroOverprint.vue b/app/components/HeroOverprint.vue index 3c0862b..0ea6f51 100644 --- a/app/components/HeroOverprint.vue +++ b/app/components/HeroOverprint.vue @@ -1,4 +1,5 @@ @@ -91,6 +113,18 @@ useSeoMeta({

{{ t('about.licenseThirdParty') }}

{{ t('about.licenseBrand') }}

+

{{ t('about.brandAssetsTitle') }}

+ + + +

{{ t('about.sourcesTitle') }}

@@ -103,6 +137,30 @@ useSeoMeta({ >tofu.tools + + + diff --git a/app/pages/char/[key].vue b/app/pages/char/[key].vue index d083e9a..fc44294 100644 --- a/app/pages/char/[key].vue +++ b/app/pages/char/[key].vue @@ -1,4 +1,5 @@ diff --git a/app/pages/index.vue b/app/pages/index.vue index d1b65b5..c149d0c 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -1,10 +1,33 @@