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