From d5a85c4ed0e552e1594dd0dccbf647b1c4ada406 Mon Sep 17 00:00:00 2001 From: "cubecraft-agents[bot]" <3458173+cubecraft-agents[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 12:54:25 +0000 Subject: [PATCH 1/3] CUB-47: Implement Tactical Dark Mode CSS Variables --- frontend/src/styles.scss | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index af13a84..a581a28 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -48,6 +48,17 @@ html { // These are NOT part of the M3 tonal palette; they are semantic overrides. // --------------------------------------------------------------------------- :root { + // --- Tactical Dark Mode color palette (CUB-47) --- + --color-surface: #0F172A; + --color-surface-light: #1E293B; + --color-primary: #38BDF8; + --color-secondary: #2DD4BF; + --color-accent: #A78BFA; + --color-danger: #F87171; + --color-text-primary: #FFFFFF; + --color-text-secondary: #94A3B8; + --color-border: #334155; + // --- Status colors --- --status-active: #38BDF8; --status-idle: #2DD4BF; @@ -90,7 +101,7 @@ html { // Global Body Styles // --------------------------------------------------------------------------- body { - background-color: var(--cc-background); + background-color: var(--color-surface); color: var(--cc-on-surface); font-family: 'Inter', 'Roboto', sans-serif; margin: 0; From c8ca182af0a3e2ccc2409d2733c953d7daf6b443 Mon Sep 17 00:00:00 2001 From: "cubecraft-agents[bot]" <3458173+cubecraft-agents[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 12:40:29 +0000 Subject: [PATCH 2/3] =?UTF-8?q?CUB-52:=20responsive=20hub=20grid=20CSS=20?= =?UTF-8?q?=E2=80=94=20extract=20styles=20to=20SCSS,=20add=202-col=20deskt?= =?UTF-8?q?op=20/=201-col=20mobile=20breakpoint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/pages/hub/hub-page.component.scss | 28 +++++++++++++++++++ .../src/app/pages/hub/hub-page.component.ts | 13 +-------- 2 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 frontend/src/app/pages/hub/hub-page.component.scss diff --git a/frontend/src/app/pages/hub/hub-page.component.scss b/frontend/src/app/pages/hub/hub-page.component.scss new file mode 100644 index 0000000..1b2c65f --- /dev/null +++ b/frontend/src/app/pages/hub/hub-page.component.scss @@ -0,0 +1,28 @@ +// ============================================================================ +// Hub Page — Responsive AgentCard Grid +// Desktop (≥1024px): 2×2 grid +// Mobile (<1024px): single-column stack +// ============================================================================ + +.hub-page { + display: grid; + grid-template-columns: 1fr; + gap: 16px; + padding: var(--cc-section-padding, 16px); + min-height: 400px; + overflow-x: hidden; +} + +.hub-page__placeholder { + color: var(--cc-on-surface-variant); + font-size: 16px; + text-align: center; + padding: 24px 0; +} + +// Desktop / kiosk breakpoint — 2-column grid +@media (min-width: 1024px) { + .hub-page { + grid-template-columns: repeat(2, 1fr); + } +} \ No newline at end of file diff --git a/frontend/src/app/pages/hub/hub-page.component.ts b/frontend/src/app/pages/hub/hub-page.component.ts index 7819be4..1749b94 100644 --- a/frontend/src/app/pages/hub/hub-page.component.ts +++ b/frontend/src/app/pages/hub/hub-page.component.ts @@ -9,18 +9,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

Command Hub — Fleet status grid will render here

`, - styles: [` - .hub-page { - display: flex; - align-items: center; - justify-content: center; - min-height: 400px; - } - .hub-page__placeholder { - color: var(--cc-on-surface-variant); - font-size: 16px; - } - `], + styleUrl: './hub-page.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) export class HubPageComponent {} \ No newline at end of file From 5375d117922e0c40b6d0203418e2fd5f431fe268 Mon Sep 17 00:00:00 2001 From: rex-bot Date: Mon, 27 Apr 2026 14:17:04 +0000 Subject: [PATCH 3/3] CUB-48: Agent Status Badge component with pulse animations --- .../agent-status-badge.component.html | 8 + .../agent-status-badge.component.scss | 146 ++++++++++++++++++ .../agent-status-badge.component.ts | 54 +++++++ .../components/agent-status-badge/index.ts | 1 + frontend/src/app/components/index.ts | 1 + 5 files changed, 210 insertions(+) create mode 100644 frontend/src/app/components/agent-status-badge/agent-status-badge.component.html create mode 100644 frontend/src/app/components/agent-status-badge/agent-status-badge.component.scss create mode 100644 frontend/src/app/components/agent-status-badge/agent-status-badge.component.ts create mode 100644 frontend/src/app/components/agent-status-badge/index.ts create mode 100644 frontend/src/app/components/index.ts diff --git a/frontend/src/app/components/agent-status-badge/agent-status-badge.component.html b/frontend/src/app/components/agent-status-badge/agent-status-badge.component.html new file mode 100644 index 0000000..e88ea86 --- /dev/null +++ b/frontend/src/app/components/agent-status-badge/agent-status-badge.component.html @@ -0,0 +1,8 @@ + + + {{ displayLabel }} + \ No newline at end of file diff --git a/frontend/src/app/components/agent-status-badge/agent-status-badge.component.scss b/frontend/src/app/components/agent-status-badge/agent-status-badge.component.scss new file mode 100644 index 0000000..331d6f9 --- /dev/null +++ b/frontend/src/app/components/agent-status-badge/agent-status-badge.component.scss @@ -0,0 +1,146 @@ +// ============================================================================ +// Agent Status Badge — per spec Section 7.3 +// Colored pill with dot indicator and optional pulse animation. +// ============================================================================ + +$badge-height: 24px; +$dot-size: 8px; +$border-radius: 12px; +$font-size: 12px; +$font-weight: 500; +$padding-x: 8px; +$gap: 6px; + +@use 'sass:color'; + +// Status color palette +$color-active: #22c55e; // green-500 +$color-idle: #9ca3af; // gray-400 +$color-thinking: #3b82f6; // blue-500 +$color-error: #ef4444; // red-500 +$color-offline: #9ca3af; // gray-400 + +// Background tints (12% opacity for soft pill background) +$bg-active: rgba($color-active, 0.12); +$bg-idle: rgba($color-idle, 0.12); +$bg-thinking: rgba($color-thinking, 0.12); +$bg-error: rgba($color-error, 0.12); +$bg-offline: rgba($color-offline, 0.12); + +// --------------------------------------------------------------------------- +// Base pill +// --------------------------------------------------------------------------- +.badge { + display: inline-flex; + align-items: center; + height: $badge-height; + padding: 0 $padding-x; + border-radius: $border-radius; + gap: $gap; + font-size: $font-size; + font-weight: $font-weight; + line-height: 1; + white-space: nowrap; + user-select: none; +} + +// --------------------------------------------------------------------------- +// Dot indicator +// --------------------------------------------------------------------------- +.badge__dot { + width: $dot-size; + height: $dot-size; + border-radius: 50%; + flex-shrink: 0; +} + +// --------------------------------------------------------------------------- +// Label text +// --------------------------------------------------------------------------- +.badge__label { + line-height: 1; +} + +// --------------------------------------------------------------------------- +// Status color variants +// --------------------------------------------------------------------------- +.badge--active { + background: $bg-active; + color: color.adjust($color-active, $lightness: -10%); + + .badge__dot { + background: $color-active; + } +} + +.badge--idle { + background: $bg-idle; + color: color.adjust($color-idle, $lightness: -15%); + + .badge__dot { + background: $color-idle; + } +} + +.badge--thinking { + background: $bg-thinking; + color: color.adjust($color-thinking, $lightness: -10%); + + .badge__dot { + background: $color-thinking; + } +} + +.badge--error { + background: $bg-error; + color: color.adjust($color-error, $lightness: -10%); + + .badge__dot { + background: $color-error; + } +} + +.badge--offline { + background: $bg-offline; + color: color.adjust($color-offline, $lightness: -15%); + + .badge__dot { + background: $color-offline; + } +} + +// --------------------------------------------------------------------------- +// Pulse animation — applied when status is active, thinking, or error +// --------------------------------------------------------------------------- +.badge--pulse { + .badge__dot { + animation: pulse-dot 2s ease-in-out infinite; + } +} + +// Active: 2s pulse +.badge--active.badge--pulse .badge__dot { + animation-duration: 2s; +} + +// Thinking: 3s pulse +.badge--thinking.badge--pulse .badge__dot { + animation-duration: 3s; +} + +// Error: 0.8s pulse (fast, urgent) +.badge--error.badge--pulse .badge__dot { + animation-duration: 0.8s; +} + +@keyframes pulse-dot { + 0%, + 100% { + opacity: 1; + transform: scale(1); + } + 50% { + opacity: 0.4; + transform: scale(1.5); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/agent-status-badge/agent-status-badge.component.ts b/frontend/src/app/components/agent-status-badge/agent-status-badge.component.ts new file mode 100644 index 0000000..a246d63 --- /dev/null +++ b/frontend/src/app/components/agent-status-badge/agent-status-badge.component.ts @@ -0,0 +1,54 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; +import { AgentStatus } from '../../models/agent.model'; + +/** + * Agent Status Badge component. + * Displays a colored pill with a pulse animation indicating the agent's current status. + * Per spec Section 7.3: Agent Card Component Interface — status indicator. + * + * Color mapping: + * - Active → green + * - Idle → gray + * - Thinking → blue + * - Error → red + * - Offline → gray (no pulse) + * + * Pulse animations: + * - Active → 2s + * - Error → 0.8s + * - Thinking → 3s + * - Idle / Offline → no pulse + */ +@Component({ + selector: 'app-agent-status-badge', + standalone: true, + imports: [], + templateUrl: './agent-status-badge.component.html', + styleUrl: './agent-status-badge.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AgentStatusBadgeComponent { + /** Current agent status — binds to the AgentStatus type from the model. */ + readonly status = input.required(); + + /** Label text shown inside the badge. Defaults to title-cased status. */ + readonly label = input(); + + get displayLabel(): string { + return this.label() ?? this.titleCase(this.status()); + } + + /** CSS class driven by the current status value. */ + get statusClass(): string { + return `badge--${this.status()}`; + } + + /** Whether the pulse animation should be active for the current status. */ + get hasPulse(): boolean { + return this.status() === 'active' || this.status() === 'thinking' || this.status() === 'error'; + } + + private titleCase(value: string): string { + return value.charAt(0).toUpperCase() + value.slice(1); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/agent-status-badge/index.ts b/frontend/src/app/components/agent-status-badge/index.ts new file mode 100644 index 0000000..e531d31 --- /dev/null +++ b/frontend/src/app/components/agent-status-badge/index.ts @@ -0,0 +1 @@ +export { AgentStatusBadgeComponent } from './agent-status-badge.component'; \ No newline at end of file diff --git a/frontend/src/app/components/index.ts b/frontend/src/app/components/index.ts new file mode 100644 index 0000000..09c8fb9 --- /dev/null +++ b/frontend/src/app/components/index.ts @@ -0,0 +1 @@ +export { AgentStatusBadgeComponent } from './agent-status-badge/agent-status-badge.component'; \ No newline at end of file