sonance-brand-mcp 1.2.4 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/components/alert-dialog.stories.tsx +142 -0
- package/dist/assets/components/alert-dialog.tsx +142 -0
- package/dist/assets/components/aspect-ratio.stories.tsx +67 -0
- package/dist/assets/components/aspect-ratio.tsx +8 -0
- package/dist/assets/components/avatar.tsx +64 -20
- package/dist/assets/components/carousel.stories.tsx +158 -0
- package/dist/assets/components/carousel.tsx +262 -0
- package/dist/assets/components/chart.stories.tsx +376 -0
- package/dist/assets/components/chart.tsx +384 -0
- package/dist/assets/components/checkbox.tsx +12 -2
- package/dist/assets/components/code.tsx +22 -20
- package/dist/assets/components/collapsible.stories.tsx +128 -0
- package/dist/assets/components/collapsible.tsx +10 -0
- package/dist/assets/components/command.stories.tsx +183 -0
- package/dist/assets/components/command.tsx +170 -0
- package/dist/assets/components/context-menu.stories.tsx +159 -0
- package/dist/assets/components/context-menu.tsx +218 -0
- package/dist/assets/components/divider.tsx +38 -35
- package/dist/assets/components/dropdown-menu.tsx +217 -0
- package/dist/assets/components/hover-card.stories.tsx +113 -0
- package/dist/assets/components/hover-card.tsx +35 -0
- package/dist/assets/components/kbd.tsx +6 -6
- package/dist/assets/components/menubar.stories.tsx +208 -0
- package/dist/assets/components/menubar.tsx +251 -0
- package/dist/assets/components/navigation-menu.stories.tsx +237 -0
- package/dist/assets/components/navigation-menu.tsx +135 -0
- package/dist/assets/components/resizable.stories.tsx +197 -0
- package/dist/assets/components/resizable.tsx +47 -0
- package/dist/assets/components/scroll-area.stories.tsx +123 -0
- package/dist/assets/components/scroll-area.tsx +48 -0
- package/dist/assets/components/scroll-shadow.tsx +29 -7
- package/dist/assets/components/separator.tsx +32 -0
- package/dist/assets/components/sheet.tsx +141 -0
- package/dist/assets/components/sidebar.stories.tsx +351 -0
- package/dist/assets/components/sidebar.tsx +760 -0
- package/dist/assets/components/toggle-group.stories.tsx +153 -0
- package/dist/assets/components/toggle-group.tsx +61 -0
- package/dist/assets/components/toggle.stories.tsx +77 -0
- package/dist/assets/components/toggle.tsx +46 -0
- package/dist/assets/components/tooltip.tsx +23 -90
- package/dist/assets/globals.css +30 -0
- package/dist/assets/logos/40th-anniversary/Sonance_40_Logo_CMYK_BEAM_BLUE_40_AND_BEAM_DARK.png +0 -0
- package/dist/assets/logos/Sonance logo dark mode.png +0 -0
- package/dist/assets/logos/Sonance logo light mode.png +0 -0
- package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_2C_Light_RGB_05162025.png +0 -0
- package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_3C_Dark_RGB_05162025.png +0 -0
- package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_White_RGB_05162025.png +0 -0
- package/dist/assets/logos/iport/IPORT_Sonance_LockUp_2C_Dark_RGB.png +0 -0
- package/dist/assets/logos/iport/IPORT_Sonance_LockUp_2C_Light_RGB.png +0 -0
- package/dist/assets/logos/james/James_Logo_Black_CMYK.png +0 -0
- package/dist/assets/logos/james/James_Logo_Black_RGB.png +0 -0
- package/dist/assets/logos/james/James_Logo_LtGray_CMYK.png +0 -0
- package/dist/assets/logos/james/James_Logo_LtGray_RGB.png +0 -0
- package/dist/assets/logos/james/James_Logo_Polished_RGB.png +0 -0
- package/dist/assets/logos/james/James_Logo_Reverse_CMYK.png +0 -0
- package/dist/assets/logos/james/James_Logo_Reverse_RGB.png +0 -0
- package/dist/assets/logos/james/James_Logo_White_CMYK.png +0 -0
- package/dist/assets/logos/life-is-better/Sonance_LifeisBetter_Dark_RGB.png +0 -0
- package/dist/assets/logos/life-is-better/Sonance_LifeisBetter_Light_RGB.png +0 -0
- package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Dark_RGB.png +0 -0
- package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Light_RGB.png +0 -0
- package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Reverse_RGB.png +0 -0
- package/dist/assets/logos/my-sonance/My.Sonance_Logo_Black_RGB.png +0 -0
- package/dist/assets/logos/my-sonance/My.Sonance_Logo_Reverse_RGB.png +0 -0
- package/dist/assets/logos/sonance/Sonance_Logo_2C_Dark_RGB.png +0 -0
- package/dist/assets/logos/sonance/Sonance_Logo_2C_Light_RGB.png +0 -0
- package/dist/assets/logos/sonance/Sonance_Logo_2C_Reverse_RGB.png +0 -0
- package/dist/assets/logos/sonance/Sonance_Logo_Black_RGB.png +0 -0
- package/dist/assets/logos/sonance/Sonance_Logo_Grayscale_RGB.png +0 -0
- package/dist/assets/logos/sonance/Sonance_Logo_Reverse_RGB.png +0 -0
- package/dist/assets/logos/sonance-academy/SonanceAcademy_Logo_Dark_CMYK.png +0 -0
- package/dist/assets/logos/sonance-academy/SonanceAcademy_Logo_Light_CMYK.png +0 -0
- package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Dark_RGB.png +0 -0
- package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Light_RGB.png +0 -0
- package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Reverse_RGB.png +0 -0
- package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Black_RGB.png +0 -0
- package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Grayscale_RGB.png +0 -0
- package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Reverse_RGB.png +0 -0
- package/dist/assets/logos/sonance-james/Sonance_James_Lockup_Dark.png +0 -0
- package/dist/assets/logos/sonance-james/Sonance_James_Lockup_Light.png +0 -0
- package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_LockupStacked_Dark.png +0 -0
- package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_LockupStacked_Light.png +0 -0
- package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_Lockup_Dark.png +0 -0
- package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_Lockup_Light.png +0 -0
- package/dist/assets/logos/trufig/TrufigLogo_Black.png +0 -0
- package/dist/assets/logos/trufig/TrufigLogo_Light.png +0 -0
- package/dist/assets/logos/trufig/TrufigWatermark_Black.png +0 -0
- package/dist/assets/logos/trufig/TrufigWatermark_Light.png +0 -0
- package/dist/index.js +416 -17
- package/package.json +1 -1
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
NavigationMenu,
|
|
4
|
+
NavigationMenuContent,
|
|
5
|
+
NavigationMenuItem,
|
|
6
|
+
NavigationMenuLink,
|
|
7
|
+
NavigationMenuList,
|
|
8
|
+
NavigationMenuTrigger,
|
|
9
|
+
navigationMenuTriggerStyle,
|
|
10
|
+
} from "./navigation-menu";
|
|
11
|
+
import { cn } from "@/lib/utils";
|
|
12
|
+
import React from "react";
|
|
13
|
+
|
|
14
|
+
const meta: Meta<typeof NavigationMenu> = {
|
|
15
|
+
title: "Components/Navigation/NavigationMenu",
|
|
16
|
+
component: NavigationMenu,
|
|
17
|
+
parameters: {
|
|
18
|
+
layout: "centered",
|
|
19
|
+
},
|
|
20
|
+
tags: ["autodocs"],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
type Story = StoryObj<typeof NavigationMenu>;
|
|
25
|
+
|
|
26
|
+
const components: { title: string; href: string; description: string }[] = [
|
|
27
|
+
{
|
|
28
|
+
title: "Alert Dialog",
|
|
29
|
+
href: "#",
|
|
30
|
+
description:
|
|
31
|
+
"A modal dialog that interrupts the user with important content and expects a response.",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
title: "Hover Card",
|
|
35
|
+
href: "#",
|
|
36
|
+
description:
|
|
37
|
+
"For sighted users to preview content available behind a link.",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
title: "Progress",
|
|
41
|
+
href: "#",
|
|
42
|
+
description:
|
|
43
|
+
"Displays an indicator showing the completion progress of a task.",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
title: "Scroll Area",
|
|
47
|
+
href: "#",
|
|
48
|
+
description: "Visually or semantically separates content.",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
title: "Tabs",
|
|
52
|
+
href: "#",
|
|
53
|
+
description:
|
|
54
|
+
"A set of layered sections of content—known as tab panels.",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
title: "Tooltip",
|
|
58
|
+
href: "#",
|
|
59
|
+
description:
|
|
60
|
+
"A popup that displays information related to an element.",
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const ListItem = React.forwardRef<
|
|
65
|
+
React.ElementRef<"a">,
|
|
66
|
+
React.ComponentPropsWithoutRef<"a">
|
|
67
|
+
>(({ className, title, children, ...props }, ref) => {
|
|
68
|
+
return (
|
|
69
|
+
<li>
|
|
70
|
+
<NavigationMenuLink asChild>
|
|
71
|
+
<a
|
|
72
|
+
ref={ref}
|
|
73
|
+
className={cn(
|
|
74
|
+
"block select-none space-y-1 rounded-sm p-3 leading-none no-underline outline-none transition-colors hover:bg-secondary-hover hover:text-foreground focus:bg-secondary-hover focus:text-foreground",
|
|
75
|
+
className
|
|
76
|
+
)}
|
|
77
|
+
{...props}
|
|
78
|
+
>
|
|
79
|
+
<div className="text-sm font-medium leading-none">{title}</div>
|
|
80
|
+
<p className="line-clamp-2 text-sm leading-snug text-foreground-muted">
|
|
81
|
+
{children}
|
|
82
|
+
</p>
|
|
83
|
+
</a>
|
|
84
|
+
</NavigationMenuLink>
|
|
85
|
+
</li>
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
ListItem.displayName = "ListItem";
|
|
89
|
+
|
|
90
|
+
export const Default: Story = {
|
|
91
|
+
render: () => (
|
|
92
|
+
<NavigationMenu>
|
|
93
|
+
<NavigationMenuList>
|
|
94
|
+
<NavigationMenuItem>
|
|
95
|
+
<NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
|
|
96
|
+
<NavigationMenuContent>
|
|
97
|
+
<ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
|
|
98
|
+
<li className="row-span-3">
|
|
99
|
+
<NavigationMenuLink asChild>
|
|
100
|
+
<a
|
|
101
|
+
className="flex h-full w-full select-none flex-col justify-end rounded-sm bg-gradient-to-b from-secondary-hover/50 to-secondary-hover p-6 no-underline outline-none focus:shadow-md"
|
|
102
|
+
href="#"
|
|
103
|
+
>
|
|
104
|
+
<div className="mb-2 mt-4 text-lg font-medium">
|
|
105
|
+
Sonance
|
|
106
|
+
</div>
|
|
107
|
+
<p className="text-sm leading-tight text-foreground-muted">
|
|
108
|
+
Premium architectural speakers and outdoor audio solutions.
|
|
109
|
+
</p>
|
|
110
|
+
</a>
|
|
111
|
+
</NavigationMenuLink>
|
|
112
|
+
</li>
|
|
113
|
+
<ListItem href="#" title="Introduction">
|
|
114
|
+
Learn about the Sonance brand and our commitment to audio excellence.
|
|
115
|
+
</ListItem>
|
|
116
|
+
<ListItem href="#" title="Installation">
|
|
117
|
+
How to get started with your Sonance audio system.
|
|
118
|
+
</ListItem>
|
|
119
|
+
<ListItem href="#" title="Support">
|
|
120
|
+
Find answers and get help from our team.
|
|
121
|
+
</ListItem>
|
|
122
|
+
</ul>
|
|
123
|
+
</NavigationMenuContent>
|
|
124
|
+
</NavigationMenuItem>
|
|
125
|
+
<NavigationMenuItem>
|
|
126
|
+
<NavigationMenuTrigger>Components</NavigationMenuTrigger>
|
|
127
|
+
<NavigationMenuContent>
|
|
128
|
+
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
|
|
129
|
+
{components.map((component) => (
|
|
130
|
+
<ListItem
|
|
131
|
+
key={component.title}
|
|
132
|
+
title={component.title}
|
|
133
|
+
href={component.href}
|
|
134
|
+
>
|
|
135
|
+
{component.description}
|
|
136
|
+
</ListItem>
|
|
137
|
+
))}
|
|
138
|
+
</ul>
|
|
139
|
+
</NavigationMenuContent>
|
|
140
|
+
</NavigationMenuItem>
|
|
141
|
+
<NavigationMenuItem>
|
|
142
|
+
<a href="#">
|
|
143
|
+
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
|
144
|
+
Documentation
|
|
145
|
+
</NavigationMenuLink>
|
|
146
|
+
</a>
|
|
147
|
+
</NavigationMenuItem>
|
|
148
|
+
</NavigationMenuList>
|
|
149
|
+
</NavigationMenu>
|
|
150
|
+
),
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export const Simple: Story = {
|
|
154
|
+
render: () => (
|
|
155
|
+
<NavigationMenu>
|
|
156
|
+
<NavigationMenuList>
|
|
157
|
+
<NavigationMenuItem>
|
|
158
|
+
<a href="#">
|
|
159
|
+
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
|
160
|
+
Products
|
|
161
|
+
</NavigationMenuLink>
|
|
162
|
+
</a>
|
|
163
|
+
</NavigationMenuItem>
|
|
164
|
+
<NavigationMenuItem>
|
|
165
|
+
<a href="#">
|
|
166
|
+
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
|
167
|
+
Solutions
|
|
168
|
+
</NavigationMenuLink>
|
|
169
|
+
</a>
|
|
170
|
+
</NavigationMenuItem>
|
|
171
|
+
<NavigationMenuItem>
|
|
172
|
+
<a href="#">
|
|
173
|
+
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
|
174
|
+
Support
|
|
175
|
+
</NavigationMenuLink>
|
|
176
|
+
</a>
|
|
177
|
+
</NavigationMenuItem>
|
|
178
|
+
<NavigationMenuItem>
|
|
179
|
+
<a href="#">
|
|
180
|
+
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
|
181
|
+
About
|
|
182
|
+
</NavigationMenuLink>
|
|
183
|
+
</a>
|
|
184
|
+
</NavigationMenuItem>
|
|
185
|
+
</NavigationMenuList>
|
|
186
|
+
</NavigationMenu>
|
|
187
|
+
),
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export const ProductsMenu: Story = {
|
|
191
|
+
render: () => (
|
|
192
|
+
<NavigationMenu>
|
|
193
|
+
<NavigationMenuList>
|
|
194
|
+
<NavigationMenuItem>
|
|
195
|
+
<NavigationMenuTrigger>Architectural</NavigationMenuTrigger>
|
|
196
|
+
<NavigationMenuContent>
|
|
197
|
+
<ul className="grid gap-3 p-4 w-[400px]">
|
|
198
|
+
<ListItem href="#" title="In-Ceiling Speakers">
|
|
199
|
+
Invisible audio solutions for residential and commercial spaces.
|
|
200
|
+
</ListItem>
|
|
201
|
+
<ListItem href="#" title="In-Wall Speakers">
|
|
202
|
+
Seamless integration into any wall surface.
|
|
203
|
+
</ListItem>
|
|
204
|
+
<ListItem href="#" title="Invisible Series">
|
|
205
|
+
Completely hidden speakers that disappear into your walls.
|
|
206
|
+
</ListItem>
|
|
207
|
+
</ul>
|
|
208
|
+
</NavigationMenuContent>
|
|
209
|
+
</NavigationMenuItem>
|
|
210
|
+
<NavigationMenuItem>
|
|
211
|
+
<NavigationMenuTrigger>Outdoor</NavigationMenuTrigger>
|
|
212
|
+
<NavigationMenuContent>
|
|
213
|
+
<ul className="grid gap-3 p-4 w-[400px]">
|
|
214
|
+
<ListItem href="#" title="Landscape Series">
|
|
215
|
+
Outdoor speakers designed to blend into your garden.
|
|
216
|
+
</ListItem>
|
|
217
|
+
<ListItem href="#" title="Patio Series">
|
|
218
|
+
Weather-resistant speakers for covered outdoor areas.
|
|
219
|
+
</ListItem>
|
|
220
|
+
<ListItem href="#" title="Subwoofers">
|
|
221
|
+
Powerful bass for your outdoor entertainment.
|
|
222
|
+
</ListItem>
|
|
223
|
+
</ul>
|
|
224
|
+
</NavigationMenuContent>
|
|
225
|
+
</NavigationMenuItem>
|
|
226
|
+
<NavigationMenuItem>
|
|
227
|
+
<a href="#">
|
|
228
|
+
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
|
229
|
+
View All
|
|
230
|
+
</NavigationMenuLink>
|
|
231
|
+
</a>
|
|
232
|
+
</NavigationMenuItem>
|
|
233
|
+
</NavigationMenuList>
|
|
234
|
+
</NavigationMenu>
|
|
235
|
+
),
|
|
236
|
+
};
|
|
237
|
+
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
|
|
5
|
+
import { ChevronDown } from "lucide-react";
|
|
6
|
+
import { cva } from "class-variance-authority";
|
|
7
|
+
import { cn } from "@/lib/utils";
|
|
8
|
+
|
|
9
|
+
const NavigationMenu = React.forwardRef<
|
|
10
|
+
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
|
|
11
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
|
|
12
|
+
>(({ className, children, ...props }, ref) => (
|
|
13
|
+
<NavigationMenuPrimitive.Root
|
|
14
|
+
ref={ref}
|
|
15
|
+
className={cn(
|
|
16
|
+
"relative z-10 flex max-w-max flex-1 items-center justify-center",
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
<NavigationMenuViewport />
|
|
23
|
+
</NavigationMenuPrimitive.Root>
|
|
24
|
+
));
|
|
25
|
+
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
|
|
26
|
+
|
|
27
|
+
const NavigationMenuList = React.forwardRef<
|
|
28
|
+
React.ElementRef<typeof NavigationMenuPrimitive.List>,
|
|
29
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
|
|
30
|
+
>(({ className, ...props }, ref) => (
|
|
31
|
+
<NavigationMenuPrimitive.List
|
|
32
|
+
ref={ref}
|
|
33
|
+
className={cn(
|
|
34
|
+
"group flex flex-1 list-none items-center justify-center space-x-1",
|
|
35
|
+
className
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
));
|
|
40
|
+
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
|
|
41
|
+
|
|
42
|
+
const NavigationMenuItem = NavigationMenuPrimitive.Item;
|
|
43
|
+
|
|
44
|
+
const navigationMenuTriggerStyle = cva(
|
|
45
|
+
"group inline-flex h-10 w-max items-center justify-center rounded-sm bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-secondary-hover hover:text-foreground focus:bg-secondary-hover focus:text-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-secondary-hover/50 data-[state=open]:bg-secondary-hover/50"
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const NavigationMenuTrigger = React.forwardRef<
|
|
49
|
+
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
|
|
50
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
|
|
51
|
+
>(({ className, children, ...props }, ref) => (
|
|
52
|
+
<NavigationMenuPrimitive.Trigger
|
|
53
|
+
ref={ref}
|
|
54
|
+
className={cn(navigationMenuTriggerStyle(), "group", className)}
|
|
55
|
+
{...props}
|
|
56
|
+
>
|
|
57
|
+
{children}{" "}
|
|
58
|
+
<ChevronDown
|
|
59
|
+
className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
|
|
60
|
+
aria-hidden="true"
|
|
61
|
+
/>
|
|
62
|
+
</NavigationMenuPrimitive.Trigger>
|
|
63
|
+
));
|
|
64
|
+
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
|
|
65
|
+
|
|
66
|
+
const NavigationMenuContent = React.forwardRef<
|
|
67
|
+
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
|
|
68
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
|
|
69
|
+
>(({ className, ...props }, ref) => (
|
|
70
|
+
<NavigationMenuPrimitive.Content
|
|
71
|
+
ref={ref}
|
|
72
|
+
className={cn(
|
|
73
|
+
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto",
|
|
74
|
+
className
|
|
75
|
+
)}
|
|
76
|
+
{...props}
|
|
77
|
+
/>
|
|
78
|
+
));
|
|
79
|
+
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
|
|
80
|
+
|
|
81
|
+
const NavigationMenuLink = NavigationMenuPrimitive.Link;
|
|
82
|
+
|
|
83
|
+
const NavigationMenuViewport = React.forwardRef<
|
|
84
|
+
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
|
|
85
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
|
|
86
|
+
>(({ className, ...props }, ref) => (
|
|
87
|
+
<div className={cn("absolute left-0 top-full flex justify-center")}>
|
|
88
|
+
<NavigationMenuPrimitive.Viewport
|
|
89
|
+
className={cn(
|
|
90
|
+
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-sm border border-border bg-card text-foreground shadow-lg",
|
|
91
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
92
|
+
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90",
|
|
93
|
+
"md:w-[var(--radix-navigation-menu-viewport-width)]",
|
|
94
|
+
className
|
|
95
|
+
)}
|
|
96
|
+
ref={ref}
|
|
97
|
+
{...props}
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
));
|
|
101
|
+
NavigationMenuViewport.displayName =
|
|
102
|
+
NavigationMenuPrimitive.Viewport.displayName;
|
|
103
|
+
|
|
104
|
+
const NavigationMenuIndicator = React.forwardRef<
|
|
105
|
+
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
|
|
106
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
|
|
107
|
+
>(({ className, ...props }, ref) => (
|
|
108
|
+
<NavigationMenuPrimitive.Indicator
|
|
109
|
+
ref={ref}
|
|
110
|
+
className={cn(
|
|
111
|
+
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
|
|
112
|
+
"data-[state=visible]:animate-in data-[state=hidden]:animate-out",
|
|
113
|
+
"data-[state=hidden]:fade-out data-[state=visible]:fade-in",
|
|
114
|
+
className
|
|
115
|
+
)}
|
|
116
|
+
{...props}
|
|
117
|
+
>
|
|
118
|
+
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
|
|
119
|
+
</NavigationMenuPrimitive.Indicator>
|
|
120
|
+
));
|
|
121
|
+
NavigationMenuIndicator.displayName =
|
|
122
|
+
NavigationMenuPrimitive.Indicator.displayName;
|
|
123
|
+
|
|
124
|
+
export {
|
|
125
|
+
navigationMenuTriggerStyle,
|
|
126
|
+
NavigationMenu,
|
|
127
|
+
NavigationMenuList,
|
|
128
|
+
NavigationMenuItem,
|
|
129
|
+
NavigationMenuContent,
|
|
130
|
+
NavigationMenuTrigger,
|
|
131
|
+
NavigationMenuLink,
|
|
132
|
+
NavigationMenuIndicator,
|
|
133
|
+
NavigationMenuViewport,
|
|
134
|
+
};
|
|
135
|
+
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
ResizableHandle,
|
|
4
|
+
ResizablePanel,
|
|
5
|
+
ResizablePanelGroup,
|
|
6
|
+
} from "./resizable";
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof ResizablePanelGroup> = {
|
|
9
|
+
title: "Components/Layout/Resizable",
|
|
10
|
+
component: ResizablePanelGroup,
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: "centered",
|
|
13
|
+
},
|
|
14
|
+
tags: ["autodocs"],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof ResizablePanelGroup>;
|
|
19
|
+
|
|
20
|
+
export const Default: Story = {
|
|
21
|
+
render: () => (
|
|
22
|
+
<ResizablePanelGroup
|
|
23
|
+
direction="horizontal"
|
|
24
|
+
className="max-w-md rounded-sm border border-border"
|
|
25
|
+
>
|
|
26
|
+
<ResizablePanel defaultSize={50}>
|
|
27
|
+
<div className="flex h-[200px] items-center justify-center p-6">
|
|
28
|
+
<span className="font-medium text-foreground">One</span>
|
|
29
|
+
</div>
|
|
30
|
+
</ResizablePanel>
|
|
31
|
+
<ResizableHandle />
|
|
32
|
+
<ResizablePanel defaultSize={50}>
|
|
33
|
+
<div className="flex h-[200px] items-center justify-center p-6">
|
|
34
|
+
<span className="font-medium text-foreground">Two</span>
|
|
35
|
+
</div>
|
|
36
|
+
</ResizablePanel>
|
|
37
|
+
</ResizablePanelGroup>
|
|
38
|
+
),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const Vertical: Story = {
|
|
42
|
+
render: () => (
|
|
43
|
+
<ResizablePanelGroup
|
|
44
|
+
direction="vertical"
|
|
45
|
+
className="min-h-[200px] max-w-md rounded-sm border border-border"
|
|
46
|
+
>
|
|
47
|
+
<ResizablePanel defaultSize={25}>
|
|
48
|
+
<div className="flex h-full items-center justify-center p-6">
|
|
49
|
+
<span className="font-medium text-foreground">Header</span>
|
|
50
|
+
</div>
|
|
51
|
+
</ResizablePanel>
|
|
52
|
+
<ResizableHandle />
|
|
53
|
+
<ResizablePanel defaultSize={75}>
|
|
54
|
+
<div className="flex h-full items-center justify-center p-6">
|
|
55
|
+
<span className="font-medium text-foreground">Content</span>
|
|
56
|
+
</div>
|
|
57
|
+
</ResizablePanel>
|
|
58
|
+
</ResizablePanelGroup>
|
|
59
|
+
),
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const WithHandle: Story = {
|
|
63
|
+
render: () => (
|
|
64
|
+
<ResizablePanelGroup
|
|
65
|
+
direction="horizontal"
|
|
66
|
+
className="min-h-[200px] max-w-md rounded-sm border border-border"
|
|
67
|
+
>
|
|
68
|
+
<ResizablePanel defaultSize={25}>
|
|
69
|
+
<div className="flex h-full items-center justify-center p-6">
|
|
70
|
+
<span className="font-medium text-foreground">Sidebar</span>
|
|
71
|
+
</div>
|
|
72
|
+
</ResizablePanel>
|
|
73
|
+
<ResizableHandle withHandle />
|
|
74
|
+
<ResizablePanel defaultSize={75}>
|
|
75
|
+
<div className="flex h-full items-center justify-center p-6">
|
|
76
|
+
<span className="font-medium text-foreground">Content</span>
|
|
77
|
+
</div>
|
|
78
|
+
</ResizablePanel>
|
|
79
|
+
</ResizablePanelGroup>
|
|
80
|
+
),
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const ThreePanels: Story = {
|
|
84
|
+
render: () => (
|
|
85
|
+
<ResizablePanelGroup
|
|
86
|
+
direction="horizontal"
|
|
87
|
+
className="min-h-[200px] max-w-lg rounded-sm border border-border"
|
|
88
|
+
>
|
|
89
|
+
<ResizablePanel defaultSize={20} minSize={15}>
|
|
90
|
+
<div className="flex h-full items-center justify-center p-4">
|
|
91
|
+
<span className="text-sm font-medium text-foreground">Nav</span>
|
|
92
|
+
</div>
|
|
93
|
+
</ResizablePanel>
|
|
94
|
+
<ResizableHandle withHandle />
|
|
95
|
+
<ResizablePanel defaultSize={60}>
|
|
96
|
+
<div className="flex h-full items-center justify-center p-4">
|
|
97
|
+
<span className="font-medium text-foreground">Main Content</span>
|
|
98
|
+
</div>
|
|
99
|
+
</ResizablePanel>
|
|
100
|
+
<ResizableHandle withHandle />
|
|
101
|
+
<ResizablePanel defaultSize={20} minSize={15}>
|
|
102
|
+
<div className="flex h-full items-center justify-center p-4">
|
|
103
|
+
<span className="text-sm font-medium text-foreground">Panel</span>
|
|
104
|
+
</div>
|
|
105
|
+
</ResizablePanel>
|
|
106
|
+
</ResizablePanelGroup>
|
|
107
|
+
),
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const NestedPanels: Story = {
|
|
111
|
+
render: () => (
|
|
112
|
+
<ResizablePanelGroup
|
|
113
|
+
direction="horizontal"
|
|
114
|
+
className="min-h-[300px] max-w-lg rounded-sm border border-border"
|
|
115
|
+
>
|
|
116
|
+
<ResizablePanel defaultSize={25}>
|
|
117
|
+
<div className="flex h-full items-center justify-center p-6">
|
|
118
|
+
<span className="font-medium text-foreground">Sidebar</span>
|
|
119
|
+
</div>
|
|
120
|
+
</ResizablePanel>
|
|
121
|
+
<ResizableHandle withHandle />
|
|
122
|
+
<ResizablePanel defaultSize={75}>
|
|
123
|
+
<ResizablePanelGroup direction="vertical">
|
|
124
|
+
<ResizablePanel defaultSize={50}>
|
|
125
|
+
<div className="flex h-full items-center justify-center p-6">
|
|
126
|
+
<span className="font-medium text-foreground">Top Panel</span>
|
|
127
|
+
</div>
|
|
128
|
+
</ResizablePanel>
|
|
129
|
+
<ResizableHandle />
|
|
130
|
+
<ResizablePanel defaultSize={50}>
|
|
131
|
+
<div className="flex h-full items-center justify-center p-6">
|
|
132
|
+
<span className="font-medium text-foreground">Bottom Panel</span>
|
|
133
|
+
</div>
|
|
134
|
+
</ResizablePanel>
|
|
135
|
+
</ResizablePanelGroup>
|
|
136
|
+
</ResizablePanel>
|
|
137
|
+
</ResizablePanelGroup>
|
|
138
|
+
),
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const IDELayout: Story = {
|
|
142
|
+
render: () => (
|
|
143
|
+
<ResizablePanelGroup
|
|
144
|
+
direction="horizontal"
|
|
145
|
+
className="min-h-[400px] max-w-2xl rounded-sm border border-border"
|
|
146
|
+
>
|
|
147
|
+
<ResizablePanel defaultSize={20} minSize={10}>
|
|
148
|
+
<div className="flex h-full flex-col bg-background p-2">
|
|
149
|
+
<p className="text-xs font-medium uppercase tracking-widest text-foreground-muted mb-2">
|
|
150
|
+
Explorer
|
|
151
|
+
</p>
|
|
152
|
+
<div className="space-y-1 text-sm text-foreground-secondary">
|
|
153
|
+
<p>📁 src</p>
|
|
154
|
+
<p className="pl-4">📁 components</p>
|
|
155
|
+
<p className="pl-4">📁 lib</p>
|
|
156
|
+
<p>📄 package.json</p>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
</ResizablePanel>
|
|
160
|
+
<ResizableHandle withHandle />
|
|
161
|
+
<ResizablePanel defaultSize={60}>
|
|
162
|
+
<ResizablePanelGroup direction="vertical">
|
|
163
|
+
<ResizablePanel defaultSize={70}>
|
|
164
|
+
<div className="flex h-full items-center justify-center bg-card p-6">
|
|
165
|
+
<span className="font-medium text-foreground">Editor</span>
|
|
166
|
+
</div>
|
|
167
|
+
</ResizablePanel>
|
|
168
|
+
<ResizableHandle />
|
|
169
|
+
<ResizablePanel defaultSize={30} minSize={15}>
|
|
170
|
+
<div className="flex h-full flex-col bg-background p-2">
|
|
171
|
+
<p className="text-xs font-medium uppercase tracking-widest text-foreground-muted mb-2">
|
|
172
|
+
Terminal
|
|
173
|
+
</p>
|
|
174
|
+
<code className="text-sm text-foreground-secondary">
|
|
175
|
+
$ npm run dev
|
|
176
|
+
</code>
|
|
177
|
+
</div>
|
|
178
|
+
</ResizablePanel>
|
|
179
|
+
</ResizablePanelGroup>
|
|
180
|
+
</ResizablePanel>
|
|
181
|
+
<ResizableHandle withHandle />
|
|
182
|
+
<ResizablePanel defaultSize={20} minSize={10}>
|
|
183
|
+
<div className="flex h-full flex-col bg-background p-2">
|
|
184
|
+
<p className="text-xs font-medium uppercase tracking-widest text-foreground-muted mb-2">
|
|
185
|
+
Outline
|
|
186
|
+
</p>
|
|
187
|
+
<div className="space-y-1 text-sm text-foreground-secondary">
|
|
188
|
+
<p>• function Button</p>
|
|
189
|
+
<p>• function Card</p>
|
|
190
|
+
<p>• function Dialog</p>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
</ResizablePanel>
|
|
194
|
+
</ResizablePanelGroup>
|
|
195
|
+
),
|
|
196
|
+
};
|
|
197
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { GripVertical } from "lucide-react";
|
|
4
|
+
import * as ResizablePrimitive from "react-resizable-panels";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
const ResizablePanelGroup = ({
|
|
8
|
+
className,
|
|
9
|
+
...props
|
|
10
|
+
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
|
|
11
|
+
<ResizablePrimitive.PanelGroup
|
|
12
|
+
className={cn(
|
|
13
|
+
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
|
|
14
|
+
className
|
|
15
|
+
)}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const ResizablePanel = ResizablePrimitive.Panel;
|
|
21
|
+
|
|
22
|
+
const ResizableHandle = ({
|
|
23
|
+
withHandle,
|
|
24
|
+
className,
|
|
25
|
+
...props
|
|
26
|
+
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
|
|
27
|
+
withHandle?: boolean;
|
|
28
|
+
}) => (
|
|
29
|
+
<ResizablePrimitive.PanelResizeHandle
|
|
30
|
+
className={cn(
|
|
31
|
+
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary focus-visible:ring-offset-1",
|
|
32
|
+
"data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0",
|
|
33
|
+
"[&[data-panel-group-direction=vertical]>div]:rotate-90",
|
|
34
|
+
className
|
|
35
|
+
)}
|
|
36
|
+
{...props}
|
|
37
|
+
>
|
|
38
|
+
{withHandle && (
|
|
39
|
+
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border border-border bg-card">
|
|
40
|
+
<GripVertical className="h-2.5 w-2.5" />
|
|
41
|
+
</div>
|
|
42
|
+
)}
|
|
43
|
+
</ResizablePrimitive.PanelResizeHandle>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
|
|
47
|
+
|