diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index 3961293c29..f3dc10aafe 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -122,7 +122,7 @@ const connectionDialogPrefill = ref(null); const connectionDialogInitialTab = ref(undefined); const settingsPageTabOpen = ref(false); const settingsPageActive = ref(false); -const settingsInitialTab = ref("editor"); +const settingsInitialTab = ref("appearance"); const settingsInitialSection = ref(undefined); const showQueryEditorDdlDialog = ref(false); const driverStoreTabOpen = ref(false); @@ -265,7 +265,7 @@ const appVersion = ref(""); const isClassicLayout = computed(() => settingsStore.editorSettings.appLayout === "classic"); const updateNotificationsEnabled = computed(() => settingsStore.editorSettings.updateNotificationsEnabled); -function openSettings(initialTab = "editor", initialSection?: string) { +function openSettings(initialTab = "appearance", initialSection?: string) { settingsInitialTab.value = initialTab; settingsInitialSection.value = initialSection; if (!settingsPageActive.value) { diff --git a/apps/desktop/src/components/diff/SchemaDiffDeployStep.vue b/apps/desktop/src/components/diff/SchemaDiffDeployStep.vue index 7af0d54bc6..26d3841a9c 100644 --- a/apps/desktop/src/components/diff/SchemaDiffDeployStep.vue +++ b/apps/desktop/src/components/diff/SchemaDiffDeployStep.vue @@ -15,7 +15,7 @@ import { ArrowLeft, Copy, Download, Play, Loader2, PlusCircle, XCircle, ArrowRig const { t } = useI18n(); const { toast } = useToast(); const settingsStore = useSettingsStore(); -const { isDark } = useTheme(); +const { isDark, themePalette } = useTheme(); const props = defineProps<{ deploySql: string; @@ -120,7 +120,7 @@ async function initEditor() { const fontSize = settingsStore.editorSettings.fontSize; const fontFamily = settingsStore.editorSettings.fontFamily; - const themeExt = await loadEditorTheme(editorTheme, appAppearance); + const themeExt = await loadEditorTheme(editorTheme, appAppearance, undefined, themePalette.value); const fontExt = editorFontTheme(EditorView, fontSize, fontFamily, { fixedHeight: true, scrollable: true }); const dialect = createDbxCodeMirrorSqlDialect(langSql, "postgres"); diff --git a/apps/desktop/src/components/editor/EditorSettingsDialog.vue b/apps/desktop/src/components/editor/EditorSettingsDialog.vue index 0b319e015d..e953e07fce 100644 --- a/apps/desktop/src/components/editor/EditorSettingsDialog.vue +++ b/apps/desktop/src/components/editor/EditorSettingsDialog.vue @@ -81,7 +81,7 @@ import { DEFAULT_SQL_SNIPPETS } from "@/lib/sql/sqlCompletion"; import AiProviderLogo from "@/components/icons/AiProviderLogo.vue"; import AppLogo from "@/components/icons/AppLogo.vue"; import SqlFormatterSettingsPanel from "./SqlFormatterSettingsPanel.vue"; -import type { AppThemeAppearance } from "@/lib/app/appTheme"; +import { APP_THEME_PALETTES, type AppThemeAppearance, type AppThemeMode, type AppThemePalette } from "@/lib/app/appTheme"; import { useConnectionStore } from "@/stores/connectionStore"; import { useSavedSqlStore } from "@/stores/savedSqlStore"; import { currentLocale, setLocale, type Locale } from "@/i18n"; @@ -95,7 +95,23 @@ const { toast } = useToast(); const settingsStore = useSettingsStore(); const connectionStore = useConnectionStore(); const savedSqlStore = useSavedSqlStore(); -const { isDark, themeMode, setThemeMode } = useTheme(); +const { isDark, themeMode, themePalette, setThemeMode, setThemePalette } = useTheme(); + +const appThemePaletteOptions = computed( + (): Array<{ value: AppThemePalette; label: string; previewColor: string }> => + APP_THEME_PALETTES.map((palette) => ({ + value: palette.value, + label: t(palette.labelKey), + previewColor: palette.previewColor, + })), +); +const selectedThemePaletteOption = computed(() => appThemePaletteOptions.value.find((option) => option.value === themePalette.value) ?? appThemePaletteOptions.value[0]); +const selectedLocaleOption = computed(() => LOCALE_OPTIONS.find((locale) => locale.value === currentLocale()) ?? LOCALE_OPTIONS[0]); +const appThemeModeOptions = computed(() => [ + { value: "light" as AppThemeMode, label: t("toolbar.themeLight"), icon: Sun }, + { value: "dark" as AppThemeMode, label: t("toolbar.themeDark"), icon: Moon }, + { value: "system" as AppThemeMode, label: t("toolbar.themeSystem"), icon: SunMoon }, +]); let cachedSystemFonts: string[] | null = null; let pendingSystemFonts: Promise | null = null; @@ -274,7 +290,9 @@ const systemFontsLoaded = ref(false); const uiScaleOptions = [0.75, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2]; const fontSearchTriggerClass = "h-8 w-full max-w-none justify-between gap-1.5 rounded-[6px] border border-input bg-transparent py-2 pl-2.5 pr-2 text-sm font-normal shadow-none hover:bg-transparent focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-expanded:bg-transparent dark:bg-input/30 dark:hover:bg-input/50"; +const appearanceFontSearchTriggerClass = `${fontSearchTriggerClass} gap-0 pl-2 pr-1.5`; const fontSearchTriggerIconClass = "size-4 text-muted-foreground"; +const appearanceFontSearchTriggerIconClass = "size-2.5 text-muted-foreground"; const disconnectTabHandlingModeDescriptionKey = computed(() => { switch (editDisconnectTabHandlingMode.value) { case "close-tabs": @@ -1123,14 +1141,14 @@ function setSidebarActivation(value: "single" | "double") { editSidebarActivation.value = value; } -const activeSettingsTab = ref("editor"); +const activeSettingsTab = ref("appearance"); const isWeb = !isTauriRuntime(); const displayedAppVersion = computed(() => (props.appVersion ? `v${props.appVersion}` : "")); type SettingsCategory = "editor" | "formatter" | "appearance" | "navigation" | "data" | "shortcuts" | "snippets" | "sync" | "ai" | "mcp" | "security" | "about"; const settingsCategoryNav = computed<{ value: SettingsCategory; label: string }[]>(() => [ + { value: "appearance", label: t("settings.appearanceTab") }, { value: "editor", label: t("settings.editorTab") }, { value: "formatter", label: t("settings.sqlFormatterTab") }, - { value: "appearance", label: t("settings.appearanceTab") }, { value: "navigation", label: t("settings.navigationTab") }, { value: "data", label: t("settings.dataTab") }, { value: "shortcuts", label: t("settings.shortcutsTab") }, @@ -1148,7 +1166,7 @@ function hasSettingsApplyFooter(value: SettingsCategory): boolean { } function settingsCategoryButton(value: SettingsCategory): string { - return ["w-full rounded-md px-3 py-2 text-left text-sm transition-colors", value === activeSettingsTab.value ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:bg-muted hover:text-foreground"].join(" "); + return ["w-auto shrink-0 whitespace-nowrap rounded-md px-3 py-2 text-left text-sm transition-colors lg:w-full", value === activeSettingsTab.value ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:bg-muted hover:text-foreground"].join(" "); } function openExternalUrl(url: string) { @@ -1477,7 +1495,7 @@ watch( () => settingsVisible.value, async (open) => { if (open) { - activeSettingsTab.value = props.initialTab || "editor"; + activeSettingsTab.value = props.initialTab || "appearance"; passwordMessage.value = ""; oldPassword.value = ""; newPassword.value = ""; @@ -1962,12 +1980,14 @@ const previewSettings = computed<{ fontSize: number; theme: EditorTheme; appAppearance: AppThemeAppearance; + appPalette: AppThemePalette; customColors?: CustomThemeColors; }>(() => ({ fontFamily: editFontFamily.value, fontSize: editFontSize.value, theme: editTheme.value, appAppearance: isDark.value ? "dark" : "light", + appPalette: themePalette.value, customColors: getPreviewCustomThemeColors(), })); @@ -2017,7 +2037,7 @@ watch( async ([ss]) => { if (!previewView.value || !fontThemeComp || !themeComp || !editorViewModule) return; - const themeExt = await loadEditorTheme(ss.theme, ss.appAppearance, ss.customColors); + const themeExt = await loadEditorTheme(ss.theme, ss.appAppearance, ss.customColors, ss.appPalette); previewView.value.dispatch({ effects: [themeComp.reconfigure(themeExt), fontThemeComp.reconfigure(editorFontTheme(editorViewModule.EditorView, ss.fontSize, ss.fontFamily))], }); @@ -2065,7 +2085,7 @@ watch(previewRef, async (el) => { previewSqlDiagnostics = previewDiagnosticsForSql(currentPreviewSql()); const ss = previewSettings.value; - const themeExt = await loadEditorTheme(ss.theme, ss.appAppearance, ss.customColors); + const themeExt = await loadEditorTheme(ss.theme, ss.appAppearance, ss.customColors, ss.appPalette); const diagnosticTheme = EditorView.baseTheme({ ".cm-settings-preview-sql-error": { textDecoration: "underline wavy var(--destructive)", @@ -2125,8 +2145,8 @@ onUnmounted(cleanupPreviewEditor); -
-