Skip to content

Commit e0d845f

Browse files
committed
feat(ui, config): add breadcrumbs component and update exports, enhance theme-switcher functionality with improved state management and accessibility features
1 parent ff2bd8f commit e0d845f

File tree

4 files changed

+88
-20
lines changed

4 files changed

+88
-20
lines changed

src/components/ui/breadcrumbs.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"use client";
2+
3+
import { Breadcrumbs as HeroBreadcrumbs, BreadcrumbItem } from "@heroui/react";
4+
5+
export default function Breadcrumbs() {
6+
return (
7+
<HeroBreadcrumbs
8+
itemClasses={{
9+
separator: "px-2",
10+
}}
11+
separator="/"
12+
>
13+
<BreadcrumbItem>Home</BreadcrumbItem>
14+
<BreadcrumbItem>Resources</BreadcrumbItem>
15+
<BreadcrumbItem>Slug Details</BreadcrumbItem>
16+
</HeroBreadcrumbs>
17+
);
18+
}

src/components/ui/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { default as BackToTop } from "./back-to-top";
2+
export { default as Breadcrumbs } from "./breadcrumbs";
23
export { default as ThemeSwitcher } from "./theme-switcher";

src/components/ui/theme-switcher.tsx

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
"use client";
2-
32
import { useEffect, useState } from "react";
3+
import { Skeleton, useSwitch, VisuallyHidden } from "@heroui/react";
44
import { useTheme } from "next-themes";
5-
import { Skeleton, Switch } from "@heroui/react";
65
import { MoonIcon, SunIcon } from "lucide-react";
76

87
function ThemeSwitcherSkeleton() {
@@ -12,36 +11,49 @@ function ThemeSwitcherSkeleton() {
1211
export default function ThemeSwitcher() {
1312
const { setTheme, resolvedTheme } = useTheme();
1413
const [mounted, setMounted] = useState<boolean>(false);
15-
const [isSelected, setIsSelected] = useState<boolean>(false);
14+
const [selected, setSelected] = useState<boolean>(false);
1615

1716
useEffect(() => {
1817
setMounted(true);
1918
}, []);
2019

2120
useEffect(() => {
2221
if (mounted) {
23-
setIsSelected(resolvedTheme === "dark");
22+
setSelected(resolvedTheme === "dark");
2423
}
2524
}, [resolvedTheme, mounted]);
2625

27-
if (!mounted) return <ThemeSwitcherSkeleton />;
26+
const { Component, slots, getBaseProps, getInputProps, getWrapperProps } =
27+
useSwitch({
28+
isSelected: selected,
29+
onChange: () => {
30+
const newTheme = selected ? "light" : "dark";
31+
setTheme(newTheme);
32+
setSelected(!selected);
33+
},
34+
});
2835

29-
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
30-
const newTheme = e.target.checked ? "dark" : "light";
31-
setTheme(newTheme);
32-
};
36+
if (!mounted) return <ThemeSwitcherSkeleton />;
3337

3438
return (
35-
<Switch
36-
size="sm"
37-
color="primary"
38-
isSelected={isSelected}
39-
onChange={handleChange}
40-
startContent={<SunIcon />}
41-
endContent={<MoonIcon />}
42-
classNames={{
43-
wrapper: "group-data-[selected=true]:bg-red-500",
44-
}}
45-
/>
39+
<Component {...getBaseProps()}>
40+
<VisuallyHidden>
41+
<input {...getInputProps()} />
42+
</VisuallyHidden>
43+
<div
44+
{...getWrapperProps()}
45+
className={slots.wrapper({
46+
class: [
47+
"w-8 h-8",
48+
"flex items-center justify-center",
49+
"bg-white group-data-[selected=true]:bg-neutral-950",
50+
"rounded-lg border-2 border-neutral-200 dark:border-neutral-800",
51+
"transition-colors duration-200 ease-in-out",
52+
],
53+
})}
54+
>
55+
{selected ? <SunIcon size={16} /> : <MoonIcon size={16} />}
56+
</div>
57+
</Component>
4658
);
4759
}

src/config/constants.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,40 @@ export const FOOTER_LINKS = [
6969
{ name: "Authors", href: "/authors" },
7070
{ name: "Blog", href: "/blog" },
7171
];
72+
73+
export const SECTIONS = [
74+
{
75+
key: "4fbcd2fc-14cd-4048-83c5-c683ccd8c212",
76+
title: "Explore",
77+
items: [
78+
{ title: "Resources", path: "/resources" },
79+
{ title: "Authors", path: "/authors" },
80+
],
81+
},
82+
{
83+
key: "4fbcd2fc-14cd-4048-83c5-c683ccd8c216",
84+
title: "Languages",
85+
items: [
86+
{ title: "Python", path: "/languages/python" },
87+
{ title: "JavaScript", path: "/languages/javascript" },
88+
{ title: "TypeScript", path: "/languages/typescript" },
89+
{ title: "Ruby", path: "/languages/ruby" },
90+
],
91+
},
92+
{
93+
key: "b0f0c9a0-a4c0-4a5f-b3a8-e0a2f5a1c2b1",
94+
title: "Frameworks & Libraries",
95+
items: [
96+
{ title: "Django", path: "/frameworks-libraries/django" },
97+
{ title: "Flask", path: "/frameworks-libraries/flask" },
98+
{ title: "FastAPI", path: "/frameworks-libraries/fastapi" },
99+
{ title: "Express", path: "/frameworks-libraries/express" },
100+
],
101+
},
102+
];
103+
104+
export const SORT_OPTIONS = [
105+
{ key: "latest", label: "Recent" },
106+
{ key: "popular", label: "Popular" },
107+
{ key: "top", label: "Most popular" },
108+
];

0 commit comments

Comments
 (0)