@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.
- package/AGENTS.md +1244 -0
- 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.
|
|
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",
|