Files
guru-connect/dashboard/src/components/layout/layout.css
Mike Swanson 43a9432b81
All checks were successful
Build and Test / Build Agent (Windows) (push) Successful in 6m56s
Build and Test / Build Server (Linux) (push) Successful in 10m15s
Build and Test / Security Audit (push) Successful in 4m12s
Build and Test / Build Summary (push) Successful in 10s
feat(dashboard): GuruConnect v2 operator console (pass 1)
React + Vite + TypeScript SPA: scaffold, operations-terminal design
system, Bearer-token auth, and the Machines view.

- Design system: OKLCH-tinted dark theme (ink-slate + signal-cyan),
  Hanken Grotesk + JetBrains Mono, status-color language
  (online/offline/granted/pending/denied/not_required), motion with
  prefers-reduced-motion honored.
- Auth: token in sessionStorage via ref (never React state), protected
  routes, 401 session teardown, admin-gated per-agent-key UI.
- Machines view: data table (sticky header, keyboard-activated rows,
  skeleton loading, actionable empty/error states), non-blocking detail
  drawer, delete confirm, admin key management with copy-once reveal.
- UI primitives: Modal (focus trap + inert + portal + dialogStack),
  Drawer, Table, Badge/StatusDot, toast, states.
- Typed API client normalizing the two error-envelope shapes.

Passed Code Review (no blockers), impeccable critique-and-polish, and
local gates (tsc/lint/build green). Dev-only Vite proxy to :3002.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 12:51:11 -07:00

216 lines
4.2 KiB
CSS

/* ============================================================= App shell === */
.shell {
display: grid;
grid-template-columns: var(--sidebar-w) 1fr;
grid-template-rows: var(--topbar-h) 1fr;
grid-template-areas:
"sidebar topbar"
"sidebar main";
height: 100vh;
overflow: hidden;
}
/* ================================================================ Sidebar === */
.sidebar {
grid-area: sidebar;
background: var(--panel-2);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
min-height: 0;
}
.sidebar__brand {
display: flex;
align-items: center;
gap: 10px;
height: var(--topbar-h);
padding: 0 16px;
border-bottom: 1px solid var(--border);
flex: 0 0 auto;
}
.sidebar__logo {
width: 26px;
height: 26px;
border-radius: 6px;
background: linear-gradient(135deg, var(--accent), var(--accent-press));
display: grid;
place-items: center;
color: var(--accent-ink);
font-weight: 800;
font-size: 14px;
flex: 0 0 auto;
}
.sidebar__name {
font-weight: 700;
font-size: 15px;
letter-spacing: 0.01em;
}
.sidebar__name small {
display: block;
font-size: 10px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-faint);
}
.sidebar__nav {
display: flex;
flex-direction: column;
gap: 2px;
padding: 12px 10px;
overflow-y: auto;
}
.sidebar__section {
font-size: 10px;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--text-faint);
padding: 14px 10px 6px;
}
.navlink {
display: flex;
align-items: center;
gap: 11px;
height: 38px;
padding: 0 11px;
border-radius: var(--radius-sm);
color: var(--text-muted);
font-size: 14px;
font-weight: 500;
transition:
background var(--dur-fast) var(--ease),
color var(--dur-fast) var(--ease);
border: 1px solid transparent;
}
.navlink:hover {
background: var(--panel);
color: var(--text);
}
.navlink--active {
background: var(--accent-soft);
color: var(--accent);
border-color: var(--accent-ring);
}
.navlink--disabled {
color: var(--text-faint);
cursor: not-allowed;
pointer-events: none;
}
.navlink__icon {
flex: 0 0 auto;
width: 18px;
height: 18px;
display: grid;
place-items: center;
}
.navlink__soon {
margin-left: auto;
font-size: 9px;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--text-faint);
border: 1px solid var(--border);
border-radius: 999px;
padding: 1px 6px;
}
/* ================================================================= Topbar === */
.topbar {
grid-area: topbar;
display: flex;
align-items: center;
gap: 16px;
padding: 0 20px;
background: var(--panel);
border-bottom: 1px solid var(--border);
}
.topbar__spacer {
flex: 1;
}
.relay {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: var(--text-muted);
padding: 5px 10px;
border: 1px solid var(--border);
border-radius: 999px;
background: var(--panel-2);
}
.relay__pip {
width: 7px;
height: 7px;
border-radius: 50%;
}
.relay--live .relay__pip {
background: var(--ok);
box-shadow: 0 0 8px var(--ok);
animation: gc-live 1.8s var(--ease) infinite;
}
.relay--down .relay__pip {
background: var(--bad);
}
.relay__label.mono {
font-size: 11px;
}
.topbar__user {
display: flex;
align-items: center;
gap: 10px;
}
.topbar__id {
display: flex;
flex-direction: column;
align-items: flex-end;
line-height: 1.2;
}
.topbar__username {
font-size: 13px;
font-weight: 600;
color: var(--text);
}
/* ================================================================== Main === */
.main {
grid-area: main;
overflow-y: auto;
min-height: 0;
}
.page {
padding: 22px 24px 40px;
max-width: 1320px;
margin: 0 auto;
}
.page__header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
margin-bottom: 18px;
}
.page__titles h1 {
font-size: 22px;
font-weight: 700;
margin: 0;
letter-spacing: -0.015em;
}
.page__subtitle {
color: var(--text-muted);
font-size: 13px;
margin-top: 3px;
}
.page__actions {
display: flex;
align-items: center;
gap: 10px;
}
.auth-gate {
display: grid;
place-items: center;
height: 100vh;
}