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:
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user