Skip to content

Commit 1cc701c

Browse files
committed
add switch to sidebar to toggle dark mode
1 parent 922a7cd commit 1cc701c

File tree

4 files changed

+54
-31
lines changed

4 files changed

+54
-31
lines changed

Diff for: app/blocks/sidebar/app-sidebar-nav.tsx

+14-25
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import { Menu } from "@/components/ui/menu"
66
import { Separator } from "@/components/ui/separator"
77
import { SidebarNav, SidebarTrigger } from "@/components/ui/sidebar"
88

9+
import { Switch } from "@/components/ui/switch"
910
import {
1011
IconCommandRegular,
1112
IconDashboard,
12-
IconDeviceDesktop,
1313
IconLogout,
1414
IconMoon,
1515
IconSettings,
@@ -34,7 +34,7 @@ export default function AppSidebarNav() {
3434
}
3535

3636
function UserMenu() {
37-
const { resolvedTheme, setTheme } = useTheme()
37+
const { theme, setTheme } = useTheme()
3838
return (
3939
<Menu>
4040
<Menu.Trigger className="ml-auto md:hidden" aria-label="Open Menu">
@@ -60,29 +60,18 @@ function UserMenu() {
6060
<IconCommandRegular />
6161
<Menu.Label>Command Menu</Menu.Label>
6262
</Menu.Item>
63-
<Menu.Submenu>
64-
<Menu.Item>
65-
{resolvedTheme === "light" ? (
66-
<IconSun />
67-
) : resolvedTheme === "dark" ? (
68-
<IconMoon />
69-
) : (
70-
<IconDeviceDesktop />
71-
)}
72-
<Menu.Label>Switch theme</Menu.Label>
73-
</Menu.Item>
74-
<Menu.Content>
75-
<Menu.Item onAction={() => setTheme("system")}>
76-
<IconDeviceDesktop /> System
77-
</Menu.Item>
78-
<Menu.Item onAction={() => setTheme("dark")}>
79-
<IconMoon /> Dark
80-
</Menu.Item>
81-
<Menu.Item onAction={() => setTheme("light")}>
82-
<IconSun /> Light
83-
</Menu.Item>
84-
</Menu.Content>
85-
</Menu.Submenu>
63+
<Menu.Item className="[&>[slot=label]+[data-slot=icon]]:right-4 [&>[slot=label]+[data-slot=icon]]:bottom-3">
64+
{theme === "dark" ? <IconMoon /> : <IconSun />}
65+
<Menu.Label>Theme</Menu.Label>
66+
<span data-slot="icon">
67+
<Switch
68+
className="ml-auto"
69+
isSelected={theme === "dark"}
70+
onChange={(e) => setTheme(theme === "dark" ? "light" : "dark")}
71+
aria-label="Toggle theme"
72+
/>
73+
</span>
74+
</Menu.Item>
8675
<Menu.Separator />
8776
<Menu.Item href="#contact-s">
8877
<Menu.Label>Contact Support</Menu.Label>

Diff for: app/blocks/sidebar/sidebar-01/app-sidebar.tsx

+23-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import {
1818
SidebarRail,
1919
SidebarSection,
2020
SidebarSectionGroup,
21+
useSidebar,
2122
} from "@/components/ui/sidebar"
23+
import { Switch } from "@/components/ui/switch"
2224
import {
2325
IconArchive,
2426
IconArrowDown,
@@ -29,7 +31,6 @@ import {
2931
IconChevronLgDown,
3032
IconCircleQuestionmark,
3133
IconClock,
32-
IconCommandRegular,
3334
IconCreditCard,
3435
IconDashboard,
3536
IconDotsHorizontal,
@@ -38,16 +39,22 @@ import {
3839
IconListBullets,
3940
IconLogout,
4041
IconMessage,
42+
IconMoon,
4143
IconNotes,
4244
IconPackage,
4345
IconPlus,
4446
IconSettings,
4547
IconShield,
4648
IconShoppingBag,
49+
IconSun,
4750
IconTicket,
4851
} from "justd-icons"
52+
import { useTheme } from "next-themes"
53+
import { twMerge } from "tailwind-merge"
4954

5055
export default function AppSidebar(props: React.ComponentProps<typeof Sidebar>) {
56+
const { theme, setTheme } = useTheme()
57+
const { state } = useSidebar()
5158
return (
5259
<Sidebar {...props}>
5360
<SidebarHeader>
@@ -210,7 +217,10 @@ export default function AppSidebar(props: React.ComponentProps<typeof Sidebar>)
210217
className="absolute right-3 size-4 transition-transform group-pressed:rotate-180"
211218
/>
212219
</Menu.Trigger>
213-
<Menu.Content placement="bottom right" className="sm:min-w-(--trigger-width)">
220+
<Menu.Content
221+
placement="bottom right"
222+
className={twMerge(state === "expanded" ? "sm:min-w-(--trigger-width)" : "sm:min-w-60")}
223+
>
214224
<Menu.Section>
215225
<Menu.Header separator>
216226
<span className="block">Kurt Cobain</span>
@@ -231,9 +241,17 @@ export default function AppSidebar(props: React.ComponentProps<typeof Sidebar>)
231241
Security
232242
</Menu.Item>
233243
<Menu.Separator />
234-
<Menu.Item>
235-
<IconCommandRegular />
236-
Command Menu
244+
<Menu.Item className="[&>[slot=label]+[data-slot=icon]]:right-4 [&>[slot=label]+[data-slot=icon]]:bottom-3">
245+
{theme === "dark" ? <IconMoon /> : <IconSun />}
246+
<Menu.Label>Theme</Menu.Label>
247+
<span data-slot="icon">
248+
<Switch
249+
className="ml-auto"
250+
isSelected={theme === "dark"}
251+
onChange={() => setTheme(theme === "dark" ? "light" : "dark")}
252+
aria-label="Toggle theme"
253+
/>
254+
</span>
237255
</Menu.Item>
238256

239257
<Menu.Item href="#contact">

Diff for: components/ui/menu.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ const MenuContent = <T extends object>({
124124
)}
125125
>
126126
<MenuPrimitive
127+
data-slot="menu-content"
127128
className={composeTailwindRenderProps(
128129
className,
129130
"grid max-h-[calc(var(--visual-viewport-height)-10rem)] grid-cols-[auto_1fr] overflow-auto rounded-xl p-1 outline-hidden [clip-path:inset(0_0_0_0_round_calc(var(--radius-lg)-2px))] sm:max-h-[inherit] *:[[role='group']+[role=group]]:mt-4 *:[[role='group']+[role=separator]]:mt-1",

Diff for: components/ui/sidebar.tsx

+16-1
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,10 @@ const footer = tv({
310310
"**:data-[slot=menu-trigger]:hover:bg-(--sidebar-accent) **:data-[slot=menu-trigger]:hover:text-fg",
311311
],
312312
variants: {
313+
expanded: {
314+
true: "",
315+
false: "**:data-[slot=menu-content]:min-w-60",
316+
},
313317
collapsed: {
314318
false: [
315319
"**:data-[slot=avatar]:*:size-8 **:data-[slot=menu-trigger]:**:data-[slot=avatar]:mr-2 **:data-[slot=avatar]:size-8",
@@ -327,7 +331,18 @@ const footer = tv({
327331
const SidebarFooter = ({ className, ...props }: React.ComponentProps<"div">) => {
328332
const { state, isMobile } = useSidebar()
329333
const collapsed = state === "collapsed" && !isMobile
330-
return <div data-sidebar-footer="true" className={footer({ collapsed, className })} {...props} />
334+
const expanded = state === "expanded"
335+
return (
336+
<div
337+
data-sidebar-footer="true"
338+
className={footer({
339+
collapsed,
340+
expanded,
341+
className,
342+
})}
343+
{...props}
344+
/>
345+
)
331346
}
332347

333348
const SidebarContent = ({ className, ...props }: React.ComponentProps<"div">) => {

0 commit comments

Comments
 (0)