fix: 兼容intel Mac旧版系统webview中样式问题

Co-authored-by: tangheng <tangheng@tanghengdeMacBook-Pro.local>
This commit is contained in:
zipg 2026-07-11 21:53:29 +08:00 committed by GitHub
parent 361f7774e9
commit 8ff0f13bd4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 1354 additions and 134 deletions

View File

@ -36,10 +36,28 @@ const { t } = useI18n();
{{ t(labelKey) }}
<span v-if="elapsedSeconds !== undefined" class="ml-1 tabular-nums text-muted-foreground/80">· {{ elapsedSeconds }}s</span>
</div>
<Button v-if="showCancel" variant="destructive" size="sm" class="h-7 gap-1.5" :disabled="cancelDisabled" @click="emit('cancel')">
<Button v-if="showCancel" variant="destructive" size="sm" class="query-loading-cancel-button h-7 gap-1.5" :disabled="cancelDisabled" @click="emit('cancel')">
<Loader2 v-if="cancelling" class="h-3.5 w-3.5 animate-spin" />
<Square v-else class="h-3.5 w-3.5 fill-current" />
{{ t(cancelLabelKey) }}
</Button>
</div>
</template>
<style>
.query-loading-cancel-button {
border: 1px solid rgba(220, 38, 38, 0.22) !important;
background-color: rgba(220, 38, 38, 0.08) !important;
color: rgb(185, 28, 28) !important;
}
.query-loading-cancel-button:hover {
background-color: rgba(220, 38, 38, 0.14) !important;
}
.dark .query-loading-cancel-button {
border-color: rgba(248, 113, 113, 0.28) !important;
background-color: rgba(248, 113, 113, 0.12) !important;
color: rgb(248, 113, 113) !important;
}
</style>

View File

@ -1059,12 +1059,12 @@ watch(driverStoreTab, (tab) => {
</script>
<template>
<div class="h-full flex flex-col">
<div class="flex-1 min-h-0 overflow-y-auto">
<div class="max-w-4xl mx-auto px-6 py-6">
<Tabs v-model="driverStoreTab" default-value="agent">
<div class="flex items-center justify-between">
<TabsList class="grid w-[360px] grid-cols-3">
<div class="driver-store-view h-full flex flex-col">
<div class="driver-store-scroll flex-1 min-h-0 overflow-y-auto">
<div class="driver-store-container max-w-4xl mx-auto px-6 py-6">
<Tabs v-model="driverStoreTab" default-value="agent" class="driver-store-tabs-root">
<div class="driver-store-header flex items-center justify-between">
<TabsList class="driver-store-tabs grid w-[360px] grid-cols-3">
<TabsTrigger value="agent" class="gap-1.5 relative">
{{ t("driverStore.agentDrivers") }}
<span v-if="agentTabUpdateCount > 0" class="inline-block h-2 w-2 rounded-full bg-red-500" />
@ -1090,7 +1090,7 @@ watch(driverStoreTab, (tab) => {
</div>
<!-- Agent Tab -->
<TabsContent value="agent" class="mt-5 space-y-5">
<TabsContent value="agent" class="driver-store-tab driver-store-agent-tab mt-5 space-y-5">
<!-- Java Runtime -->
<div class="rounded-xl border bg-muted/20 p-4 space-y-3">
<div class="flex flex-wrap items-center gap-2">
@ -1157,7 +1157,7 @@ watch(driverStoreTab, (tab) => {
<div v-else-if="filteredAgentDrivers.length === 0" class="py-12 text-center text-sm text-muted-foreground">
{{ t("driverStore.noMatchingDrivers") }}
</div>
<div v-else class="rounded-md border divide-y">
<div v-else class="driver-store-agent-list rounded-md border divide-y">
<div v-if="updatableCount > 0" class="flex items-center justify-between px-4 py-2 bg-muted/30">
<span class="text-xs text-muted-foreground">{{ t("driverStore.driversUpdatable", { count: updatableCount }) }}</span>
<Button size="sm" class="h-7 rounded-[6px] text-xs" :disabled="installing !== null || upgradingAll" @click="upgradeAll">
@ -1166,14 +1166,14 @@ watch(driverStoreTab, (tab) => {
{{ upgradingAll ? t("driverStore.upgradingProgress", { current: upgradingIndex, total: upgradingTotal }) : t("driverStore.upgradeAll") }}
</Button>
</div>
<div v-for="driver in filteredAgentDrivers" :key="driver.db_type" class="flex items-center gap-3 px-4 py-2 transition hover:bg-muted/30">
<div v-for="driver in filteredAgentDrivers" :key="driver.db_type" class="driver-store-agent-row flex items-center gap-3 px-4 py-2 transition hover:bg-muted/30">
<span class="flex h-8 w-8 items-center justify-center rounded-lg bg-muted/60 shrink-0">
<DatabaseIcon :db-type="driver.db_type" class="h-4 w-4" />
</span>
<div class="min-w-0 flex-1">
<div class="driver-store-agent-name min-w-0 flex-1">
<div class="text-sm font-medium">{{ driver.label }}</div>
</div>
<div class="flex shrink-0 items-center gap-1.5">
<div class="driver-store-agent-meta flex shrink-0 items-center gap-1.5">
<span v-if="driverRequiresJavaRuntime(driver) && driver.jre" class="rounded-full px-2 py-0.5 text-[11px]" :class="driver.jre !== '21' ? 'bg-blue-500/10 text-blue-600' : 'bg-muted text-muted-foreground'">JRE {{ driver.jre }}</span>
<template v-if="driver.installed">
<span class="rounded-full bg-muted px-2 py-0.5 text-[11px] text-muted-foreground">v{{ driver.installed_version }}</span>
@ -1184,7 +1184,7 @@ watch(driverStoreTab, (tab) => {
</template>
<span v-if="formatSize(driver.size)" class="rounded-full bg-muted px-2 py-0.5 text-[11px] text-muted-foreground">{{ formatSize(driver.size) }}</span>
</div>
<div class="flex shrink-0 items-center gap-2">
<div class="driver-store-agent-actions flex shrink-0 items-center gap-2">
<Button v-if="!driver.installed && isDriverQueued(driver.db_type)" size="sm" variant="outline" class="h-7 rounded-[6px] border-green-500/30 bg-green-500/10 text-xs text-green-700 hover:bg-green-500/15" :disabled="upgradingAll" @click="removeQueuedDriverInstall(driver.db_type)">
<Clock3 class="h-3 w-3 mr-1" />
{{ t("driverStore.queued") }}
@ -1232,7 +1232,7 @@ watch(driverStoreTab, (tab) => {
</TabsContent>
<!-- JDBC Tab -->
<TabsContent value="jdbc" class="mt-5 space-y-5">
<TabsContent value="jdbc" class="driver-store-tab driver-store-jdbc-tab mt-5 space-y-5">
<!-- JDBC Plugin -->
<div class="rounded-xl border bg-muted/20 p-4">
<div class="flex min-h-12 items-center justify-between gap-3">
@ -1311,7 +1311,7 @@ watch(driverStoreTab, (tab) => {
<Input v-if="jdbcMavenRepository === 'custom'" v-model="customJdbcMavenRepository" class="h-8 text-xs" placeholder="https://repo.example.com/repository/maven-public" @keydown.enter.prevent="installJdbcMavenDriver" />
</div>
<div class="rounded-md border">
<div class="driver-store-jdbc-list rounded-md border">
<div v-if="isLoadingJdbcDrivers" class="p-4 text-sm text-muted-foreground">
{{ t("common.loading") }}
</div>
@ -1322,8 +1322,8 @@ watch(driverStoreTab, (tab) => {
{{ t("driverStore.noMatchingDrivers") }}
</div>
<div v-else class="divide-y">
<div v-for="item in filteredJdbcDrivers" :key="item.id" class="flex items-center gap-3 p-3">
<div class="min-w-0 flex-1">
<div v-for="item in filteredJdbcDrivers" :key="item.id" class="driver-store-jdbc-row flex items-center gap-3 p-3">
<div class="driver-store-jdbc-name min-w-0 flex-1">
<div class="flex min-w-0 items-center gap-2">
<div class="truncate text-sm font-medium">{{ item.title }}</div>
<Badge variant="outline" class="h-5 shrink-0 rounded-full px-2 text-[10px] font-medium">
@ -1342,7 +1342,7 @@ watch(driverStoreTab, (tab) => {
</TabsContent>
<!-- Runtime Tab -->
<TabsContent value="storage" class="mt-5 space-y-5">
<TabsContent value="storage" class="driver-store-tab driver-store-storage-tab mt-5 space-y-5">
<!-- Storage Usage -->
<div class="rounded-xl border bg-muted/20 p-4 space-y-3">
<div class="flex items-center justify-between gap-3">
@ -1528,3 +1528,156 @@ watch(driverStoreTab, (tab) => {
</div>
</div>
</template>
<style>
.driver-store-view,
.driver-store-scroll {
overflow-x: hidden;
}
.driver-store-view {
height: 100%;
min-height: 0;
overflow: hidden;
}
.driver-store-scroll {
height: 100%;
min-height: 0;
overflow-y: auto !important;
}
.driver-store-container {
box-sizing: border-box;
width: 100%;
max-width: none !important;
margin-left: 0 !important;
margin-right: 0 !important;
padding: 1.25rem 1.5rem 1.5rem !important;
}
.driver-store-tabs {
display: grid !important;
width: 360px !important;
grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
}
.driver-store-tabs-root {
display: flex !important;
width: 100%;
min-width: 0;
flex-direction: column !important;
}
.driver-store-tabs-root > [data-slot="tabs-content"] {
width: 100%;
min-width: 0;
}
.driver-store-header {
flex-shrink: 0;
}
.driver-store-tab {
min-height: 0;
overflow: visible;
}
.driver-store-tabs-root > [data-slot="tabs-content"][hidden] {
display: none !important;
}
.driver-store-agent-tab,
.driver-store-jdbc-tab {
flex-direction: column;
gap: 1rem;
}
.driver-store-agent-tab:not([hidden]),
.driver-store-jdbc-tab:not([hidden]) {
display: flex !important;
}
.driver-store-agent-tab > :not([hidden]) ~ :not([hidden]),
.driver-store-jdbc-tab > :not([hidden]) ~ :not([hidden]) {
margin-top: 0 !important;
}
.driver-store-agent-tab > *,
.driver-store-jdbc-tab > * {
flex-shrink: 0;
}
.driver-store-agent-row {
display: flex !important;
align-items: center !important;
min-width: 0;
width: 100%;
}
.driver-store-agent-list,
.driver-store-jdbc-list {
width: 100%;
flex: 0 0 auto !important;
min-height: 0;
overflow-y: visible;
overflow-x: hidden;
}
.driver-store-agent-name,
.driver-store-jdbc-name {
flex: 1 1 auto !important;
min-width: 0 !important;
}
.driver-store-agent-meta,
.driver-store-agent-actions,
.driver-store-jdbc-row > .shrink-0,
.driver-store-jdbc-row > button {
flex-shrink: 0 !important;
}
.driver-store-jdbc-row {
display: flex !important;
align-items: center !important;
min-width: 0;
width: 100%;
}
.driver-store-jdbc-row > button {
width: 2rem !important;
height: 2rem !important;
}
@media (max-width: 900px) {
.driver-store-header {
align-items: flex-start !important;
flex-direction: column !important;
gap: 0.75rem;
}
.driver-store-tabs {
width: 100% !important;
}
.driver-store-agent-row {
align-items: flex-start !important;
flex-wrap: wrap;
}
.driver-store-jdbc-row {
align-items: flex-start !important;
flex-wrap: wrap;
}
.driver-store-agent-meta,
.driver-store-agent-actions {
margin-left: 2.75rem;
}
.driver-store-jdbc-row > .shrink-0,
.driver-store-jdbc-row > button {
margin-left: 2.75rem;
}
}
</style>

View File

@ -3616,13 +3616,13 @@ function openExternalUrl(url: string) {
<h3 v-if="category.title" class="text-sm font-medium">{{ category.title }}</h3>
</div>
<div v-if="dbPickerView === 'icon'" class="grid grid-cols-2 gap-2 sm:grid-cols-4 lg:grid-cols-5">
<div v-if="dbPickerView === 'icon'" class="connection-db-picker-grid grid grid-cols-2 gap-2 sm:grid-cols-4 lg:grid-cols-5">
<button
v-for="opt in category.options"
:key="opt.value"
type="button"
class="group flex min-h-24 flex-col items-center justify-center gap-2 rounded-xl border bg-background/70 p-3 text-center transition hover:-translate-y-0.5 hover:border-primary/40 hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
:class="selectedType === opt.value ? 'border-primary bg-primary/10 shadow-sm ring-1 ring-primary/30' : 'border-border'"
class="connection-db-picker-option group flex min-h-24 flex-col items-center justify-center gap-2 rounded-xl border bg-background/70 p-3 text-center transition hover:-translate-y-0.5 hover:border-primary/40 hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
:class="selectedType === opt.value ? 'connection-db-picker-option--selected shadow-sm' : 'border-border'"
:aria-pressed="selectedType === opt.value"
@click="onDbTypeChange(opt.value)"
@dblclick="goToConnectionStep(opt.value)"
@ -3639,8 +3639,8 @@ function openExternalUrl(url: string) {
v-for="opt in category.options"
:key="opt.value"
type="button"
class="flex items-center gap-3 rounded-lg border bg-background px-3 py-2 text-left transition hover:border-primary/40 hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
:class="selectedType === opt.value ? 'border-primary bg-primary/10 ring-1 ring-primary/30' : 'border-border'"
class="connection-db-picker-option flex items-center gap-3 rounded-lg border bg-background px-3 py-2 text-left transition hover:border-primary/40 hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
:class="selectedType === opt.value ? 'connection-db-picker-option--selected' : 'border-border'"
:aria-pressed="selectedType === opt.value"
@click="onDbTypeChange(opt.value)"
@dblclick="goToConnectionStep(opt.value)"
@ -5521,6 +5521,44 @@ function openExternalUrl(url: string) {
</template>
<style>
@media (min-width: 640px) {
.connection-db-picker-grid {
grid-template-columns: repeat(4, minmax(0, 1fr)) !important;
}
}
@media (min-width: 1024px) {
.connection-db-picker-grid {
grid-template-columns: repeat(5, minmax(0, 1fr)) !important;
}
}
.connection-db-picker-option {
color: var(--foreground);
}
.connection-db-picker-option--selected {
border-color: rgb(23, 23, 23);
background-color: rgba(23, 23, 23, 0.08);
box-shadow: 0 0 0 1px rgba(23, 23, 23, 0.24);
color: rgb(10, 10, 10);
}
.connection-db-picker-option--selected:hover {
background-color: rgba(23, 23, 23, 0.12);
}
.dark .connection-db-picker-option--selected {
border-color: rgb(208, 208, 214);
background-color: rgba(255, 255, 255, 0.08);
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.22);
color: rgb(221, 221, 226);
}
.dark .connection-db-picker-option--selected:hover {
background-color: rgba(255, 255, 255, 0.12);
}
.connection-dialog-content[data-wide="true"] .grid.grid-cols-4 {
grid-template-columns: minmax(5.5rem, 0.7fr) repeat(3, minmax(0, 1fr));
}

View File

@ -455,7 +455,7 @@ function observeElementTruncation(el: Ref<HTMLElement | null>, truncated: Ref<bo
if (!el.value) return;
const observer = new ResizeObserver(() => {
truncated.value = el.value!.scrollWidth > el.value!.clientWidth;
truncated.value = checkElementTruncation(el.value);
});
observer.observe(el.value);
@ -1260,7 +1260,10 @@ function hasSettingsApplyFooter(value: SettingsCategory): boolean {
}
function settingsCategoryButton(value: SettingsCategory): string {
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(" ");
return [
"settings-category-button w-auto shrink-0 whitespace-nowrap rounded-md px-3 py-2 text-left text-sm transition-colors lg:w-full",
value === activeSettingsTab.value ? "settings-category-button--active bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:bg-muted hover:text-foreground",
].join(" ");
}
function openExternalUrl(url: string) {
@ -2587,8 +2590,8 @@ onUnmounted(cleanupPreviewEditor);
</component>
</DialogHeader>
<div class="flex min-h-0 flex-1 flex-col gap-3 overflow-hidden lg:flex-row">
<nav class="settingsCategoryNav flex min-h-0 shrink-0 gap-1 overflow-x-auto border-b pb-3 lg:w-40 lg:flex-col lg:overflow-x-hidden lg:overflow-y-auto lg:border-b-0 lg:border-r lg:pb-0 lg:pr-3">
<div class="settings-layout flex min-h-0 flex-1 flex-col gap-3 overflow-hidden lg:flex-row">
<nav class="settingsCategoryNav settings-category-nav flex min-h-0 shrink-0 gap-1 overflow-x-auto border-b pb-3 lg:w-40 lg:flex-col lg:overflow-x-hidden lg:overflow-y-auto lg:border-b-0 lg:border-r lg:pb-0 lg:pr-3">
<button v-for="category in settingsCategoryNav" :key="category.value" type="button" :class="settingsCategoryButton(category.value)" @click="activeSettingsTab = category.value">
{{ category.label }}
</button>
@ -2892,9 +2895,9 @@ onUnmounted(cleanupPreviewEditor);
<SqlFormatterSettingsPanel v-model="editSqlFormatter" @validity-change="(value: boolean) => (sqlFormatterConfigValid = value)" />
</section>
<section v-else-if="activeSettingsTab === 'appearance'" class="flex flex-col gap-5 py-2">
<div class="grid gap-x-1.5 gap-y-4 sm:grid-cols-[minmax(0,127fr)_minmax(0,127fr)_minmax(0,191fr)_minmax(0,130fr)]">
<div class="space-y-2 min-w-0">
<section v-else-if="activeSettingsTab === 'appearance'" class="settings-appearance-section flex flex-col gap-5 py-2">
<div class="settings-appearance-top-grid">
<div class="settings-appearance-field min-w-0">
<div class="flex h-9 items-end">
<Label class="whitespace-normal leading-tight">{{ t("settings.languageTitle") }}</Label>
</div>
@ -2922,7 +2925,7 @@ onUnmounted(cleanupPreviewEditor);
</Select>
</div>
<div class="space-y-2 min-w-0">
<div class="settings-appearance-field min-w-0">
<div class="flex h-9 items-end">
<Label class="whitespace-normal leading-tight">{{ t("settings.colorTheme") }}</Label>
</div>
@ -2946,7 +2949,7 @@ onUnmounted(cleanupPreviewEditor);
</Select>
</div>
<div class="space-y-2 min-w-0">
<div class="settings-appearance-field min-w-0">
<div class="flex h-9 items-end gap-1">
<Label class="min-w-0 whitespace-normal leading-tight">{{ t("settings.uiFontFamily") }}</Label>
<HelpTooltip :label="t('settings.uiFontFamily')" trigger-class="[&_svg]:h-3 [&_svg]:w-3" content-class="max-w-64">
@ -2985,7 +2988,7 @@ onUnmounted(cleanupPreviewEditor);
</SearchableSelect>
</div>
<div class="space-y-2 min-w-0">
<div class="settings-appearance-field min-w-0">
<div class="flex h-9 items-end gap-1">
<Label class="min-w-0 whitespace-normal leading-tight">{{ t("settings.uiScale") }}</Label>
<HelpTooltip :label="t('settings.uiScale')" trigger-class="[&_svg]:h-3 [&_svg]:w-3" content-class="max-w-64">
@ -3011,17 +3014,17 @@ onUnmounted(cleanupPreviewEditor);
</div>
</div>
<div class="space-y-2">
<div class="settings-appearance-group">
<Label>{{ t("settings.theme") }}</Label>
<div class="flex flex-wrap gap-2">
<div class="settings-appearance-button-row flex flex-wrap gap-2">
<Button
v-for="option in appThemeModeOptions"
:key="option.value"
type="button"
variant="outline"
size="sm"
class="h-8 gap-1.5 rounded-[6px] px-3"
:class="themeMode === option.value ? 'border-primary/40 bg-primary/10 text-primary ring-1 ring-primary/30' : 'text-foreground'"
class="settings-choice-button h-8 gap-1.5 rounded-[6px] px-3"
:class="themeMode === option.value ? 'settings-choice-button--selected border-primary/40 bg-primary/10 text-primary ring-1 ring-primary/30' : 'text-foreground'"
@click="setThemeMode(option.value)"
>
<component :is="option.icon" class="h-3.5 w-3.5" />
@ -3032,10 +3035,10 @@ onUnmounted(cleanupPreviewEditor);
<Separator />
<div class="space-y-2">
<div class="settings-appearance-group">
<Label>{{ t("settings.appLayout") }}</Label>
<div class="grid grid-cols-2 gap-2">
<Button type="button" variant="outline" class="h-auto justify-start border p-3" :class="editAppLayout === 'separated' ? 'border-blue-300 ring-2 ring-blue-300/50' : ''" @click="setAppLayout('separated')">
<div class="settings-appearance-choice-grid">
<Button type="button" variant="outline" class="settings-choice-card h-auto justify-start border p-3" :class="editAppLayout === 'separated' ? 'settings-choice-card--selected border-blue-300 ring-2 ring-blue-300/50' : ''" @click="setAppLayout('separated')">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
@ -3050,7 +3053,7 @@ onUnmounted(cleanupPreviewEditor);
</Tooltip>
</TooltipProvider>
</Button>
<Button type="button" variant="outline" class="h-auto justify-start border p-3" :class="editAppLayout === 'classic' ? 'border-blue-300 ring-2 ring-blue-300/50' : ''" @click="setAppLayout('classic')">
<Button type="button" variant="outline" class="settings-choice-card h-auto justify-start border p-3" :class="editAppLayout === 'classic' ? 'settings-choice-card--selected border-blue-300 ring-2 ring-blue-300/50' : ''" @click="setAppLayout('classic')">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
@ -3069,10 +3072,10 @@ onUnmounted(cleanupPreviewEditor);
</div>
<!-- <div v-if="!isWeb" class="space-y-2"> -->
<div class="space-y-2">
<div class="settings-appearance-group">
<Label>{{ t("settings.iconTheme") }}</Label>
<div class="grid grid-cols-2 gap-2">
<Button type="button" variant="outline" class="h-auto justify-start border p-3" :class="editIconTheme === 'default' ? 'border-blue-300 ring-2 ring-blue-300/50' : ''" @click="setIconTheme('default')">
<div class="settings-appearance-choice-grid">
<Button type="button" variant="outline" class="settings-choice-card h-auto justify-start border p-3" :class="editIconTheme === 'default' ? 'settings-choice-card--selected border-blue-300 ring-2 ring-blue-300/50' : ''" @click="setIconTheme('default')">
<div class="flex items-center gap-3 text-left w-full min-w-0">
<img src="/icon-preview-default.png" alt="DBX" class="h-12 w-12 shrink-0" />
<TooltipProvider>
@ -3090,7 +3093,7 @@ onUnmounted(cleanupPreviewEditor);
</TooltipProvider>
</div>
</Button>
<Button type="button" variant="outline" class="h-auto justify-start border p-3" :class="editIconTheme === 'black' ? 'border-blue-300 ring-2 ring-blue-300/50' : ''" @click="setIconTheme('black')">
<Button type="button" variant="outline" class="settings-choice-card h-auto justify-start border p-3" :class="editIconTheme === 'black' ? 'settings-choice-card--selected border-blue-300 ring-2 ring-blue-300/50' : ''" @click="setIconTheme('black')">
<div class="flex items-center gap-3 text-left w-full min-w-0">
<img src="/icon-preview-black.png" alt="DBX" class="h-12 w-12 shrink-0" />
<TooltipProvider>
@ -3162,7 +3165,7 @@ onUnmounted(cleanupPreviewEditor);
<Separator />
<div class="space-y-3">
<div class="settings-appearance-group settings-option-stack">
<Label>{{ t("settings.dataGridDisplay") }}</Label>
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
<div class="space-y-1">
@ -4725,3 +4728,120 @@ onUnmounted(cleanupPreviewEditor);
</Dialog>
</component>
</template>
<style>
@media (min-width: 1024px) {
.settings-layout {
flex-direction: row !important;
}
.settings-category-nav {
width: 10rem !important;
flex-direction: column !important;
overflow-x: hidden !important;
overflow-y: auto !important;
border-bottom-width: 0 !important;
border-right: 1px solid var(--border) !important;
padding-bottom: 0 !important;
padding-right: 0.75rem !important;
}
.settings-category-button {
width: 100% !important;
text-align: left !important;
}
}
.settings-category-button--active {
background-color: rgb(23, 23, 23) !important;
color: rgb(255, 255, 255) !important;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}
.settings-choice-button {
color: rgb(23, 23, 23);
}
.settings-choice-button--selected {
border-color: rgb(96, 165, 250) !important;
background-color: rgba(59, 130, 246, 0.1) !important;
color: rgb(29, 78, 216) !important;
box-shadow: 0 0 0 1px rgba(96, 165, 250, 0.45) !important;
}
.settings-choice-button--selected svg {
color: currentColor !important;
}
.settings-choice-card--selected {
border-color: rgb(96, 165, 250) !important;
background-color: rgba(59, 130, 246, 0.04) !important;
color: rgb(23, 23, 23) !important;
box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.45) !important;
}
.settings-appearance-section > * + * {
margin-top: 1.25rem;
}
.settings-appearance-top-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
column-gap: 0.75rem;
row-gap: 1rem;
}
.settings-appearance-field > * + * {
margin-top: 0.5rem;
}
.settings-appearance-group > * + * {
margin-top: 0.625rem;
}
.settings-appearance-button-row {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.settings-appearance-choice-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.625rem;
}
.settings-option-stack > * + * {
margin-top: 0.625rem;
}
@media (max-width: 760px) {
.settings-appearance-top-grid,
.settings-appearance-choice-grid {
grid-template-columns: 1fr;
}
}
.dark .settings-category-button--active {
background-color: rgb(245, 245, 245) !important;
color: rgb(23, 23, 23) !important;
}
.dark .settings-choice-button {
color: rgb(245, 245, 245);
}
.dark .settings-choice-button--selected {
border-color: rgb(147, 197, 253) !important;
background-color: rgba(96, 165, 250, 0.18) !important;
color: rgb(191, 219, 254) !important;
box-shadow: 0 0 0 1px rgba(147, 197, 253, 0.5) !important;
}
.dark .settings-choice-card--selected {
border-color: rgb(147, 197, 253) !important;
background-color: rgba(96, 165, 250, 0.12) !important;
color: rgb(245, 245, 245) !important;
box-shadow: 0 0 0 2px rgba(147, 197, 253, 0.45) !important;
}
</style>

View File

@ -9419,8 +9419,8 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
@scroll="onTransposeScroll"
>
<template #before>
<div class="data-grid-transpose-header sticky top-0 z-20 flex h-7 border-b border-border bg-[rgb(239_239_239)] font-semibold text-muted-foreground dark:bg-muted" :style="{ width: `${transposeTotalWidth}px` }">
<div class="sticky left-0 z-30 shrink-0 border-r border-border px-3 py-1.5 bg-[rgb(239_239_239)] truncate dark:bg-muted relative" :style="{ width: `${transposePinnedWidth}px` }">
<div class="data-grid-transpose-header data-grid-header-shell sticky top-0 z-20 flex h-7 border-b border-border font-semibold text-muted-foreground" :style="{ width: `${transposeTotalWidth}px` }">
<div class="data-grid-header-cell sticky left-0 z-30 shrink-0 border-r border-border px-3 py-1.5 truncate relative" :style="{ width: `${transposePinnedWidth}px` }">
{{ t("grid.columnName") }}
<div class="absolute right-0 top-0 bottom-0 w-1.5 cursor-col-resize hover:bg-primary/30" @mousedown.stop="onTransposePinnedResizeStart" />
</div>
@ -9432,7 +9432,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
:class="{
'transpose-record-header-selected text-primary font-semibold': transposeRecordUsesFramedHeader(recordIndex),
'transpose-record-header-active text-primary': transposeRecordUsesActiveHighlight(recordIndex) && !transposeRecordUsesFramedHeader(recordIndex),
'bg-[rgb(239_239_239)] dark:bg-muted': !transposeRecordUsesActiveHighlight(recordIndex) && !transposeRecordUsesFramedHeader(recordIndex),
'data-grid-header-cell': !transposeRecordUsesActiveHighlight(recordIndex) && !transposeRecordUsesFramedHeader(recordIndex),
}"
:style="{ width: `${getTransposeRecordWidth(recordIndex)}px` }"
@click="selectTransposeRecord(recordIndex, $event)"
@ -9577,10 +9577,10 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
</div>
<template v-else>
<!-- Sticky header -->
<div ref="headerRef" class="shrink-0 bg-[rgb(239_239_239)] dark:bg-muted/60 z-10 w-full border-y border-border overflow-hidden">
<div ref="headerRef" class="data-grid-header-shell shrink-0 z-10 w-full border-y border-border overflow-hidden">
<div class="data-grid-header-row flex w-(--header-total-w) font-semibold text-foreground">
<div
class="shrink-0 px-2 py-1.5 border-r w-(--row-num-w) border-border text-center text-muted-foreground select-none cursor-default hover:bg-gray-200 dark:hover:bg-gray-800 sticky left-0 z-20 bg-[rgb(239_239_239)] dark:bg-muted"
class="data-grid-header-cell shrink-0 px-2 py-1.5 border-r w-(--row-num-w) border-border text-center text-muted-foreground select-none cursor-default hover:bg-gray-200 dark:hover:bg-gray-800 sticky left-0 z-20"
:class="{ '!bg-gray-300 dark:!bg-gray-900 outline outline-primary -outline-offset-1': isSelectingAll }"
@click="selectAllCells"
>
@ -9589,7 +9589,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
<div class="shrink-0" :style="{ width: `${horizontalColumnWindow.beforeWidth}px` }" />
<LightTooltip v-for="col in renderedGridColumns" :key="`${col.name}-${col.actualColIdx}`" :text="col.name" side="bottom" :side-offset="4" :disabled="columnHeaderTooltipsDisabled">
<div
class="shrink-0 px-2 py-1.5 border-r border-border whitespace-nowrap hover:bg-gray-200 dark:hover:bg-gray-800 select-none relative overflow-hidden"
class="data-grid-header-cell shrink-0 px-2 py-1.5 border-r border-border whitespace-nowrap hover:bg-gray-200 dark:hover:bg-gray-800 select-none relative overflow-hidden"
:class="{
'!bg-gray-300 dark:!bg-gray-900 outline outline-primary -outline-offset-1': highlightedColumnIndex === col.actualColIdx || columnIsSelected(col.visibleColIdx),
'bg-amber-500/20 ring-1 ring-inset ring-amber-500/40': currentSearchMatch?.kind === 'column' && currentSearchMatch.col === col.actualColIdx,
@ -10088,10 +10088,10 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
<div
class="data-grid-row flex border-b border-border h-6.5 w-(--total-w)"
:class="{
'bg-destructive/5 opacity-70': item.isDeleted,
'bg-primary/5': item.isNew && !isRowActive(item.displayIndex),
'bg-muted/20': item.isDraft && !isRowActive(item.displayIndex),
'bg-muted/30': !item.isNew && !item.isDraft && !item.isDeleted && !isRowActive(item.displayIndex) && item.displayIndex % 2 === 1,
'data-grid-row--deleted opacity-70': item.isDeleted,
'data-grid-row--new': item.isNew && !isRowActive(item.displayIndex),
'data-grid-row--draft': item.isDraft && !isRowActive(item.displayIndex),
'data-grid-row--striped': !item.isNew && !item.isDraft && !item.isDeleted && !isRowActive(item.displayIndex) && item.displayIndex % 2 === 1,
'active-row': isRowActive(item.displayIndex) && !item.isDeleted,
'relative z-20 overflow-visible': editingCell?.rowId === item.id,
}"
@ -11186,48 +11186,48 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
@reference "../../styles/globals.css";
[data-grid-root] {
--data-grid-row-muted-bg: rgb(248 248 248);
--data-grid-row-new-bg: rgb(243 243 243);
--data-grid-row-deleted-bg: rgb(255 244 244);
--data-grid-cell-active-bg: rgb(232 232 232);
--data-grid-cell-dirty-bg: rgb(255 248 230);
--data-grid-cell-selected-bg: rgb(226 226 226);
--data-grid-cell-selected-dirty-bg: rgb(244 229 186);
--data-grid-cell-selected-border: rgb(90 90 90);
--data-grid-cell-hover-bg: rgb(245 245 245);
--data-grid-cell-search-bg: rgb(253 245 184);
--data-grid-cell-current-search-bg: rgb(253 224 71 / 52%);
--data-grid-cell-current-search-border: rgb(234 179 8 / 82%);
--data-grid-row-number-default-bg: rgb(255 255 255);
--data-grid-row-number-new-bg: rgb(219 244 233);
--data-grid-row-number-edited-bg: rgb(253 241 219);
--data-grid-row-number-deleted-bg: rgb(255 244 244);
--data-grid-row-number-active-bg: rgb(232 232 232);
--data-grid-row-number-selected-bg: rgb(226 226 226);
--data-grid-row-muted-bg: rgb(248, 248, 248);
--data-grid-row-new-bg: rgb(243, 243, 243);
--data-grid-row-deleted-bg: rgb(255, 244, 244);
--data-grid-cell-active-bg: rgb(232, 232, 232);
--data-grid-cell-dirty-bg: rgb(255, 248, 230);
--data-grid-cell-selected-bg: rgb(226, 226, 226);
--data-grid-cell-selected-dirty-bg: rgb(244, 229, 186);
--data-grid-cell-selected-border: rgb(90, 90, 90);
--data-grid-cell-hover-bg: rgb(245, 245, 245);
--data-grid-cell-search-bg: rgb(253, 245, 184);
--data-grid-cell-current-search-bg: rgba(253, 224, 71, 0.52);
--data-grid-cell-current-search-border: rgba(234, 179, 8, 0.82);
--data-grid-row-number-default-bg: rgb(255, 255, 255);
--data-grid-row-number-new-bg: rgb(219, 244, 233);
--data-grid-row-number-edited-bg: rgb(253, 241, 219);
--data-grid-row-number-deleted-bg: rgb(255, 244, 244);
--data-grid-row-number-active-bg: rgb(232, 232, 232);
--data-grid-row-number-selected-bg: rgb(226, 226, 226);
--data-grid-scrollbar-thumb: color-mix(in oklch, var(--foreground) 30%, transparent);
--data-grid-scrollbar-thumb-hover: color-mix(in oklch, var(--foreground) 48%, transparent);
--data-grid-scrollbar-track: transparent;
}
:global(.dark) [data-grid-root] {
--data-grid-row-muted-bg: rgb(32 32 34);
--data-grid-row-new-bg: rgb(51 51 55);
--data-grid-row-deleted-bg: rgb(55 31 32);
--data-grid-cell-active-bg: rgb(64 64 64);
--data-grid-cell-dirty-bg: rgb(94 75 26);
--data-grid-cell-selected-bg: rgb(66 67 70);
--data-grid-cell-selected-dirty-bg: rgb(94 75 26);
--data-grid-cell-selected-border: rgb(170 170 175);
--data-grid-cell-hover-bg: rgb(46 47 51);
--data-grid-cell-search-bg: rgb(72 57 8);
--data-grid-cell-current-search-bg: rgb(116 87 0);
--data-grid-cell-current-search-border: rgb(239 177 0);
--data-grid-row-number-default-bg: rgb(35 37 42);
--data-grid-row-number-new-bg: rgb(33 45 40);
--data-grid-row-number-edited-bg: rgb(48 41 28);
--data-grid-row-number-deleted-bg: rgb(55 31 32);
--data-grid-row-number-active-bg: rgb(64 64 64);
--data-grid-row-number-selected-bg: rgb(66 67 70);
--data-grid-row-muted-bg: rgb(32, 32, 34);
--data-grid-row-new-bg: rgb(51, 51, 55);
--data-grid-row-deleted-bg: rgb(55, 31, 32);
--data-grid-cell-active-bg: rgb(64, 64, 64);
--data-grid-cell-dirty-bg: rgb(94, 75, 26);
--data-grid-cell-selected-bg: rgb(66, 67, 70);
--data-grid-cell-selected-dirty-bg: rgb(94, 75, 26);
--data-grid-cell-selected-border: rgb(170, 170, 175);
--data-grid-cell-hover-bg: rgb(46, 47, 51);
--data-grid-cell-search-bg: rgb(72, 57, 8);
--data-grid-cell-current-search-bg: rgb(116, 87, 0);
--data-grid-cell-current-search-border: rgb(239, 177, 0);
--data-grid-row-number-default-bg: rgb(35, 37, 42);
--data-grid-row-number-new-bg: rgb(33, 45, 40);
--data-grid-row-number-edited-bg: rgb(48, 41, 28);
--data-grid-row-number-deleted-bg: rgb(55, 31, 32);
--data-grid-row-number-active-bg: rgb(64, 64, 64);
--data-grid-row-number-selected-bg: rgb(66, 67, 70);
}
@supports (background: color-mix(in oklab, white 50%, transparent)) {
@ -11249,6 +11249,50 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
}
}
.data-grid-header-shell,
.data-grid-header-cell {
background-color: rgb(239, 239, 239);
}
:global(.dark) [data-grid-root] .data-grid-header-shell,
:global(.dark) [data-grid-root] .data-grid-header-cell {
background-color: rgb(32, 32, 34) !important;
}
:global(.dark) [data-grid-root] .data-grid-header-row {
color: rgb(215, 215, 219);
}
:global(.dark) [data-grid-root] .data-grid-header-cell:hover {
background-color: rgb(46, 47, 51) !important;
}
.data-grid-row--striped {
background-color: rgb(248, 248, 248);
}
.data-grid-row--draft,
.data-grid-row--new {
background-color: rgb(243, 243, 243);
}
.data-grid-row--deleted {
background-color: rgb(255, 244, 244);
}
:global(.dark) .data-grid-row--striped {
background-color: rgb(32, 32, 34);
}
:global(.dark) .data-grid-row--draft,
:global(.dark) .data-grid-row--new {
background-color: rgb(51, 51, 55);
}
:global(.dark) .data-grid-row--deleted {
background-color: rgb(55, 31, 32);
}
.data-grid-topbar {
--data-grid-topbar-transition-duration: 340ms;
--data-grid-topbar-transition-easing: cubic-bezier(0.22, 1, 0.36, 1);

View File

@ -43,8 +43,8 @@ function welcomeConnectionSubtitle(connection: ConnectionConfig): string {
<template>
<div class="min-w-0 flex-1 overflow-x-hidden overflow-y-auto bg-background">
<div class="mx-auto flex min-h-full w-full min-w-0 max-w-5xl flex-col justify-center gap-6 px-8 py-10">
<div class="grid min-w-0 grid-cols-1 gap-3 sm:grid-cols-3">
<div class="welcome-content mx-auto flex min-h-full w-full min-w-0 max-w-5xl flex-col justify-center gap-6 px-8 py-10">
<div class="welcome-stats-grid grid min-w-0 grid-cols-1 gap-3 sm:grid-cols-3">
<div class="min-w-0 overflow-hidden rounded-lg border bg-muted/20 px-4 py-3">
<div class="flex min-w-0 items-center gap-2 text-xs text-muted-foreground">
<Database class="h-3.5 w-3.5 shrink-0" /> <span class="min-w-0 truncate">{{ t("welcome.connections") }}</span>
@ -65,7 +65,7 @@ function welcomeConnectionSubtitle(connection: ConnectionConfig): string {
</div>
</div>
<div class="grid min-w-0 grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1.2fr)_minmax(0,0.8fr)]">
<div class="welcome-main-grid grid min-w-0 grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1.2fr)_minmax(0,0.8fr)]">
<div class="min-w-0 overflow-hidden rounded-lg border">
<div class="flex items-center justify-between border-b px-4 py-3">
<div class="text-sm font-medium">{{ t("welcome.quickConnections") }}</div>
@ -163,3 +163,21 @@ function welcomeConnectionSubtitle(connection: ConnectionConfig): string {
</div>
</div>
</template>
<style>
.welcome-content {
max-width: 64rem;
}
@media (min-width: 640px) {
.welcome-stats-grid {
grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
}
}
@media (min-width: 1024px) {
.welcome-main-grid {
grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr) !important;
}
}
</style>

View File

@ -680,12 +680,12 @@ function iconClass(type: ObjectBrowserRow["type"]) {
}
function iconBgClass(type: ObjectBrowserRow["type"]) {
if (type === "VIEW" || type === "MATERIALIZED_VIEW") return "bg-purple-500/10";
if (type === "PROCEDURE") return "bg-blue-500/10";
if (type === "FUNCTION") return "bg-amber-500/10";
if (type === "SEQUENCE") return "bg-emerald-500/10";
if (type === "PACKAGE" || type === "PACKAGE_BODY") return "bg-cyan-500/10";
return "bg-green-500/10";
if (type === "VIEW" || type === "MATERIALIZED_VIEW") return "object-browser-icon-bg object-browser-icon-bg-view";
if (type === "PROCEDURE") return "object-browser-icon-bg object-browser-icon-bg-procedure";
if (type === "FUNCTION") return "object-browser-icon-bg object-browser-icon-bg-function";
if (type === "SEQUENCE") return "object-browser-icon-bg object-browser-icon-bg-sequence";
if (type === "PACKAGE" || type === "PACKAGE_BODY") return "object-browser-icon-bg object-browser-icon-bg-package";
return "object-browser-icon-bg object-browser-icon-bg-table";
}
function isPartitionParentExpanded(row: ObjectBrowserRow) {
@ -2588,8 +2588,10 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
<span class="w-full truncate text-sm font-medium leading-tight text-foreground">{{ item.displayName }}</span>
<div class="flex items-center gap-1.5">
<span class="text-xs text-muted-foreground">{{ typeLabel(item.type) }}</span>
<span v-if="item.estimatedRows != null && item.estimatedRows > 0" class="rounded-full bg-primary/10 px-1.5 py-0.5 text-[10px] font-medium tabular-nums text-primary">{{ formatObjectBrowserCount(item.estimatedRows) }}</span>
<span v-if="item.totalBytes != null && item.totalBytes > 0" class="rounded-full bg-muted px-1.5 py-0.5 text-[10px] font-medium tabular-nums text-muted-foreground">{{ formatObjectBrowserBytes(item.totalBytes) }}</span>
<span v-if="item.estimatedRows != null && item.estimatedRows > 0" class="object-browser-stat-badge object-browser-stat-badge-rows rounded-full bg-primary/10 px-1.5 py-0.5 text-[10px] font-medium tabular-nums text-primary">{{
formatObjectBrowserCount(item.estimatedRows)
}}</span>
<span v-if="item.totalBytes != null && item.totalBytes > 0" class="object-browser-stat-badge object-browser-stat-badge-bytes rounded-full bg-muted px-1.5 py-0.5 text-[10px] font-medium tabular-nums text-muted-foreground">{{ formatObjectBrowserBytes(item.totalBytes) }}</span>
</div>
<div v-if="item.created_at?.trim() || item.updated_at?.trim()" class="flex items-center gap-1 text-[10px] text-muted-foreground/70">
<span v-if="item.created_at?.trim()">{{ formatObjectBrowserTimestamp(item.created_at) }}</span>
@ -3029,6 +3031,52 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
align-items: start;
}
.object-browser-icon-bg-table {
background-color: rgba(34, 197, 94, 0.1);
}
.object-browser-icon-bg-view {
background-color: rgba(168, 85, 247, 0.1);
}
.object-browser-icon-bg-procedure {
background-color: rgba(59, 130, 246, 0.1);
}
.object-browser-icon-bg-function {
background-color: rgba(245, 158, 11, 0.1);
}
.object-browser-icon-bg-sequence {
background-color: rgba(16, 185, 129, 0.1);
}
.object-browser-icon-bg-package {
background-color: rgba(6, 182, 212, 0.1);
}
.object-browser-stat-badge {
display: inline-flex;
align-items: center;
max-width: 100%;
line-height: 1rem;
white-space: nowrap;
}
.object-browser-stat-badge-rows {
color: var(--primary);
background-color: rgba(23, 23, 23, 0.1);
}
.object-browser-stat-badge-bytes {
color: var(--muted-foreground);
background-color: var(--muted);
}
:global(.dark) .object-browser-stat-badge-rows {
background-color: rgba(208, 208, 214, 0.12);
}
.side-panel-resizing {
user-select: none;
pointer-events: none;

View File

@ -42,7 +42,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
v-bind="{ ...$attrs, ...forwarded }"
:class="
cn(
'bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 relative grid max-h-[calc(100dvh-2rem)] w-full max-w-full gap-4 overflow-hidden rounded-xl p-4 text-sm ring-1 duration-100 outline-none pointer-events-auto sm:max-w-sm',
'bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 relative grid max-h-[calc(100dvh-2rem)] w-full max-w-sm gap-4 overflow-hidden rounded-xl border border-border p-4 text-sm shadow-lg duration-100 outline-none pointer-events-auto',
props.class,
)
"

View File

@ -25,6 +25,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<DialogOverlay />
<div class="fixed inset-0 z-50 grid place-items-center p-4 pointer-events-none">
<DialogContent
data-slot="dialog-content"
:class="cn('relative z-50 grid w-full max-w-lg my-8 gap-4 border border-border bg-background p-4 shadow-lg duration-200 sm:rounded-lg md:w-full pointer-events-auto', props.class)"
v-bind="{ ...$attrs, ...forwarded }"
@pointer-down-outside="

View File

@ -64,6 +64,12 @@ const selectedLabel = computed(() => {
return props.displayName(props.modelValue);
});
const triggerBaseClass = computed(() =>
props.triggerVariant === "outline"
? "dbx-searchable-select-trigger h-6 w-auto max-w-56 min-w-0 justify-between gap-1 px-2 text-xs font-normal shadow-none"
: "h-6 w-auto max-w-56 min-w-0 justify-between gap-1 border-0 bg-transparent px-1 text-xs font-normal shadow-none hover:bg-muted/50 focus-visible:ring-0",
);
const filteredOptions = computed(() => filterDatabaseOptions(props.options, searchText.value, props.displayName));
const customOptionValue = computed(() => props.normalizeCustom(searchText.value.trim()));
const canSelectCustom = computed(() => props.allowCustom && !!customOptionValue.value && !props.options.includes(customOptionValue.value));
@ -162,7 +168,7 @@ function handleKeydown(event: KeyboardEvent) {
<template>
<Popover v-model:open="open">
<PopoverTrigger as-child>
<Button type="button" :variant="triggerVariant" :disabled="disabled" :title="selectedLabel" :class="cn('h-6 w-auto max-w-56 min-w-0 justify-between gap-1 border-0 bg-transparent px-1 text-xs font-normal shadow-none hover:bg-muted/50 focus-visible:ring-0', triggerClass)">
<Button type="button" :variant="triggerVariant" :disabled="disabled" :title="selectedLabel" :class="cn(triggerBaseClass, triggerClass)">
<slot name="trigger-label" :value="modelValue" :label="selectedLabel" :loading="loading">
<span class="truncate">{{ loading ? loadingText : selectedLabel }}</span>
</slot>
@ -244,3 +250,36 @@ function handleKeydown(event: KeyboardEvent) {
</PopoverContent>
</Popover>
</template>
<style>
.dbx-searchable-select-trigger {
border: 1px solid rgb(229, 229, 229) !important;
background-color: rgb(255, 255, 255) !important;
box-shadow: none !important;
}
.dbx-searchable-select-trigger:hover {
background-color: rgb(250, 250, 250) !important;
}
.dbx-searchable-select-trigger[aria-expanded="true"],
.dbx-searchable-select-trigger:focus-visible {
border-color: rgb(96, 165, 250) !important;
box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.22) !important;
}
.dark .dbx-searchable-select-trigger {
border-color: rgba(255, 255, 255, 0.14) !important;
background-color: rgba(255, 255, 255, 0.08) !important;
}
.dark .dbx-searchable-select-trigger:hover {
background-color: rgba(255, 255, 255, 0.12) !important;
}
.dark .dbx-searchable-select-trigger[aria-expanded="true"],
.dark .dbx-searchable-select-trigger:focus-visible {
border-color: rgb(147, 197, 253) !important;
box-shadow: 0 0 0 2px rgba(147, 197, 253, 0.24) !important;
}
</style>

View File

@ -20,7 +20,7 @@ const forwardedProps = useForwardProps(delegatedProps);
v-bind="forwardedProps"
:class="
cn(
'border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-[6px] border bg-transparent py-2 pr-2 pl-2.5 text-sm transition-colors select-none focus-visible:ring-3 aria-invalid:ring-3 data-[size=default]:h-8 data-[size=sm]:h-7 *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*=size-])]:size-4 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0',
'dbx-select-trigger border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-[6px] border bg-transparent py-2 pr-2 pl-2.5 text-sm transition-colors select-none focus-visible:ring-3 aria-invalid:ring-3 data-[size=default]:h-8 data-[size=sm]:h-7 *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*=size-])]:size-4 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0',
props.class,
)
"
@ -31,3 +31,36 @@ const forwardedProps = useForwardProps(delegatedProps);
</SelectIcon>
</SelectTrigger>
</template>
<style>
.dbx-select-trigger:not(.border-0):not(.border-transparent) {
border: 1px solid rgb(229, 229, 229) !important;
background-color: rgb(255, 255, 255) !important;
box-shadow: none !important;
}
.dbx-select-trigger:not(.border-0):not(.border-transparent):hover {
background-color: rgb(250, 250, 250) !important;
}
.dbx-select-trigger:not(.border-0):not(.border-transparent)[data-state="open"],
.dbx-select-trigger:not(.border-0):not(.border-transparent):focus-visible {
border-color: rgb(96, 165, 250) !important;
box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.22) !important;
}
.dark .dbx-select-trigger:not(.border-0):not(.border-transparent) {
border-color: rgba(255, 255, 255, 0.14) !important;
background-color: rgba(255, 255, 255, 0.08) !important;
}
.dark .dbx-select-trigger:not(.border-0):not(.border-transparent):hover {
background-color: rgba(255, 255, 255, 0.12) !important;
}
.dark .dbx-select-trigger:not(.border-0):not(.border-transparent)[data-state="open"],
.dark .dbx-select-trigger:not(.border-0):not(.border-transparent):focus-visible {
border-color: rgb(147, 197, 253) !important;
box-shadow: 0 0 0 2px rgba(147, 197, 253, 0.24) !important;
}
</style>

View File

@ -32,16 +32,92 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
v-bind="forwarded"
:class="
cn(
'data-checked:bg-primary data-unchecked:bg-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 dark:data-unchecked:bg-input/80 shrink-0 rounded-full border border-transparent focus-visible:ring-3 aria-invalid:ring-3 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] peer group/switch relative inline-flex items-center transition-colors outline-none after:absolute after:-inset-x-3 after:-inset-y-2 data-disabled:cursor-not-allowed data-disabled:opacity-50',
'dbx-switch data-checked:bg-primary data-unchecked:bg-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 dark:data-unchecked:bg-input/80 shrink-0 rounded-full border border-transparent focus-visible:ring-3 aria-invalid:ring-3 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] peer group/switch relative inline-flex items-center transition-colors outline-none after:absolute after:-inset-x-3 after:-inset-y-2 data-disabled:cursor-not-allowed data-disabled:opacity-50',
props.class,
)
"
>
<SwitchThumb
data-slot="switch-thumb"
class="bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-primary-foreground rounded-full group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 pointer-events-none block ring-0 transition-transform"
>
<SwitchThumb data-slot="switch-thumb" class="dbx-switch-thumb bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-primary-foreground rounded-full group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 pointer-events-none block ring-0 transition-transform">
<slot name="thumb" v-bind="slotProps" />
</SwitchThumb>
</SwitchRoot>
</template>
<style>
.dbx-switch {
box-sizing: border-box;
display: inline-flex !important;
align-items: center !important;
position: relative;
flex-shrink: 0;
overflow: hidden;
border: 1px solid rgba(120, 120, 128, 0.22) !important;
background-color: rgb(229, 229, 229) !important;
vertical-align: middle;
}
.dbx-switch[data-size="default"] {
width: 32px !important;
height: 18.4px !important;
}
.dbx-switch[data-size="sm"] {
width: 24px !important;
height: 14px !important;
}
.dbx-switch-thumb {
display: block !important;
border-radius: 9999px;
background-color: rgb(255, 255, 255) !important;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.22);
transform: translateX(0) !important;
}
.dbx-switch[data-size="default"] .dbx-switch-thumb {
width: 16px !important;
height: 16px !important;
}
.dbx-switch[data-size="sm"] .dbx-switch-thumb {
width: 12px !important;
height: 12px !important;
}
.dbx-switch[data-state="checked"],
.dbx-switch[data-checked],
.dbx-switch[aria-checked="true"] {
border-color: rgb(23, 23, 23) !important;
background-color: rgb(23, 23, 23) !important;
}
.dbx-switch[data-size="default"][data-state="checked"] .dbx-switch-thumb,
.dbx-switch[data-size="default"][data-checked] .dbx-switch-thumb,
.dbx-switch[data-size="default"][aria-checked="true"] .dbx-switch-thumb {
transform: translateX(14px) !important;
}
.dbx-switch[data-size="sm"][data-state="checked"] .dbx-switch-thumb,
.dbx-switch[data-size="sm"][data-checked] .dbx-switch-thumb,
.dbx-switch[data-size="sm"][aria-checked="true"] .dbx-switch-thumb {
transform: translateX(10px) !important;
}
.dark .dbx-switch {
border-color: rgba(255, 255, 255, 0.16) !important;
background-color: rgba(255, 255, 255, 0.18) !important;
}
.dark .dbx-switch[data-state="checked"],
.dark .dbx-switch[data-checked],
.dark .dbx-switch[aria-checked="true"] {
border-color: rgb(245, 245, 245) !important;
background-color: rgb(245, 245, 245) !important;
}
.dark .dbx-switch[data-state="checked"] .dbx-switch-thumb,
.dark .dbx-switch[data-checked] .dbx-switch-thumb,
.dark .dbx-switch[aria-checked="true"] .dbx-switch-thumb {
background-color: rgb(23, 23, 23) !important;
}
</style>

View File

@ -45,6 +45,7 @@ const DATA_GRID_LIGHT_ROW_NUMBER_DELETED_BG = "rgb(255, 244, 244)";
const CANVAS_SAFE_COLOR_RE = /^(#|rgb\(|rgba\(|hsl\(|hsla\()/i;
const ADVANCED_COLOR_RE = /^(oklch\(|oklab\(|lab\(|lch\(|color\(|color-mix\()/i;
let browserColorProbe: HTMLElement | null = null;
let canvasColorProbe: CanvasRenderingContext2D | null | undefined;
interface RgbaColor {
r: number;
@ -180,14 +181,35 @@ function normalizeCssColorWithBrowser(value: string): string | null {
}
}
function normalizeColorWithCanvas(value: string): string | null {
if (!value || typeof document === "undefined") return value || null;
try {
if (canvasColorProbe === undefined) {
canvasColorProbe = document.createElement("canvas").getContext("2d");
}
const ctx = canvasColorProbe;
if (!ctx) return value;
ctx.fillStyle = "#010203";
ctx.fillStyle = value;
const first = String(ctx.fillStyle);
if (first !== "#010203") return first;
ctx.fillStyle = "#040506";
ctx.fillStyle = value;
const second = String(ctx.fillStyle);
return second !== "#040506" ? second : null;
} catch {
return null;
}
}
function toCanvasSafeColor(value: string, fallback: string): string {
const trimmed = value.trim();
if (!trimmed) return fallback;
const rgb = parseRgbColor(trimmed);
if (rgb) return formatRgb(rgb);
if (CANVAS_SAFE_COLOR_RE.test(trimmed)) return trimmed;
if (ADVANCED_COLOR_RE.test(trimmed)) return normalizeCssColorWithBrowser(trimmed) ?? parseColorMix(trimmed) ?? fallback;
return `hsl(${trimmed})`;
const candidate = rgb ? formatRgb(rgb) : CANVAS_SAFE_COLOR_RE.test(trimmed) ? trimmed : ADVANCED_COLOR_RE.test(trimmed) ? (normalizeCssColorWithBrowser(trimmed) ?? parseColorMix(trimmed) ?? fallback) : `hsl(${trimmed})`;
return normalizeColorWithCanvas(candidate) ?? normalizeColorWithCanvas(fallback) ?? fallback;
}
export function cssVarColor(getVar: (name: string) => string, name: string, fallback: string): string {
@ -243,26 +265,26 @@ export function resolveDataGridPaintTheme(options: { getVar: (name: string) => s
foreground,
mutedForeground,
primary,
rowMuted: paintToken(getVar, "--data-grid-row-muted-bg", rowMuted),
rowNew: paintToken(getVar, "--data-grid-row-new-bg", rowNew),
rowDeleted: paintToken(getVar, "--data-grid-row-deleted-bg", rowDeleted),
cellActive: paintToken(getVar, "--data-grid-cell-active-bg", cellActive),
cellDirty: paintToken(getVar, "--data-grid-cell-dirty-bg", cellDirty),
cellSelected: paintToken(getVar, "--data-grid-cell-selected-bg", cellSelected),
cellSelectedDirty: paintToken(getVar, "--data-grid-cell-selected-dirty-bg", cellSelectedDirty),
cellSelectedBorder: paintToken(getVar, "--data-grid-cell-selected-border", cellSelectedBorder),
cellSelectedSingle: paintToken(getVar, "--data-grid-cell-selected-single-bg", cellSelectedSingle),
cellSelectedSingleBorder: paintToken(getVar, "--data-grid-cell-selected-single-border", primary),
cellHover: paintToken(getVar, "--data-grid-cell-hover-bg", cellHover),
cellSearch: paintToken(getVar, "--data-grid-cell-search-bg", cellSearch),
cellCurrentSearch: paintToken(getVar, "--data-grid-cell-current-search-bg", cellCurrentSearch),
cellCurrentSearchBorder: paintToken(getVar, "--data-grid-cell-current-search-border", cellCurrentSearchBorder),
rowMuted: isDark ? rowMuted : paintToken(getVar, "--data-grid-row-muted-bg", rowMuted),
rowNew: isDark ? rowNew : paintToken(getVar, "--data-grid-row-new-bg", rowNew),
rowDeleted: isDark ? rowDeleted : paintToken(getVar, "--data-grid-row-deleted-bg", rowDeleted),
cellActive: isDark ? cellActive : paintToken(getVar, "--data-grid-cell-active-bg", cellActive),
cellDirty: isDark ? cellDirty : paintToken(getVar, "--data-grid-cell-dirty-bg", cellDirty),
cellSelected: isDark ? cellSelected : paintToken(getVar, "--data-grid-cell-selected-bg", cellSelected),
cellSelectedDirty: isDark ? cellSelectedDirty : paintToken(getVar, "--data-grid-cell-selected-dirty-bg", cellSelectedDirty),
cellSelectedBorder: isDark ? cellSelectedBorder : paintToken(getVar, "--data-grid-cell-selected-border", cellSelectedBorder),
cellSelectedSingle: isDark ? cellSelectedSingle : paintToken(getVar, "--data-grid-cell-selected-single-bg", cellSelectedSingle),
cellSelectedSingleBorder: isDark ? primary : paintToken(getVar, "--data-grid-cell-selected-single-border", primary),
cellHover: isDark ? cellHover : paintToken(getVar, "--data-grid-cell-hover-bg", cellHover),
cellSearch: isDark ? cellSearch : paintToken(getVar, "--data-grid-cell-search-bg", cellSearch),
cellCurrentSearch: isDark ? cellCurrentSearch : paintToken(getVar, "--data-grid-cell-current-search-bg", cellCurrentSearch),
cellCurrentSearchBorder: isDark ? cellCurrentSearchBorder : paintToken(getVar, "--data-grid-cell-current-search-border", cellCurrentSearchBorder),
rowNumberDefault,
rowNumberNew: paintToken(getVar, "--data-grid-row-number-new-bg", rowNumberNew),
rowNumberEdited: paintToken(getVar, "--data-grid-row-number-edited-bg", rowNumberEdited),
rowNumberDeleted: paintToken(getVar, "--data-grid-row-number-deleted-bg", rowNumberDeleted),
rowNumberActive: paintToken(getVar, "--data-grid-row-number-active-bg", rowNumberActive),
rowNumberSelected: paintToken(getVar, "--data-grid-row-number-selected-bg", rowNumberSelected),
rowNumberNew: isDark ? rowNumberNew : paintToken(getVar, "--data-grid-row-number-new-bg", rowNumberNew),
rowNumberEdited: isDark ? rowNumberEdited : paintToken(getVar, "--data-grid-row-number-edited-bg", rowNumberEdited),
rowNumberDeleted: isDark ? rowNumberDeleted : paintToken(getVar, "--data-grid-row-number-deleted-bg", rowNumberDeleted),
rowNumberActive: isDark ? rowNumberActive : paintToken(getVar, "--data-grid-row-number-active-bg", rowNumberActive),
rowNumberSelected: isDark ? rowNumberSelected : paintToken(getVar, "--data-grid-row-number-selected-bg", rowNumberSelected),
rowNumberTextClean: mutedForeground,
rowNumberTextNew: isDark ? "rgb(94, 233, 181)" : "rgb(0, 122, 85)",
rowNumberTextEdited: isDark ? "rgb(255, 210, 48)" : "rgb(187, 77, 0)",

View File

@ -1345,6 +1345,471 @@ body.dbx-table-reference-dragging * {
font-size: 12.5px;
}
@media (min-width: 640px) {
.sm\:flex-row {
flex-direction: row !important;
}
.sm\:justify-end {
justify-content: flex-end !important;
}
.sm\:grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
}
}
@media (min-width: 768px) {
.md\:w-full {
width: 100% !important;
}
.md\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
}
.md\:grid-cols-\[1fr_auto\] {
grid-template-columns: 1fr auto !important;
}
.md\:grid-cols-\[minmax\(0\,1fr\)_180px_auto\] {
grid-template-columns: minmax(0, 1fr) 180px auto !important;
}
}
@media (min-width: 1024px) {
.lg\:block {
display: block !important;
}
.lg\:hidden {
display: none !important;
}
.lg\:grid {
display: grid !important;
}
.lg\:flex-row {
flex-direction: row !important;
}
.lg\:flex-col {
flex-direction: column !important;
}
.lg\:items-center {
align-items: center !important;
}
.lg\:justify-between {
justify-content: space-between !important;
}
.lg\:justify-end {
justify-content: flex-end !important;
}
.lg\:w-40 {
width: 10rem !important;
}
.lg\:overflow-x-hidden {
overflow-x: hidden !important;
}
.lg\:overflow-y-auto {
overflow-y: auto !important;
}
.lg\:border-b-0 {
border-bottom-width: 0 !important;
}
.lg\:border-r {
border-right-width: 1px !important;
}
.lg\:pb-0 {
padding-bottom: 0 !important;
}
.lg\:pr-3 {
padding-right: 0.75rem !important;
}
.lg\:text-right {
text-align: right !important;
}
.lg\:grid-cols-6 {
grid-template-columns: repeat(6, minmax(0, 1fr)) !important;
}
.lg\:grid-cols-\[1\.2fr_0\.8fr\] {
grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr) !important;
}
.lg\:grid-cols-\[minmax\(0\,1\.6fr\)_72px_56px_76px_58px_76px_72px\] {
grid-template-columns: minmax(0, 1.6fr) 72px 56px 76px 58px 76px 72px !important;
}
}
[data-slot="dialog-content"] {
width: calc(100vw - 2rem);
max-width: 24rem;
border: 1px solid rgb(229, 229, 229);
border-color: rgb(229, 229, 229) !important;
box-shadow: 0 18px 50px rgba(0, 0, 0, 0.16);
}
.dark [data-slot="dialog-content"] {
border-color: rgba(110, 110, 114, 0.28) !important;
box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
}
[data-slot="dialog-content"][class~="max-w-sm"] {
max-width: 24rem !important;
}
[data-slot="dialog-content"][class~="max-w-md"] {
max-width: 28rem !important;
}
[data-slot="dialog-content"][class~="max-w-lg"] {
max-width: 32rem !important;
}
[data-slot="dialog-content"][class~="max-w-xl"] {
max-width: 36rem !important;
}
[data-slot="dialog-content"][class~="max-w-2xl"] {
max-width: 42rem !important;
}
[data-slot="dialog-content"][class~="max-w-4xl"] {
max-width: 56rem !important;
}
[data-slot="dialog-content"][class~="max-w-5xl"] {
max-width: 64rem !important;
}
[data-slot="dialog-content"][class~="max-w-190"] {
max-width: 47.5rem !important;
}
[data-slot="dialog-content"][class*="max-w-[92vw]"] {
max-width: 92vw !important;
}
[data-slot="dialog-content"][class*="max-w-[94vw]"] {
max-width: 94vw !important;
}
[data-slot="dialog-content"][class*="max-w-[1100px]"] {
max-width: 1100px !important;
}
[data-slot="tabs"][data-orientation="horizontal"] {
flex-direction: column !important;
}
[data-slot="tabs"][data-orientation="vertical"] {
flex-direction: row !important;
}
[data-slot="tabs-list"] {
display: inline-flex;
align-items: center;
justify-content: center;
width: fit-content;
border-radius: 6px;
color: var(--muted-foreground);
}
[data-slot="tabs-list"][data-variant="default"] {
min-height: 2rem;
padding: 3px;
background: var(--muted);
}
[data-slot="tabs-list"][data-variant="line"] {
gap: 0.25rem;
padding: 3px;
background: transparent;
border-radius: 0;
}
[data-slot="tabs"][data-orientation="vertical"] > [data-slot="tabs-list"] {
flex-direction: column !important;
height: fit-content;
}
[data-slot="tabs-trigger"] {
position: relative;
display: inline-flex;
flex: 1 1 0%;
align-items: center;
justify-content: center;
min-width: 0;
height: calc(100% - 1px);
padding: 0.125rem 0.375rem;
gap: 0.375rem;
border: 1px solid transparent;
border-radius: 0.375rem;
color: rgba(10, 10, 10, 0.6);
font-size: 0.875rem;
font-weight: 500;
line-height: 1.25rem;
white-space: nowrap;
transition:
color 150ms ease,
background-color 150ms ease,
border-color 150ms ease,
box-shadow 150ms ease;
}
[data-slot="tabs"][data-orientation="vertical"] [data-slot="tabs-trigger"] {
width: 100%;
justify-content: flex-start;
}
[data-slot="tabs-trigger"]:hover {
color: var(--foreground);
}
[data-slot="tabs-trigger"]:focus-visible {
border-color: var(--ring);
outline: 1px solid var(--ring);
box-shadow: 0 0 0 3px rgba(161, 161, 161, 0.5);
}
[data-slot="tabs-list"][data-variant="default"] > [data-slot="tabs-trigger"][aria-selected="true"],
[data-slot="tabs-list"][data-variant="default"] > [data-slot="tabs-trigger"][data-state="active"],
[data-slot="tabs-list"][data-variant="default"] > [data-slot="tabs-trigger"][data-active] {
color: var(--foreground);
background: var(--background);
border-color: transparent;
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.08),
0 1px 1px rgba(0, 0, 0, 0.04);
}
[data-slot="tabs-list"][data-variant="line"] > [data-slot="tabs-trigger"] {
background: transparent;
box-shadow: none;
}
[data-slot="tabs-list"][data-variant="line"] > [data-slot="tabs-trigger"][aria-selected="true"],
[data-slot="tabs-list"][data-variant="line"] > [data-slot="tabs-trigger"][data-state="active"],
[data-slot="tabs-list"][data-variant="line"] > [data-slot="tabs-trigger"][data-active] {
color: var(--foreground);
background: transparent;
border-color: transparent;
box-shadow: none;
}
[data-slot="tabs-list"][data-variant="line"] > [data-slot="tabs-trigger"]::after {
content: "";
position: absolute;
background: var(--foreground);
opacity: 0;
transition: opacity 150ms ease;
}
[data-slot="tabs"][data-orientation="horizontal"] [data-slot="tabs-list"][data-variant="line"] > [data-slot="tabs-trigger"]::after {
left: 0;
right: 0;
bottom: -5px;
height: 2px;
}
[data-slot="tabs"][data-orientation="vertical"] [data-slot="tabs-list"][data-variant="line"] > [data-slot="tabs-trigger"]::after {
top: 0;
right: -4px;
bottom: 0;
width: 2px;
}
[data-slot="tabs-list"][data-variant="line"] > [data-slot="tabs-trigger"][aria-selected="true"]::after,
[data-slot="tabs-list"][data-variant="line"] > [data-slot="tabs-trigger"][data-state="active"]::after,
[data-slot="tabs-list"][data-variant="line"] > [data-slot="tabs-trigger"][data-active]::after {
opacity: 1;
}
.dark [data-slot="tabs-trigger"] {
color: var(--muted-foreground);
}
.dark [data-slot="tabs-trigger"]:hover {
color: var(--foreground);
}
.dark [data-slot="tabs-list"][data-variant="default"] > [data-slot="tabs-trigger"][aria-selected="true"],
.dark [data-slot="tabs-list"][data-variant="default"] > [data-slot="tabs-trigger"][data-state="active"],
.dark [data-slot="tabs-list"][data-variant="default"] > [data-slot="tabs-trigger"][data-active] {
color: var(--foreground);
background: rgba(110, 110, 114, 0.3);
border-color: var(--input);
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.22),
0 1px 1px rgba(0, 0, 0, 0.16);
}
[data-slot="tabs-content"] {
min-width: 0;
}
.dark [data-grid-root] .data-grid-header-shell,
.dark [data-grid-root] .data-grid-header-cell,
.dark [data-grid-root] .data-grid-transpose-header,
.dark [data-grid-root] [data-grid-column-index] {
background-color: rgb(24, 25, 27) !important;
}
.dark [data-grid-root] .data-grid-header-row,
.dark [data-grid-root] .data-grid-transpose-header {
color: rgb(215, 215, 219) !important;
}
.dark [data-grid-root] .data-grid-header-cell:hover,
.dark [data-grid-root] [data-grid-column-index]:hover {
background-color: rgb(38, 39, 42) !important;
}
@media (min-width: 640px) {
[data-slot="dialog-footer"] {
flex-direction: row !important;
justify-content: flex-end !important;
}
[data-slot="dialog-content"][class~="sm:max-w-sm"] {
max-width: 24rem !important;
}
[data-slot="dialog-content"][class~="sm:max-w-md"] {
max-width: 28rem !important;
}
[data-slot="dialog-content"][class~="sm:max-w-lg"] {
max-width: 32rem !important;
}
[data-slot="dialog-content"][class~="sm:max-w-xl"] {
max-width: 36rem !important;
}
[data-slot="dialog-content"][class~="sm:max-w-2xl"] {
max-width: 42rem !important;
}
[data-slot="dialog-content"][class~="sm:max-w-3xl"] {
max-width: 48rem !important;
}
[data-slot="dialog-content"][class~="sm:max-w-4xl"] {
max-width: 56rem !important;
}
[data-slot="dialog-content"][class~="sm:max-w-5xl"] {
max-width: 64rem !important;
}
[data-slot="dialog-content"][class~="sm:max-w-190"] {
max-width: 47.5rem !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[360px]"] {
max-width: 360px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[380px]"] {
max-width: 380px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[400px]"] {
max-width: 400px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[420px]"] {
max-width: 420px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[440px]"] {
max-width: 440px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[460px]"] {
max-width: 460px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[480px]"] {
max-width: 480px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[500px]"] {
max-width: 500px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[520px]"] {
max-width: 520px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[560px]"] {
max-width: 560px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[660px]"] {
max-width: 660px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[720px]"] {
max-width: 720px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[760px]"] {
max-width: 760px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[780px]"] {
max-width: 780px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[840px]"] {
max-width: 840px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[860px]"] {
max-width: 860px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[900px]"] {
max-width: 900px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[960px]"] {
max-width: 960px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[980px]"] {
max-width: 980px !important;
}
[data-slot="dialog-content"][class*="sm:max-w-[calc(100vw-2rem)]"] {
max-width: calc(100vw - 2rem) !important;
}
[data-slot="dialog-content"][class*="sm:!max-w-[92vw]"] {
max-width: 92vw !important;
}
[data-slot="dialog-content"][class*="sm:!max-w-[min(920px,calc(100vw-48px))]"] {
max-width: min(920px, calc(100vw - 48px)) !important;
}
}
/* Splitpanes */
.splitpanes--horizontal .splitpanes__pane {
transition: none !important;
@ -1458,6 +1923,151 @@ body.dbx-table-reference-dragging * {
border-color: oklch(1 0 0 / 0.1) !important;
}
[data-slot="context-menu-content"],
[data-slot="context-menu-sub-content"],
[data-slot="dropdown-menu-content"],
[data-slot="dropdown-menu-sub-content"],
[data-slot="select-content"],
.cn-menu-translucent {
background-color: rgba(255, 255, 255, 0.96) !important;
border: 1px solid rgba(0, 0, 0, 0.1) !important;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12) !important;
--tw-ring-color: transparent !important;
--tw-ring-shadow: 0 0 transparent !important;
--tw-shadow: 0 0 transparent !important;
}
.dark [data-slot="context-menu-content"],
.dark [data-slot="context-menu-sub-content"],
.dark [data-slot="dropdown-menu-content"],
.dark [data-slot="dropdown-menu-sub-content"],
.dark [data-slot="select-content"],
.dark .cn-menu-translucent {
background-color: rgba(23, 23, 23, 0.94) !important;
border-color: rgba(255, 255, 255, 0.12) !important;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45) !important;
}
[data-slot="context-menu-item"]:hover,
[data-slot="context-menu-item"]:focus,
[data-slot="context-menu-item"][data-highlighted],
[data-slot="context-menu-checkbox-item"]:hover,
[data-slot="context-menu-checkbox-item"]:focus,
[data-slot="context-menu-checkbox-item"][data-highlighted],
[data-slot="context-menu-radio-item"]:hover,
[data-slot="context-menu-radio-item"]:focus,
[data-slot="context-menu-radio-item"][data-highlighted],
[data-slot="context-menu-sub-trigger"]:hover,
[data-slot="context-menu-sub-trigger"]:focus,
[data-slot="context-menu-sub-trigger"][data-highlighted],
[data-slot="context-menu-sub-trigger"][data-state="open"],
[data-slot="context-menu-sub-trigger"][data-open],
[data-slot="dropdown-menu-item"]:hover,
[data-slot="dropdown-menu-item"]:focus,
[data-slot="dropdown-menu-item"][data-highlighted],
[data-slot="dropdown-menu-checkbox-item"]:hover,
[data-slot="dropdown-menu-checkbox-item"]:focus,
[data-slot="dropdown-menu-checkbox-item"][data-highlighted],
[data-slot="dropdown-menu-radio-item"]:hover,
[data-slot="dropdown-menu-radio-item"]:focus,
[data-slot="dropdown-menu-radio-item"][data-highlighted],
[data-slot="dropdown-menu-sub-trigger"]:hover,
[data-slot="dropdown-menu-sub-trigger"]:focus,
[data-slot="dropdown-menu-sub-trigger"][data-highlighted],
[data-slot="dropdown-menu-sub-trigger"][data-state="open"],
[data-slot="dropdown-menu-sub-trigger"][data-open],
[data-slot="select-item"]:hover,
[data-slot="select-item"]:focus,
[data-slot="select-item"][data-highlighted],
[role="menuitem"]:hover,
[role="menuitem"]:focus {
background-color: rgba(23, 23, 23, 0.08) !important;
color: rgb(23, 23, 23) !important;
}
[data-slot="context-menu-item"]:hover svg,
[data-slot="context-menu-item"]:focus svg,
[data-slot="context-menu-item"][data-highlighted] svg,
[data-slot="context-menu-checkbox-item"]:hover svg,
[data-slot="context-menu-checkbox-item"]:focus svg,
[data-slot="context-menu-checkbox-item"][data-highlighted] svg,
[data-slot="context-menu-radio-item"]:hover svg,
[data-slot="context-menu-radio-item"]:focus svg,
[data-slot="context-menu-radio-item"][data-highlighted] svg,
[data-slot="context-menu-sub-trigger"]:hover svg,
[data-slot="context-menu-sub-trigger"]:focus svg,
[data-slot="context-menu-sub-trigger"][data-highlighted] svg,
[data-slot="context-menu-sub-trigger"][data-state="open"] svg,
[data-slot="context-menu-sub-trigger"][data-open] svg,
[data-slot="dropdown-menu-item"]:hover svg,
[data-slot="dropdown-menu-item"]:focus svg,
[data-slot="dropdown-menu-item"][data-highlighted] svg,
[data-slot="dropdown-menu-checkbox-item"]:hover svg,
[data-slot="dropdown-menu-checkbox-item"]:focus svg,
[data-slot="dropdown-menu-checkbox-item"][data-highlighted] svg,
[data-slot="dropdown-menu-radio-item"]:hover svg,
[data-slot="dropdown-menu-radio-item"]:focus svg,
[data-slot="dropdown-menu-radio-item"][data-highlighted] svg,
[data-slot="dropdown-menu-sub-trigger"]:hover svg,
[data-slot="dropdown-menu-sub-trigger"]:focus svg,
[data-slot="dropdown-menu-sub-trigger"][data-highlighted] svg,
[data-slot="dropdown-menu-sub-trigger"][data-state="open"] svg,
[data-slot="dropdown-menu-sub-trigger"][data-open] svg,
[data-slot="select-item"]:hover svg,
[data-slot="select-item"]:focus svg,
[data-slot="select-item"][data-highlighted] svg,
[role="menuitem"]:hover svg,
[role="menuitem"]:focus svg {
color: currentColor !important;
}
[data-slot="context-menu-item"][data-variant="destructive"]:hover,
[data-slot="context-menu-item"][data-variant="destructive"]:focus,
[data-slot="context-menu-item"][data-variant="destructive"][data-highlighted],
[data-slot="dropdown-menu-item"][data-variant="destructive"]:hover,
[data-slot="dropdown-menu-item"][data-variant="destructive"]:focus,
[data-slot="dropdown-menu-item"][data-variant="destructive"][data-highlighted] {
background-color: rgba(var(--destructive-rgb), 0.1) !important;
color: rgb(var(--destructive-rgb)) !important;
}
.dark [data-slot="context-menu-item"]:hover,
.dark [data-slot="context-menu-item"]:focus,
.dark [data-slot="context-menu-item"][data-highlighted],
.dark [data-slot="context-menu-checkbox-item"]:hover,
.dark [data-slot="context-menu-checkbox-item"]:focus,
.dark [data-slot="context-menu-checkbox-item"][data-highlighted],
.dark [data-slot="context-menu-radio-item"]:hover,
.dark [data-slot="context-menu-radio-item"]:focus,
.dark [data-slot="context-menu-radio-item"][data-highlighted],
.dark [data-slot="context-menu-sub-trigger"]:hover,
.dark [data-slot="context-menu-sub-trigger"]:focus,
.dark [data-slot="context-menu-sub-trigger"][data-highlighted],
.dark [data-slot="context-menu-sub-trigger"][data-state="open"],
.dark [data-slot="context-menu-sub-trigger"][data-open],
.dark [data-slot="dropdown-menu-item"]:hover,
.dark [data-slot="dropdown-menu-item"]:focus,
.dark [data-slot="dropdown-menu-item"][data-highlighted],
.dark [data-slot="dropdown-menu-checkbox-item"]:hover,
.dark [data-slot="dropdown-menu-checkbox-item"]:focus,
.dark [data-slot="dropdown-menu-checkbox-item"][data-highlighted],
.dark [data-slot="dropdown-menu-radio-item"]:hover,
.dark [data-slot="dropdown-menu-radio-item"]:focus,
.dark [data-slot="dropdown-menu-radio-item"][data-highlighted],
.dark [data-slot="dropdown-menu-sub-trigger"]:hover,
.dark [data-slot="dropdown-menu-sub-trigger"]:focus,
.dark [data-slot="dropdown-menu-sub-trigger"][data-highlighted],
.dark [data-slot="dropdown-menu-sub-trigger"][data-state="open"],
.dark [data-slot="dropdown-menu-sub-trigger"][data-open],
.dark [data-slot="select-item"]:hover,
.dark [data-slot="select-item"]:focus,
.dark [data-slot="select-item"][data-highlighted],
.dark [role="menuitem"]:hover,
.dark [role="menuitem"]:focus {
background-color: rgba(255, 255, 255, 0.12) !important;
color: rgb(245, 245, 245) !important;
}
/* Tailwind 4 falls back from bg-destructive/<alpha> to solid --destructive
when color-mix() is unavailable in older WebKit. Keep dangerous-action
surfaces translucent so red text/icons remain legible on macOS 12 WebView. */