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.faviconFileName) setFaviconFileName(media.faviconFileName);
if (media.faviconAssets) setFaviconAssets(media.faviconAssets); 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; const toolbar = stored.toolbar;
if (toolbar) { if (toolbar) {
if (toolbar.placement === "left" || toolbar.placement === "right" || toolbar.placement === "bottom") setToolbarPlacement(toolbar.placement); 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."> <SettingsCard eyebrow="ENGINE / GLASS V4" title="Параметры материала" description="Общий token-контракт ui-core; изменения сразу видны на preview, модалках и Inspector.">
<div className="catalog-glass-controls"> <div className="catalog-glass-controls">
<ControlRow label="Цвет тонировки"><ColorField value={glassMaterial.tintHex} onChange={(tintHex) => setGlassMaterial((current) => ({ ...current, tintHex }))} /></ControlRow> <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="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="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 }))} /> <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. 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 ## Button и IconButton

View File

@ -58,7 +58,7 @@
--nodedc-primary-action-color: rgb(var(--nodedc-on-accent-rgb)); --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-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-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-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-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); --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-color: rgba(247, 248, 244, 0.96);
--nodedc-primary-action-shadow: none; --nodedc-primary-action-shadow: none;
--nodedc-modal-glass-tint-rgb: 255 255 255; --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-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-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); --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-control: 24px;
--nodedc-blur-panel: 44px; --nodedc-blur-panel: 44px;
--nodedc-blur-modal: 64px; --nodedc-blur-modal: 44px;
--nodedc-modal-glass-saturation: 1.38; --nodedc-modal-glass-saturation: 1.12;
--nodedc-modal-glass-brightness: 1.06; --nodedc-modal-glass-brightness: 1.05;
--nodedc-modal-glass-outline-opacity: 0.11; --nodedc-modal-glass-outline-opacity: 0.11;
--nodedc-modal-glass-outline-soft-opacity: 0.0495; --nodedc-modal-glass-outline-soft-opacity: 0.0495;
--nodedc-modal-glass-shadow-opacity: 0.64; --nodedc-modal-glass-shadow-opacity: 0.64;

View File

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

View File

@ -1911,11 +1911,6 @@ textarea.nodedc-field__control {
overflow: hidden; overflow: hidden;
border: 0; border: 0;
border-radius: var(--nodedc-radius-modal); 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); 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)); width: min(var(--nodedc-inspector-width), calc(100vw - 3rem));
max-height: calc(100vh - 7.25rem); max-height: calc(100vh - 7.25rem);
border-radius: var(--nodedc-radius-panel); 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; pointer-events: auto;
} }
.nodedc-window::before,
.nodedc-glass-material::before { .nodedc-glass-material::before {
position: absolute; position: absolute;
z-index: -1; 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 className="nodedc-overlay nodedc-ui-root" data-placement={placement} onPointerDown={handleBackdropPointerDown}>
<div <div
ref={dialogRef} 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-size={size === "md" ? undefined : size}
data-placement={placement} data-placement={placement}
data-draggable={draggable ? "true" : undefined} data-draggable={draggable ? "true" : undefined}