Skip to content

Commit 017cc3b

Browse files
committed
Refine schema pages and navigation layout
1 parent 911f571 commit 017cc3b

10 files changed

Lines changed: 304 additions & 23 deletions

File tree

site/src/components/Footer.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { withBase } from "../utils/path";
88
</div>
99
<nav aria-label="頁腳導覽">
1010
<a href="https://github.com/laubonghaudoi/Chinese_Rime">源碼倉庫</a>
11-
<a href={withBase("/contribute/")}>貢獻指南</a>
11+
<a href={withBase("/about/")}>關於與貢獻</a>
1212
<a href="https://github.com/laubonghaudoi/Chinese_Rime/releases">版本發佈</a>
1313
</nav>
1414
</footer>

site/src/components/NavLinks.astro

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ interface Props {
88
const { active = "" } = Astro.props;
99
const links = [
1010
{ key: "catalog", label: "方案目錄", href: withBase("/catalog/") },
11-
{ key: "about", label: "關於", href: withBase("/about/") },
12-
{ key: "contribute", label: "貢獻", href: withBase("/contribute/") }
11+
{ key: "about", label: "關於", href: withBase("/about/") }
1312
];
1413
---
1514
<nav class="nav" aria-label="主導覽">
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
---
2+
import { getManifest, hasPhonology } from "../data/loader";
3+
4+
const schemas = Object.values(getManifest().schemas);
5+
const withPhonology = schemas.filter((schema) => hasPhonology(schema.schema_id)).length;
6+
const withoutPhonology = schemas.length - withPhonology;
7+
const rows = [
8+
{
9+
label: "有方案表",
10+
description: "已整理聲母、韻母與聲調資料",
11+
count: withPhonology,
12+
kind: "ready"
13+
},
14+
{
15+
label: "無方案表",
16+
description: "暫未能由碼表生成音系資料",
17+
count: withoutPhonology,
18+
kind: "pending"
19+
}
20+
];
21+
const max = Math.max(...rows.map((row) => row.count), 1);
22+
---
23+
<section class="phonology-chart" aria-labelledby="phonology-chart-title">
24+
<div class="inner">
25+
<div class="copy">
26+
<h2 id="phonology-chart-title">方案表狀態</h2>
27+
<p>方案表由 schema 與碼表自動整理出聲母、韻母和聲調。若缺少必要檔案、碼表不適合拆分,或仍待人工補正,頁面便暫不顯示方案表。</p>
28+
</div>
29+
<div class="status-bars">
30+
{rows.map((row) => {
31+
const pct = Math.max(6, Math.round((row.count / max) * 100));
32+
return (
33+
<div class:list={["status-row", row.kind]}>
34+
<span class="name">
35+
<strong>{row.label}</strong>
36+
<small>{row.description}</small>
37+
</span>
38+
<span class="track" aria-hidden="true"><span style={`width:${pct}%`} /></span>
39+
<b>{row.count}</b>
40+
</div>
41+
);
42+
})}
43+
</div>
44+
</div>
45+
</section>
46+
47+
<style>
48+
.phonology-chart {
49+
padding: 0 var(--sp-section-x) 62px;
50+
background: var(--bg-panel);
51+
}
52+
.inner {
53+
display: grid;
54+
grid-template-columns: minmax(260px, 0.72fr) minmax(0, 1fr);
55+
gap: 44px;
56+
border-top: 2px solid var(--ink);
57+
padding-top: 38px;
58+
}
59+
h2 {
60+
margin: 0;
61+
font-family: var(--ff-serif-tc);
62+
font-size: var(--fs-h2-section);
63+
letter-spacing: 0;
64+
}
65+
p {
66+
max-width: 620px;
67+
margin: 10px 0 0;
68+
color: var(--ink-meta-2);
69+
font-family: var(--ff-serif-tc);
70+
line-height: 1.7;
71+
}
72+
.status-bars {
73+
display: grid;
74+
align-content: start;
75+
gap: 18px;
76+
}
77+
.status-row {
78+
display: grid;
79+
grid-template-columns: 190px minmax(0, 1fr) 46px;
80+
gap: 16px;
81+
align-items: center;
82+
}
83+
.name {
84+
display: grid;
85+
gap: 3px;
86+
min-width: 0;
87+
font-family: var(--ff-sans-tc);
88+
}
89+
strong {
90+
color: var(--ink);
91+
font-size: 16px;
92+
font-weight: 600;
93+
line-height: 1.25;
94+
}
95+
small {
96+
color: var(--ink-meta-3);
97+
font-size: 12px;
98+
line-height: 1.35;
99+
}
100+
.track {
101+
height: 18px;
102+
background: var(--bg-elev);
103+
}
104+
.track span {
105+
display: block;
106+
height: 100%;
107+
background: var(--ink);
108+
}
109+
.pending .track span {
110+
background: var(--zhu);
111+
}
112+
b {
113+
font-family: var(--ff-sans);
114+
font-size: 17px;
115+
font-variant-numeric: tabular-nums;
116+
text-align: right;
117+
}
118+
@media (max-width: 900px) {
119+
.inner {
120+
grid-template-columns: 1fr;
121+
gap: 28px;
122+
}
123+
}
124+
@media (max-width: 620px) {
125+
.status-row {
126+
grid-template-columns: 1fr 42px;
127+
gap: 10px 12px;
128+
}
129+
.track {
130+
grid-column: 1 / -1;
131+
grid-row: 2;
132+
}
133+
b {
134+
align-self: start;
135+
}
136+
}
137+
</style>
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
---
2+
import { getManifest } from "../data/loader";
3+
4+
const schemas = Object.values(getManifest().schemas);
5+
const withRecipe = schemas.filter((schema) => Boolean(schema.recipe)).length;
6+
const withoutRecipe = schemas.length - withRecipe;
7+
const rows = [
8+
{
9+
label: "有配方",
10+
description: "可循上游配方維護與安裝",
11+
count: withRecipe,
12+
kind: "recipe"
13+
},
14+
{
15+
label: "無配方/未維護",
16+
description: "多為歷史收錄或未配方化方案",
17+
count: withoutRecipe,
18+
kind: "unmaintained"
19+
}
20+
];
21+
const max = Math.max(...rows.map((row) => row.count), 1);
22+
---
23+
<section class="recipe-chart" aria-labelledby="recipe-chart-title">
24+
<div class="inner">
25+
<div class="copy">
26+
<h2 id="recipe-chart-title">配方化狀態</h2>
27+
<p>配方通常由上游作者維護,亦較容易透過 plum 安裝。未配方化方案多為歷史收錄或獨立整理,可能缺乏持續維護與可用性保證。</p>
28+
</div>
29+
<div class="status-bars">
30+
{rows.map((row) => {
31+
const pct = Math.max(6, Math.round((row.count / max) * 100));
32+
return (
33+
<div class:list={["status-row", row.kind]}>
34+
<span class="name">
35+
<strong>{row.label}</strong>
36+
<small>{row.description}</small>
37+
</span>
38+
<span class="track" aria-hidden="true"><span style={`width:${pct}%`} /></span>
39+
<b>{row.count}</b>
40+
</div>
41+
);
42+
})}
43+
</div>
44+
</div>
45+
</section>
46+
47+
<style>
48+
.recipe-chart {
49+
padding: 0 var(--sp-section-x) 62px;
50+
background: var(--bg-panel);
51+
}
52+
.inner {
53+
display: grid;
54+
grid-template-columns: minmax(260px, 0.72fr) minmax(0, 1fr);
55+
gap: 44px;
56+
border-top: 2px solid var(--ink);
57+
padding-top: 38px;
58+
}
59+
h2 {
60+
margin: 0;
61+
font-family: var(--ff-serif-tc);
62+
font-size: var(--fs-h2-section);
63+
letter-spacing: 0;
64+
}
65+
p {
66+
max-width: 620px;
67+
margin: 10px 0 0;
68+
color: var(--ink-meta-2);
69+
font-family: var(--ff-serif-tc);
70+
line-height: 1.7;
71+
}
72+
.status-bars {
73+
display: grid;
74+
align-content: start;
75+
gap: 18px;
76+
}
77+
.status-row {
78+
display: grid;
79+
grid-template-columns: 190px minmax(0, 1fr) 46px;
80+
gap: 16px;
81+
align-items: center;
82+
}
83+
.name {
84+
display: grid;
85+
gap: 3px;
86+
min-width: 0;
87+
font-family: var(--ff-sans-tc);
88+
}
89+
strong {
90+
color: var(--ink);
91+
font-size: 16px;
92+
font-weight: 600;
93+
line-height: 1.25;
94+
}
95+
small {
96+
color: var(--ink-meta-3);
97+
font-size: 12px;
98+
line-height: 1.35;
99+
}
100+
.track {
101+
height: 18px;
102+
background: var(--bg-elev);
103+
}
104+
.track span {
105+
display: block;
106+
height: 100%;
107+
background: var(--ink);
108+
}
109+
.unmaintained .track span {
110+
background: var(--zhu);
111+
}
112+
b {
113+
font-family: var(--ff-sans);
114+
font-size: 17px;
115+
font-variant-numeric: tabular-nums;
116+
text-align: right;
117+
}
118+
@media (max-width: 900px) {
119+
.inner {
120+
grid-template-columns: 1fr;
121+
gap: 28px;
122+
}
123+
}
124+
@media (max-width: 620px) {
125+
.status-row {
126+
grid-template-columns: 1fr 42px;
127+
gap: 10px 12px;
128+
}
129+
.track {
130+
grid-column: 1 / -1;
131+
grid-row: 2;
132+
}
133+
b {
134+
align-self: start;
135+
}
136+
}
137+
</style>

site/src/components/SidebarTOC.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
2-
import { getManifest, branchSchemaCount } from "../data/loader";
2+
import { branchSchemaCount, getBranchesByNameInitial } from "../data/loader";
33
4-
const branches = getManifest().branches;
4+
const branches = getBranchesByNameInitial();
55
---
66
<aside class="toc" aria-label="語系目錄">
77
{branches.map((branch) => (

site/src/data/loader.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ export function branchSchemaCount(branch: Branch): number {
6565
return branch.dialects.reduce((sum, dialect) => sum + dialect.schemas.length, 0);
6666
}
6767

68+
export function getBranchesByNameInitial(): Branch[] {
69+
const collator = new Intl.Collator("zh-Hant-u-co-stroke");
70+
return [...MANIFEST.branches].sort((a, b) => {
71+
const aInitial = Array.from(a.name)[0] || "";
72+
const bInitial = Array.from(b.name)[0] || "";
73+
return collator.compare(aInitial, bInitial) || collator.compare(a.name, b.name) || a.key.localeCompare(b.key);
74+
});
75+
}
76+
6877
export function branchRecipeCount(branch: Branch): number {
6978
const recipes = new Set<string>();
7079
for (const dialect of branch.dialects) {

site/src/pages/about.astro

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ import ProseLayout from "../layouts/ProseLayout.astro";
5353
<p>因此,「有方案表」不等於「一定有格表」。像上古擬音、域外漢字音,或其他拼寫規則特別複雜的方案,即使已經能整理出聲母、韻母和字音對照,也可能不強行排成 IPA 格表。這樣做是為了避免把一套本來不是現代音系拼音的方案,誤解成普通的聲韻表。</p>
5454
<p>如果某個方案的聲母、韻母或聲調看起來明顯拆錯,通常代表該方案需要補充機械性的拼寫提示,例如聲調字母、額外聲母或局部 IPA 對應。這些修正只用來幫助自動解析,不會把人工整理的音系表硬寫進資料庫。</p>
5555
<p>若貢獻者希望根據自己的音韻知識修正格表,請不要直接覆寫網站生成出的 <code>phonology</code> JSON 或頁面格表;那些檔案會在下次生成時被重新產生。正確做法是修改方案原始碼表,或在 <code>script/phonology_overrides.yaml</code> 補充解析提示,例如 <code>extra_initials</code>、<code>extra_finals</code>、<code>tone_letters</code>、<code>initials_ipa</code>、<code>nuclei_ipa</code>、<code>finals_ipa</code>,必要時也可以用 <code>suppress_grids: true</code> 關閉容易誤導的格表。這樣格表仍然由可追蹤的規則生成,後續更新才不會覆蓋人工修正。</p>
56+
<h2>貢獻新方案</h2>
57+
<p>新增方案時,請同時考慮上游來源、下載包、目錄資料與 README 記錄。站點的方案目錄會由 manifest 自動更新,因此貢獻時應把來源、分類和可下載檔案都整理到資料管線中。</p>
58+
<ol>
59+
<li>確認語言分類、方案名稱、上游倉庫、預設分支與實際 <code>schema_id</code>。</li>
60+
<li>以 submodule 收錄上游配方至 <code>sources/&lt;分類&gt;/&lt;方案名稱&gt;</code>。</li>
61+
<li>將需要發佈的檔案列入 <code>script/source_info.yaml</code> 對應下載包。</li>
62+
<li>更新 <code>script/manifest_overrides.yaml</code> 的語系、方言、配方與 orphan 資料。</li>
63+
<li>重新產生 <code>site/src/data/schemas.json</code> 並執行測試。</li>
64+
</ol>
65+
<p>如有疑問,可在 GitHub 開 issue,或依 README 提供的方式聯絡維護者。</p>
5666
<h2>致謝</h2>
5767
<p>本項目依賴眾多方案作者、字表整理者、語言社群與 Rime 生態維護者的長期工作。完整名單以 README 為準。</p>
5868
<p>每個方案頁會顯示可解析出的作者、配方與上游倉庫;若作者資料缺漏,歡迎提交修正。感謝所有提供方案、回報錯誤、維護碼表與補充文檔的貢獻者。</p>

site/src/pages/catalog.astro

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import BaseLayout from "../layouts/BaseLayout.astro";
33
import FilterChips from "../components/FilterChips.astro";
44
import LanguageSection from "../components/LanguageSection.astro";
55
import SidebarTOC from "../components/SidebarTOC.astro";
6-
import { getManifest } from "../data/loader";
6+
import { getBranchesByNameInitial, getManifest } from "../data/loader";
77
88
const manifest = getManifest();
9+
const branches = getBranchesByNameInitial();
910
---
1011
<BaseLayout title="方案目錄 · 非普通話漢語拼音方案全集" active="catalog">
1112
<header class="page-head">
@@ -18,7 +19,7 @@ const manifest = getManifest();
1819
<FilterChips />
1920
<div class="catalog">
2021
<div class="tree">
21-
{manifest.branches.map((branch) => <LanguageSection branch={branch} />)}
22+
{branches.map((branch) => <LanguageSection branch={branch} />)}
2223
</div>
2324
<SidebarTOC />
2425
</div>

site/src/pages/contribute.astro

Lines changed: 0 additions & 16 deletions
This file was deleted.

site/src/pages/index.astro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
---
22
import BaseLayout from "../layouts/BaseLayout.astro";
33
import DistributionChart from "../components/DistributionChart.astro";
4+
import PhonologyStatusChart from "../components/PhonologyStatusChart.astro";
5+
import RecipeStatusChart from "../components/RecipeStatusChart.astro";
46
import { getManifest } from "../data/loader";
57
import { withBase } from "../utils/path";
68
@@ -49,6 +51,8 @@ const manifest = getManifest();
4951
</section>
5052

5153
<DistributionChart />
54+
<RecipeStatusChart />
55+
<PhonologyStatusChart />
5256
</BaseLayout>
5357

5458
<style>

0 commit comments

Comments
 (0)