docs: add UI/UX component guidelines and improve breadcrumb/tab-panel styling

Add "Komponenten in Formularen" section to boundaries-ui.md with rules
for core button classes, margin resets, checkbox sizing, sticky positioning,
icon-only buttons, responsive grids, and CSS variables. Add matching
quick-reference bullets to CLAUDE.md UI Patterns section.

Fix breadcrumb wrapping: nowrap + overflow hidden + flex-shrink for
single-line behavior. Add data-tab-panel-wide opt-out for full-width
tab panels (default 70ch).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-15 18:44:29 +02:00
parent 2ec632ac8b
commit 63be2def76
5 changed files with 32 additions and 3 deletions

View File

@@ -58,3 +58,13 @@
2. MUST NOT globale unscoped Overrides ohne klaren Scope einfuehren. 2. MUST NOT globale unscoped Overrides ohne klaren Scope einfuehren.
3. MUST Vendor-Overrides nur in `web/css/vendor-overrides/**` pflegen. 3. MUST Vendor-Overrides nur in `web/css/vendor-overrides/**` pflegen.
4. MUST bestehende CSS-Variablen bevorzugen statt neue Inline-Farbwerte zu verteilen. 4. MUST bestehende CSS-Variablen bevorzugen statt neue Inline-Farbwerte zu verteilen.
## Komponenten in Formularen
1. MUST Core-Button-Klassen (`secondary outline small`, `danger outline small`) verwenden statt Custom-Button-CSS. Custom-CSS nur fuer Layout (z.B. `border-radius: 50%`).
2. MUST `margin-bottom: 0` auf Buttons, Inputs, Selects und Labels innerhalb selbststaendiger Komponenten in Formularen resetten (Core setzt `margin-bottom: var(--app-spacing)` global).
3. MUST Checkboxen in Flex-Containern mit expliziter Groesse (`width: 1.25em; height: 1.25em`) und `flex-shrink: 0` versehen (Core nutzt `appearance: none` mit Custom-Sizing).
4. MUST `position: sticky` mit `top: calc(var(--app-topbar-height) + ...)` verwenden, nicht `top: 0` (Topbar ist sticky).
5. MUST Icon-Only-Buttons mit `data-tooltip` und `aria-label` versehen.
6. MUST bei `grid-template-columns` mit mehr als einer Spalte ein `@media`-Fallback auf Single-Column definieren.
7. MUST bestehende `--app-*` CSS-Variablen fuer Farben verwenden, nie Farbwerte hardcoden.

View File

@@ -159,6 +159,7 @@ docker/ # Dockerfiles, Nginx configs, PHP configs
### UI Patterns ### UI Patterns
- Edit pages: tabs → `Master data` | `Visibility` | optional `Danger zone` - Edit pages: tabs → `Master data` | `Visibility` | optional `Danger zone`
- **Tab panel width**: `data-tab-panel` defaults to `max-width: 70ch` (optimal for form readability). Add `data-tab-panel-wide` for panels that need full width (e.g. split layouts, side-by-side editors, preview panels, tables). Use 70ch for standard form fields (text inputs, selects, textareas); use wide for multi-column layouts or content that benefits from horizontal space.
- Titlebar partial for primary actions (Save, Save & close) - Titlebar partial for primary actions (Save, Save & close)
- Secondary actions in Aside block via `app-details-aside-actions.phtml` - Secondary actions in Aside block via `app-details-aside-actions.phtml`
- Lists use Grid.js via `initStandardListPage()` (GR-UI-LIST) - Lists use Grid.js via `initStandardListPage()` (GR-UI-LIST)
@@ -166,6 +167,9 @@ docker/ # Dockerfiles, Nginx configs, PHP configs
- New views must handle loading, empty, error, and success states (GR-UI-014) - New views must handle loading, empty, error, and success states (GR-UI-014)
- All visible text wrapped in `t('...')` - All visible text wrapped in `t('...')`
- Check existing JS/CSS components before adding new ones (GR-UI-REUSE) - Check existing JS/CSS components before adding new ones (GR-UI-REUSE)
- **Buttons**: Always use core classes (`secondary outline small`, `danger outline small`) — custom CSS only for shape/position. Icon-only buttons must have `data-tooltip` + `aria-label`.
- **Components inside forms**: Reset core `margin-bottom` on buttons/inputs/selects/labels at component scope. Checkboxes in flex need explicit `1.25em` sizing + `flex-shrink: 0`.
- **Sticky elements**: Always use `top: calc(var(--app-topbar-height) + ...)` — never `top: 0`. Multi-column grids must have a responsive single-column `@media` fallback.
- **File uploads** use `app-file-upload.phtml` partial (deliberate exception to plain-HTML inputs — the markup is too complex for inline use). See `templates/partials/app-file-upload.phtml` for the `$fileUpload` array contract. Never write file-upload markup inline; always use the partial. - **File uploads** use `app-file-upload.phtml` partial (deliberate exception to plain-HTML inputs — the markup is too complex for inline use). See `templates/partials/app-file-upload.phtml` for the `$fileUpload` array contract. Never write file-upload markup inline; always use the partial.
### Never Do This ### Never Do This

View File

@@ -26,7 +26,7 @@ $handoverSchemaFields = is_array($handoverSchemaFields ?? null) ? $handoverSchem
</fieldset> </fieldset>
</div> </div>
<div data-tab-panel="handover-protocol"> <div data-tab-panel="handover-protocol" data-tab-panel-wide>
<div class="handover-schema-split"> <div class="handover-schema-split">
<div class="handover-schema-split-editor"> <div class="handover-schema-split-editor">
<div <div

View File

@@ -9,6 +9,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
margin: 0; margin: 0;
min-width: 0;
font-size: var(--text-xs); font-size: var(--text-xs);
line-height: var(--leading-tight); line-height: var(--leading-tight);
} }
@@ -16,11 +17,13 @@
.app-breadcrumb ol { .app-breadcrumb ol {
display: flex; display: flex;
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: nowrap;
gap: 0.375rem; gap: 0.375rem;
list-style: none; list-style: none;
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow: hidden;
min-width: 0;
} }
.app-breadcrumb li { .app-breadcrumb li {
@@ -28,6 +31,13 @@
align-items: center; align-items: center;
margin: 0; margin: 0;
padding: 0; padding: 0;
min-width: 0;
flex-shrink: 1;
}
.app-breadcrumb li:first-child,
.app-breadcrumb li:last-child {
flex-shrink: 0;
} }
.app-breadcrumb li::before { .app-breadcrumb li::before {
@@ -40,12 +50,13 @@
font-size: 0.75em; /* em-relative sizing — intentional */ font-size: 0.75em; /* em-relative sizing — intentional */
margin-inline-end: 0.375rem; margin-inline-end: 0.375rem;
pointer-events: none; pointer-events: none;
flex-shrink: 0;
} }
.app-breadcrumb a, .app-breadcrumb a,
.app-breadcrumb [aria-current="page"] { .app-breadcrumb [aria-current="page"] {
display: inline-block; display: inline-block;
max-width: 18ch; max-width: 14ch;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;

View File

@@ -8,6 +8,10 @@
max-width: 70ch; max-width: 70ch;
} }
.app-details-container > section > form [data-tab-panel-wide] {
max-width: none;
}
.app-details-aside-actions { .app-details-aside-actions {
display: grid; display: grid;
gap: calc(var(--app-spacing) * 0.5); gap: calc(var(--app-spacing) * 0.5);