Refine SEO light theme and environment controls

This commit is contained in:
DCCONSTRUCTIONS
2026-07-10 20:22:42 +03:00
parent f1e28c267a
commit 4c74c22a6e
21 changed files with 437 additions and 155 deletions
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@nodedc/ui-catalog",
"version": "0.5.0",
"version": "0.5.1",
"private": true,
"type": "module",
"scripts": {
@@ -9,8 +9,8 @@
"typecheck": "tsc -b --pretty false"
},
"dependencies": {
"@nodedc/ui-core": "0.5.0",
"@nodedc/ui-react": "0.5.0",
"@nodedc/ui-core": "0.5.1",
"@nodedc/ui-react": "0.5.1",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
+36 -54
View File
@@ -38,12 +38,7 @@ import {
type ShareAccessMember,
} from "@nodedc/ui-react";
type CatalogSection = "foundation" | "controls" | "media" | "windows" | "modals" | "inspector" | "icons";
const engineAccentStyle = {
"--nodedc-accent-rgb": "255 47 146",
"--nodedc-on-accent-rgb": "11 17 23",
} as CSSProperties;
type CatalogSection = "foundation" | "controls" | "media" | "windows" | "modals" | "icons";
const accents: Array<{ label: string; value: RgbTuple; hex: string }> = [
{ label: "NODE.DC", value: [255, 47, 146], hex: "#ff2f92" },
@@ -76,7 +71,7 @@ const sectionDefinitions: Record<CatalogSection, { eyebrow: string; title: strin
controls: {
eyebrow: "02 / CONTROLS",
title: "Контролы",
description: "Кнопки, поля, selection, Engine-настройки и понятные статусы операций.",
description: "Кнопки, поля, выбор, Environment Settings и сворачиваемые секции нового Engine.",
icon: "sliders",
},
media: {
@@ -97,14 +92,8 @@ const sectionDefinitions: Record<CatalogSection, { eyebrow: string; title: strin
description: "Полная карта modal-паттернов Launcher, нового Engine и BIM Viewer.",
icon: "clipboard",
},
inspector: {
eyebrow: "06 / INSPECTOR",
title: "Инспектор",
description: "Точный новый Engine Environment Settings без legacy-инспекторов.",
icon: "settings",
},
icons: {
eyebrow: "07 / ICONS",
eyebrow: "06 / ICONS",
title: "Иконки",
description: "Канонический общий набор по Launcher, SEO, BIM Viewer и новым участкам Engine.",
icon: "grid",
@@ -232,7 +221,7 @@ export function CatalogApp() {
const [fillColor, setFillColor] = useState("#ff6caf");
const [strokeColor, setStrokeColor] = useState("#2b2b36");
const [windowOpen, setWindowOpen] = useState(false);
const [inspectorOpen, setInspectorOpen] = useState(false);
const [sidePanelOpen, setSidePanelOpen] = useState(false);
const [createModalOpen, setCreateModalOpen] = useState(false);
const [confirmOpen, setConfirmOpen] = useState(false);
const [shareAccessOpen, setShareAccessOpen] = useState(false);
@@ -307,7 +296,7 @@ export function CatalogApp() {
const closeGuideline = workspace.closeNavigation;
const inspectorSections = [
const environmentSections = [
{
id: "illumination",
label: "Подсветка",
@@ -384,7 +373,8 @@ export function CatalogApp() {
</button>
))}
</div>
<ColorField label="Свой accent" value={accentHex} onChange={setAccentHex} />
<ColorField label="Акцент приложения" value={accentHex} onChange={setAccentHex} />
<p className="catalog-preview__explanation">Акцент сразу перекрашивает environment-controls, активные действия, заливку range, file action и состояния окон. Геометрия и semantic-status при этом не меняются.</p>
</Preview>
<Preview title="Иерархия стекла" note="default / strong / soft">
<div className="catalog-surface-stack">
@@ -427,19 +417,17 @@ export function CatalogApp() {
<Select label="Статус" value={selectedStatus} options={[...selectOptions]} searchable onChange={setSelectedStatus} />
</FieldFrame>
<FieldFrame label="Engine / split select">
<div style={engineAccentStyle}>
<Select
variant="split"
label="Тип связи"
value={connectionType}
options={[
{ value: "spline", label: "Сплайн" },
{ value: "straight", label: "Прямая" },
{ value: "step", label: "Ступенчатая" },
]}
onChange={setConnectionType}
/>
</div>
<Select
variant="split"
label="Тип связи"
value={connectionType}
options={[
{ value: "spline", label: "Сплайн" },
{ value: "straight", label: "Прямая" },
{ value: "step", label: "Ступенчатая" },
]}
onChange={setConnectionType}
/>
</FieldFrame>
<Dropdown
trigger={({ open, toggle, setTriggerRef, surfaceId }) => (
@@ -456,12 +444,13 @@ export function CatalogApp() {
</Dropdown>
</div>
</Preview>
<Preview title="Environment controls" note="точная геометрия Engine">
<div className="catalog-engine-control-stack" style={engineAccentStyle}>
<ControlRow label="Цвет"><ColorField value={lightColor} onChange={setLightColor} /></ControlRow>
<RangeControl label="Яркость" value={brightness} min={0} max={100} formatValue={(value) => `${value}%`} onChange={setBrightness} />
<Checker checked={checker} label="Использовать цвет портов" onChange={setChecker} />
<ControlRow label="Применить ко всем"><Button variant="accent" shape="pill" width="full">Применить</Button></ControlRow>
<Preview title="Environment controls" note="Engine / select + accordion" className="catalog-preview--wide">
<div className="catalog-environment-demo">
<GlassSurface tone="strong" radius="panel" className="catalog-environment-card">
<div className="catalog-environment-title"><strong>Настройки окружения</strong><span>ENGINE / новый канон</span></div>
<Inspector sections={environmentSections} defaultOpen={["illumination", "connections"]} />
</GlassSurface>
<p className="catalog-preview__explanation">Здесь собраны все контролы, которые нужны новым приложениям: color palette, range, checker, split-select, accent action и раскрывающиеся sections. Отдельной вкладки Inspector в каталоге больше нет.</p>
</div>
</Preview>
<Preview title="Статусы операций" note="не цвет приложения" className="catalog-preview--wide">
@@ -517,7 +506,7 @@ export function CatalogApp() {
<p className="catalog-preview__explanation">Обычное окно блокирует фон и удерживает фокус. Правый инспектор не затемняет, не блокирует stage и не превращается в modal.</p>
<div className="catalog-inline catalog-inline--wrap">
<Button variant="accent" shape="pill" icon={<Icon name="apps" />} onClick={() => setWindowOpen(true)}>Открыть окно</Button>
<Button shape="pill" icon={<Icon name="panel" />} onClick={() => setInspectorOpen(true)}>Открыть инспектор</Button>
<Button shape="pill" icon={<Icon name="panel" />} onClick={() => setSidePanelOpen(true)}>Открыть боковую панель</Button>
</div>
</Preview>
<Preview title="Оконные действия" note="круг `46 px`">
@@ -563,15 +552,6 @@ export function CatalogApp() {
</Preview>
</div>
);
case "inspector":
return (
<div className="catalog-inspector-stage">
<GlassSurface tone="strong" radius="panel" className="catalog-inspector-card" style={engineAccentStyle}>
<div className="catalog-inspector-title"><strong>Настройки окружения</strong><span>ENGINE / новый канон</span></div>
<Inspector sections={inspectorSections} defaultOpen={["illumination", "connections", "ports"]} />
</GlassSurface>
</div>
);
case "icons":
return (
<div className="catalog-icon-catalog">
@@ -582,7 +562,7 @@ export function CatalogApp() {
<IconButton label="Развернуть"><Icon name="expand" size={20} /></IconButton>
<IconButton label="Закрыть"><Icon name="close" size={18} /></IconButton>
</div>
<p className="catalog-preview__explanation">Иконка наследует `currentColor`; фон, размер кнопки и active-state задаёт компонент поверхности, а не SVG.</p>
<p className="catalog-preview__explanation">Иконка наследует `currentColor`; фон, размер кнопки и active-state задаёт компонент поверхности, а не SVG. Glyph оптически уменьшен на 18% без изменения hit target.</p>
</Preview>
{iconGroups.map((group) => (
<section className="catalog-icon-group" key={group.title}>
@@ -668,7 +648,7 @@ export function CatalogApp() {
footer={
<>
<span className="nodedc-admin-panel__nav-icon" aria-hidden="true"><Icon name="shield" /></span>
<span>Design System 0.5</span>
<span>Design System 0.5.1</span>
</>
}
/>
@@ -708,14 +688,16 @@ export function CatalogApp() {
</Window>
<Window
open={inspectorOpen}
title="Настройки окружения"
subtitle="ENGINE / новый канон"
open={sidePanelOpen}
title="Боковая панель"
subtitle="modeless / shell contract"
placement="end"
style={engineAccentStyle}
onClose={() => setInspectorOpen(false)}
onClose={() => setSidePanelOpen(false)}
>
<Inspector sections={inspectorSections} defaultOpen={["illumination", "connections", "ports"]} />
<div className="catalog-form">
<TextField label="Название панели" value="Параметры рабочей области" readOnly />
<p className="catalog-preview__explanation">Боковая панель демонстрирует только layer-механику: она modeless, не затемняет stage и не забирает фокус. Environment controls живут в разделе «Контролы».</p>
</div>
</Window>
<Window
+22 -17
View File
@@ -14,7 +14,7 @@ body,
}
body {
background: #050506;
background: var(--nodedc-canvas);
color: var(--nodedc-text-primary);
}
@@ -38,8 +38,8 @@ textarea {
isolation: isolate;
overflow: hidden;
border-radius: var(--nodedc-radius-card);
background: #0b0b0d url("/launcher-stage-poster.png") center / cover no-repeat;
box-shadow: 0 44px 150px rgba(0, 0, 0, 0.62);
background: var(--nodedc-canvas-soft) url("/launcher-stage-poster.png") center / cover no-repeat;
box-shadow: 0 44px 150px color-mix(in srgb, var(--nodedc-canvas) 70%, transparent);
}
.catalog-launcher-stage__media,
@@ -229,7 +229,7 @@ textarea {
grid-template-columns: minmax(12rem, 1.7fr) minmax(7rem, 0.7fr) minmax(6rem, 0.6fr) minmax(9rem, 0.9fr) 6rem;
align-items: center;
gap: 0.75rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
border-bottom: 1px solid var(--nodedc-glass-outline);
color: var(--nodedc-text-secondary);
padding: 0.62rem 0.8rem;
font-size: var(--nodedc-font-size-sm);
@@ -281,7 +281,7 @@ textarea {
grid-template-rows: 3.2rem 1fr;
gap: 0.6rem;
border-radius: 1.1rem;
background: rgba(0, 0, 0, 0.22);
background: color-mix(in srgb, var(--nodedc-canvas-soft) 76%, transparent);
padding: 0.6rem;
}
@@ -307,30 +307,31 @@ textarea {
background: color-mix(in srgb, var(--nodedc-glass-control-hover) 70%, transparent) !important;
}
.catalog-inspector-stage {
display: flex;
min-height: 43rem;
justify-content: flex-end;
align-items: flex-start;
.catalog-environment-demo {
display: grid;
min-height: 30rem;
grid-template-columns: minmax(0, 24.375rem) minmax(14rem, 1fr);
align-items: start;
gap: clamp(1rem, 4vw, 4rem);
border-radius: var(--nodedc-radius-card);
background:
radial-gradient(circle at 18% 24%, rgba(var(--nodedc-accent-rgb), 0.13), transparent 22rem),
color-mix(in srgb, var(--nodedc-canvas-soft) 86%, transparent);
padding: 2rem;
padding: clamp(1rem, 3vw, 2rem);
}
.catalog-inspector-card {
.catalog-environment-card {
width: min(24.375rem, 100%);
padding: 1.125rem 0.75rem;
}
.catalog-inspector-title {
.catalog-environment-title {
display: grid;
gap: 0.3rem;
padding: 0 0.875rem 0.875rem;
}
.catalog-inspector-title span {
.catalog-environment-title span {
color: var(--nodedc-text-muted);
font-size: 0.7rem;
}
@@ -393,6 +394,10 @@ textarea {
color: var(--nodedc-text-primary);
}
.catalog-icon-tile__surface > svg {
transform: scale(var(--nodedc-icon-glyph-scale));
}
.catalog-icon-tile > span:last-child {
display: grid;
min-width: 0;
@@ -499,9 +504,9 @@ textarea {
grid-column: 1 / -1;
}
.catalog-inspector-stage {
min-height: 40rem;
justify-content: center;
.catalog-environment-demo {
min-height: auto;
grid-template-columns: 1fr;
padding: 0.75rem;
}