feat(ui): support leading resource status indicators

This commit is contained in:
Codex
2026-09-06 01:17:37 +03:00
parent 3adeb33b1b
commit 999864e5b0
5 changed files with 17 additions and 3 deletions
+1
View File
@@ -1421,6 +1421,7 @@ export function CatalogApp() {
<Preview title="Строки ресурсов" note="Mission Core / общий список">
<ResourceList aria-label="Пример списка ресурсов">
<li><ResourceRow icon={<Icon name="file" />} title="Сохранённый результат" metadata="Сегодня · доступен для просмотра" actions={<IconButton label="Просмотреть пример" onClick={() => setProjectName("Сохранённый результат")}><Icon name="eye" /></IconButton>} /></li>
<li><ResourceRow icon={<Icon name="camera" />} title="Подключённая камера" description="Индикатор перед названием" statusPlacement="leading" status={<StatusBadge variant="indicator" tone="success" aria-label="Подключено" title="Подключено" />} actions={<IconButton label="Просмотреть камеру" onClick={() => setProjectName("Подключённая камера")}><Icon name="eye" /></IconButton>} /></li>
<li><ResourceRow icon={<Icon name="camera" />} title="Подготовка камеры" metadata="Проверка потоков" progress={{label:"Подготовка камеры",value:0.8}} aria-busy="true" actions={<IconButton label="Просмотр недоступен" disabled><Icon name="eye" /></IconButton>} /></li>
</ResourceList>
<SettingsCard title="Устройства не обнаружены" description="Подключите устройство, чтобы оно появилось в списке." />
+7
View File
@@ -25,3 +25,10 @@ disabled и keyboard/focus остаются у общего контрола. С
Для длительных операций с линейной индикацией используйте `progress`
(ProgressBar: label, value, valueText). Он заменяет status, оставляет действия
справа и занимает промежуток после названия.
`statusPlacement="leading"` размещает компактный индикатор после иконки и
перед всем текстовым блоком, с выравниванием по вертикальному центру строки.
По умолчанию остаётся `trailing` перед действиями. Статус не дублируется;
во время `progress` он скрыт в любом положении. Для одной лампы используйте
StatusBadge variant="indicator" с aria-label и title. Это согласованное
06.09.2026 расположение индикатора устройств Mission Core / Node.
+2
View File
@@ -3790,9 +3790,11 @@ textarea.nodedc-field__control {
.nodedc-resource-row__copy > small { color: var(--nodedc-text-muted); font-size: var(--nodedc-font-size-xs); }
.nodedc-resource-row__actions { display: flex; align-items: center; gap: .85rem; }
.nodedc-resource-row__status { font-size: var(--nodedc-font-size-sm); }
.nodedc-resource-row--leading-status > .nodedc-resource-row__status { display: flex; align-items: center; flex: 0 0 auto; }
@media (max-width: 540px) {
.nodedc-resource-row { flex-wrap: wrap; }
.nodedc-resource-row__copy { flex-basis: calc(100% - 3rem); }
.nodedc-resource-row--leading-status > .nodedc-resource-row__copy { flex: 1 1 0; }
.nodedc-resource-row__actions { margin-left: auto; }
}
+6 -3
View File
@@ -8,22 +8,25 @@ export interface ResourceRowProps extends Omit<HTMLAttributes<HTMLDivElement>, "
description?: ReactNode;
metadata?: ReactNode;
status?: ReactNode;
statusPlacement?: "leading" | "trailing";
actions?: ReactNode;
progress?: Pick<ProgressBarProps, "label" | "value" | "valueText">;
}
/** Compact resource presentation extracted from Mission Core AI Inference.
* Actions stay canonical controls; the row itself is not a nested button. */
export function ResourceRow({ title, icon, description, metadata, status, actions, progress, className, ...props }: ResourceRowProps) {
return <div className={cn("nodedc-resource-row", progress && "nodedc-resource-row--progress", className)} {...props}>
export function ResourceRow({ title, icon, description, metadata, status, statusPlacement = "trailing", actions, progress, className, ...props }: ResourceRowProps) {
const leadingStatus = !progress && !!status && statusPlacement === "leading";
return <div className={cn("nodedc-resource-row", progress && "nodedc-resource-row--progress", leadingStatus && "nodedc-resource-row--leading-status", className)} {...props}>
{icon ? <span className="nodedc-resource-row__icon" aria-hidden="true">{icon}</span> : null}
{leadingStatus ? <div className="nodedc-resource-row__status">{status}</div> : null}
<div className="nodedc-resource-row__copy">
<strong>{title}</strong>
{description ? <span>{description}</span> : null}
{metadata ? <small>{metadata}</small> : null}
</div>
{progress ? <ProgressBar {...progress} /> : null}
{!progress && status ? <div className="nodedc-resource-row__status">{status}</div> : null}
{!progress && status && statusPlacement === "trailing" ? <div className="nodedc-resource-row__status">{status}</div> : null}
{actions ? <div className="nodedc-resource-row__actions">{actions}</div> : null}
</div>;
}
+1
View File
@@ -39,6 +39,7 @@
"behavior": [
"wrapping title",
"optional metadata and status",
"optional leading status between icon and copy, vertically centered",
"canonical action controls",
"responsive action placement"
],