Skip to content

Commit 41026e2

Browse files
committed
feat: 重构站点主题并重写教程内容
1 parent fae6d33 commit 41026e2

62 files changed

Lines changed: 1554 additions & 865 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Theme Section Architecture Implementation Plan
2+
3+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4+
5+
**Goal:** Refactor the visual theme so light mode uses light surfaces consistently, dark mode uses dark surfaces consistently, and hero/section styling follows semantic classes.
6+
7+
**Architecture:** Centralize the palette and section semantics in `src/styles/global.css`, then switch high-signal layouts to `section-hero`, `section-tint`, and `section-inverse`. Keep old styling behavior out of content sections so theme changes happen through a small set of reusable primitives.
8+
9+
**Tech Stack:** Astro, Tailwind utilities, global CSS custom properties
10+
11+
---
12+
13+
### Task 1: Add semantic section primitives
14+
15+
**Files:**
16+
- Modify: `src/styles/global.css`
17+
18+
- [ ] Define light-mode and dark-mode surface tokens for `primary`, `card`, `tint`, `hero`, `inverse`, and code surfaces.
19+
- [ ] Add semantic section classes for `section-default`, `section-tint`, `section-hero`, and `section-inverse`.
20+
- [ ] Tighten typography tokens for display headings, prose contrast, and card surfaces.
21+
22+
### Task 2: Move shared layout pieces to semantic sections
23+
24+
**Files:**
25+
- Modify: `src/components/Footer.astro`
26+
- Modify: `src/pages/index.astro`
27+
- Modify: `src/pages/en/index.astro`
28+
29+
- [ ] Keep the footer as the primary `section-inverse` surface.
30+
- [ ] Change the homepage emphasis strip from a dark block to a tinted block.
31+
- [ ] Keep the rest of the homepage hierarchy aligned with the new section semantics.
32+
33+
### Task 3: Migrate page hero sections
34+
35+
**Files:**
36+
- Modify: `src/pages/**/*.astro`
37+
38+
- [ ] Replace hero uses of the old `section-dark` class with `section-hero`.
39+
- [ ] Leave content sections on default or tinted surfaces.
40+
- [ ] Verify that hero text utilities still inherit the right local CSS variables.
41+
42+
### Task 4: Verify
43+
44+
**Files:**
45+
- Modify: none
46+
47+
- [ ] Run `npm run build`.
48+
- [ ] Review the homepage, intro page, and one syntax page in both light and dark mode.
49+
- [ ] Confirm no large dark sections remain in light mode outside explicitly inverse areas.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Theme Section Architecture Design
2+
3+
**Date:** 2026-04-09
4+
5+
## Goal
6+
7+
Make light mode stay visually light and dark mode stay visually dark, while keeping a restrained editorial tone across the site.
8+
9+
## Decisions
10+
11+
### Section semantics
12+
13+
- `default` is the standard page surface.
14+
- `tint` is the lighter secondary surface used for section separation in light mode and subtle depth in dark mode.
15+
- `inverse` is reserved for strongly inverted areas such as the footer.
16+
- `hero` is a thematic section style used for page intros. In light mode it stays warm and light. In dark mode it becomes fully dark.
17+
18+
### Color behavior
19+
20+
- Light mode should use parchment, paper, and warm gray surfaces only.
21+
- Dark mode should use deep brown-black surfaces with warm text and muted borders.
22+
- Code blocks may remain darker than surrounding content because they are tool surfaces rather than page sections.
23+
24+
### Typography behavior
25+
26+
- Keep serif display for hero and section headings.
27+
- Keep sans-serif for navigation, body copy, cards, and controls.
28+
- Reduce oversized display weight and increase body contrast for longer reading comfort.
29+
30+
## Scope
31+
32+
- Update global theme tokens and semantic section utilities in `src/styles/global.css`.
33+
- Keep the footer as the main inverse area.
34+
- Convert homepage secondary emphasis blocks away from dark-light clashes.
35+
- Make existing hero sections adopt the new semantic section style consistently.
36+
37+
## Verification
38+
39+
- Check homepage, intro page, and one syntax page in both light and dark mode.
40+
- Verify navigation, cards, prose, links, and code blocks remain readable.
41+
- Run `npm run build`.

src/components/Comments.astro

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,83 @@
11
---
2+
import { BASE_PATH, GISCUS_CONFIG } from '../config';
3+
24
interface Props {
35
slug: string;
46
}
57
68
const { slug } = Astro.props;
9+
const rawPath = Astro.url.pathname;
10+
const pathWithoutBase = rawPath.startsWith(BASE_PATH) ? rawPath.slice(BASE_PATH.length) : rawPath;
11+
const normalizedPath = (() => {
12+
const path = pathWithoutBase.startsWith('/') ? pathWithoutBase : `/${pathWithoutBase}`;
13+
return path.replace(/\/+$/, '') || '/';
14+
})();
15+
const currentLang = normalizedPath === '/en' || normalizedPath.startsWith('/en/') ? 'en' : 'zh';
16+
const commentsEnabled =
17+
GISCUS_CONFIG.enabled &&
18+
GISCUS_CONFIG.repo &&
19+
GISCUS_CONFIG.repoId &&
20+
GISCUS_CONFIG.category &&
21+
GISCUS_CONFIG.categoryId;
22+
const copy =
23+
currentLang === 'en'
24+
? {
25+
title: 'Comments',
26+
description: 'Comments are currently unavailable.',
27+
hint: 'Enable GitHub Discussions for this repository and complete the giscus configuration to turn comments on.',
28+
loginHint: 'When enabled, visitors can sign in with GitHub to join the discussion.',
29+
lang: 'en',
30+
}
31+
: {
32+
title: '评论',
33+
description: '评论区暂未开放。',
34+
hint: '需要先为这个仓库启用 GitHub Discussions,并完成 giscus 配置后,评论功能才可用。',
35+
loginHint: '启用后,访客可以使用 GitHub 账号登录并参与讨论。',
36+
lang: 'zh-CN',
37+
};
738
---
839

940
<section class="section" id="comments">
1041
<div class="container">
11-
<h2 class="font-serif text-3xl font-medium mb-6 text-[var(--text-primary)]">评论</h2>
42+
<h2 class="font-serif text-3xl font-medium mb-6 text-[var(--text-primary)]">{copy.title}</h2>
1243
<div class="card">
13-
<p class="text-[var(--text-secondary)] mb-4">
14-
本网站使用 <a href="https://giscus.app" target="_blank" rel="noopener" class="text-[var(--color-terracotta)] hover:underline">Giscus</a> 评论系统,基于 GitHub Discussions。
15-
</p>
16-
<p class="text-[var(--text-secondary)] text-sm mb-4">
17-
使用 GitHub 账号登录即可发表评论。
18-
</p>
19-
20-
<!-- Giscus container -->
21-
<div class="giscus" id="giscus-container"></div>
44+
{commentsEnabled ? (
45+
<>
46+
<p class="text-[var(--text-secondary)] mb-4">
47+
{currentLang === 'en' ? 'This site uses ' : '本网站使用 '}
48+
<a href="https://giscus.app" target="_blank" rel="noopener" class="text-[var(--color-terracotta)] hover:underline">Giscus</a>
49+
{currentLang === 'en' ? ', a comment system powered by GitHub Discussions.' : ' 评论系统,基于 GitHub Discussions。'}
50+
</p>
51+
<p class="text-[var(--text-secondary)] text-sm mb-4">{copy.loginHint}</p>
52+
<div class="giscus" id={`giscus-container-${slug}`}></div>
53+
<script
54+
src="https://giscus.app/client.js"
55+
data-repo={GISCUS_CONFIG.repo}
56+
data-repo-id={GISCUS_CONFIG.repoId}
57+
data-category={GISCUS_CONFIG.category}
58+
data-category-id={GISCUS_CONFIG.categoryId}
59+
data-mapping={GISCUS_CONFIG.mapping}
60+
data-strict={GISCUS_CONFIG.strict}
61+
data-reactions-enabled={GISCUS_CONFIG.reactionsEnabled}
62+
data-emit-metadata={GISCUS_CONFIG.emitMetadata}
63+
data-input-position={GISCUS_CONFIG.inputPosition}
64+
data-theme="preferred_color_scheme"
65+
data-lang={copy.lang}
66+
data-loading={GISCUS_CONFIG.loading}
67+
crossorigin="anonymous"
68+
async
69+
></script>
70+
</>
71+
) : (
72+
<>
73+
<p class="text-[var(--text-secondary)] mb-3">{copy.description}</p>
74+
<p class="text-[var(--text-secondary)] text-sm">{copy.hint}</p>
75+
</>
76+
)}
2277
</div>
2378
</div>
2479
</section>
2580

26-
<script
27-
src="https://giscus.app/client.js"
28-
data-repo="your-username/your-repo"
29-
data-repo-id="your-repo-id"
30-
data-category="Announcements"
31-
data-category-id="DIC_kwD..."
32-
data-mapping="pathname"
33-
data-strict="0"
34-
data-reactions-enabled="1"
35-
data-emit-metadata="0"
36-
data-input-position="bottom"
37-
data-theme="preferred_color_scheme"
38-
data-lang="zh-CN"
39-
data-loading="lazy"
40-
crossorigin="anonymous"
41-
async
42-
></script>
43-
4481
<style>
4582
.giscus-frame {
4683
margin-top: 1rem;

src/components/FeatureCard.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const { title, description, icon } = Astro.props;
99
---
1010

1111
<div class="card hover:shadow-whisper transition-shadow">
12-
<div class="w-12 h-12 rounded-[var(--radius-comfortable)] bg-[var(--color-warm-sand)] flex items-center justify-center mb-4">
12+
<div class="w-12 h-12 rounded-[var(--radius-comfortable)] bg-[var(--bg-muted)] flex items-center justify-center mb-4">
1313
<Fragment set:html={icon} />
1414
</div>
1515
<h3 class="font-serif text-xl font-medium text-[var(--text-primary)] mb-2">{title}</h3>

src/components/Footer.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { BASE_PATH } from '../config';
44
const currentYear = new Date().getFullYear();
55
---
66

7-
<footer class="section-dark py-12 mt-16">
7+
<footer class="section-inverse py-12 mt-16">
88
<div class="container">
99
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
1010
<!-- Brand -->
@@ -45,7 +45,7 @@ const currentYear = new Date().getFullYear();
4545
</div>
4646

4747
<!-- Bottom bar -->
48-
<div class="border-t border-[var(--color-dark-surface)] mt-8 pt-8 flex flex-col md:flex-row justify-between items-center gap-4">
48+
<div class="border-t border-[var(--border-dark)] mt-8 pt-8 flex flex-col md:flex-row justify-between items-center gap-4">
4949
<p class="text-[var(--text-on-dark)] opacity-60 text-sm">
5050
© {currentYear} Markdown 中文教程. 使用 Claude (Anthropic) 设计风格构建。
5151
</p>

src/components/Header.astro

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,50 @@
11
---
2+
import { BASE_PATH } from '../config';
23
import { translations } from '../i18n/translations';
34
4-
const currentLang = Astro.url.pathname.startsWith('/en') ? 'en' : 'zh';
5+
const base = BASE_PATH;
6+
const rawPath = Astro.url.pathname;
7+
const pathWithoutBase = rawPath.startsWith(base) ? rawPath.slice(base.length) : rawPath;
8+
const normalizedPath = (() => {
9+
const path = pathWithoutBase.startsWith('/') ? pathWithoutBase : `/${pathWithoutBase}`;
10+
return path.replace(/\/+$/, '') || '/';
11+
})();
12+
13+
const currentLang = normalizedPath === '/en' || normalizedPath.startsWith('/en/') ? 'en' : 'zh';
514
const t = translations[currentLang];
615
7-
const base = '/Markdown-Tutorial';
8-
const currentPath = Astro.url.pathname.replace(/^\/en/, '').replace(/^\/Markdown-Tutorial/, '');
16+
const currentPath = (() => {
17+
const path = currentLang === 'en' ? normalizedPath.replace(/^\/en(?=\/|$)/, '') || '/' : normalizedPath;
18+
return path === '/' ? '' : path;
19+
})();
20+
21+
const buildPath = (lang: 'zh' | 'en', path = '') => {
22+
if (lang === 'en') {
23+
return path ? `${base}/en${path}` : `${base}/en`;
24+
}
25+
26+
return path ? `${base}${path}` : base;
27+
};
28+
29+
const currentPageHref = buildPath(currentLang, currentPath);
30+
const languageToggleHref = buildPath(currentLang === 'en' ? 'zh' : 'en', currentPath);
931
1032
const navLinks = [
11-
{ href: currentLang === 'en' ? `${base}/en` : base, label: t.nav.home },
12-
{ href: currentLang === 'en' ? `${base}/en/basic` : `${base}/basic`, label: t.nav.basic },
13-
{ href: currentLang === 'en' ? `${base}/en/extended` : `${base}/extended`, label: t.nav.extended },
14-
{ href: currentLang === 'en' ? `${base}/en/editors` : `${base}/editors`, label: t.nav.editors },
15-
{ href: currentLang === 'en' ? `${base}/en/tools` : `${base}/tools`, label: t.nav.tools },
16-
{ href: currentLang === 'en' ? `${base}/en/about` : `${base}/about`, label: t.nav.about },
33+
{ href: buildPath(currentLang, ''), label: t.nav.home },
34+
{ href: buildPath(currentLang, '/intro'), label: t.nav.intro },
35+
{ href: buildPath(currentLang, '/basic'), label: t.nav.basic },
36+
{ href: buildPath(currentLang, '/extended'), label: t.nav.extended },
37+
{ href: buildPath(currentLang, '/editors'), label: t.nav.editors },
38+
{ href: buildPath(currentLang, '/tools'), label: t.nav.tools },
39+
{ href: buildPath(currentLang, '/about'), label: t.nav.about },
1740
];
1841
---
1942

2043
<header class="nav">
2144
<div class="container">
2245
<nav class="flex items-center justify-between h-16">
2346
<!-- Logo -->
24-
<a href={currentLang === 'en' ? `${base}/en` : base} class="flex items-center gap-2 no-underline">
47+
<a href={buildPath(currentLang, '')} class="flex items-center gap-2 no-underline">
2548
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
2649
<rect width="32" height="32" rx="8" fill="#c96442"/>
2750
<path d="M8 10h4l4 12 4-12h4" stroke="#faf9f5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
@@ -36,7 +59,7 @@ const navLinks = [
3659
<a
3760
href={link.href}
3861
class={`nav-link text-sm font-medium ${
39-
currentPath === link.href ? 'text-[var(--text-primary)]' : ''
62+
currentPageHref === link.href ? 'text-[var(--text-primary)]' : ''
4063
}`}
4164
>
4265
{link.label}
@@ -48,7 +71,7 @@ const navLinks = [
4871
<div class="flex items-center gap-4">
4972
<!-- Language Toggle -->
5073
<a
51-
href={currentLang === 'en' ? `${base}${currentPath}` : `${base}/en${currentPath}`}
74+
href={languageToggleHref}
5275
class="btn btn-secondary text-sm !py-1.5 !px-3"
5376
title={currentLang === 'en' ? 'Switch to Chinese' : '切换到英文'}
5477
>
@@ -125,7 +148,7 @@ const navLinks = [
125148
<a
126149
href={link.href}
127150
class={`nav-link px-3 py-2 rounded-[var(--radius-comfortable)] text-sm font-medium ${
128-
currentPath === link.href ? 'bg-[var(--color-warm-sand)] text-[var(--text-primary)]' : ''
151+
currentPageHref === link.href ? 'bg-[var(--bg-muted)] text-[var(--text-primary)]' : ''
129152
}`}
130153
>
131154
{link.label}

src/config.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,15 @@
11
export const BASE_PATH = '/Markdown-Tutorial';
2+
3+
export const GISCUS_CONFIG = {
4+
enabled: false,
5+
repo: '',
6+
repoId: '',
7+
category: '',
8+
categoryId: '',
9+
mapping: 'pathname',
10+
strict: '0',
11+
reactionsEnabled: '1',
12+
emitMetadata: '0',
13+
inputPosition: 'bottom',
14+
loading: 'lazy',
15+
} as const;

src/i18n/translations.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export const translations = {
33
// Navigation
44
nav: {
55
home: '首页',
6+
intro: '入门',
67
basic: '基础语法',
78
extended: '扩展语法',
89
editors: '编辑器',
@@ -36,6 +37,7 @@ export const translations = {
3637
// Navigation
3738
nav: {
3839
home: 'Home',
40+
intro: 'Getting Started',
3941
basic: 'Basic Syntax',
4042
extended: 'Extended Syntax',
4143
editors: 'Editors',

src/layouts/Layout.astro

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import '../styles/global.css';
44
interface Props {
55
title: string;
66
description?: string;
7+
lang?: string;
78
}
89
9-
const { title, description = "Markdown 中文教程 - 完整指南" } = Astro.props;
10+
const { title, description = "Markdown 中文教程 - 完整指南", lang = 'zh' } = Astro.props;
1011
---
1112

1213
<!doctype html>
13-
<html lang="zh">
14+
<html lang={lang}>
1415
<head>
1516
<meta charset="utf-8" />
1617
<link rel="icon" type="image/svg+xml" href="/Markdown-Tutorial/favicon.svg" />

0 commit comments

Comments
 (0)