@voilajsx/uikit
Version:
Cross-platform React components with beautiful themes and OKLCH color sciences - Now with mobile (Capacitor) support
430 lines (429 loc) • 16.9 kB
JavaScript
import { jsx as e, jsxs as i, Fragment as j } from "react/jsx-runtime";
import * as L from "react";
import { createContext as Y, forwardRef as V, useState as B, useLayoutEffect as Z, useEffect as O, useContext as K } from "react";
import { c as ee } from "./index-Bke1qZdk.js";
import { c as s } from "./utils-CwJPJKOE.js";
import { Button as W } from "./button.js";
import { Badge as re } from "./badge.js";
import { Separator as te } from "./separator.js";
import { TooltipProvider as ne, Tooltip as ae, TooltipTrigger as oe, TooltipContent as se } from "./tooltip.js";
import { Breadcrumb as ie, BreadcrumbList as de, BreadcrumbItem as le, BreadcrumbLink as ce, BreadcrumbPage as me, BreadcrumbSeparator as ue } from "./breadcrumb.js";
import { X as fe } from "./x-BxwubQiM.js";
import { M as _ } from "./menu-DBhEanGo.js";
import { C as he } from "./chevron-right-pz9eCjj-.js";
function $() {
return typeof window > "u" ? !1 : window.innerWidth < 1024;
}
function be(x) {
return typeof window > "u" ? x : $() ? !1 : x;
}
const X = Y({
scheme: "sidebar",
tone: "subtle",
size: "lg",
sidebarExpanded: !0,
setSidebarExpanded: () => {
},
isMobile: !1
}), pe = ee(
"min-h-screen flex bg-background",
{
variants: {
tone: {
clean: "",
subtle: "",
brand: "",
contrast: ""
}
},
defaultVariants: {
tone: "subtle"
}
}
), q = V(({
scheme: x = "sidebar",
tone: k = "subtle",
size: h = "lg",
position: g = "relative",
defaultSidebarOpen: m = !0,
className: v,
children: N
}, M) => {
const [d, n] = B($), [w, t] = B(
() => be(m)
);
Z(() => {
const l = () => {
const a = window.innerWidth < 1024, C = d;
n(a), a && !C && w ? t(!1) : !a && C && t(m);
};
return l(), window.addEventListener("resize", l), () => window.removeEventListener("resize", l);
}, [d, w, m]), O(() => (d && w ? document.body.style.overflow = "hidden" : document.body.style.overflow = "unset", () => {
document.body.style.overflow = "unset";
}), [d, w]);
const u = L.Children.toArray(N), y = u.find(
(l) => L.isValidElement(l) && l.type === I
), b = u.find(
(l) => L.isValidElement(l) && l.type === R
), T = u.find(
(l) => L.isValidElement(l) && l.type === H
);
return /* @__PURE__ */ e(X.Provider, { value: {
scheme: x,
tone: k,
size: h,
sidebarExpanded: w,
setSidebarExpanded: t,
isMobile: d
}, children: /* @__PURE__ */ i(
"div",
{
ref: M,
className: s(pe({ tone: k }), v),
children: [
/* @__PURE__ */ e("div", { className: s(
"flex-shrink-0 transition-all duration-200 ease-out overflow-hidden",
// Desktop: smooth width transition
!d && w && (h === "sm" ? "w-48" : h === "md" ? "w-56" : h === "lg" ? "w-64" : h === "xl" ? "w-72" : "w-80"),
!d && !w && "w-0",
// Mobile: don't affect layout
d && "w-0",
g === "sticky" && d && "top-0 max-h-screen",
g === "sticky" && !d && "sticky top-0 max-h-screen"
), children: y }),
/* @__PURE__ */ i("div", { className: "flex-1 flex flex-col min-w-0 transition-all duration-200 ease-out", children: [
b,
T
] })
]
}
) });
});
q.displayName = "AdminLayout";
const I = V(({
tone: x,
navigation: k = [],
currentPath: h = "",
onNavigate: g,
logo: m,
position: v,
footer: N,
className: M
}, d) => {
const { scheme: n, tone: w, size: t, sidebarExpanded: u, setSidebarExpanded: y, isMobile: b } = P(), [T, l] = B(/* @__PURE__ */ new Set()), [a, C] = B(!1), o = x || w, E = n === "compact", p = !E || a, G = () => {
E && C(!a);
}, J = (r) => {
const c = new Set(T);
c.has(r) ? c.delete(r) : c.add(r), l(c);
}, Q = (r, c = !1) => {
const z = c ? "w-[92%] flex items-center group text-left font-medium rounded-lg cursor-pointer transition-all duration-300 ease-out transform hover:scale-[1.02]" : "w-full flex items-center group text-left font-medium rounded-lg cursor-pointer transition-all duration-300 ease-out transform hover:scale-[1.02]", S = c ? p ? "ml-4 px-3 py-2" : "px-2 py-2" : p ? "px-3 py-2.5" : "px-2 py-2.5 justify-center";
let f = "";
switch (o) {
case "clean":
f = r ? "bg-muted text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground hover:bg-muted/50";
break;
case "subtle":
f = r ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground hover:bg-background/60";
break;
case "brand":
f = r ? "bg-primary-foreground/20 text-primary-foreground shadow-sm" : "text-primary-foreground/90 hover:text-primary-foreground hover:bg-primary-foreground/10";
break;
case "contrast":
f = r ? "bg-muted/20 dark:bg-muted/20 text-white shadow-sm" : "text-white hover:bg-muted/20";
break;
default:
f = r ? "bg-muted/10 text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground hover:bg-muted/50";
}
return s(z, S, f);
}, D = ({ item: r, isSubmenu: c = !1 }) => {
const z = !c && r.items && r.items.length > 0, S = T.has(r.key), f = r.href ? h === r.href : !!r.isActive, F = /* @__PURE__ */ i(
"button",
{
onClick: () => {
if (E && !a) {
C(!0);
return;
}
z ? J(r.key) : r.href && g ? (g(r.href, r), b && y(!1)) : r.onClick && (r.onClick(), b && y(!1));
},
className: Q(f, c),
children: [
!c && r.icon && /* @__PURE__ */ e(r.icon, { className: s(
"flex-shrink-0",
p ? "h-4 w-4 mr-3" : "h-5 w-5"
) }),
p && /* @__PURE__ */ i(j, { children: [
/* @__PURE__ */ e("span", { className: "flex-1 truncate text-left", children: r.label }),
r.badge && /* @__PURE__ */ e(
re,
{
variant: f ? "secondary" : "outline",
className: s(
"text-xs h-4 px-1 ml-1 flex-shrink-0",
o === "brand" && !f && "bg-primary-foreground/10 text-primary-foreground border-primary-foreground/20",
o === "brand" && f && "bg-primary-foreground/20 text-primary-foreground border-primary-foreground/30",
o === "contrast" && !f && "bg-zinc-700 text-zinc-300 border-zinc-600",
o === "contrast" && f && "bg-zinc-600 text-zinc-100 border-zinc-500"
),
children: r.badge
}
),
z && /* @__PURE__ */ e(he, { className: s(
"h-4 w-4 flex-shrink-0 transition-transform duration-200",
S && "rotate-90"
) })
] })
]
}
);
return E && !a && !c && r.icon ? /* @__PURE__ */ i("div", { className: "w-full", children: [
/* @__PURE__ */ e(ne, { children: /* @__PURE__ */ i(ae, { delayDuration: 300, children: [
/* @__PURE__ */ e(oe, { asChild: !0, children: F }),
/* @__PURE__ */ e(
se,
{
side: "right",
className: "bg-white text-black border border-gray-200 shadow-md",
children: /* @__PURE__ */ e("p", { children: r.label })
}
)
] }) }),
z && S && p && r.items && /* @__PURE__ */ e("div", { className: "overflow-hidden transition-all duration-300 mt-1", children: /* @__PURE__ */ e("div", { className: "space-y-1 pb-2", children: r.items.map((A) => /* @__PURE__ */ e(D, { item: A, isSubmenu: !0 }, A.key)) }) })
] }, r.key) : /* @__PURE__ */ i("div", { className: "w-full", children: [
F,
z && S && p && r.items && /* @__PURE__ */ e("div", { className: "overflow-hidden transition-all duration-400 ease-out mt-1", children: /* @__PURE__ */ e("div", { className: "space-y-1 pb-2 animate-in slide-in-from-top-2", children: r.items.map((A, U) => /* @__PURE__ */ e(
"div",
{
className: "transition-all duration-300 ease-out",
style: { transitionDelay: `${U * 75}ms` },
children: /* @__PURE__ */ e(D, { item: A, isSubmenu: !0 })
},
A.key
)) }) })
] }, r.key);
};
return /* @__PURE__ */ i(j, { children: [
b && u && /* @__PURE__ */ e(
"div",
{
className: "fixed inset-0 z-[60] bg-black/50 backdrop-blur-sm lg:hidden",
onClick: () => y(!1),
"aria-hidden": "true"
}
),
/* @__PURE__ */ e(
"aside",
{
ref: d,
className: s(
"border-r flex flex-col bg-background overflow-hidden",
// ✅ RESTORED: Original smooth transitions
"transition-all duration-200 ease-out",
// ✅ FIXED: Proper z-index layering for mobile
// Mobile: Higher z-index than header (z-[70] > z-[10])
b ? "fixed left-0 top-0 z-[70] h-full" : "relative h-screen",
// Mobile: slide animation
b && (u ? "translate-x-0" : "-translate-x-full"),
// Desktop: always visible but container controls width
!b && "translate-x-0",
// Fixed widths for consistent animation
n === "sidebar" && t === "sm" && "w-48",
n === "sidebar" && t === "md" && "w-56",
n === "sidebar" && t === "lg" && "w-64",
n === "sidebar" && t === "xl" && "w-72",
n === "sidebar" && t === "full" && "w-80",
n === "compact" && !a && t === "sm" && "w-12",
n === "compact" && !a && t === "md" && "w-14",
n === "compact" && !a && t === "lg" && "w-16",
n === "compact" && !a && t === "xl" && "w-18",
n === "compact" && !a && t === "full" && "w-20",
n === "compact" && a && t === "sm" && "w-48",
n === "compact" && a && t === "md" && "w-56",
n === "compact" && a && t === "lg" && "w-64",
n === "compact" && a && t === "xl" && "w-72",
n === "compact" && a && t === "full" && "w-80",
// Tone colors
o === "clean" && "bg-background/90 backdrop-blur-sm border-border/40 text-foreground",
o === "subtle" && "bg-muted/90 backdrop-blur-sm border-border/30 text-foreground",
o === "brand" && "bg-primary border-primary-foreground/20 text-primary-foreground",
o === "contrast" && "bg-zinc-900 border-zinc-700/40 text-zinc-100",
M
),
children: /* @__PURE__ */ i("div", { className: "flex flex-col h-full", children: [
/* @__PURE__ */ e("div", { className: s(
"flex items-center shadow-sm flex-shrink-0 border-b transition-all duration-300 ease-out",
o === "clean" && "border-border/40",
o === "subtle" && "border-border/30",
o === "brand" && "border-primary-foreground/20",
o === "contrast" && "border-zinc-700/40",
p ? "justify-between h-16 px-4" : "justify-center h-16 px-2"
), children: p ? /* @__PURE__ */ i(j, { children: [
m && /* @__PURE__ */ e("div", { className: s(
"flex-shrink-0",
o === "brand" && "[&_*]:text-primary-foreground",
o === "contrast" && "[&_*]:text-zinc-100"
), children: m }),
(b || E && a) && /* @__PURE__ */ e(
W,
{
variant: "ghost",
size: "icon",
onClick: () => {
b ? y(!1) : E && C(!1);
},
className: "flex-shrink-0",
children: /* @__PURE__ */ e(fe, { className: "h-4 w-4" })
}
)
] }) : /* @__PURE__ */ e(
W,
{
variant: "ghost",
size: "icon",
onClick: G,
className: "flex-shrink-0",
children: /* @__PURE__ */ e(_, { className: "h-4 w-4" })
}
) }),
/* @__PURE__ */ e("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ e("nav", { className: s(
"space-y-1 transition-all duration-300 ease-out",
p ? "p-4" : "p-2"
), children: k.map((r, c) => /* @__PURE__ */ e(
"div",
{
className: s(
"transition-all duration-300 ease-out",
p ? "opacity-100 translate-x-0" : "opacity-100"
),
style: {
transitionDelay: p ? `${c * 50}ms` : "0ms"
},
children: /* @__PURE__ */ e(D, { item: r })
},
r.key
)) }) }),
N && p && /* @__PURE__ */ i(j, { children: [
/* @__PURE__ */ e(te, { className: s(
o === "clean" && "bg-border/40",
o === "subtle" && "bg-border/30",
o === "brand" && "bg-primary-foreground/20",
o === "contrast" && "bg-zinc-700/40"
) }),
/* @__PURE__ */ e("div", { className: "flex-shrink-0 p-4", children: N })
] })
] })
}
)
] });
});
I.displayName = "AdminSidebar";
const R = V(({
tone: x,
size: k,
title: h,
position: g = "sticky",
breadcrumbs: m = [],
onBreadcrumbNavigate: v,
actions: N,
className: M
}, d) => {
const { sidebarExpanded: n, setSidebarExpanded: w, isMobile: t } = P();
return /* @__PURE__ */ e(
"header",
{
ref: d,
className: s(
"w-full shadow-sm bg-background/95 backdrop-blur-md text-foreground flex-shrink-0 border-b border-border/50",
"transition-all duration-200 ease-out",
// ✅ FIXED: Sticky on desktop, lower z-index for mobile sidebar layering
g === "sticky" && "sticky top-0",
g === "fixed" && "fixed top-0 left-0 right-0",
// Always use lower z-index so mobile sidebar appears above
"z-[10]",
g === "relative" && "relative",
M
),
children: /* @__PURE__ */ i("div", { className: "flex items-center justify-between px-4 lg:px-6 h-16", children: [
/* @__PURE__ */ i("div", { className: "flex items-center gap-4 min-w-0 flex-1", children: [
/* @__PURE__ */ e(
"button",
{
className: s(
"p-2 rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted/80 transition-all duration-300 ease-out",
"transform hover:scale-105 active:scale-95",
// Always show on mobile
t && "block",
// Show on desktop for toggle functionality
!t && "block"
),
onClick: () => w(!n),
"aria-label": n ? "Close sidebar" : "Open sidebar",
children: /* @__PURE__ */ e(_, { className: s(
"h-5 w-5 transition-transform duration-300 ease-out",
n && !t && "rotate-180"
) })
}
),
/* @__PURE__ */ i("div", { className: "min-w-0 flex-1", children: [
h && !m.length && /* @__PURE__ */ e("h1", { className: "text-lg font-semibold text-foreground truncate", children: h }),
m.length > 0 && /* @__PURE__ */ e(ie, { children: /* @__PURE__ */ e(de, { children: m.map((u, y) => /* @__PURE__ */ i(L.Fragment, { children: [
/* @__PURE__ */ e(le, { children: u.href ? /* @__PURE__ */ e(
ce,
{
asChild: !!v,
...v ? {
onClick: (b) => {
b.preventDefault(), v(u.href);
}
} : { href: u.href },
children: v ? /* @__PURE__ */ e("button", { type: "button", children: u.label }) : u.label
}
) : /* @__PURE__ */ e(me, { children: u.label }) }),
y < m.length - 1 && /* @__PURE__ */ e(ue, {})
] }, y)) }) })
] })
] }),
N && /* @__PURE__ */ e("div", { className: "flex-shrink-0", children: N })
] })
}
);
});
R.displayName = "AdminHeader";
const H = V(({
tone: x,
size: k,
className: h,
children: g
}, m) => {
const { isMobile: v } = P();
return /* @__PURE__ */ e(
"main",
{
ref: m,
className: s(
"flex-1 min-w-0 overflow-auto",
h
),
children: /* @__PURE__ */ e("div", { className: "", children: /* @__PURE__ */ e("div", { className: "w-full mx-auto", children: g }) })
}
);
});
H.displayName = "AdminContent";
const P = () => {
const x = K(X);
if (!x)
throw new Error("useAdmin must be used within an AdminLayout component");
return x;
}, Le = Object.assign(q, {
Sidebar: I,
Header: R,
Content: H
});
export {
H as AdminContent,
R as AdminHeader,
Le as AdminLayout,
I as AdminSidebar,
P as useAdmin
};
//# sourceMappingURL=admin.js.map