Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/installer-dashboard/web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { InstallerDashboard } from "./InstallerDashboard";

export function App(): JSX.Element {
return (
<div>
<div className="desktop-shell-app">
<a className="skip-link" href="#main-content">
Skip to Main Content
</a>
<main id="main-content" className="dashboard-main">
<main id="main-content" className="desktop-shell-app-main">
<InstallerDashboard />
</main>
</div>
Expand Down
102 changes: 54 additions & 48 deletions src/installer-dashboard/web/src/InstallerDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1634,22 +1634,26 @@ export function InstallerDashboard(): JSX.Element {
}, [appUpdate, appUpdateBusy]);

return (
<div className="shell">
<header className="hero">
<div className="hero-topline">
<p className="eyebrow">ICA COMMAND CENTER</p>
<p className="stamp">Multi-source</p>
</div>
<h1>Skills & Hooks Dashboard</h1>
<p>Manage repositories once, then install source-pinned skills and hooks across targets.</p>
<div className="hero-meta">
<span>{sources.length} sources</span>
<span>{installedSkillCount} skills installed</span>
<span>{installedHookCount} hooks installed</span>
<div className="shell desktop-shell-frame">
<header className="desktop-shell-header">
<div className="desktop-shell-header-bar">
<div className="desktop-shell-header-copyblock">
<p className="eyebrow">ICA DESKTOP WORKSPACE</p>
<h1>Installer Workspace</h1>
<p className="desktop-shell-header-copy">
Keep source and installation operations in a persistent desktop shell instead of a dashboard landing page.
</p>
</div>
<div className="desktop-shell-header-meta" aria-label="Desktop workspace summary">
<span>{sources.length} sources</span>
<span>{installedSkillCount} skills installed</span>
<span>{installedHookCount} hooks installed</span>
</div>
</div>
</header>

<section className="desktop-shell-grid" aria-label="Desktop workspace shell">
<div className="desktop-shell-workspace">
<section className="desktop-shell-grid" aria-label="Desktop workspace shell">
<article className="panel desktop-shell-card desktop-shell-card-operation panel-spacious">
<div className="desktop-shell-heading">
<div>
Expand Down Expand Up @@ -1805,28 +1809,28 @@ export function InstallerDashboard(): JSX.Element {
</ol>
)}
</article>
</section>

{error && (
<section className="status status-error">
<strong>Action needed:</strong> {error}
</section>
)}
{catalogLoading && (
<section className="status status-info" role="status" aria-live="polite">
<div className="status-head">
<strong>Loading skills catalog</strong>
<span>{Math.round(catalogLoadingProgress)}%</span>
</div>
<div className="status-subtle">{catalogLoadingMessage || "Working…"}</div>
<div className="status-progress" aria-hidden="true">
<div className="status-progress-bar" style={{ width: `${Math.max(5, Math.min(catalogLoadingProgress, 100))}%` }} />
</div>
</section>
)}

<div className="toolbar">
<nav className="tab-nav" role="tablist" aria-label="Dashboard sections">
{error && (
<section className="status status-error">
<strong>Action needed:</strong> {error}
</section>
)}
{catalogLoading && (
<section className="status status-info" role="status" aria-live="polite">
<div className="status-head">
<strong>Loading skills catalog</strong>
<span>{Math.round(catalogLoadingProgress)}%</span>
</div>
<div className="status-subtle">{catalogLoadingMessage || "Working…"}</div>
<div className="status-progress" aria-hidden="true">
<div className="status-progress-bar" style={{ width: `${Math.max(5, Math.min(catalogLoadingProgress, 100))}%` }} />
</div>
</section>
)}

<div className="toolbar">
<nav className="tab-nav" role="tablist" aria-label="Dashboard sections">
<button
className={`tab-btn ${activeTab === "skills" ? "is-active" : ""}`}
type="button"
Expand Down Expand Up @@ -1939,9 +1943,9 @@ export function InstallerDashboard(): JSX.Element {
</section>
)}
</div>
</div>
</div>

{activeTab === "skills" && (
{activeTab === "skills" && (
<div className="workspace tab-section">
<aside className="control-rail skills-rail">
<section className="panel action-panel panel-spacious">
Expand Down Expand Up @@ -2234,9 +2238,9 @@ export function InstallerDashboard(): JSX.Element {
</section>
</main>
</div>
)}
)}

{activeTab === "hooks" && (
{activeTab === "hooks" && (
<div className="workspace tab-section">
<aside className="control-rail skills-rail">
<section className="panel action-panel panel-spacious">
Expand Down Expand Up @@ -2367,9 +2371,9 @@ export function InstallerDashboard(): JSX.Element {
</section>
</main>
</div>
)}
)}

{activeTab === "settings" && (
{activeTab === "settings" && (
<section className="settings-grid tab-section">
<article className="panel panel-settings panel-spacious">
<h2>Repository Management</h2>
Expand Down Expand Up @@ -2571,9 +2575,9 @@ export function InstallerDashboard(): JSX.Element {
</div>
</article>
</section>
)}
)}

{activeTab === "state" && (
{activeTab === "state" && (
<section className="state-grid tab-section">
<article className="panel state-intro panel-spacious">
<h2>States & Reports</h2>
Expand Down Expand Up @@ -2826,6 +2830,8 @@ export function InstallerDashboard(): JSX.Element {
</div>
)}

</div>

{skillPickerOpen && (
<div className="publish-picker-overlay" role="presentation" onClick={() => setSkillPickerOpen(false)}>
<section
Expand All @@ -2844,13 +2850,13 @@ export function InstallerDashboard(): JSX.Element {
Close
</button>
</div>
<input
className="input input-search"
name="skill-picker-search"
autoComplete="off"
placeholder="Search by skill, source, or path…"
value={skillPickerQuery}
onChange={(event) => setSkillPickerQuery(event.target.value)}
<input
className="input input-search"
name="skill-picker-search"
autoComplete="off"
placeholder="Search by skill, source, or path…"
value={skillPickerQuery}
onChange={(event) => setSkillPickerQuery(event.target.value)}
aria-label="Search local skill bundles"
/>
<div className="publish-picker-list">
Expand Down
123 changes: 68 additions & 55 deletions src/installer-dashboard/web/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
--text: #121826;
--text-soft: #4b5b72;
--text-muted: #65758a;
--hero-meta-bg: color-mix(in srgb, var(--accent) 10%, #f2f5fa);
--status-error-border: color-mix(in srgb, var(--accent) 22%, #d5dbe5);
--status-error-bg: color-mix(in srgb, var(--accent) 12%, #f6f8fb);
--status-error-text: #4b5b72;
Expand Down Expand Up @@ -75,7 +74,6 @@ body[data-mode="dark"] {
--text: #e9eef4;
--text-soft: #c4d0dc;
--text-muted: #9eacbc;
--hero-meta-bg: color-mix(in srgb, var(--accent) 30%, #1e2329);
--status-error-border: color-mix(in srgb, var(--accent) 42%, #3d4652);
--status-error-bg: color-mix(in srgb, var(--accent) 24%, #1d2228);
--status-error-text: #cfdbe7;
Expand Down Expand Up @@ -374,71 +372,85 @@ input[type="radio"]:focus-visible {
padding: var(--space-8) var(--space-6) var(--space-9);
}

.hero {
background: var(--surface);
border: 1px solid var(--line);
border-radius: 12px;
.desktop-shell-app {
min-height: 100vh;
}

.desktop-shell-app-main {
display: block;
}

.desktop-shell-frame {
display: grid;
gap: var(--space-5);
}

.desktop-shell-header {
background:
linear-gradient(135deg, color-mix(in srgb, var(--accent) 7%, var(--surface)) 0%, var(--surface) 62%),
var(--surface);
border: 1px solid color-mix(in srgb, var(--line) 80%, transparent);
border-radius: 14px;
padding: var(--space-5) var(--space-6);
box-shadow: none;
margin-bottom: var(--space-5);
box-shadow: inset 0 1px 0 color-mix(in srgb, #ffffff 36%, transparent);
}

.hero-topline {
.desktop-shell-header-bar {
display: flex;
align-items: center;
align-items: flex-start;
justify-content: space-between;
gap: var(--space-3);
gap: var(--space-4);
}

.eyebrow {
margin: 0;
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--text-muted);
font-weight: 400;
.desktop-shell-header-copyblock {
display: grid;
gap: var(--space-3);
max-width: 46rem;
}

.stamp {
.desktop-shell-header h1 {
margin: 0;
border-radius: 8px;
border: 1px solid color-mix(in srgb, var(--line) 76%, transparent);
color: var(--text-soft);
background: transparent;
padding: 0.14rem 0.46rem;
font-size: 0.7rem;
}

.hero h1 {
margin: var(--space-3) 0 0;
font-size: clamp(1.38rem, 2.5vw, 1.78rem);
line-height: 1.2;
font-size: clamp(1.4rem, 2.5vw, 1.82rem);
line-height: 1.12;
font-weight: 300;
letter-spacing: -0.01em;
text-wrap: balance;
letter-spacing: -0.02em;
}

.hero > p {
margin: var(--space-3) 0 0;
.desktop-shell-header-copy {
margin: 0;
color: var(--text-soft);
max-width: 68ch;
font-size: 0.94rem;
font-size: 0.95rem;
line-height: 1.58;
}

.hero-meta {
margin-top: var(--space-4);
.desktop-shell-header-meta {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
gap: var(--space-2);
}

.hero-meta span {
border-radius: 8px;
background: transparent;
border: 1px solid color-mix(in srgb, var(--line) 75%, transparent);
.desktop-shell-header-meta span {
border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--line) 76%, transparent);
background: color-mix(in srgb, var(--surface) 72%, transparent);
color: var(--text-soft);
padding: 0.15rem 0.44rem;
font-size: 0.7rem;
padding: 0.2rem 0.55rem;
font-size: 0.72rem;
}

.desktop-shell-workspace {
display: grid;
gap: var(--space-5);
}

.eyebrow {
margin: 0;
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--text-muted);
font-weight: 400;
}

.desktop-shell-grid {
Expand Down Expand Up @@ -1839,10 +1851,6 @@ pre {
line-height: 1.55;
}

.dashboard-main {
display: block;
}

.skip-link {
position: absolute;
left: 0.75rem;
Expand Down Expand Up @@ -1873,10 +1881,19 @@ pre {
padding: var(--space-7) var(--space-5) var(--space-8);
}

.hero {
.desktop-shell-header {
padding: var(--space-5);
}

.desktop-shell-header-bar {
flex-direction: column;
align-items: stretch;
}

.desktop-shell-header-meta {
justify-content: flex-start;
}

.panel-spacious {
padding: var(--space-6);
}
Expand Down Expand Up @@ -1971,14 +1988,10 @@ pre {
grid-column: span 1;
}

.hero {
.desktop-shell-header {
padding: var(--space-5);
}

.hero-meta {
gap: var(--space-1);
}

.tab-nav {
width: 100%;
gap: var(--space-2);
Expand Down
Loading
Loading