fix(dialog): keep dialogs opaque over custom background image

This commit is contained in:
zipg
2026-09-26 00:40:25 +08:00
committed by GitHub
parent d6c803b17b
commit e0121fd649
8 changed files with 53 additions and 6 deletions
@@ -158,7 +158,7 @@ const previewVisible = computed(() => open.value && !!props.source);
<Dialog v-model:open="open">
<!-- 对话框整体限高:高度上限跟随 --dbx-viewport-height(兼容旧版 WebView 中 vh 不准的情况);
内部采用纵向 flex 布局,header/footer 固定,只有中间预览区滚动,保证底部按钮始终可见 -->
<DialogContent class="flex max-h-[calc(var(--dbx-viewport-height)-2rem)] flex-col overflow-hidden border border-border !bg-background text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[860px]">
<DialogContent class="flex max-h-[calc(var(--dbx-viewport-height)-2rem)] flex-col overflow-hidden border border-border !bg-background-solid text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[860px]">
<DialogHeader>
<DialogTitle class="flex items-center gap-2">
<Camera class="h-5 w-5 text-primary" />
@@ -151,7 +151,7 @@ async function copyPreview() {
<template>
<Dialog v-model:open="open">
<DialogContent class="max-h-[86vh] border border-border !bg-background text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[620px]">
<DialogContent class="max-h-[86vh] border border-border !bg-background-solid text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[620px]">
<DialogHeader>
<DialogTitle class="flex items-center gap-2">
<List class="h-5 w-5 text-primary" />
@@ -150,7 +150,7 @@ async function copyResolvedSql() {
<template>
<Dialog v-model:open="open">
<DialogContent class="max-h-[86vh] border border-border !bg-background text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[720px]">
<DialogContent class="max-h-[86vh] border border-border !bg-background-solid text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[720px]">
<DialogHeader>
<DialogTitle class="flex items-center gap-2">
<Braces class="h-5 w-5 text-primary" />
@@ -193,6 +193,17 @@ describe("SqlParameterDialog raw parameter action", () => {
});
});
describe("SqlParameterDialog surface", () => {
it("keeps the dialog background opaque while a wallpaper is active", async () => {
await mountDialog();
const content = document.body.querySelector('[data-slot="dialog-content"]');
expect(content).not.toBeNull();
const classes = content!.className;
expect(classes).toContain("bg-background-solid");
expect(classes).not.toMatch(/(^|\s)!bg-background(\s|$)/);
});
});
describe("SqlParameterDialog ignore parameter action", () => {
it("closes the dialog and emits the original SQL without remembering or mutating values", async () => {
const { state, onExecute } = await mountDialog();
@@ -147,7 +147,7 @@ async function exportSnapshot(kind: "clipboard" | "file") {
<template>
<Dialog v-model:open="open">
<DialogContent class="flex max-h-[calc(var(--dbx-viewport-height)-2rem)] flex-col overflow-hidden border border-border !bg-background text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[980px]">
<DialogContent class="flex max-h-[calc(var(--dbx-viewport-height)-2rem)] flex-col overflow-hidden border border-border !bg-background-solid text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[980px]">
<DialogHeader>
<DialogTitle class="flex items-center gap-2"><Camera class="h-5 w-5 text-primary" />{{ t("gridSnapshot.title") }}</DialogTitle>
</DialogHeader>
@@ -144,7 +144,7 @@ function displayParameterDefault(parameter: RoutineParameterValue): string {
<template>
<Dialog v-model:open="open">
<DialogContent class="max-h-[86vh] border border-border !bg-background text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[780px]">
<DialogContent class="max-h-[86vh] border border-border !bg-background-solid text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[780px]">
<DialogHeader>
<DialogTitle>{{ t("contextMenu.confirmExecuteProcedureTitle") }}</DialogTitle>
</DialogHeader>
@@ -0,0 +1,36 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import { BACKGROUND_IMAGE_SURFACE_VARS } from "@/lib/app/appBackgroundImage";
/**
* While a wallpaper is active the app republishes `--background` (and the other
* surface tokens) with the configured alpha, so a dialog that paints itself with
* `bg-background` turns translucent and its text becomes hard to read. These
* dialogs used to override the opaque `bg-popover` surface with `!bg-background`,
* so they are pinned to `bg-background-solid` here.
*/
const DIALOG_SOURCES = {
"codeSnapshot/CodeSnapshotDialog.vue": "../../../components/codeSnapshot/CodeSnapshotDialog.vue",
"grid/GridSnapshotDialog.vue": "../../../components/grid/GridSnapshotDialog.vue",
"editor/DelimitedListDialog.vue": "../../../components/editor/DelimitedListDialog.vue",
"editor/SqlParameterDialog.vue": "../../../components/editor/SqlParameterDialog.vue",
"objects/ProcedureExecutionDialog.vue": "../../../components/objects/ProcedureExecutionDialog.vue",
} as const;
describe("dialog surfaces under a wallpaper", () => {
it("keeps --background in the translucent wallpaper surface set", () => {
expect(BACKGROUND_IMAGE_SURFACE_VARS).toContain("--background");
});
for (const [label, relativePath] of Object.entries(DIALOG_SOURCES)) {
it(`${label} paints an opaque surface`, () => {
const source = readFileSync(new URL(relativePath, import.meta.url), "utf8");
const dialogContentClasses = Array.from(source.matchAll(/<DialogContent\b[^>]*class="([^"]*)"/g), (match) => match[1]);
expect(dialogContentClasses.length).toBeGreaterThan(0);
for (const classes of dialogContentClasses) {
expect(classes).toContain("bg-background-solid");
expect(classes).not.toMatch(/(^|\s)!bg-background(\s|$)/);
}
});
}
});
@@ -136,7 +136,7 @@ describe("legacy WebView CSS fallbacks", () => {
});
it("keeps the code snapshot dialog layout on the global legacy dialog fallbacks", () => {
expect(codeSnapshotDialogSource).toContain('class="flex max-h-[calc(var(--dbx-viewport-height)-2rem)] flex-col overflow-hidden border border-border !bg-background text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[860px]"');
expect(codeSnapshotDialogSource).toContain('class="flex max-h-[calc(var(--dbx-viewport-height)-2rem)] flex-col overflow-hidden border border-border !bg-background-solid text-foreground shadow-2xl !backdrop-blur-none sm:max-w-[860px]"');
expect(codeSnapshotDialogSource).not.toContain("dbx-legacy-webview");
expect(codeSnapshotDialogSource).not.toContain("@media");
expect(globalsCss).toContain('html.dbx-legacy-webview [data-slot="dialog-content"][class*="sm:max-w-[860px]"]');