Skip to content

Commit 9ced2c9

Browse files
committed
refactor: ♻️ Rewrite sidebar with shadcn
1 parent a7b5709 commit 9ced2c9

File tree

109 files changed

+2261
-72
lines changed

Some content is hidden

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

109 files changed

+2261
-72
lines changed

app.vue

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
<script setup lang="ts">
1818
import "~/styles/theme.css";
19+
import "~/styles/index.css";
1920
import { convert } from "html-to-text";
2021
import "iconify-icon";
2122
import ConfirmationModal from "./components/modals/confirmation.vue";

biome.json

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
"suspicious": {
1212
"noConsole": "off"
1313
},
14+
"performance": {
15+
"noBarrelFile": "off"
16+
},
1417
"correctness": {
1518
"noNodejsModules": "off",
1619
"noUndeclaredVariables": "off",

bun.lockb

0 Bytes
Binary file not shown.

components.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
},
1313
"framework": "nuxt",
1414
"aliases": {
15-
"components": "@/components",
15+
"components": "~/components",
1616
"utils": "@/lib/utils"
1717
}
1818
}

components/composer/autocomplete-suggestbox.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<div v-for="(suggestion, index) in topSuggestions" :key="suggestion.key"
99
@click="emit('autocomplete', suggestion.key)"
1010
:ref="el => { if (el) suggestionRefs[index] = el as Element }" :title="suggestion.key"
11-
:class="['flex justify-center shrink-0 items-center size-12 p-2 hover:bg-dark-900/70', index === selectedSuggestionIndex && 'bg-primary-500']">
11+
:class="['flex justify-center shrink-0 items-center size-12 p-2 hover:bg-dark-900/70', index === selectedSuggestionIndex && 'bg-primary2-500']">
1212
<slot :suggestion="suggestion"></slot>
1313
</div>
1414
</OverlayScrollbarsComponent>

components/composer/button.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<button v-bind="$props"
3-
:class="['rounded text-gray-300 hover:bg-dark-900/70 p-2 flex items-center justify-center duration-200', toggled && 'bg-primary-500/70 hover:bg-primary-900/70']">
3+
:class="['rounded text-gray-300 hover:bg-dark-900/70 p-2 flex items-center justify-center duration-200', toggled && 'bg-primary2-500/70 hover:bg-primary2-900/70']">
44
<slot />
55
</button>
66
</template>

components/composer/responding-to.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div v-if="respondingTo" class="mb-4" role="region" aria-label="Responding to">
33
<OverlayScrollbarsComponent :defer="true" class="max-h-72 overflow-y-auto">
4-
<Note :element="respondingTo" :small="true" :disabled="true" class="!rounded-none !bg-primary-500/10" />
4+
<Note :element="respondingTo" :small="true" :disabled="true" class="!rounded-none !bg-primary2-500/10" />
55
</OverlayScrollbarsComponent>
66
</div>
77
</template>

components/composer/uploader/file-size.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
aria-label="File size">
44
{{ formatBytes(size) }}
55
<iconify-icon v-if="uploading" icon="tabler:loader-2" width="none"
6-
class="size-4 animate-spin text-primary-500" />
6+
class="size-4 animate-spin text-primary2-500" />
77
</div>
88
</template>
99

components/inputs/checkbox-input.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<TextInput type="checkbox" v-bind="$attrs, $props"
3-
class="rounded disabled:hover:cursor-wait text-primary-700 !size-5" />
3+
class="rounded disabled:hover:cursor-wait text-primary2-700 !size-5" />
44
</template>
55

66
<script lang="ts" setup>

components/notifications/notifications-renderer.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<iconify-icon v-else-if="toast.type === 'error'" icon="tabler:alert-triangle" height="none"
1111
class="h-6 w-6 text-red-400" aria-hidden="true" />
1212
<iconify-icon v-else-if="toast.type === 'loading'" icon="tabler:loader" height="none"
13-
class="h-6 w-6 text-primary-500 animate-spin" aria-hidden="true" />
13+
class="h-6 w-6 text-primary2-500 animate-spin" aria-hidden="true" />
1414
<iconify-icon v-else-if="toast.type === 'info'" icon="tabler:info-circle" height="none"
1515
class="h-6 w-6 text-blue-500" aria-hidden="true" />
1616
</div>

components/settings/types/Enum.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
:class="['group-data-[state=checked]:font-semibold font-normal block truncate']">{{
2525
item.label }}</Select.ItemText>
2626
<Select.ItemIndicator
27-
:class="['text-primary-600 hidden group-data-[state=checked]:flex items-center justify-center']">
27+
:class="['text-primary2-600 hidden group-data-[state=checked]:flex items-center justify-center']">
2828
<iconify-icon icon="tabler:check" class="size-4" width="unset" aria-hidden="true" />
2929
</Select.ItemIndicator>
3030
</Select.Item>

components/sidebars/sidebar.vue

+278
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
<script setup lang="ts">
2+
import {
3+
BadgeCheck,
4+
Bell,
5+
ChevronRight,
6+
ChevronsUpDown,
7+
House,
8+
LogOut,
9+
MoreHorizontal,
10+
Settings2,
11+
} from "lucide-vue-next";
12+
import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar";
13+
import {
14+
Breadcrumb,
15+
BreadcrumbItem,
16+
BreadcrumbLink,
17+
BreadcrumbList,
18+
BreadcrumbPage,
19+
BreadcrumbSeparator,
20+
} from "~/components/ui/breadcrumb";
21+
import {
22+
Collapsible,
23+
CollapsibleContent,
24+
CollapsibleTrigger,
25+
} from "~/components/ui/collapsible";
26+
import {
27+
DropdownMenu,
28+
DropdownMenuContent,
29+
DropdownMenuGroup,
30+
DropdownMenuItem,
31+
DropdownMenuLabel,
32+
DropdownMenuSeparator,
33+
DropdownMenuTrigger,
34+
} from "~/components/ui/dropdown-menu";
35+
import { Separator } from "~/components/ui/separator";
36+
import {
37+
Sidebar,
38+
SidebarContent,
39+
SidebarFooter,
40+
SidebarGroup,
41+
SidebarGroupLabel,
42+
SidebarHeader,
43+
SidebarInset,
44+
SidebarMenu,
45+
SidebarMenuButton,
46+
SidebarMenuItem,
47+
SidebarMenuSub,
48+
SidebarMenuSubButton,
49+
SidebarMenuSubItem,
50+
SidebarProvider,
51+
SidebarRail,
52+
SidebarTrigger,
53+
} from "~/components/ui/sidebar";
54+
import ThemeSwitcher from "./theme-switcher.vue";
55+
56+
const data = {
57+
navMain: [
58+
{
59+
title: "Timelines",
60+
url: "#",
61+
icon: House,
62+
isActive: true,
63+
items: [
64+
{
65+
title: "Home",
66+
url: "/home",
67+
},
68+
{
69+
title: "Public",
70+
url: "/public",
71+
},
72+
{
73+
title: "Local",
74+
url: "/local",
75+
},
76+
{
77+
title: "Global",
78+
url: "/global",
79+
},
80+
],
81+
},
82+
{
83+
title: "Settings",
84+
url: "#",
85+
icon: Settings2,
86+
items: [
87+
{
88+
title: "Appearance",
89+
url: "#",
90+
},
91+
{
92+
title: "Behaviour",
93+
url: "#",
94+
},
95+
{
96+
title: "Emojis",
97+
url: "#",
98+
},
99+
{
100+
title: "Roles",
101+
url: "#",
102+
},
103+
],
104+
},
105+
],
106+
other: [
107+
{
108+
name: "Notifications",
109+
url: "/notifications",
110+
icon: Bell,
111+
},
112+
],
113+
};
114+
115+
const instance = useInstance();
116+
</script>
117+
118+
<template>
119+
<SidebarProvider>
120+
<Sidebar variant="inset" collapsible="icon">
121+
<SidebarHeader>
122+
<SidebarMenu>
123+
<SidebarMenuItem>
124+
<DropdownMenu>
125+
<SidebarMenuButton size="lg"
126+
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
127+
<Avatar shape="square" class="size-8">
128+
<AvatarImage :src="instance?.thumbnail.url ??
129+
'https://cdn.versia.pub/branding/icon.svg'
130+
" alt="" />
131+
</Avatar>
132+
<div class="grid flex-1 text-left text-sm leading-tight">
133+
<span class="truncate font-semibold">{{ instance?.title ?? 'Versia Server' }}</span>
134+
<span class="truncate text-xs">{{ "A Versia Server instance" }}</span>
135+
</div>
136+
<!-- <ChevronsUpDown class="ml-auto" /> -->
137+
</SidebarMenuButton>
138+
</DropdownMenu>
139+
</SidebarMenuItem>
140+
</SidebarMenu>
141+
</SidebarHeader>
142+
<SidebarContent>
143+
<SidebarGroup>
144+
<SidebarGroupLabel>Navigation</SidebarGroupLabel>
145+
<SidebarMenu>
146+
<Collapsible v-for="item in data.navMain" :key="item.title" as-child
147+
:default-open="item.isActive" class="group/collapsible">
148+
<SidebarMenuItem>
149+
<CollapsibleTrigger as-child>
150+
<SidebarMenuButton :tooltip="item.title">
151+
<component :is="item.icon" />
152+
<span>{{ item.title }}</span>
153+
<ChevronRight
154+
class="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
155+
</SidebarMenuButton>
156+
</CollapsibleTrigger>
157+
<CollapsibleContent>
158+
<SidebarMenuSub>
159+
<SidebarMenuSubItem v-for="subItem in item.items" :key="subItem.title">
160+
<SidebarMenuSubButton as-child>
161+
<NuxtLink :href="subItem.url">
162+
<span>{{ subItem.title }}</span>
163+
</NuxtLink>
164+
</SidebarMenuSubButton>
165+
</SidebarMenuSubItem>
166+
</SidebarMenuSub>
167+
</CollapsibleContent>
168+
</SidebarMenuItem>
169+
</Collapsible>
170+
</SidebarMenu>
171+
</SidebarGroup>
172+
<SidebarGroup class="group-data-[collapsible=icon]:hidden">
173+
<SidebarGroupLabel>Other</SidebarGroupLabel>
174+
<SidebarMenu>
175+
<SidebarMenuItem v-for="item in data.other" :key="item.name">
176+
<SidebarMenuButton as-child>
177+
<NuxtLink :href="item.url">
178+
<component :is="item.icon" />
179+
<span>{{ item.name }}</span>
180+
</NuxtLink>
181+
</SidebarMenuButton>
182+
</SidebarMenuItem>
183+
<SidebarMenuItem>
184+
<SidebarMenuButton class="text-sidebar-foreground/70">
185+
<MoreHorizontal class="text-sidebar-foreground/70" />
186+
<span>More</span>
187+
</SidebarMenuButton>
188+
</SidebarMenuItem>
189+
</SidebarMenu>
190+
</SidebarGroup>
191+
</SidebarContent>
192+
<SidebarFooter>
193+
<SidebarMenu>
194+
<SidebarMenuItem>
195+
<ThemeSwitcher />
196+
</SidebarMenuItem>
197+
<SidebarMenuItem>
198+
<DropdownMenu>
199+
<DropdownMenuTrigger as-child>
200+
<SidebarMenuButton size="lg"
201+
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
202+
<Avatar class="h-8 w-8 rounded-lg">
203+
<AvatarImage :src="identity?.account.avatar" alt="" />
204+
<AvatarFallback class="rounded-lg"> AA </AvatarFallback>
205+
</Avatar>
206+
<div class="grid flex-1 text-left text-sm leading-tight">
207+
<span class="truncate font-semibold">{{
208+
identity?.account.display_name
209+
}}</span>
210+
<span class="truncate text-xs">@{{ identity?.account.acct }}</span>
211+
</div>
212+
<ChevronsUpDown class="ml-auto size-4" />
213+
</SidebarMenuButton>
214+
</DropdownMenuTrigger>
215+
<DropdownMenuContent class="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg"
216+
side="bottom" align="end" :side-offset="4">
217+
<DropdownMenuLabel class="p-0 font-normal">
218+
<div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
219+
<Avatar class="h-8 w-8 rounded-lg">
220+
<AvatarImage :src="identity?.account.avatar" alt="" />
221+
<AvatarFallback class="rounded-lg"> AA </AvatarFallback>
222+
</Avatar>
223+
<div class="grid flex-1 text-left text-sm leading-tight">
224+
<span class="truncate font-semibold">{{
225+
identity?.account.display_name
226+
}}</span>
227+
<span class="truncate text-xs">@{{
228+
identity?.account.acct
229+
}}</span>
230+
</div>
231+
</div>
232+
</DropdownMenuLabel>
233+
<DropdownMenuSeparator />
234+
<DropdownMenuGroup>
235+
<DropdownMenuItem>
236+
<BadgeCheck />
237+
Account
238+
</DropdownMenuItem>
239+
</DropdownMenuGroup>
240+
<DropdownMenuSeparator />
241+
<DropdownMenuItem>
242+
<LogOut />
243+
Log out
244+
</DropdownMenuItem>
245+
</DropdownMenuContent>
246+
</DropdownMenu>
247+
</SidebarMenuItem>
248+
</SidebarMenu>
249+
</SidebarFooter>
250+
<SidebarRail />
251+
</Sidebar>
252+
<SidebarInset>
253+
<header
254+
class="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12 overflow-hidden">
255+
<div class="flex items-center gap-2 px-4">
256+
<SidebarTrigger class="-ml-1" />
257+
<Separator orientation="vertical" class="mr-2 h-4" />
258+
<Breadcrumb>
259+
<BreadcrumbList>
260+
<BreadcrumbItem class="hidden md:block">
261+
<BreadcrumbLink href="#">
262+
Timelines
263+
</BreadcrumbLink>
264+
</BreadcrumbItem>
265+
<BreadcrumbSeparator class="hidden md:block" />
266+
<BreadcrumbItem>
267+
<BreadcrumbPage>Home</BreadcrumbPage>
268+
</BreadcrumbItem>
269+
</BreadcrumbList>
270+
</Breadcrumb>
271+
</div>
272+
</header>
273+
<div class="flex flex-1 flex-col gap-4 pt-0 overflow-auto">
274+
<slot />
275+
</div>
276+
</SidebarInset>
277+
</SidebarProvider>
278+
</template>

0 commit comments

Comments
 (0)