From 4b2842b81cdad207787a9b0d2940149079eeff1b Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 9 May 2026 21:09:00 -0700 Subject: [PATCH 1/3] fix(chat): a2ui catalog layout polish via component-scoped CSS Replace inert Tailwind utility class strings with Angular component-scoped styles: blocks on all 18 a2ui catalog components. No Tailwind compiler is configured in this workspace so those class names were silently ignored, causing visible layout breakage (label+input running together, headings rendering inline at body size, Column/Row/List/Card having no flex gap, etc.). Each component now carries its own BEM-style CSS that faithfully reproduces the original layout intent: flex-column wrappers with 4px gap on TextField, DateTimeInput, Slider, MultipleChoice; flex-row on Row; flex-column on Column and List; padding/border/radius on all input-like elements; block-level display and correct font-size/weight hierarchy on Text h1-h5/caption/body; visible padding and hover states on Button; border+padding on Card and Modal. Column and Row convert the numeric `gap` and `alignment` inputs to real CSS via inline [style] bindings rather than gap-N Tailwind shorthand. Co-Authored-By: Claude Sonnet 4.6 --- .../a2ui/catalog/audio-player.component.ts | 8 ++- .../src/lib/a2ui/catalog/button.component.ts | 31 ++++++++-- .../src/lib/a2ui/catalog/card.component.ts | 13 +++- .../lib/a2ui/catalog/check-box.component.ts | 20 ++++++- .../src/lib/a2ui/catalog/column.component.ts | 21 ++++--- .../a2ui/catalog/date-time-input.component.ts | 27 +++++++-- .../src/lib/a2ui/catalog/divider.component.ts | 20 ++++++- .../src/lib/a2ui/catalog/icon.component.ts | 10 +++- .../src/lib/a2ui/catalog/image.component.ts | 9 ++- .../src/lib/a2ui/catalog/list.component.ts | 19 +++++- .../src/lib/a2ui/catalog/modal.component.ts | 40 +++++++++++-- .../a2ui/catalog/multiple-choice.component.ts | 48 +++++++++++---- .../src/lib/a2ui/catalog/row.component.ts | 37 ++++++++---- .../src/lib/a2ui/catalog/slider.component.ts | 18 +++++- .../src/lib/a2ui/catalog/tabs.component.ts | 34 +++++++++-- .../lib/a2ui/catalog/text-field.component.ts | 33 ++++++---- .../src/lib/a2ui/catalog/text.component.ts | 60 +++++++++++++++---- .../src/lib/a2ui/catalog/video.component.ts | 9 ++- 18 files changed, 373 insertions(+), 84 deletions(-) diff --git a/libs/chat/src/lib/a2ui/catalog/audio-player.component.ts b/libs/chat/src/lib/a2ui/catalog/audio-player.component.ts index 2ae249206..9c1ab5ae7 100644 --- a/libs/chat/src/lib/a2ui/catalog/audio-player.component.ts +++ b/libs/chat/src/lib/a2ui/catalog/audio-player.component.ts @@ -7,12 +7,18 @@ import type { Spec } from '@json-render/core'; standalone: true, template: ` `, + styles: [` + .a2ui-audio { + display: block; + width: 100%; + } + `], }) export class A2uiAudioPlayerComponent { readonly url = input(''); diff --git a/libs/chat/src/lib/a2ui/catalog/button.component.ts b/libs/chat/src/lib/a2ui/catalog/button.component.ts index a226da22c..f18515876 100644 --- a/libs/chat/src/lib/a2ui/catalog/button.component.ts +++ b/libs/chat/src/lib/a2ui/catalog/button.component.ts @@ -10,10 +10,7 @@ import { RenderElementComponent } from '@ngaf/render'; changeDetection: ChangeDetectionStrategy.OnPush, template: ` `, + styles: [` + .a2ui-btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 8px 16px; + border-radius: 8px; + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: background 120ms, opacity 120ms; + border: none; + } + .a2ui-btn:disabled { opacity: 0.5; cursor: not-allowed; } + .a2ui-btn--primary { + background: var(--a2ui-primary, #2563eb); + color: #fff; + } + .a2ui-btn--primary:hover:not(:disabled) { background: var(--a2ui-primary-hover, #1d4ed8); } + .a2ui-btn--secondary { + background: transparent; + color: var(--a2ui-input-text, rgba(255,255,255,0.8)); + border: 1px solid var(--a2ui-border, rgba(255,255,255,0.2)); + } + .a2ui-btn--secondary:hover:not(:disabled) { background: rgba(255,255,255,0.08); } + `], }) export class A2uiButtonComponent { /** v1: child Text component is rendered inside the button via childKeys. */ diff --git a/libs/chat/src/lib/a2ui/catalog/card.component.ts b/libs/chat/src/lib/a2ui/catalog/card.component.ts index 4563c836f..5783beeee 100644 --- a/libs/chat/src/lib/a2ui/catalog/card.component.ts +++ b/libs/chat/src/lib/a2ui/catalog/card.component.ts @@ -8,12 +8,23 @@ import { RenderElementComponent } from '@ngaf/render'; standalone: true, imports: [RenderElementComponent], template: ` -
+
@for (key of childKeys(); track key) { }
`, + styles: [` + .a2ui-card { + display: flex; + flex-direction: column; + gap: 8px; + border-radius: 12px; + border: 1px solid var(--a2ui-border, rgba(255,255,255,0.1)); + background: var(--a2ui-card-bg, rgba(255,255,255,0.05)); + padding: 16px; + } + `], }) export class A2uiCardComponent { /** v1: a single child key, delivered via childKeys[0] from the render framework. */ diff --git a/libs/chat/src/lib/a2ui/catalog/check-box.component.ts b/libs/chat/src/lib/a2ui/catalog/check-box.component.ts index 3eb086c63..e63de547e 100644 --- a/libs/chat/src/lib/a2ui/catalog/check-box.component.ts +++ b/libs/chat/src/lib/a2ui/catalog/check-box.component.ts @@ -8,11 +8,27 @@ import { emitBinding } from './emit-binding'; standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: ` -