@rebasepro/cli 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/skills.d.ts +1 -0
- package/dist/index.es.js +1631 -1308
- package/dist/index.es.js.map +1 -1
- package/dist/utils/package-manager.d.ts +2 -0
- package/package.json +17 -16
- package/skills/rebase-admin/SKILL.md +710 -0
- package/skills/rebase-api/SKILL.md +662 -0
- package/skills/rebase-api/references/.gitkeep +3 -0
- package/skills/rebase-auth/SKILL.md +1143 -0
- package/skills/rebase-auth/references/.gitkeep +3 -0
- package/skills/rebase-backend-postgres/SKILL.md +633 -0
- package/skills/rebase-backend-postgres/references/.gitkeep +3 -0
- package/skills/rebase-basics/SKILL.md +749 -0
- package/skills/rebase-basics/references/.gitkeep +3 -0
- package/skills/rebase-collections/SKILL.md +1328 -0
- package/skills/rebase-collections/references/.gitkeep +3 -0
- package/skills/rebase-cron-jobs/SKILL.md +699 -0
- package/skills/rebase-cron-jobs/references/.gitkeep +1 -0
- package/skills/rebase-custom-functions/SKILL.md +233 -0
- package/skills/rebase-deployment/SKILL.md +885 -0
- package/skills/rebase-deployment/references/.gitkeep +3 -0
- package/skills/rebase-design-language/SKILL.md +692 -0
- package/skills/rebase-email/SKILL.md +701 -0
- package/skills/rebase-email/references/.gitkeep +1 -0
- package/skills/rebase-entity-history/SKILL.md +485 -0
- package/skills/rebase-entity-history/references/.gitkeep +1 -0
- package/skills/rebase-local-env-setup/SKILL.md +189 -0
- package/skills/rebase-local-env-setup/references/.gitkeep +3 -0
- package/skills/rebase-realtime/SKILL.md +755 -0
- package/skills/rebase-realtime/references/.gitkeep +3 -0
- package/skills/rebase-sdk/SKILL.md +594 -0
- package/skills/rebase-sdk/references/.gitkeep +0 -0
- package/skills/rebase-storage/SKILL.md +765 -0
- package/skills/rebase-storage/references/.gitkeep +3 -0
- package/skills/rebase-studio/SKILL.md +746 -0
- package/skills/rebase-studio/references/.gitkeep +3 -0
- package/skills/rebase-ui-components/SKILL.md +1488 -0
- package/skills/rebase-ui-components/references/.gitkeep +3 -0
- package/skills/rebase-webhooks/SKILL.md +623 -0
- package/skills/rebase-webhooks/references/.gitkeep +1 -0
- package/templates/template/AGENTS.md +2 -0
- package/templates/template/CLAUDE.md +2 -0
- package/templates/template/ai-instructions.md +6 -3
- package/templates/template/backend/package.json +1 -1
- package/templates/template/backend/src/env.ts +1 -1
- package/templates/template/backend/src/index.ts +9 -6
- package/templates/template/config/collections/presets/ecommerce/orders.ts +15 -5
- package/templates/template/config/collections/presets/ecommerce/products.ts +9 -3
- package/templates/template/config/collections/users.ts +7 -10
- package/templates/template/frontend/package.json +2 -2
- package/templates/template/frontend/src/App.tsx +1 -7
- package/templates/template/frontend/vite.config.ts +0 -1
- package/templates/template/package.json +1 -0
- package/dist/commands/cli.test.d.ts +0 -1
- package/dist/commands/dev.test.d.ts +0 -1
- package/dist/commands/init.test.d.ts +0 -1
- package/dist/index.cjs +0 -1575
- package/dist/index.cjs.map +0 -1
- package/dist/utils/package-manager.test.d.ts +0 -1
- package/dist/utils/project.test.d.ts +0 -1
|
@@ -0,0 +1,692 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rebase-design-language
|
|
3
|
+
description: |
|
|
4
|
+
Comprehensive Rebase UI Design Language specification. Use this skill whenever building, modifying, or reviewing any UI view, custom page, or home page in a Rebase project. This skill covers the exact design tokens, color system, typography scale, spacing conventions, layout patterns, component usage rules, and common anti-patterns to avoid. Agents MUST read this skill before creating or modifying any visual UI.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Rebase Design Language
|
|
8
|
+
|
|
9
|
+
This document is the single source of truth for the visual design language used across all Rebase applications. Every custom view, home page, dashboard, or UI component **must** follow these rules exactly.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Foundational Principle
|
|
14
|
+
|
|
15
|
+
> **Near-zero chrome — the UI disappears so content is the interface.**
|
|
16
|
+
|
|
17
|
+
Rebase applications render inside the Rebase Shell — an admin panel with a sidebar, top bar, and content area. Custom views must feel like a native part of this panel. The design is Attio-inspired: data-dense, quiet, and monochromatic. Every element exists to serve the data, not to decorate. They must **not** look like a marketing website, a Dribbble concept, or a standalone SaaS dashboard.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 2. Component Library (`@rebasepro/ui`)
|
|
22
|
+
|
|
23
|
+
**MANDATORY**: Use `@rebasepro/ui` components for ALL UI elements. Never use raw HTML elements when a kit equivalent exists.
|
|
24
|
+
|
|
25
|
+
### Core Imports
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import {
|
|
29
|
+
// Layout
|
|
30
|
+
Card, Paper, Container, CenteredView,
|
|
31
|
+
// Typography
|
|
32
|
+
Typography, Markdown,
|
|
33
|
+
// Buttons
|
|
34
|
+
Button, IconButton, LoadingButton,
|
|
35
|
+
// Form Inputs
|
|
36
|
+
TextField, DebouncedTextField, TextareaAutosize,
|
|
37
|
+
Select, SelectItem, MultiSelect, Autocomplete,
|
|
38
|
+
Checkbox, BooleanSwitch, RadioGroup, Slider,
|
|
39
|
+
DateTimeField, ColorPicker, FileUpload,
|
|
40
|
+
// Dialogs & Overlays
|
|
41
|
+
Dialog, DialogTitle, DialogContent, DialogActions,
|
|
42
|
+
Menu, Menubar, MenuItem, Popover, Sheet,
|
|
43
|
+
// Data Display
|
|
44
|
+
Table, TableHeader, TableBody, TableRow, TableCell,
|
|
45
|
+
Tabs, Chip, Badge, Label, InfoLabel,
|
|
46
|
+
// Feedback
|
|
47
|
+
Tooltip, Skeleton, CircularProgress, Separator,
|
|
48
|
+
Alert, Collapse, ExpandablePanel,
|
|
49
|
+
// Other
|
|
50
|
+
Avatar, SearchBar, ErrorBoundary,
|
|
51
|
+
// Utilities
|
|
52
|
+
cls, defaultBorderMixin, cardMixin, cardClickableMixin, paperMixin,
|
|
53
|
+
// Icons (all from @rebasepro/ui)
|
|
54
|
+
AddIcon, DeleteIcon
|
|
55
|
+
} from "@rebasepro/ui";
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### The `cls()` Utility
|
|
59
|
+
|
|
60
|
+
Always use `cls()` from `@rebasepro/ui` for combining class names. Never use template literals for conditional classes.
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
// ✅ CORRECT
|
|
64
|
+
<div className={cls("p-4 rounded-lg", isActive && "bg-primary/10")} />
|
|
65
|
+
|
|
66
|
+
// ❌ WRONG
|
|
67
|
+
<div className={`p-4 rounded-lg ${isActive ? "bg-primary/10" : ""}`} />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 3. Color System
|
|
73
|
+
|
|
74
|
+
### Design Token Scale
|
|
75
|
+
|
|
76
|
+
Rebase uses a carefully defined set of CSS custom properties. **Never invent arbitrary color values.** Always reference these tokens.
|
|
77
|
+
|
|
78
|
+
#### Primary & Secondary
|
|
79
|
+
|
|
80
|
+
| Token | Value | Usage |
|
|
81
|
+
|------------------------|--------------|------------------------------------------|
|
|
82
|
+
| `--color-primary` | `#0070F4` | Primary actions, links, focus rings |
|
|
83
|
+
| `--color-primary-light`| oklch derived| Lighter tint of primary |
|
|
84
|
+
| `--color-primary-dark` | oklch derived| Darker shade of primary |
|
|
85
|
+
| `--color-secondary` | `#FF5B79` | Secondary accent |
|
|
86
|
+
| `--color-primary-bg` | primary/0.1 | Subtle primary backgrounds |
|
|
87
|
+
|
|
88
|
+
#### Surface Scale (Neutrals)
|
|
89
|
+
|
|
90
|
+
The surface scale goes from `50` (lightest) to `950` (darkest):
|
|
91
|
+
|
|
92
|
+
| Token | Value | Light mode usage | Dark mode usage |
|
|
93
|
+
|--------------------|-------------|------------------------|------------------------|
|
|
94
|
+
| `surface-50` | `#fafafa` | Page background | — |
|
|
95
|
+
| `surface-100` | `#f5f5f5` | Subtle backgrounds | — |
|
|
96
|
+
| `surface-200` | `#e5e5e5` | Borders, dividers | — |
|
|
97
|
+
| `surface-300` | `#d4d4d4` | Hover borders | — |
|
|
98
|
+
| `surface-400` | `#a3a3a3` | Muted text, placeholders | — |
|
|
99
|
+
| `surface-500` | `#737373` | Secondary icons | Secondary icons |
|
|
100
|
+
| `surface-600` | `#404040` | — | Muted text, labels |
|
|
101
|
+
| `surface-700` | `#262626` | — | Borders, dividers |
|
|
102
|
+
| `surface-800` | `#111111` | — | Page background |
|
|
103
|
+
| `surface-900` | `#0a0a0a` | — | Card backgrounds |
|
|
104
|
+
| `surface-950` | `#000000` | — | Deepest backgrounds |
|
|
105
|
+
|
|
106
|
+
#### Surface Accent Scale (Blue-tinted neutrals)
|
|
107
|
+
|
|
108
|
+
Used for subtle interactive backgrounds and input fields. Full 50–950 range:
|
|
109
|
+
|
|
110
|
+
| Token | Value | Usage |
|
|
111
|
+
|---------------------------|-------------|-------------------------------------|
|
|
112
|
+
| `surface-accent-50` | `#f8fafc` | Lightest accent background |
|
|
113
|
+
| `surface-accent-100` | `#f1f5f9` | Hover backgrounds (light) |
|
|
114
|
+
| `surface-accent-200` | `#e2e8f0` | Field backgrounds (light) |
|
|
115
|
+
| `surface-accent-300` | `#cbd5e1` | Accent borders (light) |
|
|
116
|
+
| `surface-accent-400` | `#94a3b8` | Muted accent text |
|
|
117
|
+
| `surface-accent-500` | `#64748b` | Mid-tone accent |
|
|
118
|
+
| `surface-accent-600` | `#475569` | Accent labels (dark) |
|
|
119
|
+
| `surface-accent-700` | `#334155` | Field backgrounds (dark) |
|
|
120
|
+
| `surface-accent-800` | `#1e293b` | Hover backgrounds (dark) |
|
|
121
|
+
| `surface-accent-900` | `#172033` | Deep accent background (dark) |
|
|
122
|
+
| `surface-accent-950` | `#0f172a` | Deepest accent background (dark) |
|
|
123
|
+
|
|
124
|
+
#### Text Colors
|
|
125
|
+
|
|
126
|
+
| Token | Value | Usage |
|
|
127
|
+
|--------------------------|------------|------------------------------------------|
|
|
128
|
+
| `text-primary` | `#212121` | Default text (light mode) |
|
|
129
|
+
| `text-secondary` | `#757575` | Secondary/helper text (light mode) |
|
|
130
|
+
| `text-disabled` | `#9e9e9e` | Disabled text (light mode) |
|
|
131
|
+
| `text-primary-dark` | `#ffffff` | Default text (dark mode) |
|
|
132
|
+
| `text-secondary-dark` | `#a0a0a9` | Secondary/helper text (dark mode) |
|
|
133
|
+
| `text-disabled-dark` | `#757580` | Disabled text (dark mode) |
|
|
134
|
+
|
|
135
|
+
### Color Rules
|
|
136
|
+
|
|
137
|
+
1. **NEVER use arbitrary Tailwind colors** like `text-violet-600`, `bg-indigo-500`, `text-fuchsia-500`, `bg-rose-500` for structural UI elements. These are only acceptable inside semantic status indicators (e.g., pipeline stage colors).
|
|
138
|
+
2. **NEVER use gradient text** (`bg-gradient-to-r ... bg-clip-text text-transparent`) for titles or headings. Use `Typography` with its built-in color prop.
|
|
139
|
+
3. **NEVER use glassmorphism** (`backdrop-blur`, `backdrop-filter`, semi-transparent backgrounds) for cards or panels. Use the `Card`, `Paper` components or standard `bg-white dark:bg-surface-900` backgrounds.
|
|
140
|
+
4. **All borders must use `defaultBorderMixin`** — never hardcode border colors like `border-surface-200` or `border-gray-300`.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 4. Typography
|
|
145
|
+
|
|
146
|
+
### The `Typography` Component
|
|
147
|
+
|
|
148
|
+
**MANDATORY**: Use `Typography` for ALL visible text. Never use raw `<h1>`, `<p>`, `<span>`, `<label>` tags.
|
|
149
|
+
|
|
150
|
+
### Variant Scale
|
|
151
|
+
|
|
152
|
+
The typography scale is compact and uses semibold weights for headings — designed for high content density.
|
|
153
|
+
|
|
154
|
+
| Variant | CSS Class | Rendered Element | Specs |
|
|
155
|
+
|--------------|-----------------------|------------------|---------------------------------------------------------|
|
|
156
|
+
| `h1` | `typography-h1` | `<h1>` | 4xl, font-semibold, tracking-tight |
|
|
157
|
+
| `h2` | `typography-h2` | `<h2>` | 3xl, font-semibold, tracking-tight |
|
|
158
|
+
| `h3` | `typography-h3` | `<h3>` | 2xl, font-semibold, tracking-tight |
|
|
159
|
+
| `h4` | `typography-h4` | `<h4>` | xl, font-semibold, tracking-[-0.01em] |
|
|
160
|
+
| `h5` | `typography-h5` | `<h5>` | lg, font-semibold, tracking-[-0.01em] |
|
|
161
|
+
| `h6` | `typography-h6` | `<h6>` | base, font-semibold, tracking-[-0.01em] |
|
|
162
|
+
| `subtitle1` | `typography-subtitle1`| `<h6>` | sm, font-semibold, tracking-[-0.01em] |
|
|
163
|
+
| `subtitle2` | `typography-subtitle2`| `<h6>` | sm, font-medium |
|
|
164
|
+
| `body1` | `typography-body1` | `<p>` | sm |
|
|
165
|
+
| `body2` | `typography-body2` | `<p>` | xs |
|
|
166
|
+
| `caption` | `typography-caption` | `<p>` | [11px], leading-[1.4] |
|
|
167
|
+
| `label` | `typography-label` | `<label>` | xs, font-medium, tracking-wide |
|
|
168
|
+
| `inherit` | `typography-inherit` | `<p>` | text-inherit (inherits parent sizing) |
|
|
169
|
+
| `button` | `typography-button` | `<span>` | xs, font-semibold, tracking-wide |
|
|
170
|
+
|
|
171
|
+
### Color Prop
|
|
172
|
+
|
|
173
|
+
| Value | Class applied | Notes |
|
|
174
|
+
|--------------|--------------------------------------------------------|-------------------------------|
|
|
175
|
+
| `"primary"` | `text-text-primary dark:text-text-primary-dark` | Default — standard text |
|
|
176
|
+
| `"secondary"`| `text-text-secondary dark:text-text-secondary-dark` | Helper/description text |
|
|
177
|
+
| `"disabled"` | `text-text-disabled dark:text-text-disabled-dark` | Disabled state |
|
|
178
|
+
| `"error"` | `text-red-600 dark:text-red-500` | Error messages |
|
|
179
|
+
| `"inherit"` | `text-inherit` | Inherits color from parent |
|
|
180
|
+
| `"initial"` | `text-current` | Uses CSS `currentColor` |
|
|
181
|
+
|
|
182
|
+
### Typography Usage Examples
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
// Page title — use h4 or h5 (the scale is compact; h1-h3 are reserved for hero contexts)
|
|
186
|
+
<Typography variant="h4">Dashboard</Typography>
|
|
187
|
+
|
|
188
|
+
// Section title
|
|
189
|
+
<Typography variant="h6">Pipeline Overview</Typography>
|
|
190
|
+
|
|
191
|
+
// Card title
|
|
192
|
+
<Typography variant="subtitle1" component="h2">Active Leads</Typography>
|
|
193
|
+
|
|
194
|
+
// Description / helper text
|
|
195
|
+
<Typography variant="body2" color="secondary">
|
|
196
|
+
Manage your pipeline here.
|
|
197
|
+
</Typography>
|
|
198
|
+
|
|
199
|
+
// Small label above a metric
|
|
200
|
+
<Typography variant="caption" color="secondary">Total Revenue</Typography>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Typography Anti-Patterns
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
// ❌ NEVER: Gradient text on headings
|
|
207
|
+
<Typography className="bg-gradient-to-r from-violet-600 to-cyan-500 bg-clip-text text-transparent">
|
|
208
|
+
|
|
209
|
+
// ❌ NEVER: Overriding font-weight excessively
|
|
210
|
+
<Typography className="font-extrabold">
|
|
211
|
+
|
|
212
|
+
// ❌ NEVER: Custom tracking/sizing overrides
|
|
213
|
+
<Typography className="tracking-widest text-[10px] uppercase">
|
|
214
|
+
|
|
215
|
+
// ✅ CORRECT: Let Typography variants handle all styling
|
|
216
|
+
<Typography variant="caption" color="secondary">Label Text</Typography>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 5. Layout Patterns
|
|
222
|
+
|
|
223
|
+
### Page-Level Layout
|
|
224
|
+
|
|
225
|
+
The reference layout used by `ContentHomePage` (the default Rebase home page):
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
<div className="py-2 overflow-auto h-full w-full bg-surface-50 dark:bg-surface-800">
|
|
229
|
+
<Container maxWidth="6xl">
|
|
230
|
+
{/* Content sections */}
|
|
231
|
+
</Container>
|
|
232
|
+
</div>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Key rules:
|
|
236
|
+
- **Wrap content in `<Container>`** with an appropriate `maxWidth` (`4xl`, `5xl`, `6xl`, `7xl`).
|
|
237
|
+
- **Page background**: `bg-surface-50 dark:bg-surface-800` (not `dark:bg-surface-950`).
|
|
238
|
+
- **Use `overflow-auto h-full w-full`** on the outermost wrapper so the page scrolls inside the admin shell.
|
|
239
|
+
|
|
240
|
+
### Card Grid Layout
|
|
241
|
+
|
|
242
|
+
For grids of cards (like navigation cards on the home page):
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
246
|
+
{/* Cards */}
|
|
247
|
+
</div>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
- Use consistent `gap-4` (not `gap-6` or `gap-8`).
|
|
251
|
+
- Use the responsive breakpoints: 1 column → 2 columns at `md` → 3 columns at `lg`.
|
|
252
|
+
|
|
253
|
+
### Section Spacing
|
|
254
|
+
|
|
255
|
+
- Between major sections: `my-10` (from `NavigationGroup`)
|
|
256
|
+
- Between subsections: `mb-4` or `mt-4`
|
|
257
|
+
- Inside cards: `p-4` (standard), `p-6` (for larger panels)
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 6. Card Patterns
|
|
262
|
+
|
|
263
|
+
### Using the `Card` Component
|
|
264
|
+
|
|
265
|
+
The `Card` component from `@rebasepro/ui` automatically applies `cardMixin` and, if an `onClick` is provided, `cardClickableMixin`.
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
// Style mixins applied by Card:
|
|
269
|
+
// cardMixin = "bg-white dark:bg-surface-900 rounded-lg border border-surface-200 dark:border-surface-700"
|
|
270
|
+
// cardClickableMixin = "hover:bg-surface-50 dark:hover:bg-surface-800 cursor-pointer transition-colors duration-150"
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
// ✅ CORRECT: Using Card component
|
|
275
|
+
<Card className="p-4">
|
|
276
|
+
<Typography variant="subtitle1">Title</Typography>
|
|
277
|
+
<Typography variant="body2" color="secondary">Description</Typography>
|
|
278
|
+
</Card>
|
|
279
|
+
|
|
280
|
+
// ✅ CORRECT: Clickable card
|
|
281
|
+
<Card onClick={() => navigate("/details")} className="p-4">
|
|
282
|
+
<Typography variant="subtitle1">Title</Typography>
|
|
283
|
+
</Card>
|
|
284
|
+
|
|
285
|
+
// ❌ WRONG: Hand-rolled card with custom styling
|
|
286
|
+
<div className="glass-card p-6 rounded-2xl shadow-sm backdrop-blur-md">
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Card Anti-Patterns
|
|
290
|
+
|
|
291
|
+
| ❌ Don't | ✅ Do |
|
|
292
|
+
|---------------------------------------------------|-----------------------------------------------|
|
|
293
|
+
| `rounded-2xl` | Let `Card` use `rounded-lg` |
|
|
294
|
+
| `shadow-lg shadow-blue-500/20` | No shadows — hover uses `bg-surface-50` only |
|
|
295
|
+
| `hover:-translate-y-1` | Don't lift cards on hover |
|
|
296
|
+
| `hover:scale-110` on icons | Use subtle `transition-colors` at most |
|
|
297
|
+
| `bg-gradient-to-br from-blue-500 to-indigo-600` | Use plain surface colors |
|
|
298
|
+
| `glass-card`, `glass-panel`, backdrop-blur | Use `Card` or `Paper` component |
|
|
299
|
+
| `hover:shadow-md`, `hover:ring-1` | Use `hover:bg-surface-50 dark:hover:bg-surface-800` |
|
|
300
|
+
|
|
301
|
+
### NavigationCard Reference Pattern
|
|
302
|
+
|
|
303
|
+
This is the gold standard for how a card should look:
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
<Card className={cls(
|
|
307
|
+
"group h-full p-4 cursor-pointer transition-colors duration-150 ease-in-out",
|
|
308
|
+
"hover:bg-surface-50 dark:hover:bg-surface-800"
|
|
309
|
+
)}>
|
|
310
|
+
<div className="flex flex-col h-full">
|
|
311
|
+
{/* Header: icon + title left, actions right */}
|
|
312
|
+
<div className="flex items-center w-full justify-between mb-1">
|
|
313
|
+
<div className="flex items-center gap-3">
|
|
314
|
+
{/* Icon: plain muted color, no background pill */}
|
|
315
|
+
<div className="flex items-center justify-center w-5 h-5 text-surface-400 dark:text-surface-500">
|
|
316
|
+
{icon}
|
|
317
|
+
</div>
|
|
318
|
+
<Typography variant="subtitle1" component="h2">{name}</Typography>
|
|
319
|
+
</div>
|
|
320
|
+
</div>
|
|
321
|
+
{/* Description indented to align with title */}
|
|
322
|
+
<div className="grow pl-8">
|
|
323
|
+
<Typography variant="caption" color="secondary">
|
|
324
|
+
<Markdown source={description} size="small" />
|
|
325
|
+
</Typography>
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
</Card>
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Key observations from NavigationCard:**
|
|
332
|
+
- Icons are **plain muted color** (`text-surface-400 dark:text-surface-500`) — no background pill, no gradient, no primary tint.
|
|
333
|
+
- Hover effect is a **single background color change** — `hover:bg-surface-50 dark:hover:bg-surface-800`. No shadows, no border changes, no rings.
|
|
334
|
+
- The card transitions use `transition-colors duration-150` — fast and minimal.
|
|
335
|
+
- No arrow icon or decorative footer — the card is the affordance.
|
|
336
|
+
- Description is offset with `pl-8` to align with the title (past the icon).
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 7. Style Mixins (`@rebasepro/ui/styles`)
|
|
341
|
+
|
|
342
|
+
Always import and use these mixins rather than hardcoding equivalent classes:
|
|
343
|
+
|
|
344
|
+
### Layout & Card Mixins
|
|
345
|
+
|
|
346
|
+
| Mixin | Classes |
|
|
347
|
+
|------------------------------|------------------------------------------------------------------------------------------------------|
|
|
348
|
+
| `defaultBorderMixin` | `border-surface-200 dark:border-surface-700` |
|
|
349
|
+
| `paperMixin` | `bg-white rounded-lg dark:bg-surface-800 border border-surface-200 dark:border-surface-700` |
|
|
350
|
+
| `cardMixin` | `bg-white dark:bg-surface-900 rounded-lg border border-surface-200 dark:border-surface-700` |
|
|
351
|
+
| `cardClickableMixin` | `hover:bg-surface-50 dark:hover:bg-surface-800 cursor-pointer transition-colors duration-150` |
|
|
352
|
+
| `cardSelectedMixin` | `bg-primary-bg/30 dark:bg-primary-bg/10 ring-1 ring-primary/75` |
|
|
353
|
+
|
|
354
|
+
### Field & Focus Mixins
|
|
355
|
+
|
|
356
|
+
| Mixin | Classes |
|
|
357
|
+
|----------------------------------|--------------------------------------------------------------------------------------------------|
|
|
358
|
+
| `fieldBackgroundMixin` | `bg-surface-accent-200/50 dark:bg-surface-900` |
|
|
359
|
+
| `fieldBackgroundInvisibleMixin` | `bg-surface-accent-200/0 dark:bg-surface-900/0` — fully transparent field background |
|
|
360
|
+
| `fieldBackgroundDisabledMixin` | `bg-surface-accent-200/50 dark:bg-surface-900/90` — slightly opaque disabled state |
|
|
361
|
+
| `fieldBackgroundHoverMixin` | `hover:bg-surface-accent-200/70 hover:dark:bg-surface-700/40` — hover highlight for fields |
|
|
362
|
+
| `focusedClasses` | `z-30 outline-none ring-2 ring-primary/75 ring-offset-0` — standard focus ring |
|
|
363
|
+
| `focusedDisabled` | `focus-visible:ring-0 focus-visible:ring-offset-0` — removes focus ring for disabled elements |
|
|
364
|
+
| `focusedInvisibleMixin` | `focus:bg-surface-accent-100/70 dark:focus:bg-surface-900/60` — subtle bg on focus for invisible fields |
|
|
365
|
+
|
|
366
|
+
### `cardSelectedMixin` Usage
|
|
367
|
+
|
|
368
|
+
Use `cardSelectedMixin` to visually mark a card as the active/selected item in a list or grid:
|
|
369
|
+
|
|
370
|
+
```tsx
|
|
371
|
+
import { Card, cls, cardSelectedMixin } from "@rebasepro/ui";
|
|
372
|
+
|
|
373
|
+
<Card className={cls("p-4", isSelected && cardSelectedMixin)}>
|
|
374
|
+
<Typography variant="subtitle1">{item.name}</Typography>
|
|
375
|
+
</Card>
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
The mixin applies a subtle primary-tinted background and a `ring-1` primary border, matching the Rebase selection style used in entity tables and multi-select UIs.
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## 8. Buttons
|
|
383
|
+
|
|
384
|
+
### Valid Button Variants
|
|
385
|
+
|
|
386
|
+
The `Button` component accepts these variants and colors. Buttons use `rounded-lg`, `transition-colors`, and no active scale effect.
|
|
387
|
+
|
|
388
|
+
```tsx
|
|
389
|
+
<Button variant="filled" color="primary">Primary Action</Button>
|
|
390
|
+
<Button variant="outlined" color="primary">Secondary Action</Button>
|
|
391
|
+
<Button variant="text" color="primary">Tertiary Action</Button>
|
|
392
|
+
<Button variant="filled" color="neutral">Neutral Button</Button>
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
| Prop | Values |
|
|
396
|
+
|-----------|-----------------------------------------------|
|
|
397
|
+
| `variant` | `"filled"`, `"outlined"`, `"text"` |
|
|
398
|
+
| `color` | `"primary"`, `"secondary"`, `"text"`, `"error"`, `"neutral"` |
|
|
399
|
+
| `size` | `"small"`, `"medium"`, `"large"`, `"xl"`, `"2xl"` |
|
|
400
|
+
|
|
401
|
+
### Button Styling Details
|
|
402
|
+
|
|
403
|
+
- Base shape: `rounded-lg` (not `rounded-md`)
|
|
404
|
+
- Transitions: `transition-colors` (not `transition-all`)
|
|
405
|
+
- Filled hover: `hover:brightness-105` (subtle, not `hover:brightness-110`)
|
|
406
|
+
- No `shadow-sm`, no `hover:shadow-md`, no `active:scale-[0.98]`
|
|
407
|
+
|
|
408
|
+
### Button Anti-Patterns
|
|
409
|
+
|
|
410
|
+
```tsx
|
|
411
|
+
// ❌ NEVER: Casting variant to bypass types
|
|
412
|
+
<Button variant={"standard" as any}>
|
|
413
|
+
|
|
414
|
+
// ❌ NEVER: Custom gradient backgrounds
|
|
415
|
+
<Button className="bg-gradient-to-r from-violet-600 to-indigo-600 text-white">
|
|
416
|
+
|
|
417
|
+
// ❌ NEVER: Custom shadow styling
|
|
418
|
+
<Button className="shadow-lg shadow-violet-500/20 hover:shadow-xl">
|
|
419
|
+
|
|
420
|
+
// ❌ NEVER: Active scale effect
|
|
421
|
+
<Button className="active:scale-[0.98]">
|
|
422
|
+
|
|
423
|
+
// ✅ CORRECT: Use proper variant and color
|
|
424
|
+
<Button variant="filled" color="primary">Submit</Button>
|
|
425
|
+
<Button variant="outlined" color="primary">Cancel</Button>
|
|
426
|
+
<Button variant="text" color="primary" startIcon={<RefreshCwIcon />}>Refresh</Button>
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## 9. Alerts & Status Messages
|
|
432
|
+
|
|
433
|
+
### Use the `Alert` Component
|
|
434
|
+
|
|
435
|
+
```tsx
|
|
436
|
+
// ✅ CORRECT
|
|
437
|
+
<Alert color="success" size="small">Lead captured successfully!</Alert>
|
|
438
|
+
<Alert color="error">Could not load dashboard statistics.</Alert>
|
|
439
|
+
<Alert color="info">Data is refreshing...</Alert>
|
|
440
|
+
<Alert color="warning">Some metrics may be stale.</Alert>
|
|
441
|
+
|
|
442
|
+
// ❌ WRONG: Hand-rolled alert div
|
|
443
|
+
<div className="p-4 rounded-xl bg-rose-500/10 border border-rose-500/20 text-rose-600">
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
| `color` prop | Usage |
|
|
447
|
+
|-------------|----------------------|
|
|
448
|
+
| `"error"` | Error messages |
|
|
449
|
+
| `"warning"` | Warnings |
|
|
450
|
+
| `"info"` | Informational |
|
|
451
|
+
| `"success"` | Success confirmations|
|
|
452
|
+
| `"base"` | Neutral notices |
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## 10. Section Headers
|
|
457
|
+
|
|
458
|
+
### How to Title a Section
|
|
459
|
+
|
|
460
|
+
Follow the `NavigationGroup` pattern — section headers are **small, uppercase, secondary-colored labels**, not large bold headings:
|
|
461
|
+
|
|
462
|
+
```tsx
|
|
463
|
+
// ✅ CORRECT: Section header pattern (from NavigationGroup)
|
|
464
|
+
<Typography
|
|
465
|
+
variant="caption"
|
|
466
|
+
component="h2"
|
|
467
|
+
color="secondary"
|
|
468
|
+
className="px-4 py-1 rounded font-medium text-[10px] uppercase tracking-[0.08em] text-surface-400 dark:text-surface-500"
|
|
469
|
+
>
|
|
470
|
+
Pipeline Stages
|
|
471
|
+
</Typography>
|
|
472
|
+
|
|
473
|
+
// ❌ WRONG: Oversized bold section title
|
|
474
|
+
<Typography variant="h6" className="font-bold text-surface-950 dark:text-surface-50">
|
|
475
|
+
Pipeline Stage Distribution
|
|
476
|
+
</Typography>
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
For panel-level titles (inside a Card or Paper), use `subtitle1`:
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
<Card className="p-4">
|
|
483
|
+
<Typography variant="subtitle1" className="mb-2">Tasks</Typography>
|
|
484
|
+
{/* content */}
|
|
485
|
+
</Card>
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## 11. Metric / KPI Cards
|
|
491
|
+
|
|
492
|
+
When displaying numeric KPIs, use plain muted icons (matching NavigationCard) — no background pill:
|
|
493
|
+
|
|
494
|
+
```tsx
|
|
495
|
+
<Card className="p-4">
|
|
496
|
+
<div className="flex items-center gap-3">
|
|
497
|
+
{/* Icon: plain muted color, no background */}
|
|
498
|
+
<div className="flex items-center justify-center w-5 h-5 text-surface-400 dark:text-surface-500">
|
|
499
|
+
<UsersIcon className="h-4 w-4" />
|
|
500
|
+
</div>
|
|
501
|
+
<div>
|
|
502
|
+
<Typography variant="caption" color="secondary">Active Leads</Typography>
|
|
503
|
+
<Typography variant="h5">{count}</Typography>
|
|
504
|
+
</div>
|
|
505
|
+
</div>
|
|
506
|
+
</Card>
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Metric Card Anti-Patterns
|
|
510
|
+
|
|
511
|
+
```tsx
|
|
512
|
+
// ❌ NEVER: Gradient icon backgrounds
|
|
513
|
+
<div className="p-4 bg-gradient-to-br from-blue-500 to-indigo-600 text-white rounded-2xl shadow-lg shadow-blue-500/20">
|
|
514
|
+
|
|
515
|
+
// ❌ NEVER: Primary-tinted icon pill (old pattern)
|
|
516
|
+
<div className="w-10 h-10 rounded-lg bg-primary/8 dark:bg-primary/10 text-primary/70">
|
|
517
|
+
|
|
518
|
+
// ❌ NEVER: Oversized rounded corners
|
|
519
|
+
<div className="rounded-2xl">
|
|
520
|
+
|
|
521
|
+
// ❌ NEVER: Animated hover scaling on icon containers
|
|
522
|
+
<div className="group-hover:scale-110 transition-transform">
|
|
523
|
+
|
|
524
|
+
// ❌ NEVER: Gradient text on values
|
|
525
|
+
<Typography className="bg-gradient-to-r from-violet-600 to-fuchsia-500 bg-clip-text text-transparent">
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## 12. Icons
|
|
531
|
+
|
|
532
|
+
- Import icons from `lucide-react` for functional/semantic icons.
|
|
533
|
+
- Import icons from `@rebasepro/ui` for navigation icons (`AddIcon`, `DeleteIcon`, etc.)
|
|
534
|
+
- **Icon treatment**: plain muted color (`text-surface-400 dark:text-surface-500`). **No** background pill, **no** primary tint, **no** gradients.
|
|
535
|
+
- Icon size: typically `h-4 w-4` or `h-5 w-5`.
|
|
536
|
+
- No decorative arrow icons on cards — the card itself is the affordance.
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
## 13. Panels & Sections (Non-Card Wrappers)
|
|
541
|
+
|
|
542
|
+
For larger content sections (like a table, form, or embedded panel), use `Paper` or apply `paperMixin`:
|
|
543
|
+
|
|
544
|
+
```tsx
|
|
545
|
+
// Using Paper component
|
|
546
|
+
<Paper className="p-4">
|
|
547
|
+
<CollectionPanel path="tasks" title={false} />
|
|
548
|
+
</Paper>
|
|
549
|
+
|
|
550
|
+
// Or with cls and paperMixin
|
|
551
|
+
<div className={cls(paperMixin, "p-4")}>
|
|
552
|
+
{/* content */}
|
|
553
|
+
</div>
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### Panel Anti-Patterns
|
|
557
|
+
|
|
558
|
+
```tsx
|
|
559
|
+
// ❌ WRONG: Custom panel styling
|
|
560
|
+
<div className="p-6 rounded-2xl border bg-white dark:bg-surface-900/50 backdrop-blur-md shadow-sm">
|
|
561
|
+
|
|
562
|
+
// ✅ CORRECT: Use Paper or paperMixin
|
|
563
|
+
<Paper className="p-4">
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## 14. Forms
|
|
569
|
+
|
|
570
|
+
Form inputs should use `@rebasepro/ui` components directly without excessive class overrides:
|
|
571
|
+
|
|
572
|
+
```tsx
|
|
573
|
+
// ✅ CORRECT
|
|
574
|
+
<TextField label="Client Name" value={name} onChange={e => setName(e.target.value)} />
|
|
575
|
+
<Select label="Package" value={pkg} onValueChange={setPkg}>
|
|
576
|
+
<SelectItem value="basic">Basic</SelectItem>
|
|
577
|
+
<SelectItem value="premium">Premium</SelectItem>
|
|
578
|
+
</Select>
|
|
579
|
+
|
|
580
|
+
// ❌ WRONG: Overriding input styling
|
|
581
|
+
<TextField className="rounded-lg border-surface-200 dark:border-surface-850 focus:border-violet-500 focus:ring-violet-500" />
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## 15. Responsive Layout Rules
|
|
587
|
+
|
|
588
|
+
1. **Container-aware, not viewport-aware**: Use `ResizeObserver` on the actual container, NOT media queries, for adaptive layout in split panels.
|
|
589
|
+
2. **Refs that observers depend on MUST render unconditionally.**
|
|
590
|
+
3. **One component, adaptive rendering**: Prefer a single component that adapts to its container width.
|
|
591
|
+
|
|
592
|
+
---
|
|
593
|
+
|
|
594
|
+
## 16. Font Stack
|
|
595
|
+
|
|
596
|
+
```css
|
|
597
|
+
--font-sans: 'Rubik', 'Roboto', 'Helvetica', 'Arial', sans-serif;
|
|
598
|
+
--font-headers: 'Rubik', 'Roboto', 'Helvetica', 'Arial', sans-serif;
|
|
599
|
+
--font-mono: 'JetBrains Mono', 'Space Mono', 'Lucida Console', monospace;
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
Ensure `@fontsource/rubik` and `@fontsource/jetbrains-mono` are imported in the entry file.
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## 17. Dark Mode
|
|
607
|
+
|
|
608
|
+
- Rebase uses `dark:` variant for dark mode classes.
|
|
609
|
+
- Custom variant: `@custom-variant dark (&:where(.dark, .dark *))`.
|
|
610
|
+
- **Always provide dark mode equivalents** for any custom styling.
|
|
611
|
+
- Standard dark mode backgrounds:
|
|
612
|
+
- Page: `dark:bg-surface-800`
|
|
613
|
+
- Cards: `dark:bg-surface-900`
|
|
614
|
+
- Borders: `dark:border-surface-700`
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
## 18. CSS-Only Rules (index.css)
|
|
619
|
+
|
|
620
|
+
The project CSS file should:
|
|
621
|
+
|
|
622
|
+
1. Import Tailwind and the UI kit CSS:
|
|
623
|
+
```css
|
|
624
|
+
@import "tailwindcss";
|
|
625
|
+
@import "@rebasepro/ui/index.css" layer(base);
|
|
626
|
+
```
|
|
627
|
+
2. Source the UI kit JS for Tailwind scanning:
|
|
628
|
+
```css
|
|
629
|
+
@source "../node_modules/@rebasepro/*/dist/**/*.js";
|
|
630
|
+
```
|
|
631
|
+
3. Define the dark mode variant:
|
|
632
|
+
```css
|
|
633
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
634
|
+
```
|
|
635
|
+
4. **Do NOT add custom utility classes** that duplicate what the UI kit provides (e.g., `glass-card`, `glass-panel`, custom shimmer animations).
|
|
636
|
+
5. **Do NOT add custom color tokens** that conflict with the UI kit's token scale.
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
## 19. Complete Anti-Pattern Checklist
|
|
641
|
+
|
|
642
|
+
Before submitting UI code, verify you have NONE of these:
|
|
643
|
+
|
|
644
|
+
| # | Anti-Pattern | Fix |
|
|
645
|
+
|---|------------------------------------------------------|--------------------------------------------------------|
|
|
646
|
+
| 1 | Raw HTML (`<h1>`, `<p>`, `<span>`, `<label>`) | Use `Typography` with appropriate variant |
|
|
647
|
+
| 2 | Hardcoded border colors | Use `defaultBorderMixin` |
|
|
648
|
+
| 3 | `as any` type casts on component props | Use correct prop values from component types |
|
|
649
|
+
| 4 | Template literal class concatenation | Use `cls()` from `@rebasepro/ui` |
|
|
650
|
+
| 5 | Gradient text on headings | Remove gradient, use `Typography` color prop |
|
|
651
|
+
| 6 | Glassmorphism (`backdrop-blur`, translucent bg) | Use `Card`, `Paper`, or solid backgrounds |
|
|
652
|
+
| 7 | `rounded-2xl` on cards/panels | Use `Card`/`Paper` which use `rounded-lg` |
|
|
653
|
+
| 8 | Colored gradient or primary-tinted icon backgrounds | Use plain `text-surface-400 dark:text-surface-500` |
|
|
654
|
+
| 9 | `hover:-translate-y-1` or `hover:scale-110` | Don't lift or scale on hover |
|
|
655
|
+
| 10| Custom shadow colors (`shadow-blue-500/20`) | No shadows on hover — use `hover:bg-surface-50` only |
|
|
656
|
+
| 11| `animate-bounce`, `animate-pulse` on alerts | Use static `Alert` component |
|
|
657
|
+
| 12| Custom CSS classes like `glass-card`, `shimmer-shine` | Remove and use standard UI kit patterns |
|
|
658
|
+
| 13| `font-extrabold` overrides on Typography | Let the variant handle font weight |
|
|
659
|
+
| 14| `text-[10px]`, `tracking-widest` custom overrides | Use `Typography variant="caption"` |
|
|
660
|
+
| 15| Per-card colored themes (blue card, green card, etc.) | Use uniform `Card` with plain muted icons |
|
|
661
|
+
| 16| `dark:bg-surface-950` for page background | Use `dark:bg-surface-800` |
|
|
662
|
+
| 17| Arbitrary Tailwind colors (`text-violet-600`, etc.) | Use design token colors |
|
|
663
|
+
| 18| `hover:shadow-md`, `hover:ring-1` on cards | Use `hover:bg-surface-50 dark:hover:bg-surface-800` |
|
|
664
|
+
| 19| `active:scale-[0.98]` on buttons | Buttons don't scale — use `transition-colors` only |
|
|
665
|
+
| 20| `border-*/60` opacity on borders | Use solid borders via `defaultBorderMixin` |
|
|
666
|
+
| 21| `bg-primary/8` icon background pills | Icons are plain color, no background container |
|
|
667
|
+
| 22| Decorative arrow icons on cards | Cards are the affordance — no `ArrowRightIcon` needed |
|
|
668
|
+
|
|
669
|
+
> **IMPORTANT FOR AGENTS:** The internal `EntityCard` component (used for card-view in collection grids) uses `hover:-translate-y-0.5` and `hover:shadow-lg`, and the Studio home page uses per-section colored icons. These are **intentional exceptions** in Rebase's own codebase for specific contexts (rich media cards with thumbnails and the Studio admin landing page). **Do NOT copy these patterns** into custom views, home pages, or dashboard cards — they are reserved for these specific internal components.
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
673
|
+
## 20. Reference Components
|
|
674
|
+
|
|
675
|
+
When building new views, always reference these existing implementations:
|
|
676
|
+
|
|
677
|
+
| Component | Location | What it demonstrates |
|
|
678
|
+
|----------------------|-------------------------------------------------------------------|--------------------------------|
|
|
679
|
+
| `NavigationCard` | `packages/admin/src/components/HomePage/NavigationCard.tsx` | Card pattern, plain icon treatment |
|
|
680
|
+
| `SmallNavigationCard`| `packages/admin/src/components/HomePage/SmallNavigationCard.tsx` | Compact card with mixins |
|
|
681
|
+
| `ContentHomePage` | `packages/admin/src/components/HomePage/ContentHomePage.tsx` | Page layout, Container usage |
|
|
682
|
+
| `NavigationGroup` | `packages/admin/src/components/HomePage/NavigationGroup.tsx` | Section headers, grouping |
|
|
683
|
+
|
|
684
|
+
---
|
|
685
|
+
|
|
686
|
+
## 21. Summary: The Design Philosophy
|
|
687
|
+
|
|
688
|
+
1. **Near-zero chrome.** The UI disappears so content is the interface. No decorative elements, no visual noise — only what serves the data.
|
|
689
|
+
2. **Data-first.** Every element exists to present or interact with data. If it doesn't serve the data, remove it.
|
|
690
|
+
3. **Quiet sophistication.** Hierarchy comes from subtle weight and size differentiation (semibold headings, medium subtitles, regular body) rather than dramatic size jumps or color contrasts.
|
|
691
|
+
4. **Monochromatic hierarchy.** One accent color (`primary` blue) used sparingly at low opacity. Icons are plain muted grays. No rainbow gradients, no per-card color themes.
|
|
692
|
+
5. **Content density.** Smaller type, tighter spacing, more data per viewport. The compressed typography scale (`sm` body text, `xs` captions, `[11px]` fine print) maximizes information density without sacrificing readability.
|