From 6f36fcd6fadfd8a7033a6d5fc829a4a8377d2cde Mon Sep 17 00:00:00 2001 From: gazdagergo Date: Wed, 25 Mar 2026 15:10:28 +0100 Subject: [PATCH 1/4] feat: redesign button component based on Figma specification Implement atomic design changes from OpenDLP UI kit: - Add new variants: primary, secondary, tertiary (ghost), icon-only - Add icon support with leading_icon, trailing_icon, and icon props - Update typography: Lato 700, 14px, 16px line-height, 0.4px spacing - Update styling: 4px border radius, 12px/16px padding - Add button-specific semantic tokens for theming - Add hover/focus CSS classes with proper state transitions - Maintain backwards compatibility: "outline" maps to "secondary" Co-Authored-By: Claude Opus 4.5 --- .../agent/547-component-redesign/button.md | 152 ++++++++++++++++++ .../agent/547-component-redesign/checkbox.md | 0 backend/static/backoffice/src/main.css | 48 ++++++ backend/static/backoffice/tokens/semantic.css | 24 ++- .../backoffice/components/button.html | 131 +++++++++++---- .../backoffice/showcase/button_component.html | 137 ++++++++++++---- 6 files changed, 427 insertions(+), 65 deletions(-) create mode 100644 backend/docs/agent/547-component-redesign/button.md create mode 100644 backend/docs/agent/547-component-redesign/checkbox.md diff --git a/backend/docs/agent/547-component-redesign/button.md b/backend/docs/agent/547-component-redesign/button.md new file mode 100644 index 00000000..3592bf24 --- /dev/null +++ b/backend/docs/agent/547-component-redesign/button.md @@ -0,0 +1,152 @@ +Redesign the button component in our design system to match the following Figma specification from the OpenDLP UI kit. The button system has 4 variants (Primary, Secondary, Tertiary, Icon-only), each with Default and Hover states, plus a Focus ring treatment. Implement this as a reusable component (React + CSS/Tailwind or CSS variables — adapt to whatever framework the project uses). + +--- + +### DESIGN TOKENS (Color Palette) + +Use CSS custom properties (or your framework's equivalent) for these semantic tokens: + +- `--color-brand-400`: #90003F (primary button default bg, focus ring border) +- `--color-brand-600`: #720046 (primary button hover bg) +- `--color-neutral-50`: #F7F7F8 (page/section background) +- `--color-neutral-200`: #E1E2E5 (hover bg for secondary, tertiary, and icon-only buttons) +- `--color-neutrals-700`: #2F3442 (secondary button border, secondary/tertiary text & icon color) +- `--color-white`: #FFFFFF (primary button text/icon color, secondary button default bg) + +--- + +### SHARED BUTTON ANATOMY + +Every button (except icon-only) is composed of three optional slots arranged horizontally: + +1. **Leading icon** (optional) — 16×16px, instance-swappable (e.g., "edit" pencil icon) +2. **Label** — text content +3. **Trailing icon** (optional) — 16×16px, instance-swappable (e.g., "chevron_forward" rotated −90° to form a dropdown caret) + +Layout: +- Flow: Horizontal (flexbox row), vertically centered +- Gap between slots: 8px +- Width: Hug content (auto), or can be set to Fixed +- Height: Hug content, resolves to 40px with the given padding + 16px line-height + +--- + +### TYPOGRAPHY (all button labels) + +- Font family: Lato +- Font weight: 600 (SemiBold) +- Font size: 14px +- Line height: 16px +- Letter spacing: 0.4px + +--- + +### VARIANT 1: PRIMARY BUTTON + +**Default state:** +- Background: brand-400 (#90003F) +- Border: none +- Border radius: 4px +- Padding: 12px top, 16px right, 12px bottom, 16px left +- Text color: white (#FFFFFF) +- Icon color: white (#FFFFFF) + +**Hover state:** +- Background: brand-600 (#720046) +- All other properties same as default + +--- + +### VARIANT 2: SECONDARY BUTTON + +**Default state:** +- Background: white (#FFFFFF) +- Border: 1px solid neutrals-700 (#2F3442), inner alignment +- Border radius: 4px +- Padding: 12px top, 16px right, 12px bottom, 16px left +- Text color: neutrals-700 (#2F3442) +- Icon color: neutrals-700 (#2F3442) + +**Hover state:** +- Background: neutral-200 (#E1E2E5) +- Border: 1px solid neutrals-700 (#2F3442) +- All other properties same as default + +--- + +### VARIANT 3: TERTIARY (GHOST) BUTTON + +**Default state:** +- Background: transparent (none) +- Border: none +- Border radius: 4px +- Padding: 12px top, 16px right, 12px bottom, 16px left +- Text color: neutrals-700 (#2F3442) +- Icon color: neutrals-700 (#2F3442) + +**Hover state:** +- Background: neutral-200 (#E1E2E5) +- All other properties same as default + +--- + +### VARIANT 4: ICON-ONLY BUTTON + +**Default state:** +- Background: transparent (none) +- Border: none +- Border radius: 4px +- Padding: 12px top, 8px right, 12px bottom, 8px left +- Contains only a single 16×16px icon (e.g., "edit" pencil), no label, no trailing icon +- Icon color: neutrals-700 (#2F3442) +- Resolves to 40×40px (square) + +**Hover state:** +- Background: neutral-200 (#E1E2E5) +- All other properties same as default + +--- + +### FOCUS RING (applies to all variants on focus/focus-visible) + +When focused, the button is wrapped in a visual focus indicator: +- Outer container padding around the button: 4px +- Border: 2px solid brand-400 (#90003F) +- Border radius: 8px (larger than the button's 4px to accommodate the offset) +- Total focused element height: ~48px (40px button + 4px padding top/bottom) + +Implementation: Use a `box-shadow` or `outline` with offset, or a pseudo-element wrapper. Prefer `outline` + `outline-offset` for accessibility: +- `outline: 2px solid #90003F` +- `outline-offset: 4px` +- `border-radius: 8px` (use a pseudo-element if outline-radius isn't supported) + +--- + +### COMPONENT API (Props) + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `variant` | `"primary" \| "secondary" \| "tertiary" \| "icon"` | `"primary"` | Visual style variant | +| `children` / `label` | `string` | — | Button label text (not used for icon variant) | +| `leadingIcon` | `ReactNode \| IconName` | `undefined` | Optional 16×16 icon before the label | +| `trailingIcon` | `ReactNode \| IconName` | `undefined` | Optional 16×16 icon after the label (e.g., dropdown caret) | +| `icon` | `ReactNode \| IconName` | `undefined` | Icon for icon-only variant | +| `disabled` | `boolean` | `false` | Disabled state (reduce opacity to ~0.5, remove pointer events) | +| `onClick` | `() => void` | — | Click handler | +| `type` | `"button" \| "submit" \| "reset"` | `"button"` | HTML button type | +| `fullWidth` | `boolean` | `false` | If true, button stretches to 100% container width | +| `as` | `"button" \| "a"` | `"button"` | Render as anchor for link-style buttons | +| `className` | `string` | — | Additional CSS class overrides | + +--- + +### IMPLEMENTATION NOTES + +1. All icons are 16×16px and should inherit their color from the button variant (white for primary, neutrals-700 for everything else). +2. The component should use CSS custom properties referencing the design tokens above, making theme changes easy. +3. Ensure keyboard accessibility: visible focus ring on Tab navigation (`:focus-visible`), not on mouse click. +4. Add `cursor: pointer` on interactive states, `cursor: not-allowed` on disabled. +5. Use `transition: background-color 150ms ease, border-color 150ms ease` for smooth hover transitions. +6. The trailing chevron icon in the Figma design is "chevron_forward" rotated −90° (pointing downward), used as a dropdown indicator. +7. The component name in Figma is "button primary" — reused across all variants with different styling overrides. In code, use a single ` + style="{{ all_styles }}" + class="{{ hover_class }} {{ focus_class }} {{ classes }}" + >{{ button_content }} {% endif %} {% endmacro %} diff --git a/backend/templates/backoffice/showcase/button_component.html b/backend/templates/backoffice/showcase/button_component.html index 1e4d770b..ea891e64 100644 --- a/backend/templates/backoffice/showcase/button_component.html +++ b/backend/templates/backoffice/showcase/button_component.html @@ -5,29 +5,50 @@ {% from "backoffice/components/showcase_section.html" import showcase_section, showcase_title, showcase_description, showcase_example, showcase_tokens %} {% from "backoffice/components/button.html" import button %} +{# Sample SVG icons for demonstration #} +{% set edit_icon %} + + + + +{% endset %} + +{% set chevron_down_icon %} + + + +{% endset %} + +{% set plus_icon %} + + + + +{% endset %} + +{% set trash_icon %} + + + + +{% endset %} + {% macro button_section() %} {% call showcase_section() %} {{ showcase_title("Button Component") }} - {{ showcase_description("Reusable button macro with variant support.") }} + {{ showcase_description("Reusable button macro with variant support and icon slots. Based on OpenDLP Figma UI specification.") }} + {# Variants Section #} {% call showcase_example('{% from "backoffice/components/button.html" import button %} - {{ button("Click me") }} - {{ button("Submit", variant="primary", type="submit") }} +{# Basic variants #} + {{ button("Primary", variant="primary") }} {{ button("Secondary", variant="secondary") }} - {{ button("Cancel", variant="outline") }} - {{ button("Disabled", disabled=true) }} - - {# Button as link (renders as instead of