Skip to content

Commit 3bfb8a0

Browse files
committed
feat(web): extend empty state workspace shells
1 parent d0c5246 commit 3bfb8a0

3 files changed

Lines changed: 54 additions & 18 deletions

File tree

packages/web/src/components/ui/MIGRATION.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
| Tooltip | 🟡 partial | native `title` hover labels | branch picker, code-editor actions, file-tree actions, git-diff close, fullscreen, topbar actions, connection-status, git status-strip branch, session/supervisor actions, selected settings actions, and workspace/terminal file-toolbar actions covered; truncation/path and other non-action long-text titles remain deferred | 2026-05-09 |
2020
| ProgressBar | 🟢 complete | `--progress-height` patterns | 0 | 2026-05-09 |
2121
| Notice | 🟢 complete | `.settings-page__notice*` | 0 | 2026-05-09 |
22-
| EmptyState | 🟡 partial | feature-specific empty state blocks | centered shared shells plus workspace desktop/mobile no-session or no-workspace empties covered; richer workspace resolving/card shells remain | 2026-05-09 |
22+
| EmptyState | 🟡 partial | feature-specific empty state blocks | centered shared shells plus workspace desktop/mobile no-session or no-workspace empties and workspace route resolving/load-failed shells covered; list-style and other feature-owned empty blocks remain | 2026-05-09 |
2323
| Tabs | 🟢 complete | `.panel-tabs`, `.panel-tab`, `.worktree-tabs`, `.worktree-tab`, feature-local workspace/terminal tab shells | 0 | 2026-05-09 |
2424
| SegmentedControl | 🟢 complete | `.settings-provider-tabs`, `.settings-provider-tab`, `.settings-provider-subnav`, `.settings-provider-subnav-button`, `.shortcuts-category-tabs`, `.shortcuts-category-tab` | 0 | 2026-05-09 |
2525
| Sheet | 🟢 complete | `.mobile-sheet*` | 0 | 2026-05-09 |
@@ -71,6 +71,6 @@
7171

7272
`SegmentedControl` now completes the bounded selector-family inventory: provider chooser tabs, provider sub-navigation, and shortcuts category selectors all use the shared primitive from the public UI barrel while preserving the existing legacy compatibility classes for zero-regression styling.
7373

74-
`EmptyState` now covers a broader bounded shell slice: config editor, terminal panel, git diff/code editor/image preview empties, the desktop workspace no-workspace shell, and the mobile agent empty shell all use the shared primitive from the public UI barrel. Richer workspace resolving/card shells and other feature-owned empty-state chromes remain intentionally deferred.
74+
`EmptyState` now covers a broader bounded shell slice: config editor, terminal panel, git diff/code editor/image preview empties, the desktop workspace no-workspace shell, the mobile agent empty shell, and the workspace route resolving/load-failed shells all use the shared primitive from the public UI barrel while preserving feature-owned card chrome such as `workspace-resolving-shell` and `workspace-resolving-card`. List-style and other feature-owned empty-state chromes remain intentionally deferred.
7575

7676
`Tabs` now complete the bounded tab-navigation inventory: workspace desktop/mobile/worktree surfaces, the topbar workspace switcher, and the desktop terminal session tabs all use the shared primitive from the public UI barrel while preserving legacy compatibility classes and feature-owned closable-tab shells where secondary close actions must remain siblings of the tab trigger for valid DOM and keyboard semantics.
Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,59 @@
1+
import type { ReactNode } from "react";
2+
import { EmptyState } from "../../../../components/ui";
13
import { useTranslation } from "../../../../lib/i18n";
24

35
interface WorkspaceEmptyStateProps {
4-
title?: string;
5-
description?: string;
6+
title?: ReactNode;
7+
description?: ReactNode;
68
}
79

8-
export function WorkspaceEmptyState({ title, description }: WorkspaceEmptyStateProps) {
10+
interface WorkspaceResolvingStateShellProps {
11+
title: ReactNode;
12+
description: ReactNode;
13+
testId?: string;
14+
}
15+
16+
const workspaceResolvingEmptyStateStyle = {
17+
minHeight: "auto",
18+
padding: 0,
19+
gap: 0,
20+
alignItems: "stretch",
21+
justifyContent: "flex-start",
22+
textAlign: "left",
23+
};
24+
25+
export function WorkspaceResolvingStateShell({
26+
title,
27+
description,
28+
testId,
29+
}: WorkspaceResolvingStateShellProps) {
930
const t = useTranslation();
1031

1132
return (
12-
<div className="workspace-resolving-shell">
33+
<div className="workspace-resolving-shell" data-testid={testId}>
1334
<div className="workspace-resolving-card">
14-
<div className="workspace-resolving-kicker">{t("workspace.title")}</div>
15-
<div className="workspace-resolving-title">{title ?? t("workspace.load_failed_title")}</div>
16-
<div className="workspace-resolving-desc">
17-
{description ?? t("workspace.load_failed_description")}
18-
</div>
35+
<EmptyState
36+
style={workspaceResolvingEmptyStateStyle}
37+
title={
38+
<div>
39+
<div className="workspace-resolving-kicker">{t("workspace.title")}</div>
40+
<div className="workspace-resolving-title">{title}</div>
41+
</div>
42+
}
43+
description={<div className="workspace-resolving-desc">{description}</div>}
44+
/>
1945
</div>
2046
</div>
2147
);
2248
}
49+
50+
export function WorkspaceEmptyState({ title, description }: WorkspaceEmptyStateProps) {
51+
const t = useTranslation();
52+
53+
return (
54+
<WorkspaceResolvingStateShell
55+
title={title ?? t("workspace.load_failed_title")}
56+
description={description ?? t("workspace.load_failed_description")}
57+
/>
58+
);
59+
}
Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import { useTranslation } from "../../../../lib/i18n";
2+
import { WorkspaceResolvingStateShell } from "./workspace-empty-state";
23

34
export function WorkspaceLoadingState() {
45
const t = useTranslation();
56

67
return (
7-
<div className="workspace-resolving-shell" data-testid="workspace-resolving-shell">
8-
<div className="workspace-resolving-card">
9-
<div className="workspace-resolving-kicker">{t("workspace.title")}</div>
10-
<div className="workspace-resolving-title">{t("workspace.loading_title")}</div>
11-
<div className="workspace-resolving-desc">{t("workspace.loading_description")}</div>
12-
</div>
13-
</div>
8+
<WorkspaceResolvingStateShell
9+
testId="workspace-resolving-shell"
10+
title={t("workspace.loading_title")}
11+
description={t("workspace.loading_description")}
12+
/>
1413
);
1514
}

0 commit comments

Comments
 (0)