@hyphen/hyphen-components 5.2.1 → 5.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/dist/components/Sidebar/Sidebar.d.ts +1 -0
- package/dist/components/Sidebar/Sidebar.stories.d.ts +1 -0
- package/dist/css/index.css +3 -3
- package/dist/css/utilities.css +7 -1
- package/dist/css/variables.css +4 -2
- package/dist/hyphen-components.cjs.development.js +143 -115
- package/dist/hyphen-components.cjs.development.js.map +1 -1
- package/dist/hyphen-components.cjs.production.min.js +1 -1
- package/dist/hyphen-components.cjs.production.min.js.map +1 -1
- package/dist/hyphen-components.esm.js +142 -114
- package/dist/hyphen-components.esm.js.map +1 -1
- package/dist/lib/tokens.d.ts +1 -1
- package/package.json +9 -9
- package/src/components/Sidebar/Sidebar.module.scss +15 -0
- package/src/components/Sidebar/Sidebar.stories.tsx +347 -227
- package/src/components/Sidebar/Sidebar.tsx +102 -53
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
SidebarMenuAction,
|
|
20
20
|
SidebarMenuBadge,
|
|
21
21
|
SidebarTrigger,
|
|
22
|
+
useSidebar,
|
|
22
23
|
} from './Sidebar';
|
|
23
24
|
import { allModes } from '../../modes';
|
|
24
25
|
import { Card } from '../Card/Card';
|
|
@@ -78,53 +79,48 @@ const data = {
|
|
|
78
79
|
name: 'Evil Corp.',
|
|
79
80
|
},
|
|
80
81
|
],
|
|
81
|
-
|
|
82
|
+
items: [
|
|
82
83
|
{
|
|
83
84
|
title: 'Dashboard',
|
|
84
85
|
url: '#',
|
|
85
|
-
icon: 'dashboard',
|
|
86
|
+
icon: 'dashboard' as IconName,
|
|
86
87
|
isActive: true,
|
|
87
88
|
},
|
|
89
|
+
{
|
|
90
|
+
title: 'Deploy',
|
|
91
|
+
url: '#',
|
|
92
|
+
icon: 'logo-deploy' as IconName,
|
|
93
|
+
},
|
|
88
94
|
{
|
|
89
95
|
title: 'Teams',
|
|
90
96
|
url: '#',
|
|
91
|
-
icon: 'users',
|
|
97
|
+
icon: 'users' as IconName,
|
|
92
98
|
},
|
|
93
99
|
{
|
|
94
100
|
title: 'Link',
|
|
95
101
|
url: '#',
|
|
96
|
-
icon: 'logo-link',
|
|
102
|
+
icon: 'logo-link' as IconName,
|
|
97
103
|
},
|
|
98
104
|
{
|
|
99
105
|
title: 'ENV',
|
|
100
106
|
url: '#',
|
|
101
|
-
icon: 'logo-env',
|
|
107
|
+
icon: 'logo-env' as IconName,
|
|
102
108
|
},
|
|
103
109
|
{
|
|
104
110
|
title: 'Toggle',
|
|
105
111
|
url: '#',
|
|
106
|
-
icon: 'logo-toggle',
|
|
107
|
-
items: [
|
|
108
|
-
{
|
|
109
|
-
title: 'Feature Toggles',
|
|
110
|
-
url: '#',
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
title: 'Segments',
|
|
114
|
-
url: '#',
|
|
115
|
-
},
|
|
116
|
-
],
|
|
112
|
+
icon: 'logo-toggle' as IconName,
|
|
117
113
|
},
|
|
118
114
|
{
|
|
119
115
|
title: 'Integrations',
|
|
120
116
|
url: '#',
|
|
121
|
-
icon: 'stack',
|
|
117
|
+
icon: 'stack' as IconName,
|
|
122
118
|
count: 23,
|
|
123
119
|
},
|
|
124
120
|
{
|
|
125
121
|
title: 'Settings',
|
|
126
122
|
url: '#',
|
|
127
|
-
icon: 'settings',
|
|
123
|
+
icon: 'settings' as IconName,
|
|
128
124
|
items: [
|
|
129
125
|
{
|
|
130
126
|
title: 'General',
|
|
@@ -162,223 +158,61 @@ const data = {
|
|
|
162
158
|
|
|
163
159
|
// type Story = StoryObj<typeof Sidebar>;
|
|
164
160
|
|
|
161
|
+
function getCookieValue(name: string): string | null {
|
|
162
|
+
const match = document.cookie.match(
|
|
163
|
+
new RegExp(
|
|
164
|
+
`(?:^|; )${name.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1')}=([^;]*)`
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
return match ? decodeURIComponent(match[1]) : null;
|
|
168
|
+
}
|
|
169
|
+
|
|
165
170
|
export const SidebarExample = () => {
|
|
166
171
|
const [activeTeam, setActiveTeam] = React.useState(data.teams[0]);
|
|
167
172
|
const isMobile = useIsMobile();
|
|
173
|
+
|
|
174
|
+
const startOpen = getCookieValue('sidebar_expanded') || 'true';
|
|
175
|
+
|
|
168
176
|
return (
|
|
169
177
|
<ResponsiveProvider>
|
|
170
|
-
<SidebarProvider>
|
|
171
|
-
<Sidebar side="left" collapsible="
|
|
172
|
-
<
|
|
173
|
-
<SidebarMenu>
|
|
174
|
-
<SidebarMenuItem>
|
|
175
|
-
<DropdownMenu>
|
|
176
|
-
<DropdownMenuTrigger asChild>
|
|
177
|
-
<SidebarMenuButton>
|
|
178
|
-
<Box
|
|
179
|
-
flex="auto"
|
|
180
|
-
direction="row"
|
|
181
|
-
gap="sm"
|
|
182
|
-
alignItems="center"
|
|
183
|
-
>
|
|
184
|
-
<Box
|
|
185
|
-
background="black"
|
|
186
|
-
borderColor="subtle"
|
|
187
|
-
borderWidth="sm"
|
|
188
|
-
width="4xl"
|
|
189
|
-
height="4xl"
|
|
190
|
-
alignItems="center"
|
|
191
|
-
justifyContent="center"
|
|
192
|
-
radius="md"
|
|
193
|
-
></Box>
|
|
194
|
-
<span className="font-weight-semibold">
|
|
195
|
-
{activeTeam.name}
|
|
196
|
-
</span>
|
|
197
|
-
</Box>
|
|
198
|
-
<Icon name="caret-up-down" />
|
|
199
|
-
</SidebarMenuButton>
|
|
200
|
-
</DropdownMenuTrigger>
|
|
201
|
-
<DropdownMenuContent
|
|
202
|
-
align="start"
|
|
203
|
-
side="bottom"
|
|
204
|
-
sideOffset={4}
|
|
205
|
-
>
|
|
206
|
-
<DropdownMenuLabel className="text-xs text-muted-foreground">
|
|
207
|
-
Organizations
|
|
208
|
-
</DropdownMenuLabel>
|
|
209
|
-
{data.teams.map((team, index) => (
|
|
210
|
-
<DropdownMenuItem
|
|
211
|
-
key={team.name}
|
|
212
|
-
onClick={() => setActiveTeam(team)}
|
|
213
|
-
>
|
|
214
|
-
{team.name}
|
|
215
|
-
<DropdownMenuShortcut>
|
|
216
|
-
⌘{index + 1}
|
|
217
|
-
</DropdownMenuShortcut>
|
|
218
|
-
</DropdownMenuItem>
|
|
219
|
-
))}
|
|
220
|
-
<DropdownMenuSeparator />
|
|
221
|
-
<DropdownMenuItem>
|
|
222
|
-
<a
|
|
223
|
-
href="https://ux.hyphen.ai"
|
|
224
|
-
className="display-flex flex-direction-row g-sm align-items-center"
|
|
225
|
-
>
|
|
226
|
-
<Icon name="add" color="tertiary" />
|
|
227
|
-
<span>Create Organization</span>
|
|
228
|
-
</a>
|
|
229
|
-
</DropdownMenuItem>
|
|
230
|
-
</DropdownMenuContent>
|
|
231
|
-
</DropdownMenu>
|
|
232
|
-
</SidebarMenuItem>
|
|
233
|
-
</SidebarMenu>
|
|
234
|
-
</SidebarHeader>
|
|
178
|
+
<SidebarProvider defaultOpen={startOpen === 'true'}>
|
|
179
|
+
<Sidebar side="left" collapsible="icon">
|
|
180
|
+
<NavHeader activeTeam={activeTeam} setActiveTeam={setActiveTeam} />
|
|
235
181
|
<SidebarContent>
|
|
236
|
-
<
|
|
237
|
-
|
|
238
|
-
<SidebarMenu>
|
|
239
|
-
{data.navMain.map((item) =>
|
|
240
|
-
item.items ? (
|
|
241
|
-
<Collapsible
|
|
242
|
-
key={item.title}
|
|
243
|
-
className="group/collapsible"
|
|
244
|
-
asChild
|
|
245
|
-
>
|
|
246
|
-
<SidebarMenuItem>
|
|
247
|
-
<CollapsibleTrigger asChild>
|
|
248
|
-
<SidebarMenuButton>
|
|
249
|
-
<Icon
|
|
250
|
-
name={item.icon as IconName}
|
|
251
|
-
color="tertiary"
|
|
252
|
-
size="lg"
|
|
253
|
-
/>
|
|
254
|
-
{item.title}
|
|
255
|
-
<Icon
|
|
256
|
-
name="caret-sm-right"
|
|
257
|
-
className="m-left-auto transform data-[state=open]:rotate-90"
|
|
258
|
-
/>
|
|
259
|
-
</SidebarMenuButton>
|
|
260
|
-
</CollapsibleTrigger>
|
|
261
|
-
<CollapsibleContent>
|
|
262
|
-
<SidebarMenuSub>
|
|
263
|
-
{item.items?.map((subItem) => (
|
|
264
|
-
<SidebarMenuSubItem key={subItem.title}>
|
|
265
|
-
<SidebarMenuSubButton asChild>
|
|
266
|
-
<a href={subItem.url}>
|
|
267
|
-
<span>{subItem.title}</span>
|
|
268
|
-
</a>
|
|
269
|
-
</SidebarMenuSubButton>
|
|
270
|
-
</SidebarMenuSubItem>
|
|
271
|
-
))}
|
|
272
|
-
</SidebarMenuSub>
|
|
273
|
-
</CollapsibleContent>
|
|
274
|
-
</SidebarMenuItem>
|
|
275
|
-
</Collapsible>
|
|
276
|
-
) : (
|
|
277
|
-
<SidebarMenuItem key={item.title}>
|
|
278
|
-
<SidebarMenuButton asChild isActive={item.isActive}>
|
|
279
|
-
<a href={item.url}>
|
|
280
|
-
<Icon
|
|
281
|
-
name={item.icon as IconName}
|
|
282
|
-
color="tertiary"
|
|
283
|
-
size="lg"
|
|
284
|
-
/>
|
|
285
|
-
<span>{item.title}</span>
|
|
286
|
-
</a>
|
|
287
|
-
</SidebarMenuButton>
|
|
288
|
-
{item.count && (
|
|
289
|
-
<SidebarMenuBadge>{item.count}</SidebarMenuBadge>
|
|
290
|
-
)}
|
|
291
|
-
</SidebarMenuItem>
|
|
292
|
-
)
|
|
293
|
-
)}
|
|
294
|
-
</SidebarMenu>
|
|
295
|
-
</SidebarGroup>
|
|
296
|
-
<SidebarGroup>
|
|
297
|
-
<SidebarGroupLabel>Favorites</SidebarGroupLabel>
|
|
298
|
-
<SidebarMenu>
|
|
299
|
-
{data.favorites.map((item) => (
|
|
300
|
-
<SidebarMenuItem key={item.name}>
|
|
301
|
-
<SidebarMenuButton asChild>
|
|
302
|
-
<a href={item.url}>
|
|
303
|
-
<Icon name={item.icon as IconName} color="tertiary" />
|
|
304
|
-
<span>{item.name}</span>
|
|
305
|
-
</a>
|
|
306
|
-
</SidebarMenuButton>
|
|
307
|
-
<DropdownMenu>
|
|
308
|
-
<DropdownMenuTrigger asChild>
|
|
309
|
-
<SidebarMenuAction>
|
|
310
|
-
<Icon name="dots" />
|
|
311
|
-
<span className="sr-only">More</span>
|
|
312
|
-
</SidebarMenuAction>
|
|
313
|
-
</DropdownMenuTrigger>
|
|
314
|
-
<DropdownMenuContent side="bottom" align="end">
|
|
315
|
-
<DropdownMenuItem>
|
|
316
|
-
<a href="https://ux.hyphen.ai">View</a>
|
|
317
|
-
</DropdownMenuItem>
|
|
318
|
-
<DropdownMenuItem>
|
|
319
|
-
<a href="https://ux.hyphen.ai">Share</a>
|
|
320
|
-
</DropdownMenuItem>
|
|
321
|
-
<DropdownMenuSeparator />
|
|
322
|
-
<DropdownMenuItem>
|
|
323
|
-
<a href="https://ux.hyphen.ai">Remove</a>
|
|
324
|
-
</DropdownMenuItem>
|
|
325
|
-
</DropdownMenuContent>
|
|
326
|
-
</DropdownMenu>
|
|
327
|
-
</SidebarMenuItem>
|
|
328
|
-
))}
|
|
329
|
-
</SidebarMenu>
|
|
330
|
-
</SidebarGroup>
|
|
182
|
+
<NavMain items={data.items} />
|
|
183
|
+
<NavFavorites favorites={data.favorites} />
|
|
331
184
|
</SidebarContent>
|
|
185
|
+
<NavFooter />
|
|
186
|
+
<SidebarRail />
|
|
187
|
+
</Sidebar>
|
|
188
|
+
<SidebarInset>
|
|
189
|
+
{isMobile && <SidebarTrigger />}
|
|
190
|
+
<Card height="100" padding="2xl">
|
|
191
|
+
content
|
|
192
|
+
</Card>
|
|
193
|
+
</SidebarInset>
|
|
194
|
+
</SidebarProvider>
|
|
195
|
+
</ResponsiveProvider>
|
|
196
|
+
);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export const SidebarCollapsed = () => {
|
|
200
|
+
const [activeTeam, setActiveTeam] = React.useState(data.teams[0]);
|
|
201
|
+
const isMobile = useIsMobile();
|
|
202
|
+
|
|
203
|
+
const startOpen = getCookieValue('false');
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<ResponsiveProvider>
|
|
207
|
+
<SidebarProvider defaultOpen={startOpen === 'true'}>
|
|
208
|
+
<Sidebar side="left" collapsible="icon">
|
|
209
|
+
<NavHeader activeTeam={activeTeam} setActiveTeam={setActiveTeam} />
|
|
210
|
+
<SidebarContent>
|
|
211
|
+
<NavMain items={data.items} />
|
|
212
|
+
<NavFavorites favorites={data.favorites} />
|
|
213
|
+
</SidebarContent>
|
|
214
|
+
<NavFooter />
|
|
332
215
|
<SidebarRail />
|
|
333
|
-
<SidebarFooter>
|
|
334
|
-
<SidebarMenu>
|
|
335
|
-
<SidebarMenuItem>
|
|
336
|
-
<DropdownMenu>
|
|
337
|
-
<DropdownMenuTrigger asChild>
|
|
338
|
-
<SidebarMenuButton>
|
|
339
|
-
<Box flex="auto" direction="column" gap="2xs">
|
|
340
|
-
<span className="font-weight-semibold">
|
|
341
|
-
{data.user.name}
|
|
342
|
-
</span>
|
|
343
|
-
<span className="truncate font-size-xs font-color-secondary">
|
|
344
|
-
{data.user.email}
|
|
345
|
-
</span>
|
|
346
|
-
</Box>
|
|
347
|
-
<Icon name="caret-up-down" />
|
|
348
|
-
</SidebarMenuButton>
|
|
349
|
-
</DropdownMenuTrigger>
|
|
350
|
-
<DropdownMenuContent side="bottom" align="end" sideOffset={4}>
|
|
351
|
-
<DropdownMenuLabel>
|
|
352
|
-
<Box flex="auto" direction="column" gap="2xs">
|
|
353
|
-
<span className="font-weight-semibold">
|
|
354
|
-
{data.user.name}
|
|
355
|
-
</span>
|
|
356
|
-
<span className="truncate font-size-xs font-color-secondary">
|
|
357
|
-
{data.user.email}
|
|
358
|
-
</span>
|
|
359
|
-
</Box>
|
|
360
|
-
</DropdownMenuLabel>
|
|
361
|
-
<DropdownMenuSeparator />
|
|
362
|
-
<DropdownMenuGroup>
|
|
363
|
-
<DropdownMenuItem>
|
|
364
|
-
<Icon name="user" color="tertiary" />
|
|
365
|
-
Profile
|
|
366
|
-
</DropdownMenuItem>
|
|
367
|
-
<DropdownMenuItem>
|
|
368
|
-
<Icon name="alarm" color="tertiary" />
|
|
369
|
-
Notifications{' '}
|
|
370
|
-
</DropdownMenuItem>
|
|
371
|
-
</DropdownMenuGroup>
|
|
372
|
-
<DropdownMenuSeparator />
|
|
373
|
-
<DropdownMenuItem>
|
|
374
|
-
<Icon name="logout" color="tertiary" />
|
|
375
|
-
Log out
|
|
376
|
-
</DropdownMenuItem>
|
|
377
|
-
</DropdownMenuContent>
|
|
378
|
-
</DropdownMenu>
|
|
379
|
-
</SidebarMenuItem>
|
|
380
|
-
</SidebarMenu>
|
|
381
|
-
</SidebarFooter>
|
|
382
216
|
</Sidebar>
|
|
383
217
|
<SidebarInset>
|
|
384
218
|
{isMobile && <SidebarTrigger />}
|
|
@@ -390,3 +224,289 @@ export const SidebarExample = () => {
|
|
|
390
224
|
</ResponsiveProvider>
|
|
391
225
|
);
|
|
392
226
|
};
|
|
227
|
+
|
|
228
|
+
interface NavItem {
|
|
229
|
+
title: string;
|
|
230
|
+
url: string;
|
|
231
|
+
icon?: IconName;
|
|
232
|
+
isActive?: boolean;
|
|
233
|
+
count?: number;
|
|
234
|
+
items?: {
|
|
235
|
+
title: string;
|
|
236
|
+
url: string;
|
|
237
|
+
}[];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const NavHeader = ({
|
|
241
|
+
activeTeam,
|
|
242
|
+
setActiveTeam,
|
|
243
|
+
}: {
|
|
244
|
+
activeTeam: any;
|
|
245
|
+
setActiveTeam: (team: any) => void;
|
|
246
|
+
}) => {
|
|
247
|
+
const { state } = useSidebar();
|
|
248
|
+
|
|
249
|
+
return (
|
|
250
|
+
<SidebarHeader>
|
|
251
|
+
<SidebarMenu>
|
|
252
|
+
<SidebarMenuItem>
|
|
253
|
+
<DropdownMenu>
|
|
254
|
+
<DropdownMenuTrigger asChild>
|
|
255
|
+
<SidebarMenuButton style={{ padding: 'var(--size-spacing-xs)' }}>
|
|
256
|
+
<Box flex="auto" direction="row" gap="sm" alignItems="center">
|
|
257
|
+
<Box
|
|
258
|
+
background="black"
|
|
259
|
+
borderColor="subtle"
|
|
260
|
+
borderWidth="sm"
|
|
261
|
+
width="24px"
|
|
262
|
+
height="24px"
|
|
263
|
+
minWidth="24px"
|
|
264
|
+
minHeight="24px"
|
|
265
|
+
alignItems="center"
|
|
266
|
+
justifyContent="center"
|
|
267
|
+
radius="sm"
|
|
268
|
+
color="white"
|
|
269
|
+
fontSize="xs"
|
|
270
|
+
fontWeight="bold"
|
|
271
|
+
>
|
|
272
|
+
AC
|
|
273
|
+
</Box>
|
|
274
|
+
<span
|
|
275
|
+
className="font-weight-semibold"
|
|
276
|
+
style={{ whiteSpace: 'nowrap' }}
|
|
277
|
+
>
|
|
278
|
+
{activeTeam.name}
|
|
279
|
+
</span>
|
|
280
|
+
</Box>
|
|
281
|
+
<Icon
|
|
282
|
+
name="caret-up-down"
|
|
283
|
+
className="group-data-collapsible-icon-hidden"
|
|
284
|
+
/>
|
|
285
|
+
</SidebarMenuButton>
|
|
286
|
+
</DropdownMenuTrigger>
|
|
287
|
+
<DropdownMenuContent
|
|
288
|
+
align="start"
|
|
289
|
+
side={state === 'expanded' ? 'bottom' : 'right'}
|
|
290
|
+
sideOffset={4}
|
|
291
|
+
>
|
|
292
|
+
<DropdownMenuLabel className="text-xs text-muted-foreground">
|
|
293
|
+
Organizations
|
|
294
|
+
</DropdownMenuLabel>
|
|
295
|
+
{data.teams.map((team, index) => (
|
|
296
|
+
<DropdownMenuItem
|
|
297
|
+
key={`team.name-${index}`}
|
|
298
|
+
onClick={() => setActiveTeam(team)}
|
|
299
|
+
>
|
|
300
|
+
{team.name}
|
|
301
|
+
<DropdownMenuShortcut>⌘{index + 1}</DropdownMenuShortcut>
|
|
302
|
+
</DropdownMenuItem>
|
|
303
|
+
))}
|
|
304
|
+
<DropdownMenuSeparator />
|
|
305
|
+
<DropdownMenuItem>
|
|
306
|
+
<a
|
|
307
|
+
href="https://ux.hyphen.ai"
|
|
308
|
+
className="display-flex flex-direction-row g-sm align-items-center"
|
|
309
|
+
>
|
|
310
|
+
<Icon name="add" color="tertiary" />
|
|
311
|
+
<span>Create Organization</span>
|
|
312
|
+
</a>
|
|
313
|
+
</DropdownMenuItem>
|
|
314
|
+
</DropdownMenuContent>
|
|
315
|
+
</DropdownMenu>
|
|
316
|
+
</SidebarMenuItem>
|
|
317
|
+
</SidebarMenu>
|
|
318
|
+
</SidebarHeader>
|
|
319
|
+
);
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const NavMain = ({ items }: { items: NavItem[] }) => {
|
|
323
|
+
const { state } = useSidebar();
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<SidebarGroup>
|
|
327
|
+
<SidebarGroupLabel>Platform</SidebarGroupLabel>
|
|
328
|
+
<SidebarMenu>
|
|
329
|
+
{items.map((item, idx) =>
|
|
330
|
+
item.items && state === 'expanded' ? (
|
|
331
|
+
<Collapsible
|
|
332
|
+
key={`${item.title}-${idx}`}
|
|
333
|
+
className="group/collapsible"
|
|
334
|
+
asChild
|
|
335
|
+
>
|
|
336
|
+
<SidebarMenuItem>
|
|
337
|
+
<CollapsibleTrigger asChild>
|
|
338
|
+
<SidebarMenuButton tooltip={item.title}>
|
|
339
|
+
<Icon
|
|
340
|
+
name={item.icon as IconName}
|
|
341
|
+
color="tertiary"
|
|
342
|
+
size="lg"
|
|
343
|
+
/>
|
|
344
|
+
{item.title}
|
|
345
|
+
<Icon
|
|
346
|
+
name="caret-sm-right"
|
|
347
|
+
className="m-left-auto transform data-[state=open]:rotate-90"
|
|
348
|
+
/>
|
|
349
|
+
</SidebarMenuButton>
|
|
350
|
+
</CollapsibleTrigger>
|
|
351
|
+
<CollapsibleContent className="test">
|
|
352
|
+
<SidebarMenuSub>
|
|
353
|
+
{item.items?.map((subItem, idx) => (
|
|
354
|
+
<SidebarMenuSubItem key={`${subItem.title}-${idx}`}>
|
|
355
|
+
<SidebarMenuSubButton asChild>
|
|
356
|
+
<a href={subItem.url}>
|
|
357
|
+
<span>{subItem.title}</span>
|
|
358
|
+
</a>
|
|
359
|
+
</SidebarMenuSubButton>
|
|
360
|
+
</SidebarMenuSubItem>
|
|
361
|
+
))}
|
|
362
|
+
</SidebarMenuSub>
|
|
363
|
+
</CollapsibleContent>
|
|
364
|
+
</SidebarMenuItem>
|
|
365
|
+
</Collapsible>
|
|
366
|
+
) : item.items && state === 'collapsed' ? (
|
|
367
|
+
<DropdownMenu>
|
|
368
|
+
<DropdownMenuTrigger asChild>
|
|
369
|
+
<SidebarMenuButton tooltip={item.title}>
|
|
370
|
+
<Icon
|
|
371
|
+
name={item.icon as IconName}
|
|
372
|
+
color="tertiary"
|
|
373
|
+
size="lg"
|
|
374
|
+
/>
|
|
375
|
+
{item.title}
|
|
376
|
+
<Icon
|
|
377
|
+
name="caret-sm-right"
|
|
378
|
+
className="m-left-auto transform data-[state=open]:rotate-90"
|
|
379
|
+
/>
|
|
380
|
+
</SidebarMenuButton>
|
|
381
|
+
</DropdownMenuTrigger>
|
|
382
|
+
<DropdownMenuContent side="right" align="start" sideOffset={4}>
|
|
383
|
+
{item.items.map((subItem, idx) => (
|
|
384
|
+
<DropdownMenuItem key={`${subItem.title}-${idx}`}>
|
|
385
|
+
<a href={subItem.url}>
|
|
386
|
+
<span>{subItem.title}</span>
|
|
387
|
+
</a>
|
|
388
|
+
</DropdownMenuItem>
|
|
389
|
+
))}
|
|
390
|
+
</DropdownMenuContent>
|
|
391
|
+
</DropdownMenu>
|
|
392
|
+
) : (
|
|
393
|
+
<SidebarMenuItem key={item.title}>
|
|
394
|
+
<SidebarMenuButton
|
|
395
|
+
asChild
|
|
396
|
+
isActive={item.isActive}
|
|
397
|
+
tooltip={item.title}
|
|
398
|
+
>
|
|
399
|
+
<a href={item.url}>
|
|
400
|
+
<Icon
|
|
401
|
+
name={item.icon as IconName}
|
|
402
|
+
color="tertiary"
|
|
403
|
+
size="lg"
|
|
404
|
+
/>
|
|
405
|
+
<span>{item.title}</span>
|
|
406
|
+
</a>
|
|
407
|
+
</SidebarMenuButton>
|
|
408
|
+
{item.count && <SidebarMenuBadge>{item.count}</SidebarMenuBadge>}
|
|
409
|
+
</SidebarMenuItem>
|
|
410
|
+
)
|
|
411
|
+
)}
|
|
412
|
+
</SidebarMenu>
|
|
413
|
+
</SidebarGroup>
|
|
414
|
+
);
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
const NavFooter = () => {
|
|
418
|
+
const { state } = useSidebar();
|
|
419
|
+
return (
|
|
420
|
+
<SidebarFooter>
|
|
421
|
+
<SidebarMenu>
|
|
422
|
+
<SidebarMenuItem>
|
|
423
|
+
<DropdownMenu>
|
|
424
|
+
<DropdownMenuTrigger asChild>
|
|
425
|
+
<SidebarMenuButton tooltip="Your Profile">
|
|
426
|
+
<Icon name="user" size="lg" color="tertiary" />
|
|
427
|
+
<Box flex="auto" direction="column" gap="2xs">
|
|
428
|
+
<span className="font-weight-semibold">{data.user.name}</span>
|
|
429
|
+
<span className="truncate font-size-xs font-color-secondary">
|
|
430
|
+
{data.user.email}
|
|
431
|
+
</span>
|
|
432
|
+
</Box>
|
|
433
|
+
<Icon
|
|
434
|
+
name="caret-up-down"
|
|
435
|
+
className="group-data-collapsible-icon-hidden"
|
|
436
|
+
/>
|
|
437
|
+
</SidebarMenuButton>
|
|
438
|
+
</DropdownMenuTrigger>
|
|
439
|
+
<DropdownMenuContent
|
|
440
|
+
side={state === 'expanded' ? 'top' : 'right'}
|
|
441
|
+
align="end"
|
|
442
|
+
sideOffset={4}
|
|
443
|
+
>
|
|
444
|
+
<DropdownMenuLabel>
|
|
445
|
+
<Box flex="auto" direction="column" gap="2xs">
|
|
446
|
+
<span className="font-weight-semibold">{data.user.name}</span>
|
|
447
|
+
<span className="truncate font-size-xs font-color-secondary">
|
|
448
|
+
{data.user.email}
|
|
449
|
+
</span>
|
|
450
|
+
</Box>
|
|
451
|
+
</DropdownMenuLabel>
|
|
452
|
+
<DropdownMenuSeparator />
|
|
453
|
+
<DropdownMenuGroup>
|
|
454
|
+
<DropdownMenuItem>
|
|
455
|
+
<Icon name="user" color="tertiary" />
|
|
456
|
+
Profile
|
|
457
|
+
</DropdownMenuItem>
|
|
458
|
+
<DropdownMenuItem>
|
|
459
|
+
<Icon name="alarm" color="tertiary" />
|
|
460
|
+
Notifications{' '}
|
|
461
|
+
</DropdownMenuItem>
|
|
462
|
+
</DropdownMenuGroup>
|
|
463
|
+
<DropdownMenuSeparator />
|
|
464
|
+
<DropdownMenuItem>
|
|
465
|
+
<Icon name="logout" color="tertiary" />
|
|
466
|
+
Log out
|
|
467
|
+
</DropdownMenuItem>
|
|
468
|
+
</DropdownMenuContent>
|
|
469
|
+
</DropdownMenu>
|
|
470
|
+
</SidebarMenuItem>
|
|
471
|
+
</SidebarMenu>
|
|
472
|
+
</SidebarFooter>
|
|
473
|
+
);
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
const NavFavorites = ({ favorites }: { favorites: typeof data.favorites }) => (
|
|
477
|
+
<SidebarGroup>
|
|
478
|
+
<SidebarGroupLabel>Favorites</SidebarGroupLabel>
|
|
479
|
+
<SidebarMenu>
|
|
480
|
+
{favorites.map((item, idx) => (
|
|
481
|
+
<SidebarMenuItem key={`${item.name}-${idx}`}>
|
|
482
|
+
<SidebarMenuButton asChild tooltip={item.name}>
|
|
483
|
+
<a href={item.url}>
|
|
484
|
+
<Icon name={item.icon as IconName} color="tertiary" size="lg" />
|
|
485
|
+
<span>{item.name}</span>
|
|
486
|
+
</a>
|
|
487
|
+
</SidebarMenuButton>
|
|
488
|
+
<DropdownMenu>
|
|
489
|
+
<DropdownMenuTrigger asChild>
|
|
490
|
+
<SidebarMenuAction className="group-data-collapsible-icon-hidden">
|
|
491
|
+
<Icon name="dots" />
|
|
492
|
+
<span className="sr-only">More</span>
|
|
493
|
+
</SidebarMenuAction>
|
|
494
|
+
</DropdownMenuTrigger>
|
|
495
|
+
<DropdownMenuContent side="bottom" align="end">
|
|
496
|
+
<DropdownMenuItem>
|
|
497
|
+
<a href="https://ux.hyphen.ai">View</a>
|
|
498
|
+
</DropdownMenuItem>
|
|
499
|
+
<DropdownMenuItem>
|
|
500
|
+
<a href="https://ux.hyphen.ai">Share</a>
|
|
501
|
+
</DropdownMenuItem>
|
|
502
|
+
<DropdownMenuSeparator />
|
|
503
|
+
<DropdownMenuItem>
|
|
504
|
+
<a href="https://ux.hyphen.ai">Remove</a>
|
|
505
|
+
</DropdownMenuItem>
|
|
506
|
+
</DropdownMenuContent>
|
|
507
|
+
</DropdownMenu>
|
|
508
|
+
</SidebarMenuItem>
|
|
509
|
+
))}
|
|
510
|
+
</SidebarMenu>
|
|
511
|
+
</SidebarGroup>
|
|
512
|
+
);
|