diff --git a/AGENTS.md b/AGENTS.md index 076c30b48..e81c62a3c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ Coolify is an open-source, self-hostable PaaS (alternative to Heroku/Netlify/Ver ## Design Reference -For UI/UX design specifications, principles, and visual standards, consult `DESIGN.md` in the [coollabsio/architecture](https://github.com/coollabsio/architecture) repo. +For UI/UX design specifications, principles, and visual standards, consult the local [`DESIGN.md`](DESIGN.md). It is the source of truth for frontend design work in this repository. ## Development Environment diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 000000000..3976dd12b --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,686 @@ +# Coolify UI design system + +This document defines Coolify's UI design system for its Livewire + Blade + +Alpine + Tailwind v4 frontend. The visual system covers the global shell, +project and environment pages, application navigation, settings surfaces, +tables, modals, toasts, terminals, and metrics. + +Use this file as the source of truth for frontend design work. Update it in the +same change whenever a new shared visual pattern or component is introduced. + +Onboarding validation and live server validation checkpoints share +`` (idle / pending / running / success / error) inside a +compact divided list, not legacy green check SVGs or fixed-width status rows. + +> **Maintainer rules** +> +> - Keep the work frontend-focused unless existing data must be exposed to the +> view. +> - Preserve routes, Livewire bindings, permissions, confirmations, and working +> interactions while changing layout and presentation. +> - Add or update tests when a UI change affects behavior. Follow the testing +> requirements in `AGENTS.md`. +> - Validate Blade with `docker exec coolify php artisan view:cache`, then clear +> it with `docker exec coolify php artisan view:clear`. +> - Build frontend assets in the Vite container with +> `docker exec coolify-vite npm run build`. +> - Use existing components before adding another styling abstraction. + +--- + +## 1. Visual direction + +The interface is compact and product-focused: + +- near-neutral layered surfaces instead of large bordered boxes; +- 13–14px UI typography and 32px controls; +- hairline rings instead of heavy borders; +- full-width data tables for dense collections; +- outline Reicon glyphs through ``; +- the Coolify purple brand accent in light mode; +- the readable Coolify yellow accent in dark mode; +- solid active-item fills (neutral black/white opacity), not accent gradients; + active state is the left accent rail plus a flat selected surface; +- sentence-case labels and headings; +- never use the em dash (`—`) in UI copy. Prefer a period, colon, comma, or + ASCII hyphen (`-`) for empty cells and separators. + +Avoid oversized titles, generic dashboard cards, strong shadows, thick +dividers, native browser selects, and isolated colored buttons that do not +match the current action styles. + +--- + +## 2. Development and cascade notes + +PHP runs in the `coolify` container. The development app is normally available +at `http://localhost:8000`, with Vite on port `5173`. + +`resources/css/app.css` still contains unlayered global element rules for +headings, labels, and tables. Tailwind utilities are layered, so the +unlayered rules can win unexpectedly. + +The settings and dense-surface CSS therefore lives as plain unlayered CSS near +the end of `resources/css/app.css`, beginning at: + +```css +/* Coollabs layer-card settings surfaces */ +``` + +Important consequences: + +- scope settings forms with `.application-settings-form` or + `.application-settings-workspace`; +- add shared surface overrides to the unlayered block instead of stacking + `!important` utilities; +- listbox panels require ancestors with `overflow: visible`; +- anchored cards use `scroll-margin-top: 7rem` to clear both fixed navigation + layers; +- modal shells reuse the layer-card classes but keep content-width sizing on + desktop; +- Alpine code inside quoted Blade attributes must not introduce conflicting + quote characters. + +--- + +## 3. Tokens and color behavior + +The surface ladder is defined in `resources/css/app.css`. + +| Token | Light | Dark | Use | +|---|---|---|---| +| `--coollabs-canvas` | near white | 10% neutral | page canvas | +| `--coollabs-elevated` | 98% neutral | 15% neutral | shells and card headers | +| `--coollabs-base` | white | 17% neutral | nested card bodies | +| `--coollabs-recessed` | 96% neutral | 20% neutral | inputs and listboxes | +| `--coollabs-fill` | 92.2% neutral | 26.9% neutral | dividers and passive fills | +| `--coollabs-line` | translucent dark | 32% neutral | control borders | +| `--coollabs-hairline` | 93.5% neutral | 26.9% neutral | shell rings | +| `--coollabs-subtle` | 55.6% neutral | 70.8% neutral | labels and muted titles | + +Accent behavior is intentionally theme-aware: + +- **Light mode:** Coolify purple (`coollabs`) for active controls, focus, + primary actions, and navigation accents. +- **Dark mode:** Coolify yellow (`warning`) for the same states because the + original purple did not provide sufficient text and ring contrast. + +Do not hard-code blue focus rings or leave yellow accent utilities active in +light mode. Primary action patterns should normally follow: + +```html +bg-coollabs/10 text-coollabs ring-coollabs/25 +dark:bg-warning/15 dark:text-warning dark:ring-warning/25 +``` + +The filled top-level action/tab treatment uses the same palette at a restrained +opacity rather than a fully saturated fill. + +--- + +## 4. Page shells and navigation + +### Global shell + +- Main sidebar groups are compact, use outline Reicons, and keep a 32px row + height. +- Active sidebar rows are rounded pills (`rounded-md`) with an accent rail on + the left plus a solid neutral selected fill (`bg-black/5` light, + `bg-white/6` dark). Hover rows use the same radius. Do not use accent-tinted + gradients on nav rows; yellow washes look muddy on dark UI. +- Nested items use a thin guide line with a visible active segment, not a thick + box border. +- The update badge sits on the version row and uses a tiny fully rounded + primary-action pill. + +### Layer-2 navigation + +Application and server pages use the same fixed second navigation layer +directly below the global topbar. Do not keep a large in-flow resource heading +or legacy `.navbar-main` tabs on one resource type while using the compact +layer-2 bar on another. Active tabs are a light brand fill: + +- purple tint in light mode; +- yellow tint in dark mode; +- no fully saturated tab background. + +Keep route-derived active state in Blade/Livewire. Do not rely only on Alpine +state because it can disappear after polling or a Livewire morph. + +The global topbar owns the current resource identity and its compact status +badges. Layer 2 owns route tabs, resource links, and contextual action buttons +only. If a resource is missing from `x-top-breadcrumb`, extend the global +topbar instead of repeating its name or status summary in layer 2. Mobile +resource navigation may repeat this context because the desktop global topbar +is hidden there. + +Only add layer-2 tabs when they represent real sibling routes inside one +context. Never repeat main-sidebar destinations such as Dashboard, Projects, +Terminal, Servers, Sources, Destinations, or Storage as a second tab row. A +single collection page does not need a tab just to fill the bar; keep its +primary action in the page header instead. When tabs are useful, their left edge +uses the same compact `pl-2` alignment as application navigation rather than +the content container's wide horizontal padding. + +The dashboard is a compact overview, not a metrics wall. Use two full-width +sections that follow the projects-page grid pattern: projects first, then +servers. Keep one `New` action in the page header and let its modal choose the +resource type. Place active deployments above the resource grids as a compact, +live-updating table rather than a metric card. Communicate server health with +the shared status badge. + +### Top-level dashboard destinations + +Every page opened directly from the main sidebar uses the same compact content +shell: + +- 24px page title and a 13px muted summary; +- the primary action at the top right using the restrained brand fill; +- no legacy `coolbox`, `.navbar-main`, or oversized subtitle block; +- four-column compact cards for small browsable collections; +- a dense table instead of cards when the collection is expected to grow; +- `x-empty` anatomy for empty states; +- `x-status-badge` for state and `x-reicon` for all interface icons. + +Collection cards are `min-h-28` or `min-h-32`, use a 32px icon tile, and keep +secondary metadata at 11px. They must not grow into dashboard-sized summary +cards. Sources, destinations, S3 storage, private keys, and shared-variable +scopes use this pattern. + +Top-level settings families such as Team, Notifications, Keys & Tokens, and +instance Settings use a compact header followed by a small route-derived tab +strip. The active tab uses the same purple-light/yellow-dark tint as resource +tabs. Do not nest `