@snow-labs/brutal-ui 0.2.1 → 0.3.0

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.
Files changed (2) hide show
  1. package/AGENTS.md +1244 -0
  2. package/package.json +3 -2
package/AGENTS.md ADDED
@@ -0,0 +1,1244 @@
1
+ # AGENTS.md — @snow-labs/brutal-ui
2
+
3
+ > **Read this first.** This is the complete design system reference for AI agents building landing pages, dashboards, and apps with `@snow-labs/brutal-ui`. Every component, every prop, every pattern — nothing else needed.
4
+
5
+ ## What is brutal-ui?
6
+
7
+ A soft brutalist design system — bold 2px borders, hard offset shadows, dynamic brand colors. Built on shadcn/ui patterns + Tailwind v4 + @base-ui/react primitives. One npm install gives you 40+ UI primitives, 15 landing page sections, 9 dashboard widgets, 5 data views, and 3 full-page templates.
8
+
9
+ ```
10
+ npm install @snow-labs/brutal-ui
11
+ ```
12
+
13
+ Peer dependencies: `react >= 18`, `react-dom >= 18`, `tailwindcss >= 4`, `@base-ui/react >= 1.0.0`
14
+
15
+ Optional peers (install only if using those components): `framer-motion`, `@tanstack/react-table`, `@atlaskit/pragmatic-drag-and-drop`, `react-masonry-css`, `react-big-calendar`, `recharts`, `react-dropzone`
16
+
17
+ ---
18
+
19
+ ## 1. Setup (CRITICAL — do this first)
20
+
21
+ ### globals.css
22
+
23
+ ```css
24
+ @import "tailwindcss";
25
+ @import "tw-animate-css";
26
+ @import "@snow-labs/brutal-ui/theme.css";
27
+
28
+ /* REQUIRED: Tell Tailwind v4 to scan brutal-ui dist for class names */
29
+ @source "../../../node_modules/@snow-labs/brutal-ui/dist";
30
+ ```
31
+
32
+ The `@source` path is relative to your CSS file. Point it at the brutal-ui `dist/` folder. Without it, Tailwind v4 won't generate utility classes used inside brutal-ui components — **buttons will have no padding, cards no borders, nothing will look right.**
33
+
34
+ ### next.config.ts (Next.js)
35
+
36
+ ```ts
37
+ const nextConfig: NextConfig = {
38
+ transpilePackages: ["@snow-labs/brutal-ui"],
39
+ };
40
+ ```
41
+
42
+ ### Brand override (optional)
43
+
44
+ Override brutal-ui's default yellow brand with your product's color:
45
+
46
+ ```css
47
+ :root {
48
+ --brand: 0 72% 51%; /* your brand hue sat light (HSL without hsl()) */
49
+ --brand-foreground: 0 0% 100%; /* text on brand bg */
50
+ --brand-muted: 0 50% 95%; /* light tint for muted sections */
51
+ }
52
+ ```
53
+
54
+ Or use a built-in theme via `data-theme` attribute on any parent:
55
+
56
+ ```html
57
+ <html data-theme="domino">
58
+ ```
59
+
60
+ Built-in themes: `snowlabs` (blue), `versionpill` (green), `domino` (teal), `unsent` (purple), `bookshelves` (orange), `bannerbear` (yellow), `coral` (coral), `lavender` (lavender), `mint` (mint), `slate` (gray), `letterbox` (red).
61
+
62
+ ---
63
+
64
+ ## 2. Design Rules
65
+
66
+ 1. **Use brutal-ui section components for landing pages.** `BrutalHero`, `BrutalFeatureGrid`, `PricingTable`, `BrutalCTA`, `BrutalFooter` handle complete sections. Don't rebuild what exists.
67
+ 2. **Use `Button` component, never custom styled links.** Button has a `render` prop: `<Button render={<Link href="/" />}>`.
68
+ 3. **Use semantic colors only.** `bg-brand`, `bg-cta`, `text-muted-foreground` — never raw hex, rgb, or hsl values.
69
+ 4. **Use CSS utility classes.** `brutal-border`, `brutal-shadow`, `brutal-hover` — never hand-code borders or shadows.
70
+ 5. **Section colors are semantic.** Only: `"white"`, `"black"`, `"brand"`, `"brand-muted"`, `"cta"`. No gray, cream, or blue.
71
+ 6. **Paired buttons use the same size.** When primary + secondary buttons appear together (hero CTA + "Learn more"), both MUST use the same `size` prop (typically `"xl"`). Never mix sizes.
72
+ 7. **Mobile CTA buttons are full-width.** Use `className="w-full sm:w-auto"` on buttons and wrap in `flex-col gap-4 sm:flex-row` containers. Buttons stack vertically on mobile, inline on desktop.
73
+ 8. **All imports come from the root.** `import { Button, BrutalHero, AppShell } from "@snow-labs/brutal-ui"` — one import path.
74
+ 9. **Typography uses brutal classes.** `brutal-h1` through `brutal-h4`, `brutal-body`, `brutal-label` — never ad-hoc font sizes.
75
+ 10. **Custom elements use the app's CSS prefix.** If your app is "Acme", prefix custom classes `acme-*`. Never pollute the brutal-ui namespace.
76
+
77
+ ---
78
+
79
+ ## 3. Theme Tokens
80
+
81
+ All values are HSL triplets (without `hsl()` wrapper). Override any in `:root {}`.
82
+
83
+ ### Core palette
84
+
85
+ | Token | Default | Purpose |
86
+ |-------|---------|---------|
87
+ | `--background` | `0 0% 100%` | Page background (white) |
88
+ | `--foreground` | `0 0% 5%` | Text color (near black) |
89
+ | `--primary` | `0 0% 5%` | Default button bg (black) |
90
+ | `--primary-foreground` | `0 0% 100%` | Default button text (white) |
91
+ | `--secondary` | `0 0% 96%` | Light gray bg |
92
+ | `--muted` | `0 0% 96%` | Muted bg |
93
+ | `--muted-foreground` | `0 0% 45%` | Muted text |
94
+ | `--destructive` | `0 84% 60%` | Error/delete red |
95
+ | `--border` | `0 0% 0%` | Border color (black) |
96
+ | `--radius` | `6px` | Base border radius |
97
+
98
+ ### Brand tokens (override these per product)
99
+
100
+ | Token | Default | Purpose |
101
+ |-------|---------|---------|
102
+ | `--brand` | `48 96% 53%` | Primary brand color (yellow) |
103
+ | `--brand-foreground` | `0 0% 0%` | Text on brand bg |
104
+ | `--brand-muted` | `48 80% 92%` | Light tinted brand bg |
105
+ | `--cta` | `155 60% 65%` | CTA button color (mint green) |
106
+ | `--cta-foreground` | `0 0% 0%` | Text on CTA bg |
107
+
108
+ ### Shadow tokens
109
+
110
+ | Token | Value |
111
+ |-------|-------|
112
+ | `--shadow-brutal` | `4px 4px 0px 0px hsl(0 0% 0%)` |
113
+ | `--shadow-brutal-sm` | `2px 2px 0px 0px hsl(0 0% 0%)` |
114
+ | `--shadow-brutal-lg` | `6px 6px 0px 0px hsl(0 0% 0%)` |
115
+ | `--shadow-brutal-xl` | `8px 8px 0px 0px hsl(0 0% 0%)` |
116
+ | `--shadow-brutal-brand` | `4px 4px 0px 0px hsl(var(--brand))` |
117
+
118
+ ---
119
+
120
+ ## 4. Typography Classes
121
+
122
+ | Class | Size | Weight | Notes |
123
+ |-------|------|--------|-------|
124
+ | `brutal-display` | clamp(3rem, 8vw, 6rem) | 900 | Hero headlines, one per page |
125
+ | `brutal-h1` | clamp(2.25rem, 6vw, 3.75rem) | 900 | Section headlines |
126
+ | `brutal-h2` | clamp(1.875rem, 5vw, 3rem) | 800 | Sub-headlines |
127
+ | `brutal-h3` | clamp(1.5rem, 4vw, 1.875rem) | 700 | Card titles |
128
+ | `brutal-h4` | clamp(1.25rem, 3vw, 1.5rem) | 700 | Small headings |
129
+ | `brutal-body` | clamp(1rem, 2vw, 1.125rem) | normal | Body text, line-height 1.6 |
130
+ | `brutal-body-lg` | clamp(1.125rem, 2.5vw, 1.25rem) | normal | Hero descriptions |
131
+ | `brutal-label` | 0.75rem | 600 | Monospace, uppercase, tracked wide |
132
+ | `brutal-caption` | 0.875rem | normal | Muted helper text |
133
+
134
+ ---
135
+
136
+ ## 5. CSS Utility Classes
137
+
138
+ ### Borders & shadows
139
+
140
+ | Class | Effect |
141
+ |-------|--------|
142
+ | `brutal-border` | 2px solid black border |
143
+ | `brutal-border-t` | Top border only |
144
+ | `brutal-border-b` | Bottom border only |
145
+ | `brutal-shadow` | 4px offset shadow |
146
+ | `brutal-shadow-sm` | 2px offset shadow |
147
+ | `brutal-shadow-lg` | 6px offset shadow |
148
+ | `brutal-hover` | Hover: lift -2px + shadow grows. Active: push +1px + shadow shrinks |
149
+
150
+ ### Background patterns
151
+
152
+ | Class | Effect |
153
+ |-------|--------|
154
+ | `brutal-dots` | Radial dot pattern, 20px spacing |
155
+ | `brutal-stripes` | Diagonal stripes, 8px pitch |
156
+ | `brutal-grain` | SVG fractal noise grain |
157
+ | `brutal-crosshatch` | Crossed diagonal lines |
158
+ | `brutal-grid-dots` | Grid dots, 16px spacing |
159
+ | `brutal-gradient-mesh` | Radial brand gradient mesh |
160
+
161
+ ### Color utilities
162
+
163
+ | Class | Effect |
164
+ |-------|--------|
165
+ | `bg-brand` | Brand bg + brand-foreground text |
166
+ | `bg-brand-muted` | Light brand tint bg |
167
+ | `bg-cta` | CTA bg + cta-foreground text |
168
+ | `text-brand` | Brand color text |
169
+ | `text-cta` | CTA color text |
170
+
171
+ ### Layout
172
+
173
+ | Class | Effect |
174
+ |-------|--------|
175
+ | `brutal-section` | Full width, padding 5rem 1.5rem |
176
+ | `brutal-section-sm` | Full width, padding 3rem 1.5rem |
177
+ | `brutal-container` | Max 72rem, centered |
178
+ | `brutal-container-sm` | Max 56rem, centered |
179
+ | `brutal-container-lg` | Max 80rem, centered |
180
+
181
+ ---
182
+
183
+ ## 6. Component Reference
184
+
185
+ All components import from the root: `import { ComponentName } from "@snow-labs/brutal-ui"`
186
+
187
+ ---
188
+
189
+ ### UI Primitives
190
+
191
+ #### Button
192
+
193
+ ```tsx
194
+ import { Button } from "@snow-labs/brutal-ui";
195
+
196
+ <Button variant="brand" size="xl">Get Started</Button>
197
+ <Button variant="outline" size="xl" render={<a href="#features" />}>Learn More</Button>
198
+ <Button variant="cta" size="xl" className="w-full sm:w-auto" render={<Link href="/signup" />}>Sign Up</Button>
199
+ ```
200
+
201
+ | Prop | Type | Default |
202
+ |------|------|---------|
203
+ | `variant` | `"default"` \| `"cta"` \| `"brand"` \| `"outline"` \| `"secondary"` \| `"ghost"` \| `"link"` \| `"destructive"` \| `"nav"` | `"default"` |
204
+ | `size` | `"xs"` \| `"sm"` \| `"default"` \| `"lg"` \| `"xl"` \| `"icon"` \| `"icon-sm"` \| `"icon-lg"` | `"default"` |
205
+ | `render` | `ReactElement` | — |
206
+ | `disabled` | `boolean` | `false` |
207
+ | `className` | `string` | — |
208
+
209
+ Size reference: `xs`=h-7, `sm`=h-8, `default`=h-10, `lg`=h-12, `xl`=h-14, `icon`=size-10
210
+
211
+ Variant colors: `default`=black, `cta`=mint, `brand`=brand color, `outline`=white w/ black border, `nav`=thin border bg-background
212
+
213
+ #### Card
214
+
215
+ ```tsx
216
+ import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, CardAction } from "@snow-labs/brutal-ui";
217
+
218
+ <Card>
219
+ <CardHeader>
220
+ <CardTitle>Title</CardTitle>
221
+ <CardDescription>Description</CardDescription>
222
+ <CardAction><Button size="sm">Edit</Button></CardAction>
223
+ </CardHeader>
224
+ <CardContent>Content here</CardContent>
225
+ <CardFooter>Footer</CardFooter>
226
+ </Card>
227
+ ```
228
+
229
+ Cards have brutal border, white bg, offset shadow, and hover lift effect.
230
+
231
+ #### Badge
232
+
233
+ ```tsx
234
+ import { Badge } from "@snow-labs/brutal-ui";
235
+
236
+ <Badge variant="brand">New</Badge>
237
+ ```
238
+
239
+ Variants: `"default"` | `"secondary"` | `"brand"` | `"cta"` | `"outline"` | `"destructive"` | `"ghost"`
240
+
241
+ #### Input
242
+
243
+ ```tsx
244
+ import { Input } from "@snow-labs/brutal-ui";
245
+
246
+ <Input type="email" placeholder="you@example.com" />
247
+ ```
248
+
249
+ Brutal border, shadow-sm, focus: shadow grows + lift. Supports all standard input props.
250
+
251
+ #### Textarea
252
+
253
+ ```tsx
254
+ import { Textarea } from "@snow-labs/brutal-ui";
255
+
256
+ <Textarea placeholder="Write something..." />
257
+ ```
258
+
259
+ Auto-expands with content via `field-sizing: content`.
260
+
261
+ #### Select
262
+
263
+ ```tsx
264
+ import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@snow-labs/brutal-ui";
265
+
266
+ <Select>
267
+ <SelectTrigger><SelectValue placeholder="Pick one" /></SelectTrigger>
268
+ <SelectContent>
269
+ <SelectItem value="a">Option A</SelectItem>
270
+ <SelectItem value="b">Option B</SelectItem>
271
+ </SelectContent>
272
+ </Select>
273
+ ```
274
+
275
+ | Prop (Trigger) | Type | Default |
276
+ |------|------|---------|
277
+ | `size` | `"sm"` \| `"default"` | `"default"` |
278
+
279
+ | Prop (Content) | Type | Default |
280
+ |------|------|---------|
281
+ | `side` | `"top"` \| `"bottom"` \| `"left"` \| `"right"` | `"bottom"` |
282
+ | `align` | `"center"` \| `"start"` \| `"end"` | `"center"` |
283
+
284
+ #### Dialog
285
+
286
+ ```tsx
287
+ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@snow-labs/brutal-ui";
288
+
289
+ <Dialog>
290
+ <DialogTrigger render={<Button />}>Open</DialogTrigger>
291
+ <DialogContent showCloseButton={true}>
292
+ <DialogHeader>
293
+ <DialogTitle>Title</DialogTitle>
294
+ <DialogDescription>Description</DialogDescription>
295
+ </DialogHeader>
296
+ {/* content */}
297
+ <DialogFooter>
298
+ <Button variant="outline">Cancel</Button>
299
+ <Button variant="brand">Confirm</Button>
300
+ </DialogFooter>
301
+ </DialogContent>
302
+ </Dialog>
303
+ ```
304
+
305
+ #### Tabs
306
+
307
+ ```tsx
308
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@snow-labs/brutal-ui";
309
+
310
+ <Tabs defaultValue="tab1">
311
+ <TabsList variant="default"> {/* "default" | "line" */}
312
+ <TabsTrigger value="tab1">Tab 1</TabsTrigger>
313
+ <TabsTrigger value="tab2">Tab 2</TabsTrigger>
314
+ </TabsList>
315
+ <TabsContent value="tab1">Content 1</TabsContent>
316
+ <TabsContent value="tab2">Content 2</TabsContent>
317
+ </Tabs>
318
+ ```
319
+
320
+ Active tab: brand bg + brand-foreground text + shadow-sm.
321
+
322
+ #### Other UI Primitives
323
+
324
+ All follow shadcn/ui composition patterns with brutal styling:
325
+
326
+ | Component | Key exports |
327
+ |-----------|-------------|
328
+ | Accordion | `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent` |
329
+ | Alert | `Alert`, `AlertTitle`, `AlertDescription` |
330
+ | Avatar | `Avatar`, `AvatarImage`, `AvatarFallback` |
331
+ | Breadcrumb | `Breadcrumb`, `BreadcrumbList`, `BreadcrumbItem`, `BreadcrumbLink`, `BreadcrumbPage`, `BreadcrumbSeparator` |
332
+ | Checkbox | `Checkbox` — size-5, brand bg when checked |
333
+ | Collapsible | `Collapsible`, `CollapsibleTrigger`, `CollapsibleContent` |
334
+ | Command | `Command`, `CommandDialog`, `CommandInput`, `CommandList`, `CommandGroup`, `CommandItem` |
335
+ | Context Menu | `ContextMenu`, `ContextMenuTrigger`, `ContextMenuContent`, `ContextMenuItem` + sub/radio/checkbox variants |
336
+ | Drawer | `Drawer`, `DrawerTrigger`, `DrawerContent`, `DrawerHeader`, `DrawerFooter` — side: top/right/bottom/left |
337
+ | Dropdown Menu | `DropdownMenu`, `DropdownMenuTrigger`, `DropdownMenuContent`, `DropdownMenuItem` + sub/radio/checkbox variants |
338
+ | Hover Card | `HoverCard`, `HoverCardTrigger`, `HoverCardContent` |
339
+ | Input Group | `InputGroup`, `InputGroupInput`, `InputGroupAddon`, `InputGroupButton` |
340
+ | Label | `Label` — text-sm, font-bold |
341
+ | Menubar | `Menubar`, `MenubarMenu`, `MenubarTrigger`, `MenubarContent`, `MenubarItem` |
342
+ | Navigation Menu | `NavigationMenu`, `NavigationMenuList`, `NavigationMenuItem`, `NavigationMenuTrigger`, `NavigationMenuContent`, `NavigationMenuLink` |
343
+ | Pagination | `Pagination`, `PaginationContent`, `PaginationItem`, `PaginationLink`, `PaginationPrevious`, `PaginationNext` |
344
+ | Popover | `Popover`, `PopoverTrigger`, `PopoverContent` |
345
+ | Progress | `Progress` — brutal border track, brand fill |
346
+ | Radio Group | `RadioGroup`, `RadioGroupItem` — size-5, brutal border |
347
+ | Scroll Area | `ScrollArea`, `ScrollBar` |
348
+ | Separator | `Separator` — h-0.5, bg-foreground |
349
+ | Sheet | `Sheet`, `SheetTrigger`, `SheetContent` — side: top/right/bottom/left |
350
+ | Skeleton | `Skeleton` — animate-pulse, bg-muted |
351
+ | Slider | `Slider` — brutal border track, brand fill, size-5 thumb |
352
+ | Switch | `Switch` — size: "sm" \| "default" |
353
+ | Toggle | `Toggle` — variant: "default" \| "outline" |
354
+ | Toggle Group | `ToggleGroup`, `ToggleGroupItem` — variant, size, spacing, orientation |
355
+ | Tooltip | `Tooltip`, `TooltipTrigger`, `TooltipContent`, `TooltipProvider` — black bg, white text, brutal border |
356
+
357
+ ---
358
+
359
+ ### Landing Page Components
360
+
361
+ #### BrutalNav
362
+
363
+ ```tsx
364
+ import { BrutalNav } from "@snow-labs/brutal-ui";
365
+
366
+ <BrutalNav
367
+ variant="transparent"
368
+ logo={<span className="font-black text-lg">Acme</span>}
369
+ links={[
370
+ { label: "Features", href: "#features" },
371
+ { label: "Pricing", href: "#pricing", badge: "NEW" },
372
+ ]}
373
+ ctaText="Start Free"
374
+ ctaHref="/signup"
375
+ />
376
+ ```
377
+
378
+ | Prop | Type | Default |
379
+ |------|------|---------|
380
+ | `variant` | `"solid"` \| `"transparent"` \| `"floating-pill"` | `"solid"` |
381
+ | `logo` | `ReactNode` | required |
382
+ | `links` | `{ label, href, badge?, active? }[]` | required |
383
+ | `ctaText` | `string` | `"Sign In"` |
384
+ | `ctaHref` | `string` | `"/admin"` |
385
+
386
+ **Variants:**
387
+ - `solid` — Sticky, brand bg, border-bottom. Best for light pages.
388
+ - `transparent` — Fixed, invisible on load, gains bg + blur on scroll (>20px). Best for dark hero backgrounds.
389
+ - `floating-pill` — Fixed pill with rounded corners, brutal border, white bg. Best for playful brands.
390
+
391
+ Mobile: Auto hamburger menu → Sheet drawer on right.
392
+
393
+ #### BrutalHero
394
+
395
+ ```tsx
396
+ import { BrutalHero } from "@snow-labs/brutal-ui";
397
+
398
+ <BrutalHero
399
+ variant="centered"
400
+ color="brand"
401
+ pattern="grid-dots"
402
+ badge="AI-Powered"
403
+ badgePosition="above"
404
+ headline="Ship faster than ever."
405
+ description="Build products in days, not months."
406
+ ctaText="Get Started"
407
+ ctaHref="/signup"
408
+ ctaVariant="cta"
409
+ secondaryText="Learn more"
410
+ secondaryHref="#features"
411
+ proof="Free forever. No credit card."
412
+ visual={<img src="/hero.png" alt="Product" />}
413
+ />
414
+ ```
415
+
416
+ | Prop | Type | Default |
417
+ |------|------|---------|
418
+ | `variant` | `"split"` \| `"centered"` \| `"overlap"` \| `"asymmetric"` | `"split"` |
419
+ | `color` | `"white"` \| `"brand"` \| `"brand-muted"` \| `"black"` | `"brand"` |
420
+ | `pattern` | `SectionPattern` | — |
421
+ | `badge` | `string` | — |
422
+ | `badgePosition` | `"above"` \| `"inline"` \| `"floating"` | `"above"` |
423
+ | `headline` | `string` | required |
424
+ | `description` | `string` | required |
425
+ | `ctaText` | `string` | required |
426
+ | `ctaHref` | `string` | — |
427
+ | `ctaVariant` | `"cta"` \| `"brand"` \| `"default"` | `"cta"` |
428
+ | `secondaryText` | `string` | — |
429
+ | `secondaryHref` | `string` | — |
430
+ | `visual` | `ReactNode` | — |
431
+ | `proof` | `string` | — |
432
+
433
+ **Variants:**
434
+ - `split` — 2-column grid: text left, visual right
435
+ - `centered` — Center-aligned, max-w-4xl
436
+ - `overlap` — Visual at 20% opacity behind text
437
+ - `asymmetric` — 3fr/2fr grid, visual rotated -2deg
438
+
439
+ `headline` is a string, not ReactNode. For JSX headlines, build a custom section with `BrutalSection`.
440
+
441
+ #### BrutalSection
442
+
443
+ ```tsx
444
+ import { BrutalSection } from "@snow-labs/brutal-ui";
445
+
446
+ <BrutalSection color="brand-muted" pattern="dots" padding="lg" containerSize="sm">
447
+ <h2 className="brutal-h2 mb-4">Custom Section</h2>
448
+ <p className="brutal-body">Anything goes here.</p>
449
+ </BrutalSection>
450
+ ```
451
+
452
+ | Prop | Type | Default |
453
+ |------|------|---------|
454
+ | `color` | `"white"` \| `"brand"` \| `"brand-muted"` \| `"black"` \| `"cta"` | `"white"` |
455
+ | `pattern` | `"dots"` \| `"stripes"` \| `"noise"` \| `"grain"` \| `"crosshatch"` \| `"grid-dots"` \| `"gradient-mesh"` \| `"none"` | — |
456
+ | `padding` | `"sm"` \| `"default"` \| `"lg"` | `"default"` |
457
+ | `containerSize` | `"sm"` \| `"default"` \| `"lg"` | `"default"` |
458
+
459
+ Use this as a wrapper when building custom sections with your own layout.
460
+
461
+ #### SectionDivider
462
+
463
+ ```tsx
464
+ import { SectionDivider } from "@snow-labs/brutal-ui";
465
+
466
+ <SectionDivider
467
+ variant="wave"
468
+ from="hsl(var(--brand))"
469
+ to="hsl(var(--background))"
470
+ flip={false}
471
+ layers={true}
472
+ />
473
+ ```
474
+
475
+ | Prop | Type | Default |
476
+ |------|------|---------|
477
+ | `variant` | `"wave"` \| `"jagged"` \| `"curve"` \| `"castle"` \| `"torn-paper"` \| `"brush-stroke"` \| `"geometric"` \| `"blob"` \| `"diagonal"` \| `"zigzag"` \| `"hand-drawn"` | `"wave"` |
478
+ | `from` | `string` | — |
479
+ | `to` | `string` | — |
480
+ | `flip` | `boolean` | `false` |
481
+ | `layers` | `boolean` | `false` |
482
+
483
+ SVG divider between sections. Height is responsive: `clamp(40px, 6vw, 80px)`. Use `from`/`to` colors matching the sections above/below.
484
+
485
+ #### BrutalFeatureGrid
486
+
487
+ ```tsx
488
+ import { BrutalFeatureGrid } from "@snow-labs/brutal-ui";
489
+
490
+ <BrutalFeatureGrid
491
+ variant="icon-left"
492
+ badge="Features"
493
+ headline="Everything you need."
494
+ description="Optional subtitle."
495
+ columns={2}
496
+ color="white"
497
+ features={[
498
+ { icon: <Zap className="size-5" />, title: "Fast", description: "Ships in days." },
499
+ { icon: <Shield className="size-5" />, title: "Secure", description: "Enterprise-grade." },
500
+ ]}
501
+ />
502
+ ```
503
+
504
+ | Prop | Type | Default |
505
+ |------|------|---------|
506
+ | `variant` | `"icon-top"` \| `"icon-left"` \| `"numbered"` \| `"bento"` | `"icon-top"` |
507
+ | `columns` | `2` \| `3` \| `4` | `3` |
508
+ | `color` | `"white"` \| `"brand"` \| `"brand-muted"` \| `"black"` | — |
509
+ | `badge` | `string` | — |
510
+ | `headline` | `string` | required |
511
+ | `description` | `string` | — |
512
+ | `features` | `{ icon?, title, description, featured?, stat? }[]` | required |
513
+
514
+ **Variants:**
515
+ - `icon-top` — Card with icon centered above title
516
+ - `icon-left` — Icon left with colored left border accent
517
+ - `numbered` — Large number (01, 02...) at 20% opacity in card
518
+ - `bento` — `featured: true` cards span 2 cols + row-span-2
519
+
520
+ #### PricingTable
521
+
522
+ ```tsx
523
+ import { PricingTable } from "@snow-labs/brutal-ui";
524
+
525
+ <PricingTable
526
+ badge="Pricing"
527
+ headline="Simple pricing."
528
+ billingToggle={true}
529
+ color="white"
530
+ popularIndex={1}
531
+ tiers={[
532
+ {
533
+ name: "Free",
534
+ description: "For individuals.",
535
+ price: { monthly: 0, annual: 0 },
536
+ features: ["5 projects", "Basic support"],
537
+ ctaText: "Get started",
538
+ ctaHref: "/signup",
539
+ ctaVariant: "outline",
540
+ },
541
+ {
542
+ name: "Pro",
543
+ description: "For teams.",
544
+ price: { monthly: 19, annual: 190 },
545
+ features: ["Unlimited projects", "Priority support"],
546
+ ctaText: "Start trial",
547
+ ctaHref: "/signup?plan=pro",
548
+ ctaVariant: "cta",
549
+ },
550
+ ]}
551
+ />
552
+ ```
553
+
554
+ | Prop | Type | Default |
555
+ |------|------|---------|
556
+ | `badge` | `string` | — |
557
+ | `headline` | `string` | — |
558
+ | `description` | `string` | — |
559
+ | `tiers` | `PricingTier[]` | required |
560
+ | `popularIndex` | `number` | — |
561
+ | `billingToggle` | `boolean` | `true` |
562
+ | `color` | `"white"` \| `"black"` | — |
563
+
564
+ Popular tier: scale-105, brand border, ring-2, "Popular" badge. Features rendered with green checkmarks.
565
+
566
+ #### BrutalTestimonials
567
+
568
+ ```tsx
569
+ import { BrutalTestimonials } from "@snow-labs/brutal-ui";
570
+
571
+ <BrutalTestimonials
572
+ variant="wall-of-love"
573
+ badge="Testimonials"
574
+ headline="Loved by teams."
575
+ color="brand-muted"
576
+ testimonials={[
577
+ { name: "Jane", handle: "@jane", text: "Amazing product!", rating: 5, role: "CTO", company: "Acme" },
578
+ ]}
579
+ />
580
+ ```
581
+
582
+ | Prop | Type | Default |
583
+ |------|------|---------|
584
+ | `variant` | `"masonry"` \| `"featured-grid"` \| `"carousel"` \| `"wall-of-love"` | `"masonry"` |
585
+ | `color` | `SectionColor` | `"brand-muted"` |
586
+ | `pattern` | `SectionPattern` | — |
587
+ | `badge` | `string` | — |
588
+ | `headline` | `string` | — |
589
+ | `testimonials` | `{ name, handle?, avatar?, text, role?, company?, rating?, featured? }[]` | required |
590
+
591
+ **Variants:**
592
+ - `masonry` — CSS multi-column, 1→2→3 cols responsive
593
+ - `featured-grid` — Large `featured: true` card left (row-span-2), smaller cards right
594
+ - `carousel` — Horizontal snap scroll, cards w-80
595
+ - `wall-of-love` — Grid 1/2/4 cols with fade overlay at bottom
596
+
597
+ #### BrutalCTA
598
+
599
+ ```tsx
600
+ import { BrutalCTA } from "@snow-labs/brutal-ui";
601
+
602
+ <BrutalCTA
603
+ variant="centered"
604
+ color="black"
605
+ pattern="gradient-mesh"
606
+ headline="Ready to start?"
607
+ description="Join thousands of teams."
608
+ ctaText="Get Started"
609
+ ctaHref="/signup"
610
+ ctaVariant="cta"
611
+ secondaryText="Contact sales"
612
+ secondaryHref="/contact"
613
+ />
614
+ ```
615
+
616
+ | Prop | Type | Default |
617
+ |------|------|---------|
618
+ | `variant` | `"centered"` \| `"split"` \| `"with-visual"` \| `"floating-card"` | `"centered"` |
619
+ | `color` | `SectionColor` | — |
620
+ | `pattern` | `SectionPattern` | — |
621
+ | `headline` | `string` | required |
622
+ | `description` | `string` | — |
623
+ | `ctaText` | `string` | required |
624
+ | `ctaHref` | `string` | — |
625
+ | `ctaVariant` | `"cta"` \| `"brand"` \| `"default"` \| `"outline"` | — |
626
+ | `secondaryText` | `string` | — |
627
+ | `visual` | `ReactNode` | — |
628
+ | `stats` | `string` | — |
629
+
630
+ `floating-card`: Rendered as a card with `-mt-16` to float above previous section. NOT wrapped in BrutalSection.
631
+
632
+ #### BrutalFooter
633
+
634
+ ```tsx
635
+ import { BrutalFooter } from "@snow-labs/brutal-ui";
636
+
637
+ <BrutalFooter
638
+ variant="mega"
639
+ logo={<span className="font-black text-lg">Acme</span>}
640
+ tagline="Build faster."
641
+ columns={[
642
+ { title: "Product", links: [{ label: "Features", href: "/features" }] },
643
+ { title: "Company", links: [{ label: "About", href: "/about" }] },
644
+ ]}
645
+ socials={{ twitter: "https://x.com/acme", github: "https://github.com/acme" }}
646
+ bottomLeft="Built with care"
647
+ bottomRight="2026 Acme Inc."
648
+ />
649
+ ```
650
+
651
+ | Prop | Type | Default |
652
+ |------|------|---------|
653
+ | `variant` | `"mega"` \| `"minimal"` \| `"newsletter"` | `"mega"` |
654
+ | `logo` | `ReactNode` | required |
655
+ | `tagline` | `string` | — |
656
+ | `columns` | `{ title, links: { label, href }[] }[]` | required |
657
+ | `socials` | `{ twitter?, github?, linkedin?, discord? }` | — |
658
+ | `bottomLeft` | `string` | `"Built with care"` |
659
+ | `bottomRight` | `string` | current year |
660
+ | `newsletter` | `{ headline?, description?, placeholder?, buttonText? }` | — |
661
+
662
+ #### Other Landing Components
663
+
664
+ **StatsBar** — Animated count-up on scroll via IntersectionObserver.
665
+
666
+ ```tsx
667
+ <StatsBar color="brand" stats={[
668
+ { value: 10000, suffix: "+", label: "Users" },
669
+ { value: 99, suffix: "%", label: "Uptime" },
670
+ ]} />
671
+ ```
672
+
673
+ Props: `stats: { value, label, prefix?, suffix? }[]`, `color: "white" | "brand" | "black"`
674
+
675
+ **FAQ** — Accordion with alternating backgrounds.
676
+
677
+ ```tsx
678
+ <FAQ badge="FAQ" headline="Common Questions" color="white" items={[
679
+ { question: "How does it work?", answer: "It just works." },
680
+ ]} />
681
+ ```
682
+
683
+ Props: `items: { question, answer }[]`, `color: "white" | "black"`, `badge?`, `headline?`
684
+
685
+ **LogoCloud** — Logo strip with optional marquee animation.
686
+
687
+ ```tsx
688
+ <LogoCloud title="Trusted by" marquee={true} color="white" logos={[
689
+ { src: "/logo1.svg", alt: "Company 1" },
690
+ ]} />
691
+ ```
692
+
693
+ Props: `logos: { src, alt, href? }[]`, `marquee?: boolean`, `color: "white" | "brand" | "black"`, `title?`
694
+
695
+ **Newsletter** — Inline email signup card.
696
+
697
+ ```tsx
698
+ <Newsletter headline="Stay updated" color="white" onSubmit={(email) => subscribe(email)} />
699
+ ```
700
+
701
+ Props: `headline?`, `description?`, `placeholder?`, `buttonText?`, `onSubmit?: (email) => void`, `color: "white" | "brand" | "black"`
702
+
703
+ **BrutalIntegrationGrid** — Icon grid of integrations/partners.
704
+
705
+ ```tsx
706
+ <BrutalIntegrationGrid badge="Integrations" headline="Works with everything." integrations={[
707
+ { icon: <SlackIcon />, name: "Slack", href: "/integrations/slack" },
708
+ ]} />
709
+ ```
710
+
711
+ Props: `integrations: { icon, name, href? }[]`, `color: "white" | "brand" | "black"`, `badge?`, `headline`, `description?`
712
+
713
+ ---
714
+
715
+ ### Dashboard Components
716
+
717
+ #### AppShell + Sidebar
718
+
719
+ The core dashboard layout. Responsive: sidebar collapses on mobile to a hamburger menu.
720
+
721
+ ```tsx
722
+ import { AppShell, Sidebar, SearchBar, UserMenu } from "@snow-labs/brutal-ui";
723
+
724
+ <AppShell
725
+ sidebar={
726
+ <Sidebar
727
+ logo={<span className="font-black">Acme</span>}
728
+ logoCollapsed={<span className="font-black">A</span>}
729
+ groups={[
730
+ {
731
+ title: "Main",
732
+ links: [
733
+ { icon: <Home className="size-4" />, label: "Dashboard", href: "/", active: true },
734
+ { icon: <FileText className="size-4" />, label: "Projects", href: "/projects", badge: 5 },
735
+ ],
736
+ },
737
+ ]}
738
+ footer={<div className="text-xs text-muted-foreground">v1.0.0</div>}
739
+ />
740
+ }
741
+ header={
742
+ <>
743
+ <SearchBar placeholder="Search..." shortcut="K" />
744
+ <UserMenu name="Jane" email="jane@acme.com" onSignOut={() => signOut()} />
745
+ </>
746
+ }
747
+ >
748
+ {/* Page content */}
749
+ </AppShell>
750
+ ```
751
+
752
+ **AppShell props:**
753
+
754
+ | Prop | Type | Default |
755
+ |------|------|---------|
756
+ | `sidebar` | `ReactNode` | required |
757
+ | `header` | `ReactNode` | — |
758
+ | `children` | `ReactNode` | required |
759
+ | `defaultCollapsed` | `boolean` | `false` |
760
+
761
+ **Sidebar props:**
762
+
763
+ | Prop | Type | Default |
764
+ |------|------|---------|
765
+ | `logo` | `ReactNode` | required |
766
+ | `logoCollapsed` | `ReactNode` | — |
767
+ | `groups` | `{ title?, links: SidebarLink[] }[]` | required |
768
+ | `footer` | `ReactNode` | — |
769
+
770
+ SidebarLink: `{ icon, label, href, active?, badge? }`
771
+
772
+ Context: `useAppShell()` → `{ collapsed, setCollapsed, mobileOpen, setMobileOpen }`
773
+
774
+ #### StatCard
775
+
776
+ ```tsx
777
+ import { StatCard } from "@snow-labs/brutal-ui";
778
+
779
+ <StatCard label="Revenue" value="$12,340" change={12.5} changeLabel="vs last month" icon={<DollarSign />} />
780
+ ```
781
+
782
+ | Prop | Type | Default |
783
+ |------|------|---------|
784
+ | `label` | `string` | required |
785
+ | `value` | `string \| number` | required |
786
+ | `change` | `number` | — |
787
+ | `changeLabel` | `string` | — |
788
+ | `icon` | `ReactNode` | — |
789
+
790
+ Change: green arrow up if >= 0, red arrow down if < 0.
791
+
792
+ #### ViewSwitcher
793
+
794
+ ```tsx
795
+ import { ViewSwitcher } from "@snow-labs/brutal-ui";
796
+
797
+ <ViewSwitcher value="table" onChange={setView} views={["table", "kanban", "grid"]} />
798
+ ```
799
+
800
+ | Prop | Type | Default |
801
+ |------|------|---------|
802
+ | `value` | `"table"` \| `"kanban"` \| `"grid"` \| `"calendar"` \| `"list"` | required |
803
+ | `onChange` | `(value) => void` | required |
804
+ | `views` | `ViewMode[]` | all 5 |
805
+
806
+ #### SearchBar
807
+
808
+ ```tsx
809
+ <SearchBar placeholder="Search projects..." shortcut="K" value={query} onChange={setQuery} />
810
+ ```
811
+
812
+ Props: `placeholder?`, `shortcut?`, `value?`, `onChange?`
813
+
814
+ #### UserMenu
815
+
816
+ ```tsx
817
+ <UserMenu
818
+ name="Jane Doe"
819
+ email="jane@acme.com"
820
+ avatar="/avatar.jpg"
821
+ items={[{ label: "Settings", href: "/settings" }]}
822
+ onSignOut={() => signOut()}
823
+ />
824
+ ```
825
+
826
+ Props: `name`, `email?`, `avatar?`, `items?: { label, href?, onClick? }[]`, `onSignOut?`
827
+
828
+ #### EmptyState
829
+
830
+ ```tsx
831
+ <EmptyState
832
+ icon={<Inbox className="size-8" />}
833
+ headline="No projects yet"
834
+ description="Create your first project to get started."
835
+ ctaText="New Project"
836
+ onAction={() => createProject()}
837
+ />
838
+ ```
839
+
840
+ Props: `icon?`, `headline`, `description?`, `ctaText?`, `ctaHref?`, `onAction?`
841
+
842
+ #### ActivityFeed
843
+
844
+ ```tsx
845
+ <ActivityFeed
846
+ groupByDate={true}
847
+ entries={[
848
+ { id: "1", name: "Jane", action: "created a project", timestamp: new Date(), avatar: "/jane.jpg" },
849
+ ]}
850
+ />
851
+ ```
852
+
853
+ Props: `entries: { id, name, action, timestamp, avatar?, metadata? }[]`, `groupByDate?: boolean`
854
+
855
+ #### FileUpload
856
+
857
+ ```tsx
858
+ <FileUpload
859
+ accept="image/*"
860
+ maxFiles={5}
861
+ maxSize={10_000_000}
862
+ onFiles={(files) => upload(files)}
863
+ />
864
+ ```
865
+
866
+ Props: `onFiles`, `accept?`, `maxFiles?`, `maxSize?`
867
+
868
+ ---
869
+
870
+ ### View Components
871
+
872
+ #### DataTable
873
+
874
+ Requires: `@tanstack/react-table`
875
+
876
+ ```tsx
877
+ import { DataTable } from "@snow-labs/brutal-ui";
878
+ import { ColumnDef } from "@tanstack/react-table";
879
+
880
+ const columns: ColumnDef<Project>[] = [
881
+ { accessorKey: "name", header: "Name" },
882
+ { accessorKey: "status", header: "Status" },
883
+ ];
884
+
885
+ <DataTable columns={columns} data={projects} searchColumn="name" pageSize={10} emptyMessage="No projects" />
886
+ ```
887
+
888
+ | Prop | Type | Default |
889
+ |------|------|---------|
890
+ | `columns` | `ColumnDef[]` | required |
891
+ | `data` | `TData[]` | required |
892
+ | `searchColumn` | `string` | — |
893
+ | `searchPlaceholder` | `string` | — |
894
+ | `pageSize` | `number` | `10` |
895
+ | `emptyMessage` | `string` | `"No data"` |
896
+
897
+ Sortable headers (click to sort), alternating striped rows, pagination.
898
+
899
+ #### KanbanBoard
900
+
901
+ Requires: `@atlaskit/pragmatic-drag-and-drop`
902
+
903
+ ```tsx
904
+ import { KanbanBoard } from "@snow-labs/brutal-ui";
905
+
906
+ <KanbanBoard
907
+ columns={[
908
+ { id: "todo", title: "To Do", cards: [{ id: "1", title: "Task 1" }] },
909
+ { id: "doing", title: "In Progress", cards: [] },
910
+ ]}
911
+ renderCard={(card) => <div className="p-2 text-sm">{card.title}</div>}
912
+ onCardMove={(cardId, from, to, index) => moveCard(cardId, from, to, index)}
913
+ onCardAdd={(columnId, title) => addCard(columnId, title)}
914
+ />
915
+ ```
916
+
917
+ | Prop | Type | Default |
918
+ |------|------|---------|
919
+ | `columns` | `{ id, title, cards: TCard[] }[]` | required |
920
+ | `renderCard` | `(card) => ReactNode` | required |
921
+ | `onCardMove` | `(cardId, from, to, index) => void` | — |
922
+ | `onCardAdd` | `(columnId, title) => void` | — |
923
+
924
+ Drag-and-drop between columns. Cards have `isDragging: opacity-50` state.
925
+
926
+ #### GridView
927
+
928
+ ```tsx
929
+ import { GridView } from "@snow-labs/brutal-ui";
930
+
931
+ <GridView columns={3} gap={6}>
932
+ <Card>...</Card>
933
+ <Card>...</Card>
934
+ </GridView>
935
+ ```
936
+
937
+ Props: `columns?: number` (default 3), `gap?: number` (Tailwind units, default 6), `children`
938
+
939
+ Uses `auto-fill` + `minmax` for responsive columns.
940
+
941
+ #### ListView
942
+
943
+ ```tsx
944
+ import { ListView } from "@snow-labs/brutal-ui";
945
+
946
+ <ListView
947
+ items={[
948
+ { id: "1", title: "Project A", subtitle: "Updated 2h ago", actions: <Button size="sm">View</Button> },
949
+ ]}
950
+ onItemClick={(item) => navigate(item.id)}
951
+ emptyMessage="Nothing here"
952
+ />
953
+ ```
954
+
955
+ Props: `items: { id, title, subtitle?, avatar?, metadata?, actions? }[]`, `onItemClick?`, `emptyMessage?`
956
+
957
+ #### CalendarView
958
+
959
+ ```tsx
960
+ import { CalendarView } from "@snow-labs/brutal-ui";
961
+
962
+ <CalendarView
963
+ events={[
964
+ { id: "1", title: "Launch", date: new Date("2026-04-01"), color: "#DC2626" },
965
+ ]}
966
+ onEventClick={(event) => openEvent(event)}
967
+ onDateClick={(date) => createEvent(date)}
968
+ />
969
+ ```
970
+
971
+ Props: `events?: { id, title, date, color? }[]`, `onEventClick?`, `onDateClick?`
972
+
973
+ Month navigation, 7-column grid, up to 3 events per day with "+N more" overflow.
974
+
975
+ ---
976
+
977
+ ### Templates
978
+
979
+ Full-page compositions. Use these to ship fast, then customize.
980
+
981
+ #### SaaSLaunchTemplate
982
+
983
+ Complete SaaS landing page: Nav → Hero → Logos → Features → Stats → Testimonials → Pricing → FAQ → CTA → Footer.
984
+
985
+ ```tsx
986
+ import { SaaSLaunchTemplate } from "@snow-labs/brutal-ui";
987
+
988
+ <SaaSLaunchTemplate
989
+ brand="Acme"
990
+ logo={<span className="font-black">Acme</span>}
991
+ nav={{ links: [...], ctaText: "Sign up", ctaHref: "/signup" }}
992
+ hero={{ headline: "...", description: "...", ctaText: "Get started", proof: "Free forever" }}
993
+ logos={[{ src: "/logo.svg", alt: "Partner" }]}
994
+ features={{ badge: "Features", headline: "...", items: [...] }}
995
+ stats={[{ value: 1000, suffix: "+", label: "Users" }]}
996
+ testimonials={{ badge: "Reviews", headline: "...", items: [...] }}
997
+ pricing={{ tiers: [...], popularIndex: 1 }}
998
+ faq={[{ question: "...", answer: "..." }]}
999
+ cta={{ headline: "Ready?", ctaText: "Start now" }}
1000
+ footer={{ tagline: "...", columns: [...], socials: { twitter: "..." } }}
1001
+ />
1002
+ ```
1003
+
1004
+ Section order: BrutalNav (solid) → BrutalHero (split, brand, noise) → wave divider → LogoCloud (marquee) → BrutalFeatureGrid (bento) → StatsBar (brand) → torn-paper divider → BrutalTestimonials (wall-of-love, brand-muted) → wave divider → PricingTable → FAQ → BrutalCTA (with-visual, black, gradient-mesh) → BrutalFooter (mega)
1005
+
1006
+ #### StudioTemplate
1007
+
1008
+ Creative/agency landing: floating-pill nav, asymmetric hero, numbered features.
1009
+
1010
+ ```tsx
1011
+ import { StudioTemplate } from "@snow-labs/brutal-ui";
1012
+
1013
+ <StudioTemplate
1014
+ logo={...}
1015
+ nav={{ links: [...] }}
1016
+ hero={{ headline: "...", description: "...", ctaText: "..." }}
1017
+ features={{ items: [...] }}
1018
+ testimonials={{ items: [...] }}
1019
+ newsletter={{ headline: "Stay updated" }}
1020
+ cta={{ headline: "...", ctaText: "..." }}
1021
+ footer={{ columns: [...] }}
1022
+ />
1023
+ ```
1024
+
1025
+ Section order: BrutalNav (floating-pill) → BrutalHero (asymmetric, brand, grain) → brush-stroke divider → BrutalFeatureGrid (numbered) → diagonal divider → BrutalTestimonials (featured-grid) → diagonal flip → Newsletter → BrutalCTA (floating-card) → BrutalFooter (minimal)
1026
+
1027
+ #### DashboardTemplate
1028
+
1029
+ Complete dashboard shell with sidebar, header, stats, and view switcher.
1030
+
1031
+ ```tsx
1032
+ import { DashboardTemplate } from "@snow-labs/brutal-ui";
1033
+
1034
+ <DashboardTemplate
1035
+ logo={<span className="font-black">Acme</span>}
1036
+ sidebarGroups={[{ title: "Main", links: [...] }]}
1037
+ user={{ name: "Jane", email: "jane@acme.com" }}
1038
+ onSignOut={() => signOut()}
1039
+ stats={[{ label: "Revenue", value: "$12k", change: 12 }]}
1040
+ views={["table", "kanban", "grid"]}
1041
+ >
1042
+ {/* Your data view content */}
1043
+ </DashboardTemplate>
1044
+ ```
1045
+
1046
+ ---
1047
+
1048
+ ## 7. Animation Presets (framer-motion)
1049
+
1050
+ Requires: `framer-motion`
1051
+
1052
+ ```tsx
1053
+ import { fadeInUp, fadeIn, scaleIn, staggerContainer, slideInLeft, slideInRight, defaultTransition, springTransition } from "@snow-labs/brutal-ui";
1054
+ import { motion } from "framer-motion";
1055
+
1056
+ <motion.div variants={staggerContainer} initial="initial" animate="animate">
1057
+ <motion.div variants={fadeInUp}>Item 1</motion.div>
1058
+ <motion.div variants={fadeInUp}>Item 2</motion.div>
1059
+ </motion.div>
1060
+ ```
1061
+
1062
+ | Preset | Effect |
1063
+ |--------|--------|
1064
+ | `fadeInUp` | opacity 0→1, y 20→0 |
1065
+ | `fadeIn` | opacity 0→1 |
1066
+ | `scaleIn` | opacity 0→1, scale 0.95→1 |
1067
+ | `slideInLeft` | opacity 0→1, x -30→0 |
1068
+ | `slideInRight` | opacity 0→1, x 30→0 |
1069
+ | `staggerContainer` | Stagger children 0.08s apart, 0.1s initial delay |
1070
+ | `defaultTransition` | 0.5s, smooth easing |
1071
+ | `springTransition` | Spring, stiffness 300, damping 30 |
1072
+
1073
+ ---
1074
+
1075
+ ## 8. Recipes
1076
+
1077
+ ### Landing page (composing sections)
1078
+
1079
+ ```tsx
1080
+ <BrutalNav variant="transparent" logo={...} links={[...]} ctaText="Start free" />
1081
+
1082
+ <BrutalHero variant="centered" color="brand" pattern="grid-dots" headline="..." ctaText="..." />
1083
+
1084
+ <SectionDivider variant="wave" from="hsl(var(--brand))" to="hsl(var(--background))" />
1085
+
1086
+ <StatsBar color="black" stats={[...]} />
1087
+
1088
+ <BrutalFeatureGrid variant="numbered" columns={3} color="brand-muted" badge="Features" headline="..." features={[...]} />
1089
+
1090
+ <BrutalFeatureGrid variant="icon-left" columns={2} color="white" headline="..." features={[...]} />
1091
+
1092
+ <SectionDivider variant="torn-paper" from="hsl(var(--background))" to="hsl(var(--brand-muted))" />
1093
+
1094
+ <BrutalTestimonials variant="wall-of-love" color="brand-muted" headline="..." testimonials={[...]} />
1095
+
1096
+ <SectionDivider variant="wave" from="hsl(var(--brand-muted))" to="hsl(var(--background))" />
1097
+
1098
+ <PricingTable billingToggle={true} color="white" popularIndex={1} tiers={[...]} />
1099
+
1100
+ <FAQ badge="FAQ" headline="Questions" color="white" items={[...]} />
1101
+
1102
+ <BrutalCTA variant="centered" color="black" pattern="gradient-mesh" headline="..." ctaText="..." />
1103
+
1104
+ <BrutalFooter variant="mega" logo={...} columns={[...]} socials={{...}} />
1105
+ ```
1106
+
1107
+ ### Dashboard page
1108
+
1109
+ ```tsx
1110
+ <AppShell
1111
+ sidebar={<Sidebar logo={...} groups={[...]} />}
1112
+ header={<><SearchBar /><UserMenu name="..." onSignOut={...} /></>}
1113
+ >
1114
+ <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4 mb-8">
1115
+ <StatCard label="Users" value="1,234" change={5.2} />
1116
+ <StatCard label="Revenue" value="$45k" change={-2.1} />
1117
+ </div>
1118
+
1119
+ <div className="flex items-center justify-between mb-6">
1120
+ <h2 className="brutal-h3">Projects</h2>
1121
+ <ViewSwitcher value={view} onChange={setView} views={["table", "grid", "kanban"]} />
1122
+ </div>
1123
+
1124
+ {view === "table" && <DataTable columns={columns} data={data} searchColumn="name" />}
1125
+ {view === "grid" && <GridView columns={3}>{data.map(d => <Card key={d.id}>...</Card>)}</GridView>}
1126
+ {view === "kanban" && <KanbanBoard columns={kanbanCols} renderCard={renderCard} />}
1127
+ </AppShell>
1128
+ ```
1129
+
1130
+ ### Custom section with brutal styling
1131
+
1132
+ ```tsx
1133
+ <BrutalSection color="white" pattern="dots">
1134
+ <div className="grid md:grid-cols-2 gap-12 items-center">
1135
+ <div>
1136
+ <Badge variant="brand" className="mb-4">How it works</Badge>
1137
+ <h2 className="brutal-h2 mb-4">Three simple steps.</h2>
1138
+ <p className="brutal-body text-muted-foreground">Get started in minutes.</p>
1139
+ </div>
1140
+ <div className="space-y-4">
1141
+ {steps.map((step, i) => (
1142
+ <Card key={i}>
1143
+ <CardContent className="flex gap-4 items-start p-5">
1144
+ <span className="brutal-display opacity-10">{String(i + 1).padStart(2, "0")}</span>
1145
+ <div>
1146
+ <h3 className="brutal-h4 mb-1">{step.title}</h3>
1147
+ <p className="brutal-caption">{step.description}</p>
1148
+ </div>
1149
+ </CardContent>
1150
+ </Card>
1151
+ ))}
1152
+ </div>
1153
+ </div>
1154
+ </BrutalSection>
1155
+ ```
1156
+
1157
+ ---
1158
+
1159
+ ## 9. Common Mistakes
1160
+
1161
+ | Mistake | Fix |
1162
+ |---------|-----|
1163
+ | Missing `@source` in globals.css | Add `@source` pointing to brutal-ui dist — without it, component styles are missing |
1164
+ | Using `color="gray"` or `color="cream"` | Those were removed. Use `"white"`, `"black"`, `"brand"`, `"brand-muted"` |
1165
+ | Hardcoding hex colors | Use CSS variables: `bg-brand`, `text-muted-foreground`, `hsl(var(--brand))` |
1166
+ | Mixing button sizes in a pair | Both primary + secondary buttons must use same `size` prop |
1167
+ | Building custom border/shadow styles | Use `brutal-border`, `brutal-shadow`, `brutal-hover` utilities |
1168
+ | Using `<a>` or `<Link>` directly for CTAs | Use `<Button render={<Link href="..." />}>` to get brutal styling |
1169
+ | Putting JSX in `headline` prop | `headline` is a `string`. For JSX, use `BrutalSection` + custom markup |
1170
+ | Forgetting `transpilePackages` in next.config | Required for Next.js to compile brutal-ui ESM |
1171
+ | Using `data-theme="blue"` | Not a valid theme. Use one of the 11 built-in theme names |
1172
+ | Importing from subpaths like `@snow-labs/brutal-ui/components/ui/button` | Import everything from root: `@snow-labs/brutal-ui` |
1173
+
1174
+ ---
1175
+
1176
+ ## 10. Full Export List
1177
+
1178
+ ```ts
1179
+ // UI Primitives (40+)
1180
+ Accordion, AccordionItem, AccordionTrigger, AccordionContent,
1181
+ Alert, AlertTitle, AlertDescription,
1182
+ Avatar, AvatarImage, AvatarFallback,
1183
+ Badge, badgeVariants,
1184
+ Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis,
1185
+ Button, buttonVariants,
1186
+ Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent,
1187
+ Checkbox,
1188
+ Collapsible, CollapsibleTrigger, CollapsibleContent,
1189
+ Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator,
1190
+ ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, /* + checkbox, radio, sub variants */
1191
+ Dialog, DialogPortal, DialogOverlay, DialogClose, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription,
1192
+ Drawer, DrawerPortal, DrawerOverlay, DrawerTrigger, DrawerClose, DrawerContent, DrawerHeader, DrawerFooter, DrawerTitle, DrawerDescription,
1193
+ DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, /* + checkbox, radio, sub variants */
1194
+ HoverCard, HoverCardTrigger, HoverCardContent,
1195
+ Input,
1196
+ InputGroup, InputGroupInput, InputGroupTextarea, InputGroupAddon,
1197
+ Label,
1198
+ Menubar, MenubarMenu, MenubarTrigger, MenubarContent, MenubarItem, /* + all sub-exports */
1199
+ NavigationMenu, NavigationMenuList, NavigationMenuItem, NavigationMenuContent, NavigationMenuTrigger, NavigationMenuLink, NavigationMenuIndicator, NavigationMenuPositioner, navigationMenuTriggerStyle,
1200
+ Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious,
1201
+ Popover, PopoverTrigger, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle,
1202
+ Progress,
1203
+ RadioGroup, RadioGroupItem,
1204
+ ScrollArea, ScrollBar,
1205
+ Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue,
1206
+ Separator,
1207
+ Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription,
1208
+ Skeleton,
1209
+ Slider,
1210
+ Switch,
1211
+ Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants,
1212
+ Textarea,
1213
+ Toggle, toggleVariants,
1214
+ ToggleGroup, ToggleGroupItem,
1215
+ Tooltip, TooltipTrigger, TooltipContent, TooltipProvider,
1216
+
1217
+ // Landing Page Components (15)
1218
+ BrutalSection, SectionDivider, WaveDivider,
1219
+ BrutalHero, BrutalNav, BrutalFooter,
1220
+ BrutalFeatureGrid, BrutalTestimonials, BrutalCTA,
1221
+ BrutalIntegrationGrid,
1222
+ PricingTable, LogoCloud, StatsBar, FAQ, Newsletter,
1223
+
1224
+ // Dashboard Components (9)
1225
+ AppShell, useAppShell, Sidebar,
1226
+ StatCard, ViewSwitcher, SearchBar, UserMenu,
1227
+ EmptyState, ActivityFeed, FileUpload,
1228
+
1229
+ // View Components (5)
1230
+ DataTable, KanbanBoard, GridView, ListView, CalendarView,
1231
+
1232
+ // Templates (3)
1233
+ SaaSLaunchTemplate, StudioTemplate, DashboardTemplate,
1234
+
1235
+ // Animations (8)
1236
+ fadeInUp, fadeIn, staggerContainer, scaleIn,
1237
+ slideInLeft, slideInRight, defaultTransition, springTransition,
1238
+
1239
+ // Utilities
1240
+ cn,
1241
+
1242
+ // Types
1243
+ SectionColor, SectionPattern, Testimonial,
1244
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snow-labs/brutal-ui",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Soft brutalist design system — bold borders, offset shadows, dynamic brand colors. Built on shadcn/ui + Tailwind v4.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,7 +35,8 @@
35
35
  },
36
36
  "files": [
37
37
  "dist",
38
- "README.md"
38
+ "README.md",
39
+ "AGENTS.md"
39
40
  ],
40
41
  "scripts": {
41
42
  "build": "tsup && cp src/theme.css dist/theme.css",