diff --git a/examples/naivebayes/index.vue b/examples/naivebayes/index.vue index 80e9908..1954d1d 100644 --- a/examples/naivebayes/index.vue +++ b/examples/naivebayes/index.vue @@ -26,12 +26,7 @@
- +
{ editor.value = payload.view } + const editorExtensions = computed(() => { - return [javascript(), useTheme().theme.value === Theme.Dark ? oneDark : []] + return [javascript(), useTheme().currentTheme.value === Theme.Dark ? oneDark : []] }) const loading = ref(false) diff --git a/examples/vue-codemirror/index.vue b/examples/vue-codemirror/index.vue index b9fa6b0..c73d629 100644 --- a/examples/vue-codemirror/index.vue +++ b/examples/vue-codemirror/index.vue @@ -26,7 +26,7 @@ import { Theme, useTheme } from '@/composables/theme' import Loading from '@/components/common/loading.vue' import languages from './languages' - import themes from './themes' + import * as themes from './themes' import Toolbar from './toolbar.vue' import Editor from './editor.vue' @@ -54,7 +54,7 @@ const langCodeMap = reactive(new Map any }>()) const currentLangCode = computed(() => langCodeMap.get(config.language)!) const currentTheme = computed(() => { - return config.theme !== 'default' ? themes[config.theme] : void 0 + return config.theme !== 'default' ? (themes as any)[config.theme] : void 0 }) const ensureLanguageCode = async (targetLanguage: string) => { diff --git a/examples/vue-codemirror/lang-code/vue/index.ts b/examples/vue-codemirror/lang-code/vue/index.ts new file mode 100644 index 0000000..86acbac --- /dev/null +++ b/examples/vue-codemirror/lang-code/vue/index.ts @@ -0,0 +1,7 @@ +import { vue } from '@codemirror/lang-vue' +import code from './vue.vue?raw' + +export default { + language: vue, + code +} diff --git a/examples/vue-codemirror/lang-code/vue/vue.vue b/examples/vue-codemirror/lang-code/vue/vue.vue new file mode 100644 index 0000000..2fe8800 --- /dev/null +++ b/examples/vue-codemirror/lang-code/vue/vue.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/examples/vue-codemirror/themes.ts b/examples/vue-codemirror/themes.ts index 188787b..5b2bc8f 100644 --- a/examples/vue-codemirror/themes.ts +++ b/examples/vue-codemirror/themes.ts @@ -1,5 +1,21 @@ -import { oneDark } from '@codemirror/theme-one-dark' - -export default { - oneDark -} as Record +export { oneDark } from '@codemirror/theme-one-dark' +export { materialDark } from 'cm6-theme-material-dark' +export { nord } from 'cm6-theme-nord' +export { + amy, + ayuLight, + barf, + bespin, + birdsOfParadise, + boysAndGirls, + clouds, + cobalt, + coolGlow, + dracula, + espresso, + noctisLilac, + rosePineDawn, + smoothy, + solarizedLight, + tomorrow +} from 'thememirror' diff --git a/package.json b/package.json index 428b0dc..a28a0b9 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@codemirror/lang-python": "^6.x", "@codemirror/lang-rust": "^6.x", "@codemirror/lang-sql": "^6.x", + "@codemirror/lang-vue": "^0.1.2", "@codemirror/lang-xml": "^6.x", "@codemirror/language": "^6.x", "@codemirror/legacy-modes": "^6.x", @@ -42,6 +43,8 @@ "@videojs-player/vue": "^1.0.0", "@videojs/themes": "^1.0.1", "axios": "^1.5.0", + "cm6-theme-material-dark": "^0.2.0", + "cm6-theme-nord": "^0.2.0", "codemirror": "^6.x", "dedent": "^1.5.1", "flv.js": "^1.6.2", @@ -55,6 +58,7 @@ "react-dom": "^18.2.0", "segmentit": "^2.0.3", "swiper": "^10.2.0", + "thememirror": "^2.0.1", "video.js": "^8.5.2", "vue": "^3.3.4", "vue-codemirror": "^6.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80cef64..3affd1e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ dependencies: '@codemirror/lang-sql': specifier: ^6.x version: 6.3.3(@codemirror/view@6.15.3)(@lezer/common@1.0.2) + '@codemirror/lang-vue': + specifier: ^0.1.2 + version: 0.1.2 '@codemirror/lang-xml': specifier: ^6.x version: 6.0.1(@codemirror/view@6.15.3) @@ -83,6 +86,12 @@ dependencies: axios: specifier: ^1.5.0 version: 1.5.0 + cm6-theme-material-dark: + specifier: ^0.2.0 + version: 0.2.0(@codemirror/language@6.3.2)(@codemirror/state@6.1.4)(@codemirror/view@6.15.3)(@lezer/highlight@1.1.3) + cm6-theme-nord: + specifier: ^0.2.0 + version: 0.2.0(@codemirror/language@6.3.2)(@codemirror/state@6.1.4)(@codemirror/view@6.15.3)(@lezer/highlight@1.1.3) codemirror: specifier: ^6.x version: 6.0.1(@lezer/common@1.0.2) @@ -122,6 +131,9 @@ dependencies: swiper: specifier: ^10.2.0 version: 10.2.0 + thememirror: + specifier: ^2.0.1 + version: 2.0.1(@codemirror/language@6.3.2)(@codemirror/state@6.1.4)(@codemirror/view@6.15.3) video.js: specifier: ^8.5.2 version: 8.5.2 @@ -598,6 +610,17 @@ packages: - '@lezer/common' dev: false + /@codemirror/lang-vue@0.1.2: + resolution: {integrity: sha512-D4YrefiRBAr+CfEIM4S3yvGSbYW+N69mttIfGMEf7diHpRbmygDxS+R/5xSqjgtkY6VO6qmUrre1GkRcWeZa9A==} + dependencies: + '@codemirror/lang-html': 6.4.0 + '@codemirror/lang-javascript': 6.1.2 + '@codemirror/language': 6.3.2 + '@lezer/common': 1.0.2 + '@lezer/highlight': 1.1.3 + '@lezer/lr': 1.3.10 + dev: false + /@codemirror/lang-xml@6.0.1(@codemirror/view@6.15.3): resolution: {integrity: sha512-0tvycUTElajCcRKgsszhKjWX+uuOogdu5+enpfqYA+j0gnP8ek7LRxujh2/XMPRdXt/hwOML4slJLE7r2eX3yQ==} dependencies: @@ -1036,6 +1059,12 @@ packages: '@lezer/common': 1.0.2 dev: false + /@lezer/lr@1.3.10: + resolution: {integrity: sha512-BZfVvf7Re5BIwJHlZXbJn9L8lus5EonxQghyn+ih8Wl36XMFBPTXC0KM0IdUtj9w/diPHsKlXVgL+AlX2jYJ0Q==} + dependencies: + '@lezer/common': 1.0.2 + dev: false + /@lezer/markdown@1.0.2: resolution: {integrity: sha512-8CY0OoZ6V5EzPjSPeJ4KLVbtXdLBd8V6sRCooN5kHnO28ytreEGTyrtU/zUwo/XLRzGr/e1g44KlzKi3yWGB5A==} dependencies: @@ -1566,6 +1595,34 @@ packages: fsevents: 2.3.2 dev: true + /cm6-theme-material-dark@0.2.0(@codemirror/language@6.3.2)(@codemirror/state@6.1.4)(@codemirror/view@6.15.3)(@lezer/highlight@1.1.3): + resolution: {integrity: sha512-H09JZihzg4w0mTtOqo5bQdxItkQWw+ergKlk7BSfwYjaR2nOi+wIN0R+ByAo7bON8GbFODvjTxH3EIqdhovFeA==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@lezer/highlight': ^1.0.0 + dependencies: + '@codemirror/language': 6.3.2 + '@codemirror/state': 6.1.4 + '@codemirror/view': 6.15.3 + '@lezer/highlight': 1.1.3 + dev: false + + /cm6-theme-nord@0.2.0(@codemirror/language@6.3.2)(@codemirror/state@6.1.4)(@codemirror/view@6.15.3)(@lezer/highlight@1.1.3): + resolution: {integrity: sha512-jTh+5nvl+N/5CtTK7UVcrxDCj2AOStvbNM8uP6tx6amq4QaaLDlapjMw+MNzEkvxcPnHY+YM91tbklS2KNlR2w==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@lezer/highlight': ^1.0.0 + dependencies: + '@codemirror/language': 6.3.2 + '@codemirror/state': 6.1.4 + '@codemirror/view': 6.15.3 + '@lezer/highlight': 1.1.3 + dev: false + /codemirror@6.0.1(@lezer/common@1.0.2): resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} dependencies: @@ -3088,6 +3145,18 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /thememirror@2.0.1(@codemirror/language@6.3.2)(@codemirror/state@6.1.4)(@codemirror/view@6.15.3): + resolution: {integrity: sha512-d5i6FVvWWPkwrm4cHLI3t9AT1OrkAt7Ig8dtdYSofgF7C/eiyNuq6zQzSTusWTde3jpW9WLvA9J/fzNKMUsd0w==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + dependencies: + '@codemirror/language': 6.3.2 + '@codemirror/state': 6.1.4 + '@codemirror/view': 6.15.3 + dev: false + /titleize@3.0.0: resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} engines: {node: '>=12'} diff --git a/src/components/layout/navbar.vue b/src/components/layout/navbar.vue index afe19b5..a100aaf 100644 --- a/src/components/layout/navbar.vue +++ b/src/components/layout/navbar.vue @@ -18,7 +18,7 @@ const toggleTheme = () => { const currentIndex = THEMES.indexOf(theme.theme.value) const newIndex = currentIndex === THEMES.length - 1 ? 0 : currentIndex + 1 - theme.set(THEMES[newIndex]) + theme.setTheme(THEMES[newIndex]) } const activatedTheme = computed(() => { diff --git a/src/composables/theme.ts b/src/composables/theme.ts index cf195fa..aadf8b6 100644 --- a/src/composables/theme.ts +++ b/src/composables/theme.ts @@ -1,4 +1,4 @@ -import { App, inject, ref, readonly } from 'vue' +import { App, inject, ref, computed, readonly } from 'vue' import storage from '@/services/storage' export enum Theme { @@ -38,9 +38,27 @@ const createThemeStore = (defaultTheme: Theme) => { } } + const systemTheme = ref(defaultTheme) + const initOnClient = () => { + systemTheme.value = getSystemTheme() || defaultTheme + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ({ matches }) => { + systemTheme.value = matches ? Theme.Dark : Theme.Light + }) + } + + const currentTheme = computed(() => { + if (theme.value === Theme.System) { + return systemTheme.value + } else { + return theme.value + } + }) + return { theme: readonly(theme), - set: setTheme + currentTheme, + setTheme, + initOnClient } } diff --git a/src/csr.ts b/src/csr.ts index 133df2c..c5805cb 100644 --- a/src/csr.ts +++ b/src/csr.ts @@ -8,7 +8,7 @@ import { createUniversalApp } from './main' import '@/styles/app.scss' -const { app, router, visitor } = createUniversalApp({ +const { app, router, visitor, theme } = createUniversalApp({ // MARK: use `createApp`, not `createSSRApp`, to avoid hydrate appCreator: createApp, routerHistory: createWebHistory(), @@ -20,6 +20,7 @@ const { app, router, visitor } = createUniversalApp({ app.use(highlight) app.use(adsense, { ID: GOOGLE_ADSENSE_CLIENT_ID, enabledAutoAD: false }) visitor.resetStateOnClient() +theme.initOnClient() router.isReady().finally(() => { app.mount('#app', true).$nextTick(() => {