Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 6 additions & 12 deletions src/components/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ This directory contains the shadcn-vue UI components used in SQLKit.
Located in `src/components/layout/`:

- **AppLayout** - Main application layout wrapper
- **AppHeader** - Top navigation header with theme toggle
- **AppHeader** - Top navigation header
- **AppSidebar** - Left sidebar navigation
- **ThemeToggle** - Dark/light mode toggle button

## Theme

Expand Down Expand Up @@ -50,14 +49,9 @@ import { Input } from '@/components/ui/input'

## Theme System

The theme system uses the `useTheme` composable:
The theme system is managed by the Pinia `appStore` (`src/store/appStore.ts`):

```vue
<script setup lang="ts">
import { useTheme } from '@/composables/useTheme'

const { theme: _theme, isDark: _isDark, setTheme: _setTheme, toggleTheme: _toggleTheme } = useTheme()
</script>
```

Theme preferences are persisted in localStorage and respect system preferences.
- `themeType` (`auto` | `dark` | `light`) is the user preference, persisted via pinia-plugin-persistedstate.
- `uiThemeType` (`dark` | `light`) is the resolved effective theme.
- `applyUiTheme` toggles the `theme` attribute and `.dark` class on `<html>`.
- Monaco editor themes are derived from `appStore.uiThemeType` in `useMonacoEditor`.
5 changes: 3 additions & 2 deletions src/components/SQLEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useI18n } from 'vue-i18n'
import { ProgressBar } from '@/components/ui/progress'
import { useMonacoEditor } from '@/composables/useMonacoEditor'
import { usePlatform } from '@/composables/usePlatform'
import { useTheme } from '@/composables/useTheme'
import { ThemeType, useAppStore } from '@/store/appStore'

type Props = {
modelValue?: string
Expand Down Expand Up @@ -48,7 +48,8 @@ const emit = defineEmits<{
}>()

const editorContainer = ref<HTMLElement | null>(null)
const { isDark } = useTheme()
const appStore = useAppStore()
const isDark = computed(() => appStore.uiThemeType === ThemeType.DARK)
const { modifierKey, altKey } = usePlatform()
const { t } = useI18n()

Expand Down
13 changes: 0 additions & 13 deletions src/components/layout/ThemeToggle.vue

This file was deleted.

25 changes: 17 additions & 8 deletions src/components/markdown-render.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
<script setup lang="ts">
import DOMPurify from 'dompurify'
import hljs from 'highlight.js'
import hljsThemeDarkUrl from 'highlight.js/styles/atom-one-dark.css?url'
import hljsThemeLightUrl from 'highlight.js/styles/atom-one-light.css?url'
import MarkdownIt from 'markdown-it'
import taskLists from 'markdown-it-task-lists'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { onUnmounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { toast } from '@/composables/useNotifications'
import { ThemeType, useAppStore } from '@/store/appStore'

const props = defineProps<{
markdown: string
}>()

const { t } = useI18n()
const appStore = useAppStore()

// Lazy-load highlight.js theme CSS after mount to avoid blocking initial render
let _themeLoaded = false
onMounted(() => {
if (!_themeLoaded) {
_themeLoaded = true
import('highlight.js/styles/atom-one-dark.css')
// Load the highlight.js theme matching the current UI theme via a single
// module-level <link> so it can be swapped at runtime without flicker.
let highlightLink: HTMLLinkElement | null = null
function applyHighlightTheme(uiThemeType: Exclude<ThemeType, ThemeType.AUTO>) {
const href = uiThemeType === ThemeType.DARK ? hljsThemeDarkUrl : hljsThemeLightUrl
if (!highlightLink) {
highlightLink = document.createElement('link')
highlightLink.rel = 'stylesheet'
document.head.appendChild(highlightLink)
}
})
highlightLink.href = href
}
watch(() => appStore.uiThemeType, applyHighlightTheme, { immediate: true })

const parsedMarkdown = ref('')

Expand Down
6 changes: 3 additions & 3 deletions src/composables/useMonacoEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'

import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import { onBeforeUnmount } from 'vue'
import { ThemeType, useAppStore } from '@/store/appStore'
import { hasGrammar } from './sqlCompletion/dialects'
import { getCompletionProvider } from './sqlCompletion/provider'
import {
Expand All @@ -15,7 +16,6 @@ import {
parseSqlStatements,
SQL_EXECUTE_GUTTER_CLASS,
} from './useSqlStatements'
import { useTheme } from './useTheme'

// Import only SQL-related grammars instead of all Monaco languages
// (Typescript/CSS/HTML/JSON workers alone add ~8MB to the bundle).
Expand Down Expand Up @@ -62,7 +62,7 @@ export function useMonacoEditor(containerRef: Ref<HTMLElement | null>, initialVa
let parsedStatements: SqlStatement[] = []
let registeredCallbacks: EditorCallbacks | null = null
let refreshDebounceTimer: ReturnType<typeof setTimeout> | null = null
const { isDark } = useTheme()
const appStore = useAppStore()

/** Monaco ships grammars only for sql/mysql/pgsql; other dialect ids use the generic sql grammar. Completion still resolves the real dialect profile per-editor. */
const resolveEditorLanguage = (id: SQLDialect): SQLDialect => hasGrammar(id) ? id : 'sql'
Expand Down Expand Up @@ -98,7 +98,7 @@ export function useMonacoEditor(containerRef: Ref<HTMLElement | null>, initialVa
editor = monaco.editor.create(containerRef.value, {
value: initialValue.value,
language: resolveEditorLanguage(options.language || 'sql'),
theme: isDark.value ? 'vs-dark' : 'vs',
theme: appStore.uiThemeType === ThemeType.DARK ? 'vs-dark' : 'vs',
automaticLayout: true,
readOnly: options.readOnly || false,
minimap: { enabled: options.minimap !== false },
Expand Down
85 changes: 0 additions & 85 deletions src/composables/useTheme.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/store/appStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ export const useAppStore = defineStore('app', {
this.sidebarCollapsed = collapsed
},
getEditorTheme() {
return this.uiThemeType === ThemeType.DARK ? 'vs-dark' : 'vs-light'
return this.uiThemeType === ThemeType.DARK ? 'vs-dark' : 'vs'
},

// ── Provider CRUD ────────────────────────────────────────────────────
Expand Down
4 changes: 2 additions & 2 deletions tests/store/appStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,11 @@ describe('appStore', () => {
})

describe('getEditorTheme', () => {
it('should return vs-light for light theme', () => {
it('should return vs for light theme', () => {
const store = useAppStore()
store.uiThemeType = ThemeType.LIGHT

expect(store.getEditorTheme()).toBe('vs-light')
expect(store.getEditorTheme()).toBe('vs')
})

it('should return vs-dark for dark theme', () => {
Expand Down
Loading