mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-28 16:09:17 +00:00
feat(editor): follow app theme
This commit is contained in:
@@ -20,9 +20,11 @@ import {
|
||||
DEFAULT_EDITOR_SETTINGS,
|
||||
type AiProvider,
|
||||
type AiApiStyle,
|
||||
type EditorTheme,
|
||||
} from "@/stores/settingsStore";
|
||||
import { loadEditorTheme, editorFontTheme } from "@/lib/editorThemes";
|
||||
import { isTauriRuntime } from "@/lib/tauriRuntime";
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
import { aiListModels, aiTestConnection, listSystemFonts, type AiModelInfo } from "@/lib/api";
|
||||
import { eventToShortcut } from "@/lib/keyboardShortcuts";
|
||||
import {
|
||||
@@ -34,9 +36,11 @@ import {
|
||||
} from "@/lib/shortcutRegistry";
|
||||
import { normalizeSidebarHiddenTablePrefixes } from "@/lib/sidebarTableNameDisplay";
|
||||
import AiProviderLogo from "@/components/icons/AiProviderLogo.vue";
|
||||
import type { AppThemeAppearance } from "@/lib/appTheme";
|
||||
|
||||
const { t } = useI18n();
|
||||
const settingsStore = useSettingsStore();
|
||||
const { isDark } = useTheme();
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean;
|
||||
@@ -540,10 +544,16 @@ async function aiTestConn() {
|
||||
const previewRef = ref<HTMLDivElement>();
|
||||
const previewView = shallowRef<EditorViewType | null>(null);
|
||||
|
||||
const previewSettings = computed(() => ({
|
||||
const previewSettings = computed<{
|
||||
fontFamily: string;
|
||||
fontSize: number;
|
||||
theme: EditorTheme;
|
||||
appAppearance: AppThemeAppearance;
|
||||
}>(() => ({
|
||||
fontFamily: editFontFamily.value,
|
||||
fontSize: editFontSize.value,
|
||||
theme: editTheme.value,
|
||||
appAppearance: isDark.value ? "dark" : "light",
|
||||
}));
|
||||
|
||||
const previewSql = `SELECT u.id, u.name
|
||||
@@ -559,7 +569,7 @@ watch(
|
||||
async (ss) => {
|
||||
if (!previewView.value || !fontThemeComp || !themeComp || !editorViewModule) return;
|
||||
|
||||
const themeExt = await loadEditorTheme(ss.theme);
|
||||
const themeExt = await loadEditorTheme(ss.theme, ss.appAppearance);
|
||||
previewView.value.dispatch({
|
||||
effects: [
|
||||
themeComp.reconfigure(themeExt),
|
||||
@@ -600,7 +610,7 @@ watch(previewRef, async (el) => {
|
||||
themeComp = new Compartment();
|
||||
|
||||
const ss = previewSettings.value;
|
||||
const themeExt = await loadEditorTheme(ss.theme);
|
||||
const themeExt = await loadEditorTheme(ss.theme, ss.appAppearance);
|
||||
|
||||
const state = EditorState.create({
|
||||
doc: previewSql,
|
||||
|
||||
@@ -16,6 +16,7 @@ import { resolveExecutableSql } from "@/lib/sqlExecutionTarget";
|
||||
import { formatSqlText, type SqlFormatDialect } from "@/lib/sqlFormatter";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
import {
|
||||
buildSqlCompletionItemsFromContext,
|
||||
getSqlFunctionSignatureHelp,
|
||||
@@ -68,6 +69,7 @@ const editorRef = ref<HTMLDivElement>();
|
||||
const view = shallowRef<EditorViewType | null>(null);
|
||||
const connectionStore = useConnectionStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const { isDark } = useTheme();
|
||||
const MAX_COMPLETION_TABLES = 200;
|
||||
const liveFontSize = ref(settingsStore.editorSettings.fontSize);
|
||||
const gestureStartFontSize = ref(settingsStore.editorSettings.fontSize);
|
||||
@@ -98,6 +100,10 @@ let buildSqlDiagnosticExtension: (() => import("@codemirror/state").Extension) |
|
||||
let buildSqlSignatureExtension: (() => import("@codemirror/state").Extension) | null = null;
|
||||
let codeMirrorSnippetCompletion: typeof import("@codemirror/autocomplete").snippetCompletion;
|
||||
|
||||
function editorThemeAppearance() {
|
||||
return isDark.value ? "dark" : "light";
|
||||
}
|
||||
|
||||
// Completion cache
|
||||
let cachedTables: Array<{ name: string; schema?: string; type?: "table" | "view" }> = [];
|
||||
// Persistent column cache keyed by "schema.table" or "table"
|
||||
@@ -649,7 +655,7 @@ onMounted(async () => {
|
||||
keywords: (baseDialect.spec.keywords || "") + " " + extraKeywords,
|
||||
});
|
||||
|
||||
const theme = await loadEditorTheme(ss.theme);
|
||||
const theme = await loadEditorTheme(ss.theme, editorThemeAppearance());
|
||||
|
||||
const state = EditorState.create({
|
||||
doc: props.modelValue,
|
||||
@@ -908,8 +914,8 @@ watch(
|
||||
|
||||
// Reactively apply editor settings changes
|
||||
watch(
|
||||
() => settingsStore.editorSettings,
|
||||
async (ss) => {
|
||||
[() => settingsStore.editorSettings, () => isDark.value],
|
||||
async ([ss]) => {
|
||||
if (!view.value || !codeMirrorTheme || !fontThemeComp || !wordWrapComp || !runKeymapComp || !editorViewModule) {
|
||||
return;
|
||||
}
|
||||
@@ -917,7 +923,7 @@ watch(
|
||||
liveFontSize.value = ss.fontSize;
|
||||
}
|
||||
syncEditorFontCssVars(liveFontSize.value, ss.fontFamily);
|
||||
const themeExt = await loadEditorTheme(ss.theme);
|
||||
const themeExt = await loadEditorTheme(ss.theme, editorThemeAppearance());
|
||||
view.value.dispatch({
|
||||
effects: [
|
||||
codeMirrorTheme.reconfigure(themeExt),
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
Globe,
|
||||
Moon,
|
||||
Sun,
|
||||
Monitor,
|
||||
SunMoon,
|
||||
Check,
|
||||
History,
|
||||
Bot,
|
||||
@@ -223,7 +223,7 @@ function onToolbarDblClick(e: MouseEvent) {
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="h-8 w-8" :aria-label="t('toolbar.theme')">
|
||||
<Monitor v-if="themeMode === 'system'" class="h-4 w-4" />
|
||||
<SunMoon v-if="themeMode === 'system'" class="h-4 w-4" />
|
||||
<Moon v-else-if="isDark" class="h-4 w-4" />
|
||||
<Sun v-else class="h-4 w-4" />
|
||||
</Button>
|
||||
@@ -252,7 +252,7 @@ function onToolbarDblClick(e: MouseEvent) {
|
||||
:class="{ 'bg-accent': themeMode === 'system' }"
|
||||
@select="emit('set-theme-mode', 'system')"
|
||||
>
|
||||
<Monitor class="h-4 w-4" />
|
||||
<SunMoon class="h-4 w-4" />
|
||||
{{ t("toolbar.themeSystem") }}
|
||||
<Check v-if="themeMode === 'system'" class="ml-auto h-4 w-4" />
|
||||
</DropdownMenuItem>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Extension } from "@codemirror/state";
|
||||
import type { EditorTheme } from "@/stores/settingsStore";
|
||||
import type { AppThemeAppearance } from "@/lib/appTheme";
|
||||
|
||||
type CodeMirrorStyleSpec = Parameters<typeof import("@codemirror/view").EditorView.theme>[0];
|
||||
|
||||
@@ -7,8 +8,18 @@ export const EDITOR_FONT_SIZE_CSS_VAR = "--dbx-editor-font-size";
|
||||
export const EDITOR_FONT_FAMILY_CSS_VAR = "--dbx-editor-font-family";
|
||||
|
||||
/** Load a CodeMirror theme extension by theme name. */
|
||||
export async function loadEditorTheme(theme: EditorTheme): Promise<Extension> {
|
||||
switch (theme) {
|
||||
export function resolveEditorTheme(theme: EditorTheme, appAppearance: AppThemeAppearance): Exclude<EditorTheme, "app"> {
|
||||
if (theme === "app") return appAppearance === "dark" ? "one-dark" : "vscode-light";
|
||||
return theme;
|
||||
}
|
||||
|
||||
/** Load a CodeMirror theme extension by theme name. */
|
||||
export async function loadEditorTheme(
|
||||
theme: EditorTheme,
|
||||
appAppearance: AppThemeAppearance = "dark",
|
||||
): Promise<Extension> {
|
||||
const resolvedTheme = resolveEditorTheme(theme, appAppearance);
|
||||
switch (resolvedTheme) {
|
||||
case "one-dark":
|
||||
return (await import("@codemirror/theme-one-dark")).oneDark;
|
||||
case "vscode-dark":
|
||||
|
||||
@@ -148,6 +148,7 @@ function inferAiProviderFromConfig(config: Partial<AiConfig> | null | undefined)
|
||||
}
|
||||
|
||||
export type EditorTheme =
|
||||
| "app"
|
||||
| "one-dark"
|
||||
| "vscode-dark"
|
||||
| "vscode-light"
|
||||
@@ -178,6 +179,7 @@ export interface EditorSettings {
|
||||
}
|
||||
|
||||
export const EDITOR_THEMES: { value: EditorTheme; label: string; dark: boolean }[] = [
|
||||
{ value: "app", label: "Follow app theme", dark: false },
|
||||
{ value: "one-dark", label: "One Dark", dark: true },
|
||||
{ value: "vscode-dark", label: "VS Dark+", dark: true },
|
||||
{ value: "vscode-light", label: "VS Light+", dark: false },
|
||||
@@ -189,6 +191,8 @@ export const EDITOR_THEMES: { value: EditorTheme; label: string; dark: boolean }
|
||||
{ value: "xcode", label: "Xcode", dark: false },
|
||||
];
|
||||
|
||||
const EDITOR_THEME_VALUES = new Set<EditorTheme>(EDITOR_THEMES.map((theme) => theme.value));
|
||||
|
||||
export const FONT_FAMILIES: { value: string; label: string }[] = [
|
||||
{ value: "'JetBrains Mono', 'Fira Code', monospace", label: "JetBrains Mono" },
|
||||
{ value: "'Fira Code', monospace", label: "Fira Code" },
|
||||
@@ -202,7 +206,7 @@ export const FONT_FAMILIES: { value: string; label: string }[] = [
|
||||
export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
|
||||
fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
|
||||
fontSize: 13,
|
||||
theme: "one-dark",
|
||||
theme: "app",
|
||||
executeMode: "all",
|
||||
wordWrap: false,
|
||||
compactTabTitle: false,
|
||||
@@ -245,7 +249,7 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>): Edit
|
||||
return {
|
||||
fontFamily: settings.fontFamily ?? DEFAULT_EDITOR_SETTINGS.fontFamily,
|
||||
fontSize: settings.fontSize ?? DEFAULT_EDITOR_SETTINGS.fontSize,
|
||||
theme: settings.theme ?? DEFAULT_EDITOR_SETTINGS.theme,
|
||||
theme: settings.theme && EDITOR_THEME_VALUES.has(settings.theme) ? settings.theme : DEFAULT_EDITOR_SETTINGS.theme,
|
||||
executeMode: settings.executeMode ?? DEFAULT_EDITOR_SETTINGS.executeMode,
|
||||
wordWrap: settings.wordWrap ?? DEFAULT_EDITOR_SETTINGS.wordWrap,
|
||||
compactTabTitle: settings.compactTabTitle ?? DEFAULT_EDITOR_SETTINGS.compactTabTitle,
|
||||
|
||||
Reference in New Issue
Block a user