feat(ui): stabilize laboratory viewer primitives

This commit is contained in:
Codex
2026-08-24 22:31:35 +03:00
parent c7e136cc14
commit 6e7255ecdb
17 changed files with 590 additions and 30 deletions
+52 -2
View File
@@ -33,6 +33,7 @@ import {
Select,
ShareAccessModal,
ShareLinkModal,
SplitPane,
SortableItem,
SortableScope,
SettingsCard,
@@ -219,7 +220,7 @@ const iconGroups: Array<{ title: string; note: string; icons: IconName[] }> = [
{
title: "Контент",
note: "SEO / BIM / Engine",
icons: ["image", "video", "file", "folder", "clipboard", "settings"],
icons: ["camera", "plan", "play", "stop", "image", "video", "file", "folder", "clipboard", "settings"],
},
];
@@ -228,6 +229,7 @@ const iconLabels: Record<IconName, string> = {
alert: "Предупреждение",
apps: "Приложения",
building: "Компания",
camera: "Камера",
check: "Готово",
"chevron-down": "Раскрыть",
"chevron-left": "Назад",
@@ -256,6 +258,8 @@ const iconLabels: Record<IconName, string> = {
minimize: "Свернуть",
network: "Связи",
panel: "Панель",
plan: "План",
play: "Воспроизвести",
target: "Таргеты",
plus: "Добавить",
profile: "Профиль",
@@ -265,6 +269,7 @@ const iconLabels: Record<IconName, string> = {
settings: "Настройки",
shield: "Доступ",
sliders: "Параметры",
stop: "Остановить",
trash: "Удалить",
upload: "Загрузить",
users: "Участники",
@@ -362,6 +367,7 @@ export function CatalogApp() {
const [workspaceWindowDemoOpen, setWorkspaceWindowDemoOpen] = useState(true);
const [workspaceWindowDemoMaximized, setWorkspaceWindowDemoMaximized] = useState(false);
const [workspaceWindowDemoRect, setWorkspaceWindowDemoRect] = useState<WorkspaceWindowRect>({ x: 24, y: 24, width: 340, height: 230 });
const [splitPaneDemoSize, setSplitPaneDemoSize] = useState(50);
const [sidePanelDemoOpen, setSidePanelDemoOpen] = useState(true);
const [createModalOpen, setCreateModalOpen] = useState(false);
const [confirmOpen, setConfirmOpen] = useState(false);
@@ -1327,7 +1333,7 @@ export function CatalogApp() {
case "controls":
return (
<div className="catalog-grid">
<Preview title="Selection" note="integrated / split">
<Preview title="Selection" note="integrated / split / inline">
<div className="catalog-form">
<FieldFrame label="Hub / integrated select">
<Select label="Статус" value={selectedStatus} options={[...selectOptions]} searchable onChange={setSelectedStatus} />
@@ -1345,6 +1351,19 @@ export function CatalogApp() {
onChange={setConnectionType}
/>
</FieldFrame>
<FieldFrame label="Toolbar / inline select">
<Select
variant="inline"
label="Скорость воспроизведения"
value="1"
options={[
{ value: "0.5", label: "0,5×" },
{ value: "1", label: "1×" },
{ value: "2", label: "2×" },
]}
onChange={() => undefined}
/>
</FieldFrame>
<Dropdown
trigger={({ open, toggle, setTriggerRef, surfaceId }) => (
<Button ref={setTriggerRef} aria-expanded={open} aria-controls={surfaceId} icon={<Icon name="chevron-down" />} onClick={toggle}>Действия</Button>
@@ -1397,6 +1416,21 @@ export function CatalogApp() {
<IconButton label="Закрыть"><Icon name="close" /></IconButton>
</div>
</Preview>
<Preview title="Вертикальная рейка" note="glass pill / круг `46 px`" className="catalog-preview--compact">
<GlassSurface
className="catalog-icon-rail-demo"
tone="strong"
radius="pill"
padding="sm"
materialRim={false}
role="toolbar"
aria-label="Режимы просмотра"
>
<IconButton label="Камера" aria-pressed="true"><Icon name="camera" /></IconButton>
<IconButton label="3D"><span aria-hidden="true">3D</span></IconButton>
<IconButton label="План"><Icon name="plan" /></IconButton>
</GlassSurface>
</Preview>
<Preview title="Workspace window" note="inline / bounded / controlled" className="catalog-preview--wide catalog-workspace-window-preview">
<div ref={workspaceWindowDemoRef} className="catalog-workspace-window-demo">
{workspaceWindowDemoOpen ? (
@@ -1435,6 +1469,20 @@ export function CatalogApp() {
</div>
<p className="catalog-preview__explanation">Rectangle, maximize, close и stacking остаются состоянием приложения; дизайн-система владеет одинаковой bounded-геометрией и доступным управлением.</p>
</Preview>
<Preview title="Split pane" note="pointer / keyboard / controlled" className="catalog-preview--wide catalog-split-pane-preview">
<div className="catalog-split-pane-demo">
<SplitPane
primarySize={splitPaneDemoSize}
onPrimarySizeChange={setSplitPaneDemoSize}
minPrimarySize={25}
minSecondarySize={25}
separatorLabel="Изменить ширину синхронных представлений"
primary={<div className="catalog-split-pane-demo__panel"><Icon name="video" /><strong>Видео</strong></div>}
secondary={<div className="catalog-split-pane-demo__panel"><Icon name="grid" /><strong>Пространственная сцена</strong></div>}
/>
</div>
<p className="catalog-preview__explanation">Граница изменяет контролируемую долю панелей; клавиши и pointer используют одни ограничения, а resize контейнера не сбрасывает выбранное соотношение.</p>
</Preview>
<Preview title="Application side panel" note="end / push / controlled" className="catalog-preview--wide catalog-side-panel-preview">
<div className="catalog-side-panel-demo">
{sidePanelDemoOpen ? (
@@ -1638,6 +1686,8 @@ export function CatalogApp() {
<div className="catalog-icon-catalog">
<Preview title="Размеры и поверхности" note="glyph 16 px" className="catalog-preview--wide">
<div className="catalog-window-actions-demo">
<IconButton label="Камера включена" aria-pressed="true"><Icon name="camera" /></IconButton>
<IconButton label="План"><Icon name="plan" /></IconButton>
<IconButton label="Добавить"><Icon name="plus" /></IconButton>
<IconButton label="Обновить"><Icon name="refresh" /></IconButton>
<IconButton label="Развернуть"><Icon name="expand" /></IconButton>