Files
dbx/src/stores/settingsStore.ts
T

142 lines
5.0 KiB
TypeScript

import { defineStore } from "pinia";
import { ref } from "vue";
import * as api from "@/lib/tauri";
export type AiProvider = "claude" | "openai" | "custom";
export type AiApiStyle = "completions" | "responses";
export interface AiConfig {
provider: AiProvider;
apiKey: string;
endpoint: string;
model: string;
apiStyle: AiApiStyle;
}
const defaultConfigs: Record<AiProvider, Omit<AiConfig, "apiKey">> = {
claude: { provider: "claude", endpoint: "https://api.anthropic.com/v1/messages", model: "claude-sonnet-4-20250514", apiStyle: "completions" },
openai: { provider: "openai", endpoint: "https://api.openai.com/v1/chat/completions", model: "gpt-4o", apiStyle: "completions" },
custom: { provider: "custom", endpoint: "", model: "", apiStyle: "completions" },
};
export type EditorTheme = "one-dark" | "vscode-dark" | "vscode-light" | "nord" | "okaidia" | "material" | "duotone-light" | "duotone-dark" | "xcode";
export interface EditorSettings {
fontFamily: string;
fontSize: number;
theme: EditorTheme;
}
export const EDITOR_THEMES: { value: EditorTheme; label: string; dark: boolean }[] = [
{ value: "one-dark", label: "One Dark", dark: true },
{ value: "vscode-dark", label: "VS Dark+", dark: true },
{ value: "vscode-light", label: "VS Light+", dark: false },
{ value: "nord", label: "Nord", dark: true },
{ value: "okaidia", label: "Okaidia", dark: true },
{ value: "material", label: "Material", dark: true },
{ value: "duotone-light", label: "Duotone Light", dark: false },
{ value: "duotone-dark", label: "Duotone Dark", dark: true },
{ value: "xcode", label: "Xcode", dark: false },
];
export const FONT_FAMILIES: { value: string; label: string }[] = [
{ value: "'JetBrains Mono', 'Fira Code', monospace", label: "JetBrains Mono" },
{ value: "'Fira Code', monospace", label: "Fira Code" },
{ value: "'Cascadia Code', monospace", label: "Cascadia Code" },
{ value: "'Source Code Pro', monospace", label: "Source Code Pro" },
{ value: "'SF Mono', 'Menlo', monospace", label: "SF Mono / Menlo" },
{ value: "'Consolas', 'Courier New', monospace", label: "Consolas" },
{ value: "monospace", label: "System Monospace" },
];
export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
fontSize: 13,
theme: "one-dark",
};
export const STORAGE_KEY = "dbx-editor-settings";
const OLD_FONT_SIZE_KEY = "dbx-query-editor-font-size";
function loadEditorSettings(): EditorSettings {
// Try new format first
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (raw) {
const parsed = JSON.parse(raw) as Partial<EditorSettings>;
return {
fontFamily: parsed.fontFamily ?? DEFAULT_EDITOR_SETTINGS.fontFamily,
fontSize: parsed.fontSize ?? DEFAULT_EDITOR_SETTINGS.fontSize,
theme: parsed.theme ?? DEFAULT_EDITOR_SETTINGS.theme,
};
}
} catch { /* ignore */ }
// Migrate old font-size key if new settings don't exist
try {
const oldSize = localStorage.getItem(OLD_FONT_SIZE_KEY);
if (oldSize) {
const parsed = parseInt(oldSize, 10);
if (!isNaN(parsed)) {
const migrated: EditorSettings = {
...DEFAULT_EDITOR_SETTINGS,
fontSize: parsed,
};
saveEditorSettings(migrated);
localStorage.removeItem(OLD_FONT_SIZE_KEY);
return migrated;
}
}
} catch { /* ignore */ }
return { ...DEFAULT_EDITOR_SETTINGS };
}
function saveEditorSettings(settings: EditorSettings) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));
}
export const useSettingsStore = defineStore("settings", () => {
const aiConfig = ref<AiConfig>({ ...defaultConfigs.claude, apiKey: "", apiStyle: "completions" });
const isAiConfigLoaded = ref(false);
const editorSettings = ref<EditorSettings>(loadEditorSettings());
async function initAiConfig() {
if (isAiConfigLoaded.value) return;
const legacy = localStorage.getItem("dbx-ai-config");
const saved = await api.loadAiConfig().catch(() => null);
if (saved) {
aiConfig.value = saved;
} else if (legacy) {
aiConfig.value = JSON.parse(legacy);
await api.saveAiConfig(aiConfig.value).catch(() => {});
localStorage.removeItem("dbx-ai-config");
}
isAiConfigLoaded.value = true;
}
function updateAiConfig(config: Partial<AiConfig>) {
const previousProvider = aiConfig.value.provider;
if (config.provider && config.provider !== previousProvider) {
Object.assign(aiConfig.value, defaultConfigs[config.provider]);
}
Object.assign(aiConfig.value, config);
api.saveAiConfig(aiConfig.value).catch(() => {});
}
function isConfigured(): boolean {
return !!aiConfig.value.apiKey && !!aiConfig.value.endpoint;
}
function updateEditorSettings(partial: Partial<EditorSettings>) {
Object.assign(editorSettings.value, partial);
saveEditorSettings(editorSettings.value);
}
return {
aiConfig, isAiConfigLoaded, initAiConfig, updateAiConfig, isConfigured,
editorSettings, updateEditorSettings,
};
});