diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index a42e8a8fb9..a57d7f4bdf 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -9,6 +9,7 @@ import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import type { ConnectionConfig, DatabaseType, @@ -49,6 +50,7 @@ import { KeyRound, Link2, List, + Pipette, Plus, Search, ShieldCheck, @@ -287,6 +289,28 @@ const colorOptions = [ { value: "#a855f7", class: "bg-purple-500", labelKey: "connection.colorPurple" }, ]; +const isPresetColor = (color: string | undefined) => colorOptions.some((c) => c.value === (color || "")); +const customColorInput = ref(""); +const customColorOpen = ref(false); + +function applyCustomColor(value: string) { + form.value.color = value; + customColorInput.value = value; +} + +function handlePresetClick(color: string) { + form.value.color = color; + customColorInput.value = ""; +} + +function handleCustomColorPicked(value: string) { + applyCustomColor(value); +} + +function handleCustomColorInput(value: string) { + applyCustomColor(value); +} + const driverProfiles: Record< string, { @@ -551,6 +575,7 @@ watch( etcd_endpoints: config.etcd_endpoints || "", }; h2ConnectionMode.value = h2ConnectionModeForConfig(config); + customColorInput.value = config.color || ""; selectedTransportLayerId.value = form.value.transport_layers?.[0]?.id || null; selectedType.value = profile; if (profile === "oceanbase") { @@ -2151,8 +2176,45 @@ function openExternalUrl(url: string) { form.color === color.value ? 'ring-2 ring-ring ring-offset-2' : 'border-border', ]" :title="t(color.labelKey)" - @click="form.color = color.value" + @click="handlePresetClick(color.value)" /> + + + + + +
+ + +
+
+
diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index 970c061338..835903e279 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -306,6 +306,7 @@ export default { colorRed: "Red", colorBlue: "Blue", colorPurple: "Purple", + colorCustom: "Custom color", }, editor: { pressToExecute: "Press {mod}+Enter to execute", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index 6057061056..d6602ba709 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -288,6 +288,7 @@ export default { colorRed: "Rojo", colorBlue: "Azul", colorPurple: "Morado", + colorCustom: "Color personalizado", }, editor: { pressToExecute: "Presiona {mod}+Enter para ejecutar", diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts index dbc4647fdd..abc7a01f96 100644 --- a/apps/desktop/src/i18n/locales/it.ts +++ b/apps/desktop/src/i18n/locales/it.ts @@ -300,6 +300,7 @@ export default { colorRed: "Rosso", colorBlue: "Blu", colorPurple: "Viola", + colorCustom: "Colore personalizzato", }, editor: { pressToExecute: "Premi {mod}+Enter per eseguire", diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts index 8939a0388e..d179952083 100644 --- a/apps/desktop/src/i18n/locales/pt-BR.ts +++ b/apps/desktop/src/i18n/locales/pt-BR.ts @@ -299,6 +299,7 @@ export default { colorRed: "Vermelho", colorBlue: "Azul", colorPurple: "Roxo", + colorCustom: "Cor personalizada", }, editor: { pressToExecute: "Pressione {mod}+Enter para executar", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index bb0553de2a..844a8edb62 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -302,6 +302,7 @@ export default { colorRed: "红色", colorBlue: "蓝色", colorPurple: "紫色", + colorCustom: "自定义颜色", }, editor: { pressToExecute: "按 {mod}+Enter 执行查询", diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts index 97fe362ade..07384b03d6 100644 --- a/apps/desktop/src/i18n/locales/zh-TW.ts +++ b/apps/desktop/src/i18n/locales/zh-TW.ts @@ -291,6 +291,7 @@ export default { colorRed: "紅色", colorBlue: "藍色", colorPurple: "紫色", + colorCustom: "自訂顏色", }, editor: { pressToExecute: "按 {mod}+Enter 執行查詢", diff --git a/apps/desktop/src/lib/color.ts b/apps/desktop/src/lib/color.ts index c83f607c80..498d1baa0f 100644 --- a/apps/desktop/src/lib/color.ts +++ b/apps/desktop/src/lib/color.ts @@ -1,6 +1,18 @@ export function hexToRgba(color: string | undefined, alpha: number): string | undefined { if (!color) return undefined; - const hex = color.trim().replace(/^#/, ""); + const trimmed = color.trim(); + + // Already rgba/rgb: replace or add alpha, then return + const rgbaMatch = trimmed.match(/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.]+)\s*\)$/i); + if (rgbaMatch) { + return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`; + } + const rgbMatch = trimmed.match(/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i); + if (rgbMatch) { + return `rgba(${rgbMatch[1]}, ${rgbMatch[2]}, ${rgbMatch[3]}, ${alpha})`; + } + + const hex = trimmed.replace(/^#/, ""); const normalized = hex.length === 3 ? hex