fix(desktop): scope dark styles and restore dialog blur

This commit is contained in:
t8y2 2026-07-30 08:48:58 +08:00
parent 3143683b5a
commit e78a510485
No known key found for this signature in database
6 changed files with 55 additions and 8 deletions

View File

@ -34,6 +34,7 @@ import { useVisibilityChange } from "@/composables/useVisibilityChange";
import { useWebDavAutoUpload } from "@/composables/useWebDavAutoUpload";
import { useScheduledDatabaseBackups } from "@/composables/useScheduledDatabaseBackups";
import { shouldDrawDesktopWindowFrame } from "@/composables/useWindowControls";
import { startDialogBackdropSync, stopDialogBackdropSync } from "@/lib/app/dialogBackdrop";
import { useSaveSqlFolderSelection } from "@/composables/useSaveSqlFolderSelection";
import "@/i18n";
import { translateBackendError } from "@/i18n/backend-errors";
@ -2087,6 +2088,7 @@ onMounted(async () => {
});
applyTheme();
void applyUiScale(settingsStore.editorSettings.uiScale);
startDialogBackdropSync();
window.addEventListener("keydown", handleKeydown);
window.addEventListener("dbx-open-driver-store", openDriverStoreFromEvent);
if (isDesktop) {
@ -2147,6 +2149,7 @@ onMounted(async () => {
});
onUnmounted(() => {
stopDialogBackdropSync();
cleanupTauriListeners();
cleanupCloseActionPromptListener();
if (updateCheckTimer) {

View File

@ -570,15 +570,15 @@ defineExpose({ focus, dismiss: editor.dismiss, rememberHistory: editor.rememberH
0 1px color-mix(in oklab, var(--background) 96%, var(--muted) 4%);
}
:global(.dark) .data-grid-topbar-condition-label--where {
:global(.dark .data-grid-topbar-condition-label--where) {
color: rgb(96 165 250);
}
:global(.dark) .data-grid-topbar-condition-label--order {
:global(.dark .data-grid-topbar-condition-label--order) {
color: rgb(251 146 60);
}
:global(.dark) .data-grid-topbar-condition-label--floating {
:global(.dark .data-grid-topbar-condition-label--floating) {
text-shadow:
-1px 0 rgb(24, 24, 27),
1px 0 rgb(24, 24, 27),
@ -617,7 +617,7 @@ defineExpose({ focus, dismiss: editor.dismiss, rememberHistory: editor.rememberH
line-height: 1.5rem;
}
:global(.dark) .data-grid-topbar-condition-input {
:global(.dark .data-grid-topbar-condition-input) {
color: rgb(244, 244, 245);
background-color: transparent !important;
}
@ -657,7 +657,7 @@ defineExpose({ focus, dismiss: editor.dismiss, rememberHistory: editor.rememberH
--data-grid-condition-suffix-width: 0px;
}
:global(.dark) .data-grid-topbar-condition-pane--expanded {
:global(.dark .data-grid-topbar-condition-pane--expanded) {
background: rgb(24, 24, 27) !important;
color: rgb(244, 244, 245);
box-shadow:
@ -706,11 +706,11 @@ defineExpose({ focus, dismiss: editor.dismiss, rememberHistory: editor.rememberH
color: rgb(249 115 22 / 70%);
}
:global(.dark) .data-grid-topbar-condition-input--where.data-grid-topbar-condition-input--compact::placeholder {
:global(.dark .data-grid-topbar-condition-input--where.data-grid-topbar-condition-input--compact::placeholder) {
color: rgb(147 197 253 / 70%);
}
:global(.dark) .data-grid-topbar-condition-input--order.data-grid-topbar-condition-input--compact::placeholder {
:global(.dark .data-grid-topbar-condition-input--order.data-grid-topbar-condition-input--compact::placeholder) {
color: rgb(253 186 116 / 70%);
}
</style>

View File

@ -124,6 +124,14 @@ describe("DataGridConditionEditor quote completion", () => {
expect(floatingLabelCss).not.toContain("box-shadow:");
});
it("keeps dark condition styles scoped to their target elements", () => {
const source = readFileSync(resolve(process.cwd(), "apps/desktop/src/components/grid/DataGridConditionEditor.vue"), "utf8");
expect(source).not.toContain(":global(.dark) .data-grid");
expect(source).toContain(":global(.dark .data-grid-topbar-condition-label--floating)");
expect(source).toContain(":global(.dark .data-grid-topbar-condition-pane--expanded)");
});
it("scrolls the caret into view after accepting a long completion", () => {
const source = readFileSync(resolve(process.cwd(), "apps/desktop/src/components/grid/DataGridConditionEditor.vue"), "utf8");

View File

@ -0,0 +1,24 @@
const DIALOG_BACKDROP_CLASS = "dbx-dialog-backdrop-active";
let dialogBackdropObserver: MutationObserver | undefined;
function hasDialogOverlay(): boolean {
return Array.from(document.body.children).some((child) => child.matches('[data-slot="dialog-overlay"]') || child.querySelector('[data-slot="dialog-overlay"]'));
}
function syncDialogBackdrop() {
document.documentElement.classList.toggle(DIALOG_BACKDROP_CLASS, hasDialogOverlay());
}
export function startDialogBackdropSync() {
if (typeof document === "undefined" || dialogBackdropObserver) return;
dialogBackdropObserver = new MutationObserver(syncDialogBackdrop);
dialogBackdropObserver.observe(document.body, { childList: true });
syncDialogBackdrop();
}
export function stopDialogBackdropSync() {
dialogBackdropObserver?.disconnect();
dialogBackdropObserver = undefined;
document.documentElement.classList.remove(DIALOG_BACKDROP_CLASS);
}

View File

@ -6,6 +6,8 @@ const dialogContentSource = readFileSync(new URL("../../components/ui/dialog/Dia
const dialogScrollContentSource = readFileSync(new URL("../../components/ui/dialog/DialogScrollContent.vue", import.meta.url), "utf8");
const dialogOverlaySource = readFileSync(new URL("../../components/ui/dialog/DialogOverlay.vue", import.meta.url), "utf8");
const connectionDialogSource = readFileSync(new URL("../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
const dialogBackdropSource = readFileSync(new URL("../../lib/app/dialogBackdrop.ts", import.meta.url), "utf8");
const appSource = readFileSync(new URL("../../App.vue", import.meta.url), "utf8");
const desktopIndexSource = readFileSync(new URL("../../../index.html", import.meta.url), "utf8");
const connectionDialogLegacyCss = readFileSync(new URL("../../../public/connection-dialog-legacy.css", import.meta.url), "utf8");
@ -44,9 +46,15 @@ describe("legacy WebView CSS fallbacks", () => {
expect(connectionDialogSource).toContain("max-height: calc(var(--dbx-viewport-height) - 2rem);");
});
it("avoids full-window backdrop filters that can blank WebKit after a dialog closes", () => {
it("blurs the stable app root instead of the transient dialog overlay", () => {
expect(dialogOverlaySource).not.toContain("backdrop-filter");
expect(dialogOverlaySource).toContain("bg-black/10");
expect(globalsCss).toContain("html.dbx-dialog-backdrop-active #root");
expect(globalsCss).toContain("filter: blur(4px);");
expect(dialogBackdropSource).toContain("dialogBackdropObserver.observe(document.body, { childList: true })");
expect(dialogBackdropSource).not.toContain("subtree: true");
expect(appSource).toContain("startDialogBackdropSync();");
expect(appSource).toContain("stopDialogBackdropSync();");
});
it("keeps legacy tab triggers connected to the configured corner style", () => {

View File

@ -270,6 +270,10 @@
}
}
html.dbx-dialog-backdrop-active #root {
filter: blur(4px);
}
.dark {
--background: rgb(19 20 22);
--foreground: rgb(215 215 219);