feat: enhance UI components and add vibrant theme support
- Updated layout and styling for various dashboard pages including stock adjustments, counts, transfers, wastage, and vendors to improve responsiveness and visual consistency. - Introduced a vibrant theme option in the theme toggle component, allowing users to switch between light, dark, and vibrant themes. - Refactored button styles across login and forgot password pages for better accessibility and visual feedback. - Improved sidebar navigation with expanded functionality for items without dedicated pages. - Enhanced data table styling for better readability and user interaction. - Added new background images to support the vibrant theme.
This commit is contained in:
@@ -47,6 +47,9 @@ const navItems: {
|
||||
/** Where clicking the row actually navigates, if different from `href`. `href` itself
|
||||
* stays the section prefix used to decide whether this row is "active". */
|
||||
landingHref?: string
|
||||
/** This item's own href has no page of its own (no landingHref either) — clicking the
|
||||
* row should only expand/collapse its children, never navigate. */
|
||||
expandOnly?: boolean
|
||||
icon: LucideIcon
|
||||
chevron?: boolean
|
||||
children?: { title: string; code: string; href: string; icon: LucideIcon }[]
|
||||
@@ -106,6 +109,7 @@ const navItems: {
|
||||
title: "Settings",
|
||||
code: "settings",
|
||||
href: "/dashboard/settings",
|
||||
expandOnly: true,
|
||||
icon: Settings,
|
||||
chevron: true,
|
||||
children: [
|
||||
@@ -139,9 +143,13 @@ function SidebarContent({
|
||||
const [expanded, setExpanded] = useState<Record<string, boolean>>({})
|
||||
|
||||
useEffect(() => {
|
||||
const parent = items.find((i) =>
|
||||
i.children?.some((c) => pathname === c.href || pathname.startsWith(`${c.href}/`))
|
||||
)
|
||||
const parent = items.find((i) => {
|
||||
if (!i.children?.length) return false
|
||||
if (i.children.some((c) => pathname === c.href || pathname.startsWith(`${c.href}/`))) return true
|
||||
// Landing on the parent's own hub page (e.g. /dashboard/settings itself,
|
||||
// not one of its children) should also reveal its sub-items.
|
||||
return pathname === i.href || pathname.startsWith(`${i.href}/`)
|
||||
})
|
||||
if (parent) {
|
||||
setExpanded((prev) => (prev[parent.code] ? prev : { ...prev, [parent.code]: true }))
|
||||
}
|
||||
@@ -153,7 +161,7 @@ function SidebarContent({
|
||||
return (
|
||||
<nav
|
||||
className={cn(
|
||||
"flex h-full flex-col rounded-3xl bg-card p-3 shadow-sm ring-1 ring-foreground/10 transition-[width] duration-300 ease-in-out",
|
||||
"sidebar-surface flex h-full flex-col rounded-3xl bg-card p-3 shadow-sm ring-1 ring-foreground/10 transition-[width] duration-300 ease-in-out",
|
||||
!isMobile && (collapsed ? "w-20" : "w-64")
|
||||
)}
|
||||
>
|
||||
@@ -187,7 +195,7 @@ function SidebarContent({
|
||||
|
||||
{/* Nav items — scrolls internally when it overflows, without a visible
|
||||
scrollbar so the rounded panel stays clean. */}
|
||||
<ul className="flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
|
||||
<ul className="flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
|
||||
{items.map((item) => {
|
||||
const isActive =
|
||||
item.href === "/dashboard" ? pathname === item.href : pathname.startsWith(item.href)
|
||||
@@ -205,15 +213,18 @@ function SidebarContent({
|
||||
<Link
|
||||
href={item.landingHref ?? item.href}
|
||||
title={iconOnly ? item.title : undefined}
|
||||
onClick={onClose}
|
||||
onClick={() => {
|
||||
onClose?.()
|
||||
if (hasChildren) setExpanded((prev) => (prev[item.code] ? prev : { ...prev, [item.code]: true }))
|
||||
}}
|
||||
className={cn(
|
||||
"flex flex-1 items-center gap-3 rounded-2xl px-4 py-3 text-base font-semibold",
|
||||
"flex flex-1 items-center gap-3 rounded-2xl px-4 py-1.5 text-base font-normal",
|
||||
iconOnly && "justify-center px-0",
|
||||
isActive ? "text-primary" : "text-foreground"
|
||||
)}
|
||||
>
|
||||
<item.icon
|
||||
className={cn("size-5 shrink-0", isActive ? "text-primary" : "text-muted-foreground")}
|
||||
className={cn("size-3.5 shrink-0", isActive ? "text-primary" : "text-muted-foreground")}
|
||||
/>
|
||||
{!iconOnly && (
|
||||
<>
|
||||
@@ -270,14 +281,14 @@ function SidebarContent({
|
||||
onClick={onClose}
|
||||
tabIndex={isOpen ? undefined : -1}
|
||||
className={cn(
|
||||
"flex items-center gap-2.5 rounded-xl px-3 py-2 text-sm font-medium transition-colors",
|
||||
"flex items-center gap-2.5 rounded-xl px-3 py-1 text-sm font-medium transition-colors",
|
||||
childActive
|
||||
? "bg-primary/10 text-primary"
|
||||
: "text-muted-foreground hover:bg-muted hover:text-foreground"
|
||||
)}
|
||||
>
|
||||
<child.icon
|
||||
className={cn("size-4 shrink-0", childActive ? "text-primary" : "text-muted-foreground")}
|
||||
className={cn("size-3 shrink-0", childActive ? "text-primary" : "text-muted-foreground")}
|
||||
/>
|
||||
{child.title}
|
||||
</Link>
|
||||
@@ -362,9 +373,9 @@ export function AppSidebar() {
|
||||
type="button"
|
||||
onClick={() => setMobileOpen(true)}
|
||||
aria-label="Open menu"
|
||||
className="fixed top-5 left-5 z-40 flex size-10 items-center justify-center rounded-2xl bg-card shadow-sm ring-1 ring-foreground/10 text-muted-foreground hover:bg-muted lg:hidden"
|
||||
className="fixed top-8 left-5 z-40 flex size-8 items-center justify-center rounded-xl bg-card shadow-sm ring-1 ring-foreground/10 text-muted-foreground hover:bg-muted lg:hidden"
|
||||
>
|
||||
<Menu className="size-5" />
|
||||
<Menu className="size-4" />
|
||||
</button>
|
||||
|
||||
{/* ── Mobile overlay backdrop ──────────────────────── */}
|
||||
|
||||
@@ -164,8 +164,8 @@ export function Header() {
|
||||
}
|
||||
|
||||
return (
|
||||
<header className="mx-6 mt-3 mb-6 flex items-center justify-between gap-2 rounded-3xl bg-card py-4 pr-4 pl-14 shadow-sm ring-1 ring-foreground/10 lg:mx-8 lg:mt-4 lg:gap-4 lg:p-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<header className="mx-3 mt-3 mb-3 flex items-center justify-between gap-2 rounded-3xl bg-card py-4 pr-3 pl-12 shadow-sm ring-1 ring-foreground/10 sm:mx-6 sm:pr-4 sm:pl-14 lg:mx-8 lg:mt-4 lg:mb-4 lg:gap-4 lg:p-4">
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2 sm:gap-3">
|
||||
{showBackButton && (
|
||||
<button
|
||||
type="button"
|
||||
@@ -176,10 +176,10 @@ export function Header() {
|
||||
<ArrowLeft className="size-5" />
|
||||
</button>
|
||||
)}
|
||||
<h1 className="text-base font-bold tracking-tight text-foreground sm:text-xl">{title}</h1>
|
||||
<h1 className="min-w-0 truncate text-base font-bold tracking-tight text-foreground sm:text-xl">{title}</h1>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 sm:gap-3">
|
||||
<div className="flex shrink-0 items-center gap-1.5 sm:gap-3">
|
||||
<ThemeToggle />
|
||||
|
||||
<Popover>
|
||||
|
||||
Reference in New Issue
Block a user