DESIGN.md
Rama master · réplica de lectura del repositorio original.
# Design Conventions
UI and visual conventions for the admin and members portals. Read this when working on ActiveAdmin pages, members views, or CSS.
## CSS
Native CSS. Propshaft serves `admin.css` and `member.css`, which `@import` sheets under `shared/`, `admin/`, and `members/`. Save and refresh.
**New widget.** Add a file next to its siblings, `@import` it from the portal entry, name the thing (`.panel-action-row`). Do not attach a long class string to a one-off `div`.
- Colors and space live in `shared/tokens.css`. Change them there. Numbered greys/greens stay put. Semantic names flip on `html.dark` / `.dark`. Do not invent a token for a 1–2× pair, a hover-only green, a status inversion, or CodeJar hex.
- Stored preference is `system|light|dark` on `html[data-theme]`. Paint via `html.dark` / `.dark`. Do not switch to `@media (prefers-color-scheme)` or `light-dark()`.
- Markup we own uses semantic classes (`.btn`, `.status-tag`, `.panel`). Name the thing, not the paint.
- Prefix members layout chrome (`member-app`, `member-nav`) and Stimulus maps (`member-menu-open`). Admin chrome uses `admin-` the same way. Page widgets do not (`shop-cart`, `billing-card`).
- Tiny utilities live in `shared/utilities.css` (`is-*`, `cluster` / `stack`, `icon-*`, type helpers). Read that file. Do not grow a spacing scale in HTML. Tooltip/menu visibility is nested (`.tooltip.is-visible`).
- ActiveAdmin gem HTML is styled with descendant selectors. Do not fork gem templates to rename their classes.
- Members page gutter is `--inline-space` (`1rem` on mobile, `1ch` from `48rem`) on rewritten chrome, with matching bleeds. Formtastic and tables stay `rem`. Do not find-replace rem.
- `@media` repeats rem (`48rem` / `64rem` / `40rem`). `var()` is invalid in queries. `@custom-media` waits for a later Safari floor (today 16.6).
- Icons: Lucide SVGs via `icon("name")`. Size and mute them in CSS.
## Icons in Panels and Form Fieldsets
Both `panel` and `f.inputs` support the `icon:` option:
```ruby
panel "Title", icon: "icon-name" do
# ...
end
f.inputs "Title", icon: "icon-name" do
f.input :field
end
```
Icons render at half opacity at `1.25rem` (`.icon-5` / `.panel-title-icon`) — a muted visual cue, not a distraction.
**Only titled fieldsets get icons** — bare `f.inputs do` blocks (no title string) should never receive an icon.
When a fieldset has extra options, place `icon:` before them:
```ruby
f.inputs "Title", icon: "icon-name", data: { controller: "..." } do
f.inputs "Title", icon: "icon-name", "data-controller" => "..." do
```
Use the same icon for the same concept everywhere (panels, fieldsets, nav).
### Icon Mapping
All icons are sourced from [Lucide](https://lucide.dev), stored as SVGs in
`app/assets/images/icons/`. Two custom exceptions are noted below.
The panel icon for a concept **must** match the nav icon when one exists.
#### Resource / Model Icons
| Concept | Icon Name | Nav | Notes |
| ------------------ | ------------------ | :-: | ------------------------------------- |
| Member | `users` | ✓ | Plural for collections |
| Producer | `user-round-group` | | Shared shop and basket content source |
| Membership | `calendar-range` | ✓ | |
| Delivery | `calendar` | | |
| Basket | `shopping-bag` | ✓ | Paniers nav (basket_content.rb) |
| Shop / Shop Orders | `shopping-basket` | ✓ | Shop nav (active_admin.rb) |
| Activity | `handshake` | ✓ | Nav uses same icon |
| Invoice / Billing | `banknotes` | ✓ | ⚠️ Custom Heroicon (no Lucide plural) |
| Payment | `banknotes` | ✓ | Same as above |
| Absence | `tent` | | |
| Temporary address | `clock-fading` | | Overlay row; CTA uses `map-pin-house` |
| Email / Mails | `mails` | ✓ | Plural; nav uses `mail` |
| Newsletter | `megaphone` | | |
| Mail Template | `clipboard` | | |
| Announcement | `megaphone` | | Same as newsletter |
| Bidding Round | `scale` | | |
| Shares | `receipt-text` | | |
| Basket Content | `sprout` | | |
| Price reduction | `ticket-percent` | | Not the shop tag icon |
#### Non-Model / Generic Panel Icons
| Concept | Icon Name | Notes |
| ------------------- | ------------------------ | --------------------------- |
| Details | `notebook-text` | ID, dates, validation info |
| Contact | `contact-round` | Name, email, phone, address |
| Billing (panel) | `banknotes` | ⚠️ Custom Heroicon |
| Amount / Pricing | `receipt-text` | Monetary breakdown |
| Notes | `notepad-text` | Free-text notes |
| Comments | `message-square-text` | ActiveAdmin comments |
| Waiting / Pending | `clock` | Waiting membership |
| Config / Settings | `sliders-horizontal` | Configuration options |
| Renewal | `refresh-cw` | Membership renewal |
| Sheets / PDF | `file-spreadsheet` | PDF sheet documents |
| Attachments | `paperclip` | File attachments |
| Notifications | `mail-check` | Email notifications |
| Registration / Form | `form` | Member registration form |
| Recipients | `users` | Mail recipients list |
| Preview | `eye` | Content preview |
| Carpooling | `car` | Carpooling info |
| State / Status | `circle-check-big` | State/validation info |
| Address / Location | `map` | Physical address |
| Overdue Notices | `mail-warning` | Overdue/reminder notices |
| Periods | `calendar-days` | Delivery cycle periods |
| Information | `info` | Info/help text |
| Missing Deliveries | `triangle-alert` | Warning/missing data |
| Support | `life-buoy` | Help / support |
| Updates | `gift` | What's new |
| Analytics | `chart-no-axes-combined` | Historical year-over-year |
### Custom Icons
Two icons in `app/assets/images/icons/` are **not** from Lucide:
- **`banknotes`** — Custom Heroicon (stacked bills). Lucide only has singular `banknote`.
Used for billing/payment panels and nav.
- **`redo-off`** — Custom icon (redo arrow with slash). Hand-made for "no renewal" state.
### Adding New Icons
1. Find the icon on [Lucide](https://lucide.dev)
2. Download the SVG and save to `app/assets/images/icons/{name}.svg`
3. Set `stroke-width="1.5"` and remove the `class` attribute
4. Use via `icon("name")`, `panel "Title", icon: "name"`, or `f.inputs "Title", icon: "name"`
### Style Guidelines
- **Lucide only** — all icons come from Lucide (two custom exceptions noted above)
- **24px / stroke 1.5** — all SVGs use `width="24" height="24"` and `stroke-width="1.5"`
- **Match nav icons** — if a concept has a nav icon, the panel must use the same one
- **One icon per concept** — same concept = same icon everywhere