feat: add dark theme and toggle
This commit is contained in:
parent
22a6bc4b82
commit
654f6f77ea
17 changed files with 575 additions and 281 deletions
115
package-lock.json
generated
115
package-lock.json
generated
|
|
@ -11,8 +11,10 @@
|
||||||
"@radix-ui/react-collapsible": "^1.1.7",
|
"@radix-ui/react-collapsible": "^1.1.7",
|
||||||
"@radix-ui/react-dialog": "^1.1.10",
|
"@radix-ui/react-dialog": "^1.1.10",
|
||||||
"@radix-ui/react-hover-card": "^1.1.14",
|
"@radix-ui/react-hover-card": "^1.1.14",
|
||||||
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
"@radix-ui/react-separator": "^1.1.4",
|
"@radix-ui/react-separator": "^1.1.4",
|
||||||
"@radix-ui/react-slot": "^1.2.3",
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
|
"@radix-ui/react-switch": "^1.2.5",
|
||||||
"@radix-ui/react-tooltip": "^1.2.3",
|
"@radix-ui/react-tooltip": "^1.2.3",
|
||||||
"@tailwindcss/vite": "^4.1.4",
|
"@tailwindcss/vite": "^4.1.4",
|
||||||
"@tanstack/react-query": "^5.83.0",
|
"@tanstack/react-query": "^5.83.0",
|
||||||
|
|
@ -1426,6 +1428,52 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-label": {
|
||||||
|
"version": "2.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz",
|
||||||
|
"integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-primitive": "2.1.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.2.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-popper": {
|
"node_modules/@radix-ui/react-popper": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.4.tgz",
|
||||||
|
|
@ -1584,6 +1632,58 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-switch": {
|
||||||
|
"version": "1.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.5.tgz",
|
||||||
|
"integrity": "sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.2",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
"@radix-ui/react-context": "1.1.2",
|
||||||
|
"@radix-ui/react-primitive": "2.1.3",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||||
|
"@radix-ui/react-use-previous": "1.1.1",
|
||||||
|
"@radix-ui/react-use-size": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.2.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-tooltip": {
|
"node_modules/@radix-ui/react-tooltip": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.3.tgz",
|
||||||
|
|
@ -1715,6 +1815,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-use-previous": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-use-rect": {
|
"node_modules/@radix-ui/react-use-rect": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,10 @@
|
||||||
"@radix-ui/react-collapsible": "^1.1.7",
|
"@radix-ui/react-collapsible": "^1.1.7",
|
||||||
"@radix-ui/react-dialog": "^1.1.10",
|
"@radix-ui/react-dialog": "^1.1.10",
|
||||||
"@radix-ui/react-hover-card": "^1.1.14",
|
"@radix-ui/react-hover-card": "^1.1.14",
|
||||||
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
"@radix-ui/react-separator": "^1.1.4",
|
"@radix-ui/react-separator": "^1.1.4",
|
||||||
"@radix-ui/react-slot": "^1.2.3",
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
|
"@radix-ui/react-switch": "^1.2.5",
|
||||||
"@radix-ui/react-tooltip": "^1.2.3",
|
"@radix-ui/react-tooltip": "^1.2.3",
|
||||||
"@tailwindcss/vite": "^4.1.4",
|
"@tailwindcss/vite": "^4.1.4",
|
||||||
"@tanstack/react-query": "^5.83.0",
|
"@tanstack/react-query": "^5.83.0",
|
||||||
|
|
|
||||||
|
|
@ -10,68 +10,68 @@ import { Link } from "react-router"
|
||||||
import { useState, useRef, useEffect } from "react"
|
import { useState, useRef, useEffect } from "react"
|
||||||
|
|
||||||
export default function EntriesListSidebar() {
|
export default function EntriesListSidebar() {
|
||||||
const scrollRef = useRef(null)
|
const scrollRef = useRef(null)
|
||||||
const [isOpen, setIsOpen] = useState(() => {
|
const [isOpen, setIsOpen] = useState(() => {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
const saved = sessionStorage.getItem("entries_list_sidebar_open")
|
const saved = sessionStorage.getItem("entries_list_sidebar_open")
|
||||||
return saved ? JSON.parse(saved) : false
|
return saved ? JSON.parse(saved) : false
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
const { data: entries, isLoading } = useQuery({
|
const { data: entries, isLoading } = useQuery({
|
||||||
queryKey: ["entries_list"],
|
queryKey: ["entries_list"],
|
||||||
queryFn: () => api.get("/entries").then((res) => res.data),
|
queryFn: () => api.get("/entries").then((res) => res.data),
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
sessionStorage.setItem("entries_list_sidebar_open", JSON.stringify(isOpen))
|
sessionStorage.setItem("entries_list_sidebar_open", JSON.stringify(isOpen))
|
||||||
}, [isOpen])
|
}, [isOpen])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const savedScroll = sessionStorage.getItem("entries_list_sidebar_scroll_position")
|
const savedScroll = sessionStorage.getItem("entries_list_sidebar_scroll_position")
|
||||||
if (savedScroll && scrollRef.current) {
|
if (savedScroll && scrollRef.current) {
|
||||||
scrollRef.current.scrollTop = parseInt(savedScroll)
|
scrollRef.current.scrollTop = parseInt(savedScroll)
|
||||||
}
|
}
|
||||||
}, [entries])
|
}, [entries])
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
if (scrollRef.current) {
|
if (scrollRef.current) {
|
||||||
sessionStorage.setItem("entries_list_sidebar_scroll_position", scrollRef.current.scrollTop)
|
sessionStorage.setItem("entries_list_sidebar_scroll_position", scrollRef.current.scrollTop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapsible open={isOpen} onOpenChange={setIsOpen} className="group/collapsible">
|
<Collapsible open={isOpen} onOpenChange={setIsOpen} className="group/collapsible">
|
||||||
<SidebarMenuItem key="entries">
|
<SidebarMenuItem key="entries">
|
||||||
<CollapsibleTrigger asChild className="rounded-none">
|
<CollapsibleTrigger asChild className="rounded-none">
|
||||||
<SidebarMenuButton asChild className="rounded-none">
|
<SidebarMenuButton asChild className="rounded-none">
|
||||||
<a href="#">
|
<a href="#">
|
||||||
<FileText />
|
<FileText />
|
||||||
<span>Entries</span>
|
<span>Entries</span>
|
||||||
<Badge className="ml-0" variant="secondary">
|
<Badge className="ml-0" variant="secondary">
|
||||||
{entries?.count}
|
{entries?.count}
|
||||||
</Badge>
|
</Badge>
|
||||||
<ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
|
<ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
|
||||||
</a>
|
</a>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</CollapsibleTrigger>
|
</CollapsibleTrigger>
|
||||||
<CollapsibleContent>
|
<CollapsibleContent>
|
||||||
<div ref={scrollRef} onScroll={handleScroll} className="max-h-100 overflow-y-auto">
|
<div ref={scrollRef} onScroll={handleScroll} className="max-h-100 overflow-y-auto">
|
||||||
<SidebarMenuSub>
|
<SidebarMenuSub>
|
||||||
{entries?.data.map((item, i) => (
|
{entries?.data.map((item, i) => (
|
||||||
<SidebarMenuItem key={i}>
|
<SidebarMenuItem key={i}>
|
||||||
<Link to={`/entries/${item.title}`}>
|
<Link to={`/entries/${item.title}`}>
|
||||||
<span className="text-xs text-black hover:text-gray-600 active:text-gray-700 focus:text-gray-900">
|
<span className="text-xs text-foreground dark:hover:text-green-300 dark:active:text-green-400 hover:text-gray-600 active:text-gray-700 focus:text-gray-900 dark:focus:text-green-900">
|
||||||
{item.title.replace(/_/g, " ")}
|
{item.title.replace(/_/g, " ")}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
))}
|
))}
|
||||||
</SidebarMenuSub>
|
</SidebarMenuSub>
|
||||||
</div>
|
</div>
|
||||||
</CollapsibleContent>
|
</CollapsibleContent>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ export default function TagListSidebar() {
|
||||||
{tags?.data.map((item, i) => (
|
{tags?.data.map((item, i) => (
|
||||||
<SidebarMenuItem key={i}>
|
<SidebarMenuItem key={i}>
|
||||||
<Link to={`/tags/${item}`}>
|
<Link to={`/tags/${item}`}>
|
||||||
<span className="text-xs text-black hover:text-gray-600 active:text-gray-700 focus:text-gray-900">
|
<span className="text-xs text-foreground dark:hover:text-green-300 dark:active:text-green-400 hover:text-gray-600 active:text-gray-700 focus:text-gray-900 dark:focus:text-green-900">
|
||||||
{item}
|
{item}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
28
src/components/ThemeToggle.tsx
Normal file
28
src/components/ThemeToggle.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { useState } from "react"
|
||||||
|
import { Label } from "@/components/ui/label"
|
||||||
|
import { Switch } from "@/components/ui/switch"
|
||||||
|
import { useTheme } from "@/context/ThemeProvider"
|
||||||
|
|
||||||
|
export default function ThemeToggle() {
|
||||||
|
const { theme, setTheme } = useTheme()
|
||||||
|
|
||||||
|
const [darkMode, setDarkMode] = useState(false)
|
||||||
|
const handleToggle = (checked) => {
|
||||||
|
setTheme(theme === "dark" ? "light" : "dark")
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(darkMode)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold mb-4">Theme</h3>
|
||||||
|
|
||||||
|
<p className="text-sm">
|
||||||
|
The theme is set automatically to your system default. You can change this below.
|
||||||
|
</p>
|
||||||
|
<div className="flex items-start space-x-2 mt-5">
|
||||||
|
<Switch id="dark-theme" checked={theme === "dark"} onCheckedChange={handleToggle} />
|
||||||
|
<Label htmlFor="dark-theme">Dark theme</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
22
src/components/ui/label.tsx
Normal file
22
src/components/ui/label.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Label({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
||||||
|
return (
|
||||||
|
<LabelPrimitive.Root
|
||||||
|
data-slot="label"
|
||||||
|
className={cn(
|
||||||
|
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Label }
|
||||||
29
src/components/ui/switch.tsx
Normal file
29
src/components/ui/switch.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as SwitchPrimitive from "@radix-ui/react-switch"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Switch({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
|
||||||
|
return (
|
||||||
|
<SwitchPrimitive.Root
|
||||||
|
data-slot="switch"
|
||||||
|
className={cn(
|
||||||
|
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<SwitchPrimitive.Thumb
|
||||||
|
data-slot="switch-thumb"
|
||||||
|
className={cn(
|
||||||
|
"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SwitchPrimitive.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Switch }
|
||||||
|
|
@ -24,7 +24,7 @@ const footerMenu = [
|
||||||
|
|
||||||
{
|
{
|
||||||
title: "Settings",
|
title: "Settings",
|
||||||
url: "#",
|
url: "/settings",
|
||||||
icon: Settings,
|
icon: Settings,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
@ -75,10 +75,18 @@ export function AppSidebar() {
|
||||||
{footerMenu.map((item) => (
|
{footerMenu.map((item) => (
|
||||||
<SidebarMenuItem key={item.title}>
|
<SidebarMenuItem key={item.title}>
|
||||||
<SidebarMenuButton asChild className="rounded-none">
|
<SidebarMenuButton asChild className="rounded-none">
|
||||||
<a href={item.url}>
|
<Link to={item.url}>
|
||||||
|
<item.icon />
|
||||||
|
<span>{item.title}</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/*
|
||||||
|
<a href={item.url}>
|
||||||
<item.icon />
|
<item.icon />
|
||||||
<span>{item.title}</span>
|
<span>{item.title}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
*/}
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -4,61 +4,61 @@ import api from "../api/eolas-api"
|
||||||
import { Link } from "react-router"
|
import { Link } from "react-router"
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
accessorKey: "title",
|
accessorKey: "title",
|
||||||
header: "Title",
|
header: "Title",
|
||||||
cell: ({ cell, row }) => {
|
cell: ({ cell, row }) => {
|
||||||
return (
|
return (
|
||||||
<Link to={`entries/${row.original.title}`}>
|
<Link to={`entries/${row.original.title}`}>
|
||||||
<span className="text-black underline-offset-3 underline hover:text-gray-700">
|
<span className="text-foreground underline-offset-3 underline hover:text-gray-700 dark:hover:text-green-300">
|
||||||
{row.original.title}
|
{row.original.title}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "date",
|
accessorKey: "date",
|
||||||
header: "Date",
|
header: "Date",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "time",
|
accessorKey: "time",
|
||||||
header: "Time",
|
header: "Time",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function RecentEdits() {
|
export default function RecentEdits() {
|
||||||
const { data, isLoading } = useQuery({
|
const { data, isLoading } = useQuery({
|
||||||
queryKey: ["entries_recent"],
|
queryKey: ["entries_recent"],
|
||||||
queryFn: () => api.get("/entries?limit=20&sort=date").then((res) => res.data),
|
queryFn: () => api.get("/entries?limit=20&sort=date").then((res) => res.data),
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(data)
|
console.log(data)
|
||||||
const parsed = data?.data?.map((entry) => {
|
const parsed = data?.data?.map((entry) => {
|
||||||
const [date, time] = entry?.last_modified?.split(" ")
|
const [date, time] = entry?.last_modified?.split(" ")
|
||||||
return {
|
return {
|
||||||
title: entry.title.replace(/_/g, " "),
|
title: entry.title.replace(/_/g, " "),
|
||||||
date: new Date(date).toLocaleString("en-GB", {
|
date: new Date(date).toLocaleString("en-GB", {
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
}),
|
}),
|
||||||
time: time,
|
time: time,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="border w-full">
|
<div className="border w-full">
|
||||||
<div className="border-b py-2 px-4 lg:px-6 bg-sidebar">
|
<div className="border-b py-2 px-4 lg:px-6 bg-sidebar">
|
||||||
<h2 className="scroll-m-20 font-semibold">Recent edits</h2>
|
<h2 className="scroll-m-20 font-semibold">Recent edits</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 lg:p-6">
|
<div className="p-4 lg:p-6">
|
||||||
<div className="container mx-auto py-2">
|
<div className="container mx-auto py-2">
|
||||||
<RecentEditsDataTable columns={columns} data={parsed || []} loading={isLoading} />
|
<RecentEditsDataTable columns={columns} data={parsed || []} loading={isLoading} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8
src/containers/Settings.tsx
Normal file
8
src/containers/Settings.tsx
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import ThemeToggle from "@/components/ThemeToggle"
|
||||||
|
export default function Settings() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ThemeToggle />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
72
src/context/ThemeProvider.tsx
Normal file
72
src/context/ThemeProvider.tsx
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import { createContext, useContext, useEffect, useState } from "react"
|
||||||
|
|
||||||
|
type Theme = "dark" | "light" | "system"
|
||||||
|
|
||||||
|
type ThemeProviderProps = {
|
||||||
|
children: React.ReactNode
|
||||||
|
defaultTheme?: Theme
|
||||||
|
storageKey?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThemeProviderState = {
|
||||||
|
theme: Theme
|
||||||
|
setTheme: (theme: Theme) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: ThemeProviderState = {
|
||||||
|
theme: "system",
|
||||||
|
setTheme: () => null,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThemeProviderContext = createContext<ThemeProviderState>(initialState)
|
||||||
|
|
||||||
|
export function ThemeProvider({
|
||||||
|
children,
|
||||||
|
defaultTheme = "system",
|
||||||
|
storageKey = "vite-ui-theme",
|
||||||
|
...props
|
||||||
|
}: ThemeProviderProps) {
|
||||||
|
const [theme, setTheme] = useState<Theme>(
|
||||||
|
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const root = window.document.documentElement
|
||||||
|
|
||||||
|
root.classList.remove("light", "dark")
|
||||||
|
|
||||||
|
if (theme === "system") {
|
||||||
|
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
|
? "dark"
|
||||||
|
: "light"
|
||||||
|
|
||||||
|
root.classList.add(systemTheme)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root.classList.add(theme)
|
||||||
|
}, [theme])
|
||||||
|
|
||||||
|
const value = {
|
||||||
|
theme,
|
||||||
|
setTheme: (theme: Theme) => {
|
||||||
|
localStorage.setItem(storageKey, theme)
|
||||||
|
setTheme(theme)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeProviderContext.Provider {...props} value={value}>
|
||||||
|
{children}
|
||||||
|
</ThemeProviderContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTheme = () => {
|
||||||
|
const context = useContext(ThemeProviderContext)
|
||||||
|
|
||||||
|
if (context === undefined) throw new Error("useTheme must be used within a ThemeProvider")
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
218
src/index.css
218
src/index.css
|
|
@ -4,120 +4,124 @@
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--radius-sm: calc(var(--radius) - 4px);
|
--radius-sm: calc(var(--radius) - 4px);
|
||||||
--radius-md: calc(var(--radius) - 2px);
|
--radius-md: calc(var(--radius) - 2px);
|
||||||
--radius-lg: var(--radius);
|
--radius-lg: var(--radius);
|
||||||
--radius-xl: calc(var(--radius) + 4px);
|
--radius-xl: calc(var(--radius) + 4px);
|
||||||
--color-background: var(--background);
|
--color-background: var(--background);
|
||||||
--color-foreground: var(--foreground);
|
--color-foreground: var(--foreground);
|
||||||
--color-card: var(--card);
|
--color-card: var(--card);
|
||||||
--color-card-foreground: var(--card-foreground);
|
--color-card-foreground: var(--card-foreground);
|
||||||
--color-popover: var(--popover);
|
--color-popover: var(--popover);
|
||||||
--color-popover-foreground: var(--popover-foreground);
|
--color-popover-foreground: var(--popover-foreground);
|
||||||
--color-primary: var(--primary);
|
--color-primary: var(--primary);
|
||||||
--color-primary-foreground: var(--primary-foreground);
|
--color-primary-foreground: var(--primary-foreground);
|
||||||
--color-secondary: var(--secondary);
|
--color-secondary: var(--secondary);
|
||||||
--color-secondary-foreground: var(--secondary-foreground);
|
--color-secondary-foreground: var(--secondary-foreground);
|
||||||
--color-muted: var(--muted);
|
--color-muted: var(--muted);
|
||||||
--color-muted-foreground: var(--muted-foreground);
|
--color-muted-foreground: var(--muted-foreground);
|
||||||
--color-accent: var(--accent);
|
--color-accent: var(--accent);
|
||||||
--color-accent-foreground: var(--accent-foreground);
|
--color-accent-foreground: var(--accent-foreground);
|
||||||
--color-destructive: var(--destructive);
|
--color-destructive: var(--destructive);
|
||||||
--color-border: var(--border);
|
--color-border: var(--border);
|
||||||
--color-input: var(--input);
|
--color-input: var(--input);
|
||||||
--color-ring: var(--ring);
|
--color-ring: var(--ring);
|
||||||
--color-chart-1: var(--chart-1);
|
--color-chart-1: var(--chart-1);
|
||||||
--color-chart-2: var(--chart-2);
|
--color-chart-2: var(--chart-2);
|
||||||
--color-chart-3: var(--chart-3);
|
--color-chart-3: var(--chart-3);
|
||||||
--color-chart-4: var(--chart-4);
|
--color-chart-4: var(--chart-4);
|
||||||
--color-chart-5: var(--chart-5);
|
--color-chart-5: var(--chart-5);
|
||||||
--color-sidebar: var(--sidebar);
|
--color-sidebar: var(--sidebar);
|
||||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||||
--color-sidebar-primary: var(--sidebar-primary);
|
--color-sidebar-primary: var(--sidebar-primary);
|
||||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||||
--color-sidebar-accent: var(--sidebar-accent);
|
--color-sidebar-accent: var(--sidebar-accent);
|
||||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||||
--color-sidebar-border: var(--sidebar-border);
|
--color-sidebar-border: var(--sidebar-border);
|
||||||
--color-sidebar-ring: var(--sidebar-ring);
|
--color-sidebar-ring: var(--sidebar-ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--radius: 0.625rem;
|
--radius: 0.625rem;
|
||||||
--background: oklch(1 0 0);
|
--background: oklch(1 0 0);
|
||||||
--foreground: oklch(0.145 0 0);
|
--foreground: oklch(0.145 0 0);
|
||||||
--card: oklch(1 0 0);
|
--card: oklch(1 0 0);
|
||||||
--card-foreground: oklch(0.145 0 0);
|
--card-foreground: oklch(0.145 0 0);
|
||||||
--popover: oklch(1 0 0);
|
--popover: oklch(1 0 0);
|
||||||
--popover-foreground: oklch(0.145 0 0);
|
--popover-foreground: oklch(0.145 0 0);
|
||||||
--primary: oklch(0.205 0 0);
|
--primary: oklch(0.205 0 0);
|
||||||
--primary-foreground: oklch(0.985 0 0);
|
--primary-foreground: oklch(0.985 0 0);
|
||||||
--secondary: oklch(0.97 0 0);
|
--secondary: oklch(0.97 0 0);
|
||||||
--secondary-foreground: oklch(0.205 0 0);
|
--secondary-foreground: oklch(0.205 0 0);
|
||||||
--muted: oklch(0.97 0 0);
|
--muted: oklch(0.97 0 0);
|
||||||
--muted-foreground: oklch(0.556 0 0);
|
--muted-foreground: oklch(0.556 0 0);
|
||||||
--accent: oklch(0.97 0 0);
|
--accent: oklch(0.97 0 0);
|
||||||
--accent-foreground: oklch(0.205 0 0);
|
--accent-foreground: oklch(0.205 0 0);
|
||||||
--destructive: oklch(0.577 0.245 27.325);
|
--destructive: oklch(0.577 0.245 27.325);
|
||||||
--border: oklch(0.922 0 0);
|
--border: oklch(0.922 0 0);
|
||||||
--input: oklch(0.922 0 0);
|
--input: oklch(0.922 0 0);
|
||||||
--ring: oklch(0.708 0 0);
|
--ring: oklch(0.708 0 0);
|
||||||
--chart-1: oklch(0.646 0.222 41.116);
|
--chart-1: oklch(0.646 0.222 41.116);
|
||||||
--chart-2: oklch(0.6 0.118 184.704);
|
--chart-2: oklch(0.6 0.118 184.704);
|
||||||
--chart-3: oklch(0.398 0.07 227.392);
|
--chart-3: oklch(0.398 0.07 227.392);
|
||||||
--chart-4: oklch(0.828 0.189 84.429);
|
--chart-4: oklch(0.828 0.189 84.429);
|
||||||
--chart-5: oklch(0.769 0.188 70.08);
|
--chart-5: oklch(0.769 0.188 70.08);
|
||||||
--sidebar: oklch(0.985 0 0);
|
--sidebar: oklch(0.985 0 0);
|
||||||
--sidebar-foreground: oklch(0.145 0 0);
|
--sidebar-foreground: oklch(0.145 0 0);
|
||||||
--sidebar-primary: oklch(0.205 0 0);
|
--sidebar-primary: oklch(0.205 0 0);
|
||||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||||
--sidebar-accent: oklch(0.97 0 0);
|
--sidebar-accent: oklch(0.97 0 0);
|
||||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||||
--sidebar-border: oklch(0.922 0 0);
|
--sidebar-border: oklch(0.922 0 0);
|
||||||
--sidebar-ring: oklch(0.708 0 0);
|
--sidebar-ring: oklch(0.708 0 0);
|
||||||
|
color-scheme: light;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
--background: oklch(0.145 0 0);
|
--background: oklch(0.145 0 0);
|
||||||
--foreground: oklch(0.985 0 0);
|
--foreground: oklch(0.985 0 0);
|
||||||
--card: oklch(0.205 0 0);
|
--card: oklch(0.205 0 0);
|
||||||
--card-foreground: oklch(0.985 0 0);
|
--card-foreground: oklch(0.985 0 0);
|
||||||
--popover: oklch(0.205 0 0);
|
--popover: oklch(0.205 0 0);
|
||||||
--popover-foreground: oklch(0.985 0 0);
|
--popover-foreground: oklch(0.985 0 0);
|
||||||
--primary: oklch(0.922 0 0);
|
--primary: oklch(0.922 0 0);
|
||||||
--primary-foreground: oklch(0.205 0 0);
|
--primary-foreground: oklch(0.205 0 0);
|
||||||
--secondary: oklch(0.269 0 0);
|
--secondary: oklch(0.269 0 0);
|
||||||
--secondary-foreground: oklch(0.985 0 0);
|
--secondary-foreground: oklch(0.985 0 0);
|
||||||
--muted: oklch(0.269 0 0);
|
--muted: oklch(0.269 0 0);
|
||||||
--muted-foreground: oklch(0.708 0 0);
|
--muted-foreground: oklch(0.708 0 0);
|
||||||
--accent: oklch(0.269 0 0);
|
--accent: oklch(0.269 0 0);
|
||||||
--accent-foreground: oklch(0.985 0 0);
|
--accent-foreground: oklch(0.985 0 0);
|
||||||
--destructive: oklch(0.704 0.191 22.216);
|
--destructive: oklch(0.704 0.191 22.216);
|
||||||
--border: oklch(1 0 0 / 10%);
|
--border: oklch(1 0 0 / 10%);
|
||||||
--input: oklch(1 0 0 / 15%);
|
--input: oklch(1 0 0 / 15%);
|
||||||
--ring: oklch(0.556 0 0);
|
--ring: oklch(0.556 0 0);
|
||||||
--chart-1: oklch(0.488 0.243 264.376);
|
--chart-1: oklch(0.488 0.243 264.376);
|
||||||
--chart-2: oklch(0.696 0.17 162.48);
|
--chart-2: oklch(0.696 0.17 162.48);
|
||||||
--chart-3: oklch(0.769 0.188 70.08);
|
--chart-3: oklch(0.769 0.188 70.08);
|
||||||
--chart-4: oklch(0.627 0.265 303.9);
|
--chart-4: oklch(0.627 0.265 303.9);
|
||||||
--chart-5: oklch(0.645 0.246 16.439);
|
--chart-5: oklch(0.645 0.246 16.439);
|
||||||
--sidebar: oklch(0.205 0 0);
|
--sidebar: oklch(0.205 0 0);
|
||||||
--sidebar-foreground: oklch(0.985 0 0);
|
--sidebar-foreground: oklch(0.985 0 0);
|
||||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||||
--sidebar-accent: oklch(0.269 0 0);
|
--sidebar-accent: oklch(0.269 0 0);
|
||||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||||
--sidebar-border: oklch(1 0 0 / 10%);
|
--sidebar-border: oklch(1 0 0 / 10%);
|
||||||
--sidebar-ring: oklch(0.556 0 0);
|
--sidebar-ring: oklch(0.556 0 0);
|
||||||
|
color-scheme: dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
* {
|
* {
|
||||||
@apply border-border outline-ring/50;
|
@apply border-border outline-ring/50;
|
||||||
}
|
}
|
||||||
html {
|
|
||||||
font-family: "Inter", sans-serif;
|
html {
|
||||||
}
|
font-family: "Inter", sans-serif;
|
||||||
body {
|
}
|
||||||
@apply bg-background text-foreground;
|
|
||||||
}
|
body {
|
||||||
|
@apply bg-background text-foreground;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
src/pages/Settings.tsx
Normal file
6
src/pages/Settings.tsx
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import Page from "@/templates/Page"
|
||||||
|
import { default as SettingsContainer } from "@/containers/Settings"
|
||||||
|
|
||||||
|
export default function Settings() {
|
||||||
|
return <Page pageTitle="Settings" pageBody={<SettingsContainer />} />
|
||||||
|
}
|
||||||
|
|
@ -4,55 +4,55 @@ import { HoverCard, HoverCardContent, HoverCardTrigger } from "@/components/ui/h
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Main pageTitle="Home">
|
<Main pageTitle="Home">
|
||||||
<div className="flex-1 flex flex-col overflow-auto">
|
<div className="flex-1 flex flex-col overflow-auto">
|
||||||
<div className="@container/main flex flex-col">
|
<div className="@container/main flex flex-col">
|
||||||
<div className="p-4 lg:p-6 flex flex-1">
|
<div className="p-4 lg:p-6 flex flex-1">
|
||||||
<div className="border w-full">
|
<div className="border w-full">
|
||||||
<div className="border-b py-2 px-4 lg:px-6 bg-sidebar">
|
<div className="border-b py-2 px-4 lg:px-6 bg-sidebar">
|
||||||
<h2 className="scroll-m-20 font-semibold">Welcome</h2>
|
<h2 className="scroll-m-20 font-semibold">Welcome</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 lg:p-6">
|
<div className="p-4 lg:p-6">
|
||||||
<p className="leading-7 [&:not(:first-child)]:mt-6 font-normal">
|
<p className="leading-7 [&:not(:first-child)]:mt-6 font-normal">
|
||||||
<HoverCard>
|
<HoverCard>
|
||||||
<HoverCardTrigger asChild>
|
<HoverCardTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="rounded-none mr-1 font-normal text-base"
|
className="rounded-none mr-1 font-normal text-base"
|
||||||
>
|
>
|
||||||
Eólas
|
Eólas
|
||||||
</Button>
|
</Button>
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
<HoverCardContent className="w-70 rounded-none">
|
<HoverCardContent className="w-70 rounded-none">
|
||||||
<div className="flex justify-between gap-4">
|
<div className="flex justify-between gap-4">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<h4 className="text-sm font-semibold">🇮🇪</h4>
|
<h4 className="text-sm font-semibold">🇮🇪</h4>
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
Irish for "knowledge", especially knowledge gained
|
Irish for "knowledge", especially knowledge gained
|
||||||
through practical experience.
|
through practical experience.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</HoverCardContent>
|
</HoverCardContent>
|
||||||
</HoverCard>
|
</HoverCard>
|
||||||
is{" "}
|
is{" "}
|
||||||
<a
|
<a
|
||||||
className="text-black underline-offset-3 font-medium underline hover:text-gray-700"
|
className="text-foreground underline-offset-3 font-medium underline hover:text-gray-700 dark:hover:text-green-300"
|
||||||
href="#"
|
href="#"
|
||||||
>
|
>
|
||||||
my
|
my
|
||||||
</a>{" "}
|
</a>{" "}
|
||||||
technical knowledge management system, or "second-brain", comprising
|
technical knowledge management system, or "second-brain", comprising
|
||||||
notes from the study of software engineering and computer science.
|
notes from the study of software engineering and computer science.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/*
|
{/*
|
||||||
|
|
||||||
<div className="bg-muted rounded-none p-3 font-medium text-sm text-muted-foreground my-4 mb-6">
|
<div className="bg-muted rounded-none p-3 font-medium text-sm text-muted-foreground my-4 mb-6">
|
||||||
<p className="">
|
<p className="">
|
||||||
|
|
@ -74,12 +74,12 @@ I'm
|
||||||
|
|
||||||
|
|
||||||
*/}
|
*/}
|
||||||
<div className="px-4 lg:px-6 flex-1 flex">
|
<div className="px-4 lg:px-6 flex-1 flex">
|
||||||
<RecentEdits />
|
<RecentEdits />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Main>
|
</Main>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import Main from "@/templates/Main"
|
|
||||||
import { useParams } from "react-router"
|
import { useParams } from "react-router"
|
||||||
import Page from "./Page"
|
import Page from "./Page"
|
||||||
export default function Entry() {
|
export default function Entry() {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import AppHeader from "@/components/AppHeader"
|
import AppHeader from "@/components/AppHeader"
|
||||||
import { AppSidebar } from "@/containers/AppSidebar"
|
import { AppSidebar } from "@/containers/AppSidebar"
|
||||||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"
|
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"
|
||||||
|
import { ThemeProvider } from "@/context/ThemeProvider"
|
||||||
|
|
||||||
export default function Main({ children, pageTitle }) {
|
export default function Main({ children, pageTitle }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<ThemeProvider storageKey="app-theme">
|
||||||
<SidebarProvider variant="inset">
|
<SidebarProvider variant="inset">
|
||||||
<AppSidebar />
|
<AppSidebar />
|
||||||
<SidebarInset>
|
<SidebarInset>
|
||||||
|
|
@ -12,6 +13,6 @@ export default function Main({ children, pageTitle }) {
|
||||||
<main>{children}</main>
|
<main>{children}</main>
|
||||||
</SidebarInset>
|
</SidebarInset>
|
||||||
</SidebarProvider>
|
</SidebarProvider>
|
||||||
</>
|
</ThemeProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ export default function Page({ pageTitle = null, pageBody = null, titleComponent
|
||||||
<div className="flex-1 flex flex-col overflow-auto">
|
<div className="flex-1 flex flex-col overflow-auto">
|
||||||
<div className="@container/main flex flex-col">
|
<div className="@container/main flex flex-col">
|
||||||
<div className="flex flex-1">
|
<div className="flex flex-1">
|
||||||
<div className="border-l-none w-full">
|
<div className="border-none w-full">
|
||||||
<div className="border-b py-2 px-4 lg:px-6 bg-sidebar">
|
<div className="border-b py-2 px-4 lg:px-6 bg-sidebar">
|
||||||
<h2 className="scroll-m-20 font-semibold">
|
<h2 className="scroll-m-20 font-semibold">
|
||||||
{titleComponent ? titleComponent : <span>{pageTitle}</span>}
|
{titleComponent ? titleComponent : <span>{pageTitle}</span>}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue