Unify modal and inspector glass material

This commit is contained in:
DCCONSTRUCTIONS 2026-07-11 13:07:47 +03:00
parent d873427fe2
commit d3e2859ca1
7 changed files with 24 additions and 23 deletions

View File

@ -419,7 +419,15 @@ export function CatalogApp() {
if (media.faviconFileName) setFaviconFileName(media.faviconFileName);
if (media.faviconAssets) setFaviconAssets(media.faviconAssets);
}
if (stored.glass) setGlassMaterial({ ...defaultGlassMaterial, ...stored.glass });
if (stored.glass) {
const legacyDefaultOpacity = stored.glass.version !== 4 && stored.glass.tintOpacity === 54;
setGlassMaterial({
...defaultGlassMaterial,
...stored.glass,
version: 4,
tintOpacity: legacyDefaultOpacity ? defaultGlassMaterial.tintOpacity : stored.glass.tintOpacity,
});
}
const toolbar = stored.toolbar;
if (toolbar) {
if (toolbar.placement === "left" || toolbar.placement === "right" || toolbar.placement === "bottom") setToolbarPlacement(toolbar.placement);
@ -904,7 +912,7 @@ export function CatalogApp() {
<SettingsCard eyebrow="ENGINE / GLASS V4" title="Параметры материала" description="Общий token-контракт ui-core; изменения сразу видны на preview, модалках и Inspector.">
<div className="catalog-glass-controls">
<ControlRow label="Цвет тонировки"><ColorField value={glassMaterial.tintHex} onChange={(tintHex) => setGlassMaterial((current) => ({ ...current, tintHex }))} /></ControlRow>
<RangeControl label=розрачность" value={glassMaterial.tintOpacity} min={0} max={96} formatValue={(value) => `${value}%`} onChange={(tintOpacity) => setGlassMaterial((current) => ({ ...current, tintOpacity }))} />
<RangeControl label=лотность тонировки" value={glassMaterial.tintOpacity} min={0} max={100} formatValue={(value) => `${value}%`} onChange={(tintOpacity) => setGlassMaterial((current) => ({ ...current, version: 4, tintOpacity }))} />
<RangeControl label="Blur" value={glassMaterial.blur} min={0} max={120} formatValue={(value) => `${value}px`} onChange={(blur) => setGlassMaterial((current) => ({ ...current, blur }))} />
<RangeControl label="Saturation" value={glassMaterial.saturation} min={70} max={220} formatValue={(value) => `${value}%`} onChange={(saturation) => setGlassMaterial((current) => ({ ...current, saturation }))} />
<RangeControl label="Brightness" value={glassMaterial.brightness} min={70} max={160} formatValue={(value) => `${value}%`} onChange={(brightness) => setGlassMaterial((current) => ({ ...current, brightness }))} />

View File

@ -12,7 +12,7 @@
Material rim допустим только как часть floating glass. Жёсткая цветная рамка, случайный browser outline или debug border не являются rim.
`GlassMaterialSurface` — отдельный переносимый контракт Engine Glass V4. Он централизует tint/opacity, blur, saturation, brightness, gradient rim и shadow. Его используют только modal `Window` и modeless draggable Inspector; обычные Launcher/SEO панели остаются непрозрачными. Настройки применяются через `applyGlassMaterial`, поэтому consumer не пересобирает CSS материала вручную.
`GlassMaterialSurface` — отдельный переносимый контракт Engine Glass V4. Он централизует tint/opacity, blur, saturation, brightness, gradient rim и shadow. Его используют только modal `Window` и modeless draggable Inspector; обычные Launcher/SEO панели остаются непрозрачными. Сам `Window` всегда получает класс `nodedc-glass-material` и `data-material="glass-v4"`, поэтому sharing, confirmation и остальные modal-паттерны физически используют тот же surface, что Inspector и лабораторный preview. Настройки применяются через `applyGlassMaterial`, поэтому consumer не пересобирает CSS материала вручную.
## Button и IconButton

View File

@ -58,7 +58,7 @@
--nodedc-primary-action-color: rgb(var(--nodedc-on-accent-rgb));
--nodedc-primary-action-shadow: 0 12px 28px rgb(var(--nodedc-accent-rgb) / 0.2);
--nodedc-modal-glass-tint-rgb: 11 11 14;
--nodedc-modal-glass-tint-opacity: 0.54;
--nodedc-modal-glass-tint-opacity: 0.94;
--nodedc-modal-surface: linear-gradient(180deg, rgba(255, 255, 255, 0.068), rgba(255, 255, 255, 0.02)), rgb(var(--nodedc-modal-glass-tint-rgb) / var(--nodedc-modal-glass-tint-opacity));
--nodedc-modal-shadow: 0 34px 120px rgb(0 0 0 / var(--nodedc-modal-glass-shadow-opacity)), 0 10px 32px rgba(0, 0, 0, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.045);
--nodedc-floating-surface: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.012)), rgba(10, 10, 13, 0.94);
@ -123,7 +123,7 @@
--nodedc-primary-action-color: rgba(247, 248, 244, 0.96);
--nodedc-primary-action-shadow: none;
--nodedc-modal-glass-tint-rgb: 255 255 255;
--nodedc-modal-glass-tint-opacity: 0.72;
--nodedc-modal-glass-tint-opacity: 0.94;
--nodedc-modal-surface: linear-gradient(180deg, rgba(255, 255, 255, 0.88), rgba(255, 255, 255, 0.36)), rgb(var(--nodedc-modal-glass-tint-rgb) / var(--nodedc-modal-glass-tint-opacity));
--nodedc-modal-shadow: 0 24px 72px rgb(0 0 0 / var(--nodedc-modal-glass-shadow-light-opacity)), inset 0 1px 0 rgba(255, 255, 255, 0.8);
--nodedc-floating-surface: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(255, 255, 255, 0.72)), rgba(255, 255, 255, 0.94);

View File

@ -38,9 +38,9 @@
--nodedc-blur-control: 24px;
--nodedc-blur-panel: 44px;
--nodedc-blur-modal: 64px;
--nodedc-modal-glass-saturation: 1.38;
--nodedc-modal-glass-brightness: 1.06;
--nodedc-blur-modal: 44px;
--nodedc-modal-glass-saturation: 1.12;
--nodedc-modal-glass-brightness: 1.05;
--nodedc-modal-glass-outline-opacity: 0.11;
--nodedc-modal-glass-outline-soft-opacity: 0.0495;
--nodedc-modal-glass-shadow-opacity: 0.64;

View File

@ -1,4 +1,5 @@
export interface GlassMaterialSettings {
version?: 4;
tintHex: string;
tintOpacity: number;
blur: number;
@ -9,11 +10,12 @@ export interface GlassMaterialSettings {
}
export const defaultGlassMaterial: GlassMaterialSettings = {
version: 4,
tintHex: "#0b0b0e",
tintOpacity: 54,
blur: 64,
saturation: 138,
brightness: 106,
tintOpacity: 94,
blur: 44,
saturation: 112,
brightness: 105,
outlineOpacity: 11,
shadowOpacity: 64,
};

View File

@ -1911,11 +1911,6 @@ textarea.nodedc-field__control {
overflow: hidden;
border: 0;
border-radius: var(--nodedc-radius-modal);
background: var(--nodedc-modal-surface);
color: var(--nodedc-text-primary);
box-shadow: var(--nodedc-modal-shadow);
backdrop-filter: blur(var(--nodedc-blur-modal)) saturate(var(--nodedc-modal-glass-saturation)) brightness(var(--nodedc-modal-glass-brightness));
-webkit-backdrop-filter: blur(var(--nodedc-blur-modal)) saturate(var(--nodedc-modal-glass-saturation)) brightness(var(--nodedc-modal-glass-brightness));
animation: nodedc-window-in var(--nodedc-duration-normal) var(--nodedc-ease-standard);
}
@ -1931,14 +1926,9 @@ textarea.nodedc-field__control {
width: min(var(--nodedc-inspector-width), calc(100vw - 3rem));
max-height: calc(100vh - 7.25rem);
border-radius: var(--nodedc-radius-panel);
background: var(--nodedc-modal-surface);
box-shadow: var(--nodedc-modal-shadow);
backdrop-filter: blur(var(--nodedc-blur-modal)) saturate(var(--nodedc-modal-glass-saturation)) brightness(var(--nodedc-modal-glass-brightness));
-webkit-backdrop-filter: blur(var(--nodedc-blur-modal)) saturate(var(--nodedc-modal-glass-saturation)) brightness(var(--nodedc-modal-glass-brightness));
pointer-events: auto;
}
.nodedc-window::before,
.nodedc-glass-material::before {
position: absolute;
z-index: -1;

View File

@ -151,7 +151,8 @@ export function Window({
<div className="nodedc-overlay nodedc-ui-root" data-placement={placement} onPointerDown={handleBackdropPointerDown}>
<div
ref={dialogRef}
className={cn("nodedc-window nodedc-material-rim", className)}
className={cn("nodedc-window nodedc-glass-material nodedc-material-rim", className)}
data-material="glass-v4"
data-size={size === "md" ? undefined : size}
data-placement={placement}
data-draggable={draggable ? "true" : undefined}