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:
2026-07-27 11:11:26 +05:30
parent ae20bc4e34
commit c564916c60
56 changed files with 331 additions and 264 deletions
@@ -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>