Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5fc5265
Fix: show exercise question text + improve exercise UI
Jun 9, 2026
54c8057
Improve rendering quality across all chapters
Jun 9, 2026
a26c23a
Content: add chapter overviews + fix adaptChapter to read them
Jun 9, 2026
a139007
UX: fix rubric button + improve hint button state
Jun 9, 2026
8904dd5
Feature: surface commonMistakes in LearningPanel
Jun 9, 2026
92ef4b7
Fix: render chapter overview with MathText (supports LaTeX + bold)
Jun 9, 2026
750367c
Fix: MathText uses div wrapper for multi-paragraph content
Jun 9, 2026
1d0ca85
UX: show exercise number in workspace + polish
Jun 9, 2026
1c5eb6d
WX: Add WeChat Mini Program (wx-miniprogram/)
Jun 9, 2026
4093e39
wx: improve parser + add continue-learning to index
Jun 9, 2026
fc116d1
wx: add 3-slide onboarding flow for first launch
Jun 9, 2026
822debb
wx: polish study page — difficulty pills, verdict labels, haptics
Jun 9, 2026
53e2099
wx: add message timestamps and animated typing indicator to chat
Jun 9, 2026
f2c1203
wx: add progress bar and completion badge to chapter page header
Jun 9, 2026
7086d63
wx: add learning stats grid to settings page
Jun 9, 2026
ee51480
wx: improve API error handling + add chat retry button
Jun 9, 2026
5e5e815
wx: add exercise count and best score badges to KP nav bar
Jun 9, 2026
25df8ca
wx: add share functionality to index and settings pages
Jun 9, 2026
f741e1f
wx: add first-visit hints on index and chapter pages
Jun 9, 2026
b842f4b
wx: add chapter breadcrumb to study tab + bump version to 1.1.0
Jun 9, 2026
e9eaad9
wx: add difficulty filter chips to exercise list
Jun 9, 2026
dd85400
wx: add reset-all-progress to settings + clearAllProgress utility
Jun 9, 2026
6362945
wx: show chapter-completion modal when finishing last KP
Jun 9, 2026
5808868
wx: add quick-reply suggestion chips to chat page
Jun 9, 2026
9a315f9
wx: add next-KP button at bottom of learn tab
Jun 9, 2026
7be1c4a
docs: frame dual-end learning workbench upgrade
Jun 20, 2026
5ddbf1f
feat(web): add diagram engine and editorial workbench polish
Jun 20, 2026
94a6f85
feat(wx): render teaching diagrams in study flow
Jun 20, 2026
6eb326a
content: add gaodeng shuxue scaffold and final exam sources
Jun 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@ build/
*.db
*.sqlite
*.sqlite3
*.log
.superpowers/
tmp/
temp/
.cache/

# Local git worktrees used for parallel AI development.
.worktrees/

# WeChat Mini Program — API key config (do not commit)
wx-miniprogram/config.js

# WeChat Mini Program — generated data bundle (rebuilt from content/)
wx-miniprogram/data/all-chapters.js
218 changes: 218 additions & 0 deletions app/fonts.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/* 自托管字体 —— 由 scripts/fetch-fonts.mjs 生成,请勿手改。
中文走本地宋体/思源回退(见 globals.css 字体栈)。 */

@font-face {
font-family: 'Spectral';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('/fonts/spectral-400-italic-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'Spectral';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('/fonts/spectral-400-italic-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'Spectral';
font-style: italic;
font-weight: 500;
font-display: swap;
src: url('/fonts/spectral-500-italic-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'Spectral';
font-style: italic;
font-weight: 500;
font-display: swap;
src: url('/fonts/spectral-500-italic-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'Spectral';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/spectral-400-normal-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'Spectral';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/spectral-400-normal-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'Spectral';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/fonts/spectral-500-normal-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'Spectral';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/fonts/spectral-500-normal-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'Spectral';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('/fonts/spectral-600-normal-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'Spectral';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('/fonts/spectral-600-normal-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'Spectral';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/spectral-700-normal-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'Spectral';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/spectral-700-normal-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('/fonts/source-serif-4-400-italic-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('/fonts/source-serif-4-400-italic-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/source-serif-4-400-normal-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/source-serif-4-400-normal-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/fonts/source-serif-4-500-normal-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/fonts/source-serif-4-500-normal-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('/fonts/source-serif-4-600-normal-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('/fonts/source-serif-4-600-normal-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'IBM Plex Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/ibm-plex-mono-400-normal-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'IBM Plex Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/ibm-plex-mono-400-normal-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
font-family: 'IBM Plex Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/fonts/ibm-plex-mono-500-normal-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
font-family: 'IBM Plex Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/fonts/ibm-plex-mono-500-normal-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
Loading