sonance-brand-mcp 1.3.111 → 1.3.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/api/sonance-save-image/route.ts +625 -0
- package/dist/assets/api/sonance-vision-apply/image-styling-detection.ts +1360 -0
- package/dist/assets/api/sonance-vision-apply/route.ts +988 -57
- package/dist/assets/api/sonance-vision-apply/styling-detection.ts +730 -0
- package/dist/assets/api/sonance-vision-apply/theme-discovery.ts +1 -1
- package/dist/assets/brand-system.ts +13 -12
- package/dist/assets/components/accordion.tsx +15 -7
- package/dist/assets/components/alert-dialog.tsx +35 -10
- package/dist/assets/components/alert.tsx +11 -10
- package/dist/assets/components/avatar.tsx +4 -4
- package/dist/assets/components/badge.tsx +16 -12
- package/dist/assets/components/button.stories.tsx +3 -3
- package/dist/assets/components/button.tsx +50 -31
- package/dist/assets/components/calendar.tsx +12 -8
- package/dist/assets/components/card.tsx +35 -29
- package/dist/assets/components/checkbox.tsx +9 -8
- package/dist/assets/components/code.tsx +19 -11
- package/dist/assets/components/command.tsx +32 -13
- package/dist/assets/components/context-menu.tsx +37 -16
- package/dist/assets/components/dialog.tsx +8 -5
- package/dist/assets/components/divider.tsx +15 -5
- package/dist/assets/components/drawer.tsx +4 -3
- package/dist/assets/components/dropdown-menu.tsx +15 -13
- package/dist/assets/components/hover-card.tsx +4 -1
- package/dist/assets/components/image.tsx +1 -1
- package/dist/assets/components/input.tsx +29 -14
- package/dist/assets/components/kbd.stories.tsx +3 -3
- package/dist/assets/components/kbd.tsx +29 -13
- package/dist/assets/components/listbox.tsx +8 -8
- package/dist/assets/components/menubar.tsx +50 -23
- package/dist/assets/components/navbar.stories.tsx +140 -13
- package/dist/assets/components/navbar.tsx +22 -5
- package/dist/assets/components/navigation-menu.tsx +28 -6
- package/dist/assets/components/pagination.tsx +10 -10
- package/dist/assets/components/popover.tsx +10 -8
- package/dist/assets/components/progress.tsx +6 -4
- package/dist/assets/components/radio-group.tsx +5 -5
- package/dist/assets/components/select.tsx +49 -29
- package/dist/assets/components/separator.tsx +3 -3
- package/dist/assets/components/sheet.tsx +4 -4
- package/dist/assets/components/sidebar.tsx +10 -10
- package/dist/assets/components/skeleton.tsx +13 -5
- package/dist/assets/components/slider.tsx +12 -10
- package/dist/assets/components/switch.tsx +4 -4
- package/dist/assets/components/table.tsx +5 -5
- package/dist/assets/components/tabs.tsx +8 -8
- package/dist/assets/components/textarea.tsx +11 -9
- package/dist/assets/components/toast.tsx +7 -7
- package/dist/assets/components/toggle.tsx +27 -7
- package/dist/assets/components/tooltip.tsx +10 -8
- package/dist/assets/components/user.tsx +8 -6
- package/dist/assets/dev-tools/SonanceDevTools.tsx +429 -362
- package/dist/assets/dev-tools/components/ApplyFirstPreview.tsx +10 -10
- package/dist/assets/dev-tools/components/ChatHistory.tsx +11 -7
- package/dist/assets/dev-tools/components/ChatInterface.tsx +61 -20
- package/dist/assets/dev-tools/components/ChatTabBar.tsx +1 -1
- package/dist/assets/dev-tools/components/DiffPreview.tsx +1 -1
- package/dist/assets/dev-tools/components/InlineDiffPreview.tsx +360 -36
- package/dist/assets/dev-tools/components/InspectorOverlay.tsx +9 -9
- package/dist/assets/dev-tools/components/PropertiesPanel.tsx +743 -93
- package/dist/assets/dev-tools/components/ScreenshotAnnotator.tsx +1 -1
- package/dist/assets/dev-tools/components/SectionHighlight.tsx +1 -1
- package/dist/assets/dev-tools/components/VisionDiffPreview.tsx +7 -7
- package/dist/assets/dev-tools/components/VisionModeBorder.tsx +4 -64
- package/dist/assets/dev-tools/hooks/index.ts +69 -0
- package/dist/assets/dev-tools/hooks/useComponentDetection.ts +132 -0
- package/dist/assets/dev-tools/hooks/useComputedStyles.ts +171 -65
- package/dist/assets/dev-tools/hooks/useContentHash.ts +212 -0
- package/dist/assets/dev-tools/hooks/useElementScanner.ts +398 -0
- package/dist/assets/dev-tools/hooks/useImageDetection.ts +162 -0
- package/dist/assets/dev-tools/hooks/useTextDetection.ts +217 -0
- package/dist/assets/dev-tools/panels/ComponentsPanel.tsx +160 -57
- package/dist/assets/dev-tools/panels/TextPanel.tsx +10 -10
- package/dist/assets/dev-tools/types.ts +42 -0
- package/dist/assets/globals.css +225 -9
- package/dist/assets/styles/brand-overrides.css +3 -2
- package/dist/assets/utils.ts +2 -1
- package/package.json +1 -1
|
@@ -3,18 +3,33 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|
|
3
3
|
import { cn } from "@/lib/utils";
|
|
4
4
|
|
|
5
5
|
const kbdVariants = cva(
|
|
6
|
-
|
|
6
|
+
cn(
|
|
7
|
+
"inline-flex items-center justify-center font-mono font-medium",
|
|
8
|
+
"transition-all backdrop-blur-sm"
|
|
9
|
+
),
|
|
7
10
|
{
|
|
8
11
|
variants: {
|
|
9
12
|
variant: {
|
|
10
|
-
default:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
default: cn(
|
|
14
|
+
"bg-white/60 dark:bg-white/5",
|
|
15
|
+
"border border-black/10 dark:border-white/10",
|
|
16
|
+
"text-foreground shadow-sm"
|
|
17
|
+
),
|
|
18
|
+
outline: cn(
|
|
19
|
+
"bg-transparent",
|
|
20
|
+
"border border-black/15 dark:border-white/15",
|
|
21
|
+
"text-foreground-muted"
|
|
22
|
+
),
|
|
23
|
+
glass: cn(
|
|
24
|
+
"bg-white/40 dark:bg-white/5",
|
|
25
|
+
"border border-black/5 dark:border-white/10",
|
|
26
|
+
"text-foreground-muted shadow-sm"
|
|
27
|
+
),
|
|
13
28
|
},
|
|
14
29
|
size: {
|
|
15
|
-
sm: "h-4 sm:h-5 min-w-4 sm:min-w-5 px-0.5 sm:px-1 text-[9px] sm:text-[10px] rounded-
|
|
16
|
-
md: "h-5 sm:h-6 min-w-5 sm:min-w-6 px-1 sm:px-1.5 text-[10px] sm:text-xs rounded-
|
|
17
|
-
lg: "h-6 sm:h-7 min-w-6 sm:min-w-7 px-1.5 sm:px-2 text-xs sm:text-sm rounded",
|
|
30
|
+
sm: "h-4 sm:h-5 min-w-4 sm:min-w-5 px-0.5 sm:px-1 text-[9px] sm:text-[10px] rounded-md",
|
|
31
|
+
md: "h-5 sm:h-6 min-w-5 sm:min-w-6 px-1 sm:px-1.5 text-[10px] sm:text-xs rounded-md",
|
|
32
|
+
lg: "h-6 sm:h-7 min-w-6 sm:min-w-7 px-1.5 sm:px-2 text-xs sm:text-sm rounded-lg",
|
|
18
33
|
},
|
|
19
34
|
},
|
|
20
35
|
defaultVariants: {
|
|
@@ -36,12 +51,13 @@ export const Kbd = forwardRef<HTMLElement, KbdProps>(
|
|
|
36
51
|
if (keys) {
|
|
37
52
|
const keyArray = Array.isArray(keys) ? keys : [keys];
|
|
38
53
|
return (
|
|
39
|
-
<span
|
|
54
|
+
<span data-sonance-name="kbd" className="inline-flex items-center gap-1">
|
|
40
55
|
{keyArray.map((key, index) => (
|
|
41
56
|
<kbd
|
|
42
57
|
key={index}
|
|
43
58
|
ref={index === 0 ? ref : undefined}
|
|
44
|
-
|
|
59
|
+
data-sonance-name="kbd"
|
|
60
|
+
className={cn(kbdVariants({ variant, size }), className)}
|
|
45
61
|
{...props}
|
|
46
62
|
>
|
|
47
63
|
{formatKey(key)}
|
|
@@ -54,7 +70,8 @@ export const Kbd = forwardRef<HTMLElement, KbdProps>(
|
|
|
54
70
|
return (
|
|
55
71
|
<kbd
|
|
56
72
|
ref={ref}
|
|
57
|
-
|
|
73
|
+
data-sonance-name="kbd"
|
|
74
|
+
className={cn(kbdVariants({ variant, size }), className)}
|
|
58
75
|
{...props}
|
|
59
76
|
>
|
|
60
77
|
{children}
|
|
@@ -103,8 +120,8 @@ interface KeyboardShortcutProps {
|
|
|
103
120
|
|
|
104
121
|
export function KeyboardShortcut({ keys, label, className }: KeyboardShortcutProps) {
|
|
105
122
|
return (
|
|
106
|
-
<span
|
|
107
|
-
{label && <span
|
|
123
|
+
<span data-sonance-name="kbd" className={cn("inline-flex items-center gap-1.5 sm:gap-2 flex-wrap", className)}>
|
|
124
|
+
{label && <span className="text-xs sm:text-sm text-foreground-muted">{label}</span>}
|
|
108
125
|
<Kbd keys={keys} />
|
|
109
126
|
</span>
|
|
110
127
|
);
|
|
@@ -123,4 +140,3 @@ export const shortcuts = {
|
|
|
123
140
|
newTab: ["cmd", "t"],
|
|
124
141
|
closeTab: ["cmd", "w"],
|
|
125
142
|
} as const;
|
|
126
|
-
|
|
@@ -11,9 +11,9 @@ const getItemStateStyles = (state?: ListboxItemState, isSelected?: boolean) => {
|
|
|
11
11
|
if (!state || state === "default") return "";
|
|
12
12
|
|
|
13
13
|
const stateMap: Record<string, string> = {
|
|
14
|
-
hover: "bg-
|
|
15
|
-
focus: "ring-2 ring-
|
|
16
|
-
selected: "bg-
|
|
14
|
+
hover: "bg-white/50 dark:bg-white/5",
|
|
15
|
+
focus: "ring-2 ring-[color:var(--sonance-blue)]/30 ring-inset",
|
|
16
|
+
selected: "bg-[color:var(--sonance-blue)] text-white",
|
|
17
17
|
disabled: "opacity-50 cursor-not-allowed",
|
|
18
18
|
};
|
|
19
19
|
|
|
@@ -82,7 +82,7 @@ export function Listbox({
|
|
|
82
82
|
<ul
|
|
83
83
|
role="listbox"
|
|
84
84
|
aria-multiselectable={multiple}
|
|
85
|
-
className="border border-border
|
|
85
|
+
className="bg-white/70 dark:bg-white/[0.03] backdrop-blur-sm border border-black/8 dark:border-white/8 divide-y divide-black/5 dark:divide-white/5 rounded-xl overflow-hidden"
|
|
86
86
|
>
|
|
87
87
|
{children}
|
|
88
88
|
</ul>
|
|
@@ -137,10 +137,10 @@ export const ListboxItem = forwardRef<HTMLLIElement, ListboxItemProps>(
|
|
|
137
137
|
onClick={() => !isDisabled && onChange(value)}
|
|
138
138
|
className={cn(
|
|
139
139
|
"flex items-center gap-3 px-4 py-3 cursor-pointer",
|
|
140
|
-
"transition-
|
|
140
|
+
"transition-all duration-150",
|
|
141
141
|
finalSelected
|
|
142
|
-
? "bg-
|
|
143
|
-
: "hover:bg-
|
|
142
|
+
? "bg-[color:var(--sonance-blue)] text-white"
|
|
143
|
+
: "hover:bg-white/50 dark:hover:bg-white/5",
|
|
144
144
|
isDisabled && "cursor-not-allowed opacity-50",
|
|
145
145
|
getItemStateStyles(state, finalSelected),
|
|
146
146
|
className
|
|
@@ -186,7 +186,7 @@ export function ListboxSection({ title, children, className }: ListboxSectionPro
|
|
|
186
186
|
return (
|
|
187
187
|
<li data-sonance-name="listbox" className={className}>
|
|
188
188
|
{title && (
|
|
189
|
-
<div className="px-4 py-2 text-xs font-medium uppercase tracking-widest text-foreground-muted bg-
|
|
189
|
+
<div className="px-4 py-2 text-xs font-medium uppercase tracking-widest text-foreground-muted bg-white/50 dark:bg-white/[0.02]">
|
|
190
190
|
{title}
|
|
191
191
|
</div>
|
|
192
192
|
)}
|
|
@@ -17,8 +17,12 @@ const Menubar = React.forwardRef<
|
|
|
17
17
|
>(({ className, ...props }, ref) => (
|
|
18
18
|
<MenubarPrimitive.Root
|
|
19
19
|
ref={ref}
|
|
20
|
+
data-sonance-name="menubar"
|
|
20
21
|
className={cn(
|
|
21
|
-
"flex h-10 items-center space-x-1 rounded-
|
|
22
|
+
"flex h-10 items-center space-x-1 rounded-xl p-1",
|
|
23
|
+
"bg-white/70 dark:bg-white/5 backdrop-blur-sm",
|
|
24
|
+
"border border-black/8 dark:border-white/8",
|
|
25
|
+
"shadow-sm",
|
|
22
26
|
className
|
|
23
27
|
)}
|
|
24
28
|
{...props}
|
|
@@ -33,9 +37,10 @@ const MenubarTrigger = React.forwardRef<
|
|
|
33
37
|
<MenubarPrimitive.Trigger
|
|
34
38
|
ref={ref}
|
|
35
39
|
className={cn(
|
|
36
|
-
"flex cursor-default select-none items-center rounded-
|
|
37
|
-
"
|
|
38
|
-
"
|
|
40
|
+
"flex cursor-default select-none items-center rounded-lg px-3 py-1.5 text-sm font-medium outline-none",
|
|
41
|
+
"transition-all duration-150",
|
|
42
|
+
"focus:bg-white/60 dark:focus:bg-white/10 focus:text-foreground",
|
|
43
|
+
"data-[state=open]:bg-white/60 dark:data-[state=open]:bg-white/10 data-[state=open]:text-foreground",
|
|
39
44
|
className
|
|
40
45
|
)}
|
|
41
46
|
{...props}
|
|
@@ -52,9 +57,10 @@ const MenubarSubTrigger = React.forwardRef<
|
|
|
52
57
|
<MenubarPrimitive.SubTrigger
|
|
53
58
|
ref={ref}
|
|
54
59
|
className={cn(
|
|
55
|
-
"flex cursor-default select-none items-center rounded-
|
|
56
|
-
"
|
|
57
|
-
"
|
|
60
|
+
"flex cursor-default select-none items-center rounded-xl px-2 py-1.5 text-sm outline-none",
|
|
61
|
+
"transition-all duration-150",
|
|
62
|
+
"focus:bg-white/60 dark:focus:bg-white/10 focus:text-foreground",
|
|
63
|
+
"data-[state=open]:bg-white/60 dark:data-[state=open]:bg-white/10 data-[state=open]:text-foreground",
|
|
58
64
|
inset && "pl-8",
|
|
59
65
|
className
|
|
60
66
|
)}
|
|
@@ -73,7 +79,10 @@ const MenubarSubContent = React.forwardRef<
|
|
|
73
79
|
<MenubarPrimitive.SubContent
|
|
74
80
|
ref={ref}
|
|
75
81
|
className={cn(
|
|
76
|
-
"z-50 min-w-[8rem] overflow-hidden rounded-
|
|
82
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-xl p-1 text-foreground",
|
|
83
|
+
"bg-white/90 dark:bg-black/80 backdrop-blur-xl",
|
|
84
|
+
"border border-black/10 dark:border-white/10",
|
|
85
|
+
"shadow-[0_8px_32px_rgba(0,0,0,0.12)] dark:shadow-[0_8px_32px_rgba(0,0,0,0.4)]",
|
|
77
86
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
78
87
|
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
79
88
|
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
@@ -103,9 +112,14 @@ const MenubarContent = React.forwardRef<
|
|
|
103
112
|
alignOffset={alignOffset}
|
|
104
113
|
sideOffset={sideOffset}
|
|
105
114
|
className={cn(
|
|
106
|
-
"z-50 min-w-[12rem] overflow-hidden rounded-
|
|
107
|
-
"
|
|
108
|
-
"
|
|
115
|
+
"z-50 min-w-[12rem] overflow-hidden rounded-xl p-1 text-foreground",
|
|
116
|
+
"bg-white/90 dark:bg-black/80 backdrop-blur-xl",
|
|
117
|
+
"border border-black/10 dark:border-white/10",
|
|
118
|
+
"shadow-[0_8px_32px_rgba(0,0,0,0.12)] dark:shadow-[0_8px_32px_rgba(0,0,0,0.4)]",
|
|
119
|
+
"data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
120
|
+
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
121
|
+
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
|
|
122
|
+
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
109
123
|
className
|
|
110
124
|
)}
|
|
111
125
|
{...props}
|
|
@@ -124,8 +138,10 @@ const MenubarItem = React.forwardRef<
|
|
|
124
138
|
<MenubarPrimitive.Item
|
|
125
139
|
ref={ref}
|
|
126
140
|
className={cn(
|
|
127
|
-
"relative flex cursor-default select-none items-center rounded-
|
|
128
|
-
"
|
|
141
|
+
"relative flex cursor-default select-none items-center rounded-xl px-2 py-1.5 text-sm outline-none",
|
|
142
|
+
"transition-all duration-150",
|
|
143
|
+
"focus:bg-white/60 dark:focus:bg-white/10 focus:text-foreground",
|
|
144
|
+
"focus:shadow-[0_0_12px_var(--glow-primary-subtle)]",
|
|
129
145
|
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
130
146
|
inset && "pl-8",
|
|
131
147
|
className
|
|
@@ -142,15 +158,17 @@ const MenubarCheckboxItem = React.forwardRef<
|
|
|
142
158
|
<MenubarPrimitive.CheckboxItem
|
|
143
159
|
ref={ref}
|
|
144
160
|
className={cn(
|
|
145
|
-
"relative flex cursor-default select-none items-center rounded-
|
|
146
|
-
"
|
|
161
|
+
"relative flex cursor-default select-none items-center rounded-xl py-1.5 pl-8 pr-2 text-sm outline-none",
|
|
162
|
+
"transition-all duration-150",
|
|
163
|
+
"focus:bg-white/60 dark:focus:bg-white/10 focus:text-foreground",
|
|
164
|
+
"focus:shadow-[0_0_12px_var(--glow-primary-subtle)]",
|
|
147
165
|
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
148
166
|
className
|
|
149
167
|
)}
|
|
150
168
|
checked={checked}
|
|
151
169
|
{...props}
|
|
152
170
|
>
|
|
153
|
-
<span
|
|
171
|
+
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
154
172
|
<MenubarPrimitive.ItemIndicator>
|
|
155
173
|
<Check className="h-4 w-4" />
|
|
156
174
|
</MenubarPrimitive.ItemIndicator>
|
|
@@ -167,14 +185,16 @@ const MenubarRadioItem = React.forwardRef<
|
|
|
167
185
|
<MenubarPrimitive.RadioItem
|
|
168
186
|
ref={ref}
|
|
169
187
|
className={cn(
|
|
170
|
-
"relative flex cursor-default select-none items-center rounded-
|
|
171
|
-
"
|
|
188
|
+
"relative flex cursor-default select-none items-center rounded-xl py-1.5 pl-8 pr-2 text-sm outline-none",
|
|
189
|
+
"transition-all duration-150",
|
|
190
|
+
"focus:bg-white/60 dark:focus:bg-white/10 focus:text-foreground",
|
|
191
|
+
"focus:shadow-[0_0_12px_var(--glow-primary-subtle)]",
|
|
172
192
|
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
173
193
|
className
|
|
174
194
|
)}
|
|
175
195
|
{...props}
|
|
176
196
|
>
|
|
177
|
-
<span
|
|
197
|
+
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
178
198
|
<MenubarPrimitive.ItemIndicator>
|
|
179
199
|
<Circle className="h-2 w-2 fill-current" />
|
|
180
200
|
</MenubarPrimitive.ItemIndicator>
|
|
@@ -208,7 +228,7 @@ const MenubarSeparator = React.forwardRef<
|
|
|
208
228
|
>(({ className, ...props }, ref) => (
|
|
209
229
|
<MenubarPrimitive.Separator
|
|
210
230
|
ref={ref}
|
|
211
|
-
className={cn("-mx-1 my-1 h-px bg-
|
|
231
|
+
className={cn("-mx-1 my-1 h-px bg-black/8 dark:bg-white/8", className)}
|
|
212
232
|
{...props}
|
|
213
233
|
/>
|
|
214
234
|
));
|
|
@@ -219,12 +239,20 @@ const MenubarShortcut = ({
|
|
|
219
239
|
...props
|
|
220
240
|
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
|
221
241
|
return (
|
|
222
|
-
<span
|
|
242
|
+
<span
|
|
243
|
+
data-sonance-name="menubar"
|
|
244
|
+
className={cn(
|
|
245
|
+
"ml-auto text-xs tracking-widest text-foreground-muted",
|
|
246
|
+
"px-1.5 py-0.5 rounded-md",
|
|
247
|
+
"bg-white/40 dark:bg-white/5",
|
|
248
|
+
"border border-black/5 dark:border-white/10",
|
|
249
|
+
className
|
|
250
|
+
)}
|
|
223
251
|
{...props}
|
|
224
252
|
/>
|
|
225
253
|
);
|
|
226
254
|
};
|
|
227
|
-
MenubarShortcut.
|
|
255
|
+
MenubarShortcut.displayName = "MenubarShortcut";
|
|
228
256
|
|
|
229
257
|
export {
|
|
230
258
|
Menubar,
|
|
@@ -244,4 +272,3 @@ export {
|
|
|
244
272
|
MenubarSub,
|
|
245
273
|
MenubarShortcut,
|
|
246
274
|
};
|
|
247
|
-
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
|
|
2
|
+
import Image from 'next/image';
|
|
2
3
|
import {
|
|
3
4
|
Navbar,
|
|
4
5
|
NavbarContent,
|
|
@@ -9,6 +10,24 @@ import {
|
|
|
9
10
|
} from './navbar';
|
|
10
11
|
import { Button } from './button';
|
|
11
12
|
|
|
13
|
+
// Logo paths for different contexts
|
|
14
|
+
const LOGO_DARK = '/logos/sonance/Sonance_Logo_2C_Dark_RGB.png'; // Charcoal text - for light backgrounds
|
|
15
|
+
const LOGO_LIGHT = '/logos/sonance/Sonance_Logo_2C_Light_RGB.png'; // White/light text - for dark backgrounds
|
|
16
|
+
|
|
17
|
+
// Reusable logo component for stories
|
|
18
|
+
function NavbarLogo({ variant = 'dark' }: { variant?: 'dark' | 'light' }) {
|
|
19
|
+
return (
|
|
20
|
+
<Image
|
|
21
|
+
src={variant === 'dark' ? LOGO_DARK : LOGO_LIGHT}
|
|
22
|
+
alt="Sonance"
|
|
23
|
+
width={120}
|
|
24
|
+
height={24}
|
|
25
|
+
className="h-5 w-auto object-contain"
|
|
26
|
+
priority
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
12
31
|
const meta: Meta<typeof Navbar> = {
|
|
13
32
|
title: 'Components/Navigation/Navbar',
|
|
14
33
|
component: Navbar,
|
|
@@ -39,7 +58,7 @@ export const Default: Story = {
|
|
|
39
58
|
<Navbar>
|
|
40
59
|
<NavbarContent>
|
|
41
60
|
<NavbarBrand>
|
|
42
|
-
<
|
|
61
|
+
<NavbarLogo variant="dark" />
|
|
43
62
|
</NavbarBrand>
|
|
44
63
|
<NavbarItems>
|
|
45
64
|
<NavbarItem href="#" active>Home</NavbarItem>
|
|
@@ -58,14 +77,14 @@ export const Dark: Story = {
|
|
|
58
77
|
<Navbar variant="dark">
|
|
59
78
|
<NavbarContent>
|
|
60
79
|
<NavbarBrand>
|
|
61
|
-
<
|
|
80
|
+
<NavbarLogo variant="light" />
|
|
62
81
|
</NavbarBrand>
|
|
63
82
|
<NavbarItems>
|
|
64
83
|
<NavbarItem href="#" active>Home</NavbarItem>
|
|
65
84
|
<NavbarItem href="#">Products</NavbarItem>
|
|
66
85
|
<NavbarItem href="#">About</NavbarItem>
|
|
67
86
|
</NavbarItems>
|
|
68
|
-
<Button id="nav-button-
|
|
87
|
+
<Button id="nav-button-outline" size="sm" variant="outline" className="text-white border-white/30 hover:bg-white/10">Sign In</Button>
|
|
69
88
|
</NavbarContent>
|
|
70
89
|
</Navbar>
|
|
71
90
|
),
|
|
@@ -77,14 +96,14 @@ export const Transparent: Story = {
|
|
|
77
96
|
<Navbar variant="transparent" className="text-white">
|
|
78
97
|
<NavbarContent>
|
|
79
98
|
<NavbarBrand>
|
|
80
|
-
<
|
|
99
|
+
<NavbarLogo variant="light" />
|
|
81
100
|
</NavbarBrand>
|
|
82
101
|
<NavbarItems>
|
|
83
102
|
<NavbarItem href="#" active>Home</NavbarItem>
|
|
84
103
|
<NavbarItem href="#">Products</NavbarItem>
|
|
85
104
|
<NavbarItem href="#">About</NavbarItem>
|
|
86
105
|
</NavbarItems>
|
|
87
|
-
<Button id="nav-button-
|
|
106
|
+
<Button id="nav-button-outline" size="sm" variant="outline" className="text-white border-white/30 hover:bg-white/10">Sign In</Button>
|
|
88
107
|
</NavbarContent>
|
|
89
108
|
</Navbar>
|
|
90
109
|
</div>
|
|
@@ -97,7 +116,7 @@ export const Blur: Story = {
|
|
|
97
116
|
<Navbar variant="blur">
|
|
98
117
|
<NavbarContent>
|
|
99
118
|
<NavbarBrand>
|
|
100
|
-
<
|
|
119
|
+
<NavbarLogo variant="dark" />
|
|
101
120
|
</NavbarBrand>
|
|
102
121
|
<NavbarItems>
|
|
103
122
|
<NavbarItem href="#" active>Home</NavbarItem>
|
|
@@ -114,10 +133,56 @@ export const Blur: Story = {
|
|
|
114
133
|
),
|
|
115
134
|
};
|
|
116
135
|
|
|
136
|
+
export const Sticky: Story = {
|
|
137
|
+
render: () => (
|
|
138
|
+
<div className="h-[400px] overflow-auto bg-background-secondary">
|
|
139
|
+
<Navbar sticky>
|
|
140
|
+
<NavbarContent>
|
|
141
|
+
<NavbarBrand>
|
|
142
|
+
<NavbarLogo variant="dark" />
|
|
143
|
+
</NavbarBrand>
|
|
144
|
+
<NavbarItems>
|
|
145
|
+
<NavbarItem href="#" active>Home</NavbarItem>
|
|
146
|
+
<NavbarItem href="#">Products</NavbarItem>
|
|
147
|
+
<NavbarItem href="#">About</NavbarItem>
|
|
148
|
+
</NavbarItems>
|
|
149
|
+
<Button id="nav-button" size="sm">Sign In</Button>
|
|
150
|
+
</NavbarContent>
|
|
151
|
+
</Navbar>
|
|
152
|
+
<div className="p-8 space-y-4">
|
|
153
|
+
{Array.from({ length: 10 }).map((_, i) => (
|
|
154
|
+
<p key={i} className="text-foreground-secondary">
|
|
155
|
+
Scroll down to see the sticky navbar in action. Lorem ipsum dolor sit amet,
|
|
156
|
+
consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore.
|
|
157
|
+
</p>
|
|
158
|
+
))}
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const NoBorder: Story = {
|
|
165
|
+
render: () => (
|
|
166
|
+
<Navbar bordered={false}>
|
|
167
|
+
<NavbarContent>
|
|
168
|
+
<NavbarBrand>
|
|
169
|
+
<NavbarLogo variant="dark" />
|
|
170
|
+
</NavbarBrand>
|
|
171
|
+
<NavbarItems>
|
|
172
|
+
<NavbarItem href="#" active>Home</NavbarItem>
|
|
173
|
+
<NavbarItem href="#">Products</NavbarItem>
|
|
174
|
+
<NavbarItem href="#">About</NavbarItem>
|
|
175
|
+
</NavbarItems>
|
|
176
|
+
<Button id="nav-button" size="sm">Sign In</Button>
|
|
177
|
+
</NavbarContent>
|
|
178
|
+
</Navbar>
|
|
179
|
+
),
|
|
180
|
+
};
|
|
181
|
+
|
|
117
182
|
export const Responsive: Story = {
|
|
118
183
|
render: () => (
|
|
119
184
|
<ResponsiveNavbar
|
|
120
|
-
brand={<
|
|
185
|
+
brand={<NavbarLogo variant="dark" />}
|
|
121
186
|
items={[
|
|
122
187
|
{ label: 'Home', href: '#', active: true },
|
|
123
188
|
{ label: 'Products', href: '#' },
|
|
@@ -129,13 +194,12 @@ export const Responsive: Story = {
|
|
|
129
194
|
),
|
|
130
195
|
};
|
|
131
196
|
|
|
132
|
-
export const
|
|
197
|
+
export const WithActions: Story = {
|
|
133
198
|
render: () => (
|
|
134
199
|
<Navbar>
|
|
135
200
|
<NavbarContent>
|
|
136
201
|
<NavbarBrand>
|
|
137
|
-
<
|
|
138
|
-
<span id="nav-span-sonance" className="text-xl font-semibold">Sonance</span>
|
|
202
|
+
<NavbarLogo variant="dark" />
|
|
139
203
|
</NavbarBrand>
|
|
140
204
|
<NavbarItems>
|
|
141
205
|
<NavbarItem href="#" active>Home</NavbarItem>
|
|
@@ -160,7 +224,7 @@ export const ResponsiveMatrix: Story = {
|
|
|
160
224
|
<h4 id="nav-h4-mobile-375px" className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
|
|
161
225
|
<div className="w-[375px] border border-dashed border-border overflow-hidden">
|
|
162
226
|
<ResponsiveNavbar
|
|
163
|
-
brand={<
|
|
227
|
+
brand={<NavbarLogo variant="dark" />}
|
|
164
228
|
items={[
|
|
165
229
|
{ label: 'Home', href: '#', active: true },
|
|
166
230
|
{ label: 'Products', href: '#' },
|
|
@@ -177,7 +241,7 @@ export const ResponsiveMatrix: Story = {
|
|
|
177
241
|
<Navbar>
|
|
178
242
|
<NavbarContent>
|
|
179
243
|
<NavbarBrand>
|
|
180
|
-
<
|
|
244
|
+
<NavbarLogo variant="dark" />
|
|
181
245
|
</NavbarBrand>
|
|
182
246
|
<NavbarItems>
|
|
183
247
|
<NavbarItem href="#" active>Home</NavbarItem>
|
|
@@ -196,7 +260,7 @@ export const ResponsiveMatrix: Story = {
|
|
|
196
260
|
<Navbar>
|
|
197
261
|
<NavbarContent>
|
|
198
262
|
<NavbarBrand>
|
|
199
|
-
<
|
|
263
|
+
<NavbarLogo variant="dark" />
|
|
200
264
|
</NavbarBrand>
|
|
201
265
|
<NavbarItems>
|
|
202
266
|
<NavbarItem href="#" active>Home</NavbarItem>
|
|
@@ -216,3 +280,66 @@ export const ResponsiveMatrix: Story = {
|
|
|
216
280
|
</div>
|
|
217
281
|
),
|
|
218
282
|
};
|
|
283
|
+
|
|
284
|
+
// All Variants Side by Side
|
|
285
|
+
export const AllVariants: Story = {
|
|
286
|
+
render: () => (
|
|
287
|
+
<div className="space-y-8">
|
|
288
|
+
<div>
|
|
289
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Default</h4>
|
|
290
|
+
<Navbar>
|
|
291
|
+
<NavbarContent>
|
|
292
|
+
<NavbarBrand><NavbarLogo variant="dark" /></NavbarBrand>
|
|
293
|
+
<NavbarItems>
|
|
294
|
+
<NavbarItem href="#" active>Home</NavbarItem>
|
|
295
|
+
<NavbarItem href="#">Products</NavbarItem>
|
|
296
|
+
</NavbarItems>
|
|
297
|
+
<Button size="sm">Sign In</Button>
|
|
298
|
+
</NavbarContent>
|
|
299
|
+
</Navbar>
|
|
300
|
+
</div>
|
|
301
|
+
|
|
302
|
+
<div>
|
|
303
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Dark</h4>
|
|
304
|
+
<Navbar variant="dark">
|
|
305
|
+
<NavbarContent>
|
|
306
|
+
<NavbarBrand><NavbarLogo variant="light" /></NavbarBrand>
|
|
307
|
+
<NavbarItems>
|
|
308
|
+
<NavbarItem href="#" active>Home</NavbarItem>
|
|
309
|
+
<NavbarItem href="#">Products</NavbarItem>
|
|
310
|
+
</NavbarItems>
|
|
311
|
+
<Button size="sm" variant="outline" className="text-white border-white/30 hover:bg-white/10">Sign In</Button>
|
|
312
|
+
</NavbarContent>
|
|
313
|
+
</Navbar>
|
|
314
|
+
</div>
|
|
315
|
+
|
|
316
|
+
<div className="bg-gradient-to-r from-sonance-charcoal to-sonance-gray-700 p-0">
|
|
317
|
+
<h4 className="text-xs uppercase text-white/60 mb-2 px-4 pt-4">Transparent (on gradient)</h4>
|
|
318
|
+
<Navbar variant="transparent" className="text-white">
|
|
319
|
+
<NavbarContent>
|
|
320
|
+
<NavbarBrand><NavbarLogo variant="light" /></NavbarBrand>
|
|
321
|
+
<NavbarItems>
|
|
322
|
+
<NavbarItem href="#" active>Home</NavbarItem>
|
|
323
|
+
<NavbarItem href="#">Products</NavbarItem>
|
|
324
|
+
</NavbarItems>
|
|
325
|
+
<Button size="sm" variant="outline" className="text-white border-white/30 hover:bg-white/10">Sign In</Button>
|
|
326
|
+
</NavbarContent>
|
|
327
|
+
</Navbar>
|
|
328
|
+
</div>
|
|
329
|
+
|
|
330
|
+
<div className="bg-gradient-to-r from-sonance-blue to-foundation-green p-0">
|
|
331
|
+
<h4 className="text-xs uppercase text-white/60 mb-2 px-4 pt-4">Blur (on gradient)</h4>
|
|
332
|
+
<Navbar variant="blur">
|
|
333
|
+
<NavbarContent>
|
|
334
|
+
<NavbarBrand><NavbarLogo variant="dark" /></NavbarBrand>
|
|
335
|
+
<NavbarItems>
|
|
336
|
+
<NavbarItem href="#" active>Home</NavbarItem>
|
|
337
|
+
<NavbarItem href="#">Products</NavbarItem>
|
|
338
|
+
</NavbarItems>
|
|
339
|
+
<Button size="sm">Sign In</Button>
|
|
340
|
+
</NavbarContent>
|
|
341
|
+
</Navbar>
|
|
342
|
+
</div>
|
|
343
|
+
</div>
|
|
344
|
+
),
|
|
345
|
+
};
|
|
@@ -13,14 +13,30 @@ interface NavbarProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
13
13
|
export const Navbar = forwardRef<HTMLElement, NavbarProps>(
|
|
14
14
|
({ className, variant = "default", sticky = false, bordered = true, children, ...props }, ref) => {
|
|
15
15
|
const variantClasses = {
|
|
16
|
-
default: "bg-
|
|
16
|
+
default: "bg-white/70 dark:bg-white/[0.03] backdrop-blur-lg",
|
|
17
17
|
dark: "bg-sonance-charcoal text-sonance-white",
|
|
18
18
|
transparent: "bg-transparent",
|
|
19
|
-
blur: "bg-
|
|
19
|
+
blur: "bg-white/60 dark:bg-black/40 backdrop-blur-xl",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const borderClasses = {
|
|
23
|
+
default: "border-b border-black/8 dark:border-white/8",
|
|
24
|
+
dark: "border-b border-white/10",
|
|
25
|
+
transparent: "",
|
|
26
|
+
blur: "border-b border-black/8 dark:border-white/8",
|
|
20
27
|
};
|
|
21
28
|
|
|
22
29
|
return (
|
|
23
|
-
<nav
|
|
30
|
+
<nav
|
|
31
|
+
ref={ref}
|
|
32
|
+
data-sonance-name="navbar"
|
|
33
|
+
className={cn(
|
|
34
|
+
"w-full px-4 md:px-6 py-3",
|
|
35
|
+
variantClasses[variant],
|
|
36
|
+
bordered && borderClasses[variant],
|
|
37
|
+
sticky && "sticky top-0 z-50",
|
|
38
|
+
className
|
|
39
|
+
)}
|
|
24
40
|
{...props}
|
|
25
41
|
>
|
|
26
42
|
{children}
|
|
@@ -133,7 +149,8 @@ export function NavbarMobileMenu({ isOpen, children, className }: NavbarMobileMe
|
|
|
133
149
|
<div
|
|
134
150
|
className={cn(
|
|
135
151
|
"md:hidden absolute left-0 right-0 top-full",
|
|
136
|
-
"bg-
|
|
152
|
+
"bg-white/90 dark:bg-black/80 backdrop-blur-xl",
|
|
153
|
+
"border-b border-black/10 dark:border-white/10 shadow-xl",
|
|
137
154
|
"animate-in slide-in-from-top-2 duration-200",
|
|
138
155
|
className
|
|
139
156
|
)}
|
|
@@ -198,7 +215,7 @@ export function ResponsiveNavbar({
|
|
|
198
215
|
{item.label}
|
|
199
216
|
</a>
|
|
200
217
|
))}
|
|
201
|
-
{actions && <div className="pt-4 border-t border-border">{actions}</div>}
|
|
218
|
+
{actions && <div className="pt-4 border-t border-black/8 dark:border-white/8">{actions}</div>}
|
|
202
219
|
</NavbarMobileMenu>
|
|
203
220
|
</Navbar>
|
|
204
221
|
);
|
|
@@ -12,6 +12,7 @@ const NavigationMenu = React.forwardRef<
|
|
|
12
12
|
>(({ className, children, ...props }, ref) => (
|
|
13
13
|
<NavigationMenuPrimitive.Root
|
|
14
14
|
ref={ref}
|
|
15
|
+
data-sonance-name="navigation-menu"
|
|
15
16
|
className={cn(
|
|
16
17
|
"relative z-10 flex max-w-max flex-1 items-center justify-center",
|
|
17
18
|
className
|
|
@@ -42,7 +43,16 @@ NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
|
|
|
42
43
|
const NavigationMenuItem = NavigationMenuPrimitive.Item;
|
|
43
44
|
|
|
44
45
|
const navigationMenuTriggerStyle = cva(
|
|
45
|
-
|
|
46
|
+
cn(
|
|
47
|
+
"group inline-flex h-10 w-max items-center justify-center rounded-xl px-4 py-2 text-sm font-medium",
|
|
48
|
+
"transition-all duration-150",
|
|
49
|
+
"bg-transparent backdrop-blur-sm",
|
|
50
|
+
"hover:bg-white/60 dark:hover:bg-white/10 hover:text-foreground",
|
|
51
|
+
"focus:bg-white/60 dark:focus:bg-white/10 focus:text-foreground focus:outline-none",
|
|
52
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
53
|
+
"data-[active]:bg-white/50 dark:data-[active]:bg-white/8",
|
|
54
|
+
"data-[state=open]:bg-white/60 dark:data-[state=open]:bg-white/10"
|
|
55
|
+
)
|
|
46
56
|
);
|
|
47
57
|
|
|
48
58
|
const NavigationMenuTrigger = React.forwardRef<
|
|
@@ -70,7 +80,12 @@ const NavigationMenuContent = React.forwardRef<
|
|
|
70
80
|
<NavigationMenuPrimitive.Content
|
|
71
81
|
ref={ref}
|
|
72
82
|
className={cn(
|
|
73
|
-
"left-0 top-0 w-full
|
|
83
|
+
"left-0 top-0 w-full",
|
|
84
|
+
"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out",
|
|
85
|
+
"data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out",
|
|
86
|
+
"data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52",
|
|
87
|
+
"data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52",
|
|
88
|
+
"md:absolute md:w-auto",
|
|
74
89
|
className
|
|
75
90
|
)}
|
|
76
91
|
{...props}
|
|
@@ -84,10 +99,18 @@ const NavigationMenuViewport = React.forwardRef<
|
|
|
84
99
|
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
|
|
85
100
|
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
|
|
86
101
|
>(({ className, ...props }, ref) => (
|
|
87
|
-
<div
|
|
102
|
+
<div
|
|
103
|
+
data-sonance-name="navigation-menu"
|
|
104
|
+
className={cn("absolute left-0 top-full flex justify-center")}
|
|
105
|
+
>
|
|
88
106
|
<NavigationMenuPrimitive.Viewport
|
|
89
107
|
className={cn(
|
|
90
|
-
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden
|
|
108
|
+
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden",
|
|
109
|
+
"rounded-xl backdrop-blur-xl",
|
|
110
|
+
"bg-white/90 dark:bg-black/80",
|
|
111
|
+
"border border-black/10 dark:border-white/10",
|
|
112
|
+
"shadow-[0_8px_32px_rgba(0,0,0,0.12)] dark:shadow-[0_8px_32px_rgba(0,0,0,0.4)]",
|
|
113
|
+
"text-foreground",
|
|
91
114
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
92
115
|
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90",
|
|
93
116
|
"md:w-[var(--radix-navigation-menu-viewport-width)]",
|
|
@@ -115,7 +138,7 @@ const NavigationMenuIndicator = React.forwardRef<
|
|
|
115
138
|
)}
|
|
116
139
|
{...props}
|
|
117
140
|
>
|
|
118
|
-
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-
|
|
141
|
+
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-white/80 dark:bg-white/10 shadow-md" />
|
|
119
142
|
</NavigationMenuPrimitive.Indicator>
|
|
120
143
|
));
|
|
121
144
|
NavigationMenuIndicator.displayName =
|
|
@@ -132,4 +155,3 @@ export {
|
|
|
132
155
|
NavigationMenuIndicator,
|
|
133
156
|
NavigationMenuViewport,
|
|
134
157
|
};
|
|
135
|
-
|