Skip to content

Commit 878ef28

Browse files
committed
sidebar and helpers added
1 parent 942d732 commit 878ef28

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2073
-1
lines changed

package-lock.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
<script lang="ts" module>
2+
import AudioWaveform from '@lucide/svelte/icons/audio-waveform';
3+
import BookOpen from '@lucide/svelte/icons/book-open';
4+
import Bot from '@lucide/svelte/icons/bot';
5+
import ChartPie from '@lucide/svelte/icons/chart-pie';
6+
import Command from '@lucide/svelte/icons/command';
7+
import Frame from '@lucide/svelte/icons/frame';
8+
import GalleryVerticalEnd from '@lucide/svelte/icons/gallery-vertical-end';
9+
import Map from '@lucide/svelte/icons/map';
10+
import Settings2 from '@lucide/svelte/icons/settings-2';
11+
import SquareTerminal from '@lucide/svelte/icons/square-terminal';
12+
import { useClerkContext } from 'svelte-clerk/client';
13+
import type { UserResource } from '@clerk/types';
14+
15+
// This is sample data.
16+
const data = {
17+
user: {
18+
name: 'shadcn',
19+
20+
avatar: ''
21+
},
22+
teams: [
23+
{
24+
name: 'Acme Inc',
25+
logo: GalleryVerticalEnd,
26+
plan: 'Enterprise'
27+
},
28+
{
29+
name: 'Acme Corp.',
30+
logo: AudioWaveform,
31+
plan: 'Startup'
32+
},
33+
{
34+
name: 'Evil Corp.',
35+
logo: Command,
36+
plan: 'Free'
37+
}
38+
],
39+
navMain: [
40+
{
41+
title: 'Playground',
42+
url: '#',
43+
icon: SquareTerminal,
44+
isActive: true,
45+
items: [
46+
{
47+
title: 'History',
48+
url: '#'
49+
},
50+
{
51+
title: 'Starred',
52+
url: '#'
53+
},
54+
{
55+
title: 'Settings',
56+
url: '#'
57+
}
58+
]
59+
},
60+
{
61+
title: 'Models',
62+
url: '#',
63+
icon: Bot,
64+
items: [
65+
{
66+
title: 'Genesis',
67+
url: '#'
68+
},
69+
{
70+
title: 'Explorer',
71+
url: '#'
72+
},
73+
{
74+
title: 'Quantum',
75+
url: '#'
76+
}
77+
]
78+
},
79+
{
80+
title: 'Documentation',
81+
url: '#',
82+
icon: BookOpen,
83+
items: [
84+
{
85+
title: 'Introduction',
86+
url: '#'
87+
},
88+
{
89+
title: 'Get Started',
90+
url: '#'
91+
},
92+
{
93+
title: 'Tutorials',
94+
url: '#'
95+
},
96+
{
97+
title: 'Changelog',
98+
url: '#'
99+
}
100+
]
101+
},
102+
{
103+
title: 'Settings',
104+
url: '#',
105+
icon: Settings2,
106+
items: [
107+
{
108+
title: 'General',
109+
url: '#'
110+
},
111+
{
112+
title: 'Team',
113+
url: '#'
114+
},
115+
{
116+
title: 'Billing',
117+
url: '#'
118+
},
119+
{
120+
title: 'Limits',
121+
url: '#'
122+
}
123+
]
124+
}
125+
],
126+
projects: [
127+
{
128+
name: 'Design Engineering',
129+
url: '#',
130+
icon: Frame
131+
},
132+
{
133+
name: 'Sales & Marketing',
134+
url: '#',
135+
icon: ChartPie
136+
},
137+
{
138+
name: 'Travel',
139+
url: '#',
140+
icon: Map
141+
}
142+
]
143+
};
144+
</script>
145+
146+
<script lang="ts">
147+
import NavMain from '@/lib/components/sidebar/NavMain.svelte';
148+
import NavProjects from '@/lib/components/sidebar/NavProjects.svelte';
149+
import NavUser from '@/lib/components/sidebar/NavUser.svelte';
150+
import TeamSwitcher from '@/lib/components/sidebar/TeamSwitcher.svelte';
151+
import * as Sidebar from '@/lib/components/ui/sidebar/index.js';
152+
import type { ComponentProps } from 'svelte';
153+
154+
let {
155+
ref = $bindable(null),
156+
collapsible = 'icon',
157+
user,
158+
...restProps
159+
}: ComponentProps<typeof Sidebar.Root> & {
160+
user?: UserResource;
161+
} = $props();
162+
163+
const userData = $derived({
164+
name: user?.firstName ?? 'User',
165+
email: user?.emailAddresses[0]?.emailAddress ?? '',
166+
avatar: user?.imageUrl ?? ''
167+
});
168+
</script>
169+
170+
<Sidebar.Root bind:ref {collapsible} {...restProps}>
171+
<Sidebar.Header>
172+
<TeamSwitcher teams={data.teams} />
173+
</Sidebar.Header>
174+
<Sidebar.Content>
175+
<NavMain items={data.navMain} />
176+
<NavProjects projects={data.projects} />
177+
</Sidebar.Content>
178+
<Sidebar.Footer>
179+
<NavUser user={userData} />
180+
</Sidebar.Footer>
181+
<Sidebar.Rail />
182+
</Sidebar.Root>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<script lang="ts">
2+
import * as Collapsible from '@/lib/components/ui/collapsible/index.js';
3+
import * as Sidebar from '@/lib/components/ui/sidebar/index.js';
4+
import ChevronRight from '@lucide/svelte/icons/chevron-right';
5+
6+
let {
7+
items
8+
}: {
9+
items: {
10+
title: string;
11+
url: string;
12+
// this should be `Component` after @lucide/svelte updates types
13+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
14+
icon?: any;
15+
isActive?: boolean;
16+
items?: {
17+
title: string;
18+
url: string;
19+
}[];
20+
}[];
21+
} = $props();
22+
</script>
23+
24+
<Sidebar.Group>
25+
<Sidebar.GroupLabel>Platform</Sidebar.GroupLabel>
26+
<Sidebar.Menu>
27+
{#each items as mainItem (mainItem.title)}
28+
<Collapsible.Root open={mainItem.isActive} class="group/collapsible">
29+
{#snippet child({ props })}
30+
<Sidebar.MenuItem {...props}>
31+
<Collapsible.Trigger>
32+
{#snippet child({ props })}
33+
<Sidebar.MenuButton {...props}>
34+
{#snippet tooltipContent()}
35+
{mainItem.title}
36+
{/snippet}
37+
{#if mainItem.icon}
38+
<mainItem.icon />
39+
{/if}
40+
<span>{mainItem.title}</span>
41+
<ChevronRight
42+
class="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90"
43+
/>
44+
</Sidebar.MenuButton>
45+
{/snippet}
46+
</Collapsible.Trigger>
47+
<Collapsible.Content>
48+
{#if mainItem.items}
49+
<Sidebar.MenuSub>
50+
{#each mainItem.items as subItem (subItem.title)}
51+
<Sidebar.MenuSubItem>
52+
<Sidebar.MenuSubButton>
53+
{#snippet child({ props })}
54+
<a href={subItem.url} {...props}>
55+
<span>{subItem.title}</span>
56+
</a>
57+
{/snippet}
58+
</Sidebar.MenuSubButton>
59+
</Sidebar.MenuSubItem>
60+
{/each}
61+
</Sidebar.MenuSub>
62+
{/if}
63+
</Collapsible.Content>
64+
</Sidebar.MenuItem>
65+
{/snippet}
66+
</Collapsible.Root>
67+
{/each}
68+
</Sidebar.Menu>
69+
</Sidebar.Group>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<script lang="ts">
2+
import * as DropdownMenu from '@/lib/components/ui/dropdown-menu/index.js';
3+
import { useSidebar } from '@/lib/components/ui/sidebar/context.svelte.js';
4+
import * as Sidebar from '@/lib/components/ui/sidebar/index.js';
5+
import Ellipsis from '@lucide/svelte/icons/ellipsis';
6+
import Folder from '@lucide/svelte/icons/folder';
7+
import Forward from '@lucide/svelte/icons/forward';
8+
import Trash2 from '@lucide/svelte/icons/trash-2';
9+
10+
let {
11+
projects
12+
}: {
13+
projects: {
14+
name: string;
15+
url: string;
16+
// This should be `Component` after @lucide/svelte updates types
17+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
18+
icon: any;
19+
}[];
20+
} = $props();
21+
22+
const sidebar = useSidebar();
23+
</script>
24+
25+
<Sidebar.Group class="group-data-[collapsible=icon]:hidden">
26+
<Sidebar.GroupLabel>Projects</Sidebar.GroupLabel>
27+
<Sidebar.Menu>
28+
{#each projects as item (item.name)}
29+
<Sidebar.MenuItem>
30+
<Sidebar.MenuButton>
31+
{#snippet child({ props })}
32+
<a href={item.url} {...props}>
33+
<item.icon />
34+
<span>{item.name}</span>
35+
</a>
36+
{/snippet}
37+
</Sidebar.MenuButton>
38+
<DropdownMenu.Root>
39+
<DropdownMenu.Trigger>
40+
{#snippet child({ props })}
41+
<Sidebar.MenuAction showOnHover {...props}>
42+
<Ellipsis />
43+
<span class="sr-only">More</span>
44+
</Sidebar.MenuAction>
45+
{/snippet}
46+
</DropdownMenu.Trigger>
47+
<DropdownMenu.Content
48+
class="w-48 rounded-lg"
49+
side={sidebar.isMobile ? 'bottom' : 'right'}
50+
align={sidebar.isMobile ? 'end' : 'start'}
51+
>
52+
<DropdownMenu.Item>
53+
<Folder class="text-muted-foreground" />
54+
<span>View Project</span>
55+
</DropdownMenu.Item>
56+
<DropdownMenu.Item>
57+
<Forward class="text-muted-foreground" />
58+
<span>Share Project</span>
59+
</DropdownMenu.Item>
60+
<DropdownMenu.Separator />
61+
<DropdownMenu.Item>
62+
<Trash2 class="text-muted-foreground" />
63+
<span>Delete Project</span>
64+
</DropdownMenu.Item>
65+
</DropdownMenu.Content>
66+
</DropdownMenu.Root>
67+
</Sidebar.MenuItem>
68+
{/each}
69+
</Sidebar.Menu>
70+
</Sidebar.Group>

0 commit comments

Comments
 (0)