feat: 前端界面优化
This commit is contained in:
@@ -22,7 +22,9 @@ describe("shared operation dialogs", () => {
|
|||||||
expect(html).toContain('aria-labelledby=');
|
expect(html).toContain('aria-labelledby=');
|
||||||
expect(html).toContain('aria-describedby=');
|
expect(html).toContain('aria-describedby=');
|
||||||
expect(html).toContain('aria-busy="true"');
|
expect(html).toContain('aria-busy="true"');
|
||||||
|
expect(html).toContain("关闭确认停用");
|
||||||
expect(operationControlsSource).toContain('event.key === "Escape"');
|
expect(operationControlsSource).toContain('event.key === "Escape"');
|
||||||
|
expect(operationControlsSource).toContain('document.body.style.overflow = "hidden"');
|
||||||
expect(operationControlsSource).toContain("previousFocus?.focus()");
|
expect(operationControlsSource).toContain("previousFocus?.focus()");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,13 @@ export function ConfirmDialog({ open, title, description, confirmLabel, danger,
|
|||||||
aria-busy={busy}
|
aria-busy={busy}
|
||||||
onClick={(event) => event.stopPropagation()}
|
onClick={(event) => event.stopPropagation()}
|
||||||
>
|
>
|
||||||
|
<div className="panel-header dialog-panel-header">
|
||||||
<h2 id={titleId}>{title}</h2>
|
<h2 id={titleId}>{title}</h2>
|
||||||
|
<button type="button" className="theme-upload drawer-close" aria-label={`关闭${title}`} onClick={onCancel} disabled={busy}>
|
||||||
|
<X size={14} />
|
||||||
|
<span>关闭</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<p id={descriptionId}>{description}</p>
|
<p id={descriptionId}>{description}</p>
|
||||||
{children}
|
{children}
|
||||||
<div className="confirm-actions">
|
<div className="confirm-actions">
|
||||||
@@ -75,7 +81,7 @@ export function ManagementDialog({ open, title, description, wide, onClose, chil
|
|||||||
aria-describedby={description ? descriptionId : undefined}
|
aria-describedby={description ? descriptionId : undefined}
|
||||||
onClick={(event) => event.stopPropagation()}
|
onClick={(event) => event.stopPropagation()}
|
||||||
>
|
>
|
||||||
<div className="panel-header">
|
<div className="panel-header dialog-panel-header">
|
||||||
<h2 id={titleId}>{title}</h2>
|
<h2 id={titleId}>{title}</h2>
|
||||||
<button type="button" className="theme-upload drawer-close" aria-label={`关闭${title}`} onClick={onClose}>
|
<button type="button" className="theme-upload drawer-close" aria-label={`关闭${title}`} onClick={onClose}>
|
||||||
<X size={14} />
|
<X size={14} />
|
||||||
@@ -109,8 +115,11 @@ function useDialogLifecycle(open: boolean, onClose: () => void, canClose: boolea
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("keydown", handleKeyDown);
|
document.addEventListener("keydown", handleKeyDown);
|
||||||
|
const previousBodyOverflow = document.body.style.overflow;
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener("keydown", handleKeyDown);
|
document.removeEventListener("keydown", handleKeyDown);
|
||||||
|
document.body.style.overflow = previousBodyOverflow;
|
||||||
previousFocus?.focus();
|
previousFocus?.focus();
|
||||||
};
|
};
|
||||||
}, [canClose, onClose, open]);
|
}, [canClose, onClose, open]);
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ describe("first-party console pages", () => {
|
|||||||
expect(html).not.toContain("role=\"dialog\"");
|
expect(html).not.toContain("role=\"dialog\"");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("labels uploaded profile backgrounds as active and built-in presets as fallback", () => {
|
it("keeps profile background controls focused on custom uploads", () => {
|
||||||
const originalWindow = globalThis.window;
|
const originalWindow = globalThis.window;
|
||||||
Object.defineProperty(globalThis, "window", {
|
Object.defineProperty(globalThis, "window", {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
@@ -265,10 +265,12 @@ describe("first-party console pages", () => {
|
|||||||
const html = renderToStaticMarkup(<ProfileSettingsPage {...pageProps()} />);
|
const html = renderToStaticMarkup(<ProfileSettingsPage {...pageProps()} />);
|
||||||
|
|
||||||
expect(html).toContain("自定义背景");
|
expect(html).toContain("自定义背景");
|
||||||
expect(html).toContain("机甲格纳库");
|
expect(html).toContain("上传背景");
|
||||||
expect(html).toContain("备用");
|
expect(html).toContain("移除背景");
|
||||||
expect(html).toContain("当前显示自定义上传背景;机甲格纳库 仅作为移除上传后的备用桌面。");
|
expect(html).toContain("当前显示自定义上传背景;移除后回到主题配色背景。");
|
||||||
expect(html).toContain('aria-pressed="false"');
|
expect(html).not.toContain("机甲格纳库");
|
||||||
|
expect(html).not.toContain("粉月魔法阵");
|
||||||
|
expect(html).not.toContain("备用");
|
||||||
} finally {
|
} finally {
|
||||||
Object.defineProperty(globalThis, "window", {
|
Object.defineProperty(globalThis, "window", {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
|
|||||||
@@ -5,15 +5,11 @@ import type { PageComponentProps } from "../contracts/page";
|
|||||||
import { defaultPageForUser } from "../routes/routes";
|
import { defaultPageForUser } from "../routes/routes";
|
||||||
import {
|
import {
|
||||||
applyBackgroundImage,
|
applyBackgroundImage,
|
||||||
applyThemeBackgroundPreset,
|
|
||||||
applyThemePalette,
|
applyThemePalette,
|
||||||
loadThemeState,
|
loadThemeState,
|
||||||
persistBackgroundImage,
|
persistBackgroundImage,
|
||||||
persistThemeBackgroundPreset,
|
|
||||||
persistThemePalette,
|
persistThemePalette,
|
||||||
themeBackgroundPresets,
|
|
||||||
themePalettes,
|
themePalettes,
|
||||||
type ThemeBackgroundId,
|
|
||||||
type ThemePaletteId,
|
type ThemePaletteId,
|
||||||
type WorkspaceThemeState
|
type WorkspaceThemeState
|
||||||
} from "../theme/tokens";
|
} from "../theme/tokens";
|
||||||
@@ -46,9 +42,8 @@ export function ProfileSettingsPage({ session, onNavigate, onLogout, onProfileSa
|
|||||||
}, [session]);
|
}, [session]);
|
||||||
|
|
||||||
const activePalette = useMemo(() => themePalettes.find((palette) => palette.id === themeState.paletteId) ?? themePalettes[0], [themeState.paletteId]);
|
const activePalette = useMemo(() => themePalettes.find((palette) => palette.id === themeState.paletteId) ?? themePalettes[0], [themeState.paletteId]);
|
||||||
const activeBackground = useMemo(() => themeBackgroundPresets.find((preset) => preset.id === themeState.backgroundPresetId) ?? themeBackgroundPresets[0], [themeState.backgroundPresetId]);
|
|
||||||
const hasCustomBackground = Boolean(themeState.backgroundImage);
|
const hasCustomBackground = Boolean(themeState.backgroundImage);
|
||||||
const backgroundMetricValue = hasCustomBackground ? "自定义背景" : activeBackground.label;
|
const backgroundMetricValue = hasCustomBackground ? "已上传" : "主题配色";
|
||||||
|
|
||||||
async function saveProfile(event: FormEvent<HTMLFormElement>) {
|
async function saveProfile(event: FormEvent<HTMLFormElement>) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -91,16 +86,6 @@ export function ProfileSettingsPage({ session, onNavigate, onLogout, onProfileSa
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectBackgroundPreset(backgroundPresetId: ThemeBackgroundId) {
|
|
||||||
applyThemeBackgroundPreset(backgroundPresetId);
|
|
||||||
persistThemeBackgroundPreset(backgroundPresetId);
|
|
||||||
setThemeState((current) => {
|
|
||||||
const nextState = { ...current, backgroundPresetId };
|
|
||||||
void persistThemePreference(nextState);
|
|
||||||
return nextState;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleBackgroundUpload(event: ChangeEvent<HTMLInputElement>) {
|
function handleBackgroundUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||||
const file = event.target.files?.[0];
|
const file = event.target.files?.[0];
|
||||||
event.target.value = "";
|
event.target.value = "";
|
||||||
@@ -219,31 +204,8 @@ export function ProfileSettingsPage({ session, onNavigate, onLogout, onProfileSa
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="profile-panel-title">
|
<div className="profile-panel-title">
|
||||||
<MoonStar size={15} />
|
<Upload size={15} />
|
||||||
<strong>背景桌面</strong>
|
<strong>自定义背景</strong>
|
||||||
</div>
|
|
||||||
<div className="background-preset-grid profile-background-grid">
|
|
||||||
{themeBackgroundPresets.map((preset) => {
|
|
||||||
const isFallbackPreset = preset.id === themeState.backgroundPresetId;
|
|
||||||
const isVisiblePreset = isFallbackPreset && !hasCustomBackground;
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={preset.id}
|
|
||||||
type="button"
|
|
||||||
className={cx("background-preset-option", isVisiblePreset && "background-preset-option-active", hasCustomBackground && isFallbackPreset && "background-preset-option-fallback")}
|
|
||||||
aria-pressed={isVisiblePreset}
|
|
||||||
title={hasCustomBackground ? `${preset.summary},当前自定义背景正在显示;此预设会在移除上传背景后显示` : preset.summary}
|
|
||||||
onClick={() => selectBackgroundPreset(preset.id)}
|
|
||||||
>
|
|
||||||
<span className="background-preset-preview" style={{ background: preset.preview }} aria-hidden="true" />
|
|
||||||
<span className="background-preset-label">
|
|
||||||
{isVisiblePreset ? <Sparkles size={13} /> : <MoonStar size={13} />}
|
|
||||||
{preset.label}
|
|
||||||
{hasCustomBackground && isFallbackPreset && <span className="background-preset-fallback-badge">备用</span>}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="theme-background-actions">
|
<div className="theme-background-actions">
|
||||||
<label className="theme-upload" title="上传自定义背景桌面">
|
<label className="theme-upload" title="上传自定义背景桌面">
|
||||||
@@ -258,7 +220,7 @@ export function ProfileSettingsPage({ session, onNavigate, onLogout, onProfileSa
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<span className="theme-background-note">{themeState.backgroundImage ? `当前显示自定义上传背景;${activeBackground.label} 仅作为移除上传后的备用桌面。` : "当前使用内置背景桌面。"}</span>
|
<span className="theme-background-note">{themeState.backgroundImage ? "当前显示自定义上传背景;移除后回到主题配色背景。" : "当前仅使用主题配色背景。"}</span>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -112,4 +112,45 @@ describe("platform web shared theme CSS", () => {
|
|||||||
expect(mobileRule).toContain(".app-nav-copy strong");
|
expect(mobileRule).toContain(".app-nav-copy strong");
|
||||||
expect(mobileRule).toContain("display: block");
|
expect(mobileRule).toContain("display: block");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps desktop sidebar controls pinned inside the viewport", () => {
|
||||||
|
const themeCss = readFileSync(new URL("./base.css", import.meta.url), "utf8");
|
||||||
|
const shellRule = themeCss.slice(themeCss.indexOf(".app-shell {"), themeCss.indexOf(".workspace-background-layer"));
|
||||||
|
const sidebarRule = themeCss.slice(themeCss.indexOf(".app-sidebar {"), themeCss.indexOf(".app-brand {"));
|
||||||
|
|
||||||
|
expect(shellRule).toContain("min-height: 100dvh");
|
||||||
|
expect(sidebarRule).toContain("position: sticky");
|
||||||
|
expect(sidebarRule).toContain("height: 100dvh");
|
||||||
|
expect(sidebarRule).toContain("overflow-y: auto");
|
||||||
|
expect(sidebarRule).toContain("overscroll-behavior: contain");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps dialogs and drawers internally scrollable on short viewports", () => {
|
||||||
|
const themeCss = readFileSync(new URL("./base.css", import.meta.url), "utf8");
|
||||||
|
const dialogRule = themeCss.slice(themeCss.indexOf("/* ---- drawer ---- */"), themeCss.indexOf(".plugin-detail-actions"));
|
||||||
|
const confirmStart = themeCss.indexOf("/* ---- confirm dialog ---- */");
|
||||||
|
const confirmRule = themeCss.slice(confirmStart, themeCss.indexOf(".confirm-actions {", confirmStart));
|
||||||
|
const mobileRule = themeCss.slice(themeCss.indexOf("/* ---- narrow screens ---- */"), themeCss.indexOf("/* A state view inside an already framed surface"));
|
||||||
|
|
||||||
|
expect(dialogRule).toContain(".dialog-panel-header");
|
||||||
|
expect(dialogRule).toContain(".drawer-panel > .panel-header");
|
||||||
|
expect(dialogRule).toContain("position: sticky");
|
||||||
|
expect(dialogRule).toContain("overflow-y: auto");
|
||||||
|
expect(dialogRule).toContain("overscroll-behavior: contain");
|
||||||
|
expect(confirmRule).toContain("max-height: calc(100dvh - 32px)");
|
||||||
|
expect(confirmRule).toContain("overflow-y: auto");
|
||||||
|
expect(mobileRule).toContain("max-height: calc(100dvh - 20px)");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps magical card decoration from becoming square background patches", () => {
|
||||||
|
const themeCss = readFileSync(new URL("./base.css", import.meta.url), "utf8");
|
||||||
|
const magicalSurfaceRule = themeCss.slice(
|
||||||
|
themeCss.indexOf(':root[data-theme-palette="magical-girl"] .metric-card'),
|
||||||
|
themeCss.indexOf(':root[data-theme-palette="magical-girl"] :where(')
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(magicalSurfaceRule).toContain("background: var(--panel-material)");
|
||||||
|
expect(magicalSurfaceRule).not.toContain("background-size: 56px 56px");
|
||||||
|
expect(magicalSurfaceRule).not.toContain("background-image: var(--corner-sparkle), var(--panel-material)");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+148
-36
@@ -102,7 +102,7 @@ button {
|
|||||||
/* ---- app shell with themed background ---- */
|
/* ---- app shell with themed background ---- */
|
||||||
|
|
||||||
.app-shell {
|
.app-shell {
|
||||||
min-height: 100vh;
|
min-height: 100dvh;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: var(--sidebar-width, 216px) minmax(0, 1fr);
|
grid-template-columns: var(--sidebar-width, 216px) minmax(0, 1fr);
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -125,12 +125,12 @@ button {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
background-image: var(--workspace-background-image), var(--workspace-background-pattern-image);
|
background-image: var(--workspace-background-image);
|
||||||
background-size: cover, var(--workspace-background-pattern-size);
|
background-size: cover;
|
||||||
background-position: center, var(--workspace-background-pattern-position);
|
background-position: center;
|
||||||
background-repeat: no-repeat, var(--workspace-background-pattern-repeat);
|
background-repeat: no-repeat;
|
||||||
filter: var(--workspace-background-pattern-filter);
|
filter: none;
|
||||||
opacity: var(--workspace-background-pattern-opacity);
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,13 +389,16 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app-sidebar {
|
.app-sidebar {
|
||||||
position: relative;
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 14px;
|
gap: 14px;
|
||||||
width: var(--sidebar-width, 216px);
|
width: var(--sidebar-width, 216px);
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
height: 100dvh;
|
||||||
|
max-height: 100dvh;
|
||||||
padding: 16px 10px;
|
padding: 16px 10px;
|
||||||
border-right: 1px solid color-mix(in srgb, var(--line) 72%, transparent);
|
border-right: 1px solid color-mix(in srgb, var(--line) 72%, transparent);
|
||||||
background:
|
background:
|
||||||
@@ -404,6 +407,10 @@ button {
|
|||||||
backdrop-filter: blur(26px) saturate(1.2);
|
backdrop-filter: blur(26px) saturate(1.2);
|
||||||
box-shadow: inset -1px 0 0 color-mix(in srgb, var(--rim-light) 24%, transparent), 12px 0 34px rgba(0, 0, 0, 0.34);
|
box-shadow: inset -1px 0 0 color-mix(in srgb, var(--rim-light) 24%, transparent), 12px 0 34px rgba(0, 0, 0, 0.34);
|
||||||
transition: width 180ms ease, padding 180ms ease;
|
transition: width 180ms ease, padding 180ms ease;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-brand {
|
.app-brand {
|
||||||
@@ -1028,6 +1035,7 @@ button {
|
|||||||
.theme-upload {
|
.theme-upload {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
@@ -1038,9 +1046,16 @@ button {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
box-shadow: inset 0 1px 0 var(--crystal-rim);
|
box-shadow: inset 0 1px 0 var(--crystal-rim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theme-upload svg,
|
||||||
|
.theme-upload span {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
.theme-upload:hover,
|
.theme-upload:hover,
|
||||||
.theme-upload:focus-visible {
|
.theme-upload:focus-visible {
|
||||||
border-color: var(--accent);
|
border-color: var(--accent);
|
||||||
@@ -1064,9 +1079,7 @@ button {
|
|||||||
background:
|
background:
|
||||||
radial-gradient(900px 430px at 82% 10%, var(--background-glow-1), transparent 64%),
|
radial-gradient(900px 430px at 82% 10%, var(--background-glow-1), transparent 64%),
|
||||||
radial-gradient(740px 420px at 14% 82%, var(--background-glow-3), transparent 62%),
|
radial-gradient(740px 420px at 14% 82%, var(--background-glow-3), transparent 62%),
|
||||||
var(--workspace-background-pattern-image),
|
|
||||||
var(--background-base);
|
var(--background-base);
|
||||||
background-size: auto, auto, var(--workspace-background-pattern-size), auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-card {
|
.auth-card {
|
||||||
@@ -1329,15 +1342,9 @@ button {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
border: 1px solid var(--crystal-rim);
|
border: 1px solid var(--crystal-rim);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background:
|
background: color-mix(in srgb, var(--surface-solid) 36%, transparent);
|
||||||
var(--corner-sparkle),
|
color: var(--ink);
|
||||||
radial-gradient(circle at 30% 20%, rgba(255, 255, 255, 0.86), transparent 34%),
|
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--rim-light) 28%, transparent);
|
||||||
linear-gradient(135deg, var(--pink), var(--accent));
|
|
||||||
background-size: 54px 54px, auto, auto;
|
|
||||||
background-position: right -5px top -4px, center, center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
color: #ffffff;
|
|
||||||
box-shadow: var(--jelly-inset), 0 10px 26px var(--candy-glow), 0 0 18px var(--moonbeam);
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1481,17 +1488,18 @@ button {
|
|||||||
min-height: 30px;
|
min-height: 30px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.58);
|
border: 1px solid color-mix(in srgb, var(--line-strong) 54%, rgba(255, 255, 255, 0.16));
|
||||||
background: var(--glass-wash), var(--gold-soft);
|
background: color-mix(in srgb, var(--surface-solid) 78%, rgba(255, 255, 255, 0.08));
|
||||||
color: #6f4d00;
|
color: var(--ink);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
box-shadow: inset 0 1px 0 var(--crystal-rim), 0 8px 20px var(--glass-shadow);
|
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--rim-light) 26%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-status-ready {
|
.page-status-ready {
|
||||||
background: var(--success-soft);
|
background: color-mix(in srgb, var(--success-soft) 72%, var(--surface-solid));
|
||||||
color: var(--success);
|
border-color: color-mix(in srgb, var(--success) 42%, var(--line));
|
||||||
|
color: color-mix(in srgb, var(--success) 82%, var(--ink));
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-summary-strip {
|
.page-summary-strip {
|
||||||
@@ -1725,10 +1733,7 @@ button {
|
|||||||
:root[data-theme-palette="magical-girl"] .confirm-panel,
|
:root[data-theme-palette="magical-girl"] .confirm-panel,
|
||||||
:root[data-theme-palette="magical-girl"] .plugin-group,
|
:root[data-theme-palette="magical-girl"] .plugin-group,
|
||||||
:root[data-theme-palette="magical-girl"] .operation-item {
|
:root[data-theme-palette="magical-girl"] .operation-item {
|
||||||
background-image: var(--corner-sparkle), var(--panel-material);
|
background: var(--panel-material);
|
||||||
background-size: 56px 56px, auto;
|
|
||||||
background-position: right 6px top 4px, center;
|
|
||||||
background-repeat: no-repeat, no-repeat;
|
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2521,6 +2526,29 @@ button {
|
|||||||
opacity: var(--frame-accessory-opacity);
|
opacity: var(--frame-accessory-opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:where(
|
||||||
|
.metric-card,
|
||||||
|
.overview-card,
|
||||||
|
.console-panel,
|
||||||
|
.catalog-card,
|
||||||
|
.server-card,
|
||||||
|
.server-detail-header,
|
||||||
|
.resource-table-wrap,
|
||||||
|
.provider-table-wrap,
|
||||||
|
.server-table-wrap,
|
||||||
|
.plugin-group,
|
||||||
|
.operation-item,
|
||||||
|
.confirm-panel,
|
||||||
|
.drawer-panel,
|
||||||
|
.server-toolbar,
|
||||||
|
.state-view
|
||||||
|
)::after {
|
||||||
|
content: none;
|
||||||
|
background: none;
|
||||||
|
box-shadow: none;
|
||||||
|
filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
.resource-table,
|
.resource-table,
|
||||||
.provider-table {
|
.provider-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -3567,12 +3595,14 @@ button {
|
|||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(6px);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.drawer-panel {
|
.drawer-panel {
|
||||||
width: min(440px, 100%);
|
width: min(440px, 100%);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
max-height: 100dvh;
|
||||||
display: grid;
|
display: grid;
|
||||||
align-content: start;
|
align-content: start;
|
||||||
gap: 14px;
|
gap: 14px;
|
||||||
@@ -3582,7 +3612,9 @@ button {
|
|||||||
border-left: 1px solid var(--line);
|
border-left: 1px solid var(--line);
|
||||||
box-shadow: inset 1px 0 0 var(--crystal-rim), -18px 0 42px var(--glass-shadow);
|
box-shadow: inset 1px 0 0 var(--crystal-rim), -18px 0 42px var(--glass-shadow);
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.plugin-detail-panel {
|
.plugin-detail-panel {
|
||||||
@@ -3596,10 +3628,11 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.management-dialog-panel {
|
.management-dialog-panel {
|
||||||
width: min(720px, 100%);
|
width: min(720px, calc(100vw - 32px));
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: min(760px, calc(100dvh - 32px));
|
max-height: min(760px, calc(100dvh - 32px));
|
||||||
overflow: auto;
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-left: 1px solid var(--line);
|
border-left: 1px solid var(--line);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -3607,7 +3640,49 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.management-dialog-wide {
|
.management-dialog-wide {
|
||||||
width: min(920px, 100%);
|
width: min(920px, calc(100vw - 32px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.management-dialog-backdrop {
|
||||||
|
place-items: center;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme-palette] .drawer-panel,
|
||||||
|
:root[data-theme-palette] .management-dialog-panel,
|
||||||
|
:root[data-theme-palette] .confirm-panel {
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-panel-header,
|
||||||
|
.drawer-panel > .panel-header,
|
||||||
|
.confirm-panel > .panel-header {
|
||||||
|
position: sticky;
|
||||||
|
top: -20px;
|
||||||
|
z-index: 4;
|
||||||
|
margin: -20px -20px 12px;
|
||||||
|
padding: 16px 20px 12px;
|
||||||
|
border-bottom: 1px solid color-mix(in srgb, var(--line) 72%, transparent);
|
||||||
|
background: var(--glass-wash), var(--surface-raised);
|
||||||
|
-webkit-backdrop-filter: blur(20px) saturate(1.12);
|
||||||
|
backdrop-filter: blur(20px) saturate(1.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.management-dialog-panel .dialog-form > .confirm-actions,
|
||||||
|
.drawer-panel > .confirm-actions,
|
||||||
|
.confirm-panel > .confirm-actions,
|
||||||
|
.runtime-task-actions {
|
||||||
|
position: sticky;
|
||||||
|
bottom: -20px;
|
||||||
|
z-index: 4;
|
||||||
|
margin: 4px -20px -20px;
|
||||||
|
padding: 12px 20px 16px;
|
||||||
|
border-top: 1px solid color-mix(in srgb, var(--line) 72%, transparent);
|
||||||
|
background: var(--glass-wash), var(--surface-raised);
|
||||||
|
-webkit-backdrop-filter: blur(20px) saturate(1.12);
|
||||||
|
backdrop-filter: blur(20px) saturate(1.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-description {
|
.dialog-description {
|
||||||
@@ -3931,7 +4006,7 @@ button {
|
|||||||
padding: 13px;
|
padding: 13px;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: var(--corner-sparkle), var(--jelly-highlight), var(--glass-wash), var(--surface);
|
background: var(--corner-sparkle), var(--surface);
|
||||||
background-size: 52px 52px, auto, auto, auto;
|
background-size: 52px 52px, auto, auto, auto;
|
||||||
background-position: right 8px top 6px, center, center, center;
|
background-position: right 8px top 6px, center, center, center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
@@ -4225,10 +4300,13 @@ button {
|
|||||||
padding: 16px;
|
padding: 16px;
|
||||||
background: rgba(61, 36, 65, 0.38);
|
background: rgba(61, 36, 65, 0.38);
|
||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(6px);
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.confirm-panel {
|
.confirm-panel {
|
||||||
width: min(460px, 100%);
|
width: min(460px, 100%);
|
||||||
|
max-height: calc(100dvh - 32px);
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 14px;
|
gap: 14px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
@@ -4238,7 +4316,9 @@ button {
|
|||||||
backdrop-filter: blur(24px) saturate(1.28);
|
backdrop-filter: blur(24px) saturate(1.28);
|
||||||
box-shadow: var(--jelly-inset), inset 0 0 0 1px var(--diamond-line), 0 18px 48px var(--glass-shadow), 0 0 34px var(--moonbeam);
|
box-shadow: var(--jelly-inset), inset 0 0 0 1px var(--diamond-line), 0 18px 48px var(--glass-shadow), 0 0 34px var(--moonbeam);
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.confirm-panel h2 {
|
.confirm-panel h2 {
|
||||||
@@ -4916,6 +4996,38 @@ button {
|
|||||||
|
|
||||||
.drawer-panel {
|
.drawer-panel {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
max-height: 100dvh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-backdrop {
|
||||||
|
padding: max(10px, env(safe-area-inset-top)) 10px max(10px, env(safe-area-inset-bottom));
|
||||||
|
place-items: stretch center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-panel,
|
||||||
|
.management-dialog-panel,
|
||||||
|
.management-dialog-wide {
|
||||||
|
width: min(100%, calc(100vw - 20px));
|
||||||
|
max-height: calc(100dvh - 20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.management-dialog-panel .management-form,
|
||||||
|
.management-dialog-panel .provider-form .form-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.management-dialog-panel .dialog-form > .confirm-actions,
|
||||||
|
.drawer-panel > .confirm-actions,
|
||||||
|
.confirm-panel > .confirm-actions,
|
||||||
|
.runtime-task-actions {
|
||||||
|
justify-content: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.management-dialog-panel .dialog-form > .confirm-actions > *,
|
||||||
|
.drawer-panel > .confirm-actions > *,
|
||||||
|
.confirm-panel > .confirm-actions > *,
|
||||||
|
.runtime-task-actions > * {
|
||||||
|
flex: 1 1 140px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user