feat: make each theme have independent settings (color, font, size, c…#1567
Merged
Conversation
…ode theme) Previously all themes shared the same primaryColor, fontFamily, fontSize, codeBlockTheme, headingStyles, isShowLineNumber, and isMacCodeBlock. Now each theme stores its own configuration in a single localStorage key (MD__themeSettings), and switching themes automatically loads the corresponding settings. Added backward-compatible migration that reads legacy localStorage keys and merges them into the current theme's settings on first load. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
🚀 Cloudflare Workers Preview has been successfully deployed! Preview URL: https://md-pr-1567.doocs.workers.dev Built with commit 3eb4559 |
|
🚀 Surge Preview has been successfully deployed! Preview URL: https://doocs-md-preview-pr-1567.surge.sh Built with commit 3eb4559 |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces per-theme style configuration in the web app so that switching themes also switches associated settings (color/font/size/code theme/heading styles/line numbers/Mac code block), while adding a one-time migration from legacy localStorage keys.
Changes:
- Adds shared types/helpers for per-theme settings (
PerThemeSettings,defaultPerThemeSettings, and a theme→settings map type). - Updates the theme Pinia store to persist settings per theme under a single key and expose per-theme settings via writable
computedrefs. - Adds backward-compatible migration from legacy unprefixed localStorage keys into the current theme’s per-theme settings.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| packages/shared/src/configs/style.ts | Introduces per-theme settings types and a default factory function used by the web store. |
| apps/web/src/stores/theme.ts | Reworks theme-related persisted state into a per-theme settings map and adds legacy key migration logic. |
Comment on lines
+22
to
+82
| // 每个主题的独立配置(持久化到 localStorage) | ||
| const themeSettings = store.reactive<PerThemeSettingsMap>( | ||
| addPrefix(`themeSettings`), | ||
| {}, | ||
| ) | ||
|
|
||
| // 文本大小 | ||
| const fontSize = store.reactive(`size`, defaultStyleConfig.fontSize) | ||
| // --- Legacy migration: run once on store init --- | ||
| const hasAnyLegacyKey = LEGACY_KEYS.some(key => localStorage.getItem(key) !== null) | ||
| const migrationKey = `MD__legacy_migrated` | ||
| const alreadyMigrated = localStorage.getItem(migrationKey) !== null | ||
|
|
||
| // 主色 | ||
| const primaryColor = store.reactive(`color`, defaultStyleConfig.primaryColor) | ||
| if (hasAnyLegacyKey && !alreadyMigrated) { | ||
| const targetTheme = theme.value | ||
| const existing = themeSettings.value[targetTheme] ?? defaultPerThemeSettings() | ||
| const settings: PerThemeSettings = { ...existing } | ||
|
|
||
| // 代码块主题 | ||
| const codeBlockTheme = store.reactive(`codeBlockTheme`, defaultStyleConfig.codeBlockTheme) | ||
| const legacyFont = localStorage.getItem(`fonts`) | ||
| if (legacyFont) | ||
| settings.fontFamily = legacyFont | ||
|
|
||
| // 图注格式 | ||
| const legend = store.reactive(`legend`, defaultStyleConfig.legend) | ||
| const legacySize = localStorage.getItem(`size`) | ||
| if (legacySize) | ||
| settings.fontSize = legacySize | ||
|
|
||
| const legacyColor = localStorage.getItem(`color`) | ||
| if (legacyColor) | ||
| settings.primaryColor = legacyColor | ||
|
|
||
| const legacyCodeTheme = localStorage.getItem(`codeBlockTheme`) | ||
| if (legacyCodeTheme) | ||
| settings.codeBlockTheme = legacyCodeTheme | ||
|
|
||
| const legacyHeading = localStorage.getItem(`headingStyles`) | ||
| if (legacyHeading) { | ||
| try { | ||
| settings.headingStyles = JSON.parse(legacyHeading) | ||
| } | ||
| catch { /* ignore parse error */ } | ||
| } | ||
|
|
||
| const legacyMacBlock = localStorage.getItem(`isMacCodeBlock`) | ||
| if (legacyMacBlock !== null) | ||
| settings.isMacCodeBlock = legacyMacBlock === `true` | ||
|
|
||
| const legacyLineNum = localStorage.getItem(`isShowLineNumber`) | ||
| if (legacyLineNum !== null) | ||
| settings.isShowLineNumber = legacyLineNum === `true` | ||
|
|
||
| themeSettings.value = { | ||
| ...themeSettings.value, | ||
| [targetTheme]: settings, | ||
| } | ||
|
|
||
| // Mark migration as done | ||
| localStorage.setItem(migrationKey, `1`) | ||
|
|
||
| // Clean up legacy keys | ||
| for (const key of LEGACY_KEYS) { | ||
| localStorage.removeItem(key) | ||
| } | ||
| } |
| const fontSize = store.reactive(`size`, defaultStyleConfig.fontSize) | ||
| // --- Legacy migration: run once on store init --- | ||
| const hasAnyLegacyKey = LEGACY_KEYS.some(key => localStorage.getItem(key) !== null) | ||
| const migrationKey = `MD__legacy_migrated` |
Comment on lines
+28
to
+82
| // --- Legacy migration: run once on store init --- | ||
| const hasAnyLegacyKey = LEGACY_KEYS.some(key => localStorage.getItem(key) !== null) | ||
| const migrationKey = `MD__legacy_migrated` | ||
| const alreadyMigrated = localStorage.getItem(migrationKey) !== null | ||
|
|
||
| // 主色 | ||
| const primaryColor = store.reactive(`color`, defaultStyleConfig.primaryColor) | ||
| if (hasAnyLegacyKey && !alreadyMigrated) { | ||
| const targetTheme = theme.value | ||
| const existing = themeSettings.value[targetTheme] ?? defaultPerThemeSettings() | ||
| const settings: PerThemeSettings = { ...existing } | ||
|
|
||
| // 代码块主题 | ||
| const codeBlockTheme = store.reactive(`codeBlockTheme`, defaultStyleConfig.codeBlockTheme) | ||
| const legacyFont = localStorage.getItem(`fonts`) | ||
| if (legacyFont) | ||
| settings.fontFamily = legacyFont | ||
|
|
||
| // 图注格式 | ||
| const legend = store.reactive(`legend`, defaultStyleConfig.legend) | ||
| const legacySize = localStorage.getItem(`size`) | ||
| if (legacySize) | ||
| settings.fontSize = legacySize | ||
|
|
||
| const legacyColor = localStorage.getItem(`color`) | ||
| if (legacyColor) | ||
| settings.primaryColor = legacyColor | ||
|
|
||
| const legacyCodeTheme = localStorage.getItem(`codeBlockTheme`) | ||
| if (legacyCodeTheme) | ||
| settings.codeBlockTheme = legacyCodeTheme | ||
|
|
||
| const legacyHeading = localStorage.getItem(`headingStyles`) | ||
| if (legacyHeading) { | ||
| try { | ||
| settings.headingStyles = JSON.parse(legacyHeading) | ||
| } | ||
| catch { /* ignore parse error */ } | ||
| } | ||
|
|
||
| const legacyMacBlock = localStorage.getItem(`isMacCodeBlock`) | ||
| if (legacyMacBlock !== null) | ||
| settings.isMacCodeBlock = legacyMacBlock === `true` | ||
|
|
||
| const legacyLineNum = localStorage.getItem(`isShowLineNumber`) | ||
| if (legacyLineNum !== null) | ||
| settings.isShowLineNumber = legacyLineNum === `true` | ||
|
|
||
| themeSettings.value = { | ||
| ...themeSettings.value, | ||
| [targetTheme]: settings, | ||
| } | ||
|
|
||
| // Mark migration as done | ||
| localStorage.setItem(migrationKey, `1`) | ||
|
|
||
| // Clean up legacy keys | ||
| for (const key of LEGACY_KEYS) { | ||
| localStorage.removeItem(key) | ||
| } | ||
| } |
Comment on lines
+168
to
178
| // 重置样式(仅重置当前主题的配置) | ||
| const resetStyle = () => { | ||
| themeSettings.value = { | ||
| ...themeSettings.value, | ||
| [theme.value]: defaultPerThemeSettings(), | ||
| } | ||
| isCiteStatus.value = defaultStyleConfig.isCiteStatus | ||
| isMacCodeBlock.value = defaultStyleConfig.isMacCodeBlock | ||
| isShowLineNumber.value = defaultStyleConfig.isShowLineNumber | ||
| isCountStatus.value = defaultStyleConfig.isCountStatus | ||
|
|
||
| theme.value = defaultStyleConfig.theme | ||
| fontFamily.value = defaultStyleConfig.fontFamily | ||
| fontSize.value = defaultStyleConfig.fontSize | ||
| primaryColor.value = defaultStyleConfig.primaryColor | ||
| codeBlockTheme.value = defaultStyleConfig.codeBlockTheme | ||
| legend.value = defaultStyleConfig.legend | ||
| headingStyles.value = { ...defaultStyleConfig.headingStyles } | ||
|
|
||
| isUseIndent.value = false | ||
| isUseJustify.value = false | ||
| } |
…ode theme) Previously all themes shared the same primaryColor, fontFamily, fontSize, codeBlockTheme, headingStyles, isShowLineNumber, and isMacCodeBlock. Now each theme stores its own configuration in a single localStorage key (MD__themeSettings), and switching themes automatically loads the corresponding settings. Added backward-compatible migration that reads legacy localStorage keys and merges them into the current theme's per-theme settings on first load. Migration runs synchronously before store.reactive() installs its watch, with all localStorage access wrapped in try/catch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
🗑️ Cloudflare Workers preview deployment has been cleaned up. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…ode theme)
Previously all themes shared the same primaryColor, fontFamily, fontSize, codeBlockTheme, headingStyles, isShowLineNumber, and isMacCodeBlock. Now each theme stores its own configuration in a single localStorage key (MD__themeSettings), and switching themes automatically loads the corresponding settings.
Added backward-compatible migration that reads legacy localStorage keys and merges them into the current theme's settings on first load.