@umituz/web-dashboard 1.0.7 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/BrandLogo.d.ts +18 -0
- package/dist/components/BrandLogo.js +88 -0
- package/dist/components/BrandLogo.js.map +1 -0
- package/dist/components/DashboardHeader.d.ts +36 -0
- package/dist/components/DashboardHeader.js +225 -0
- package/dist/components/DashboardHeader.js.map +1 -0
- package/dist/components/DashboardLayout.d.ts +45 -0
- package/dist/components/DashboardLayout.js +501 -0
- package/dist/components/DashboardLayout.js.map +1 -0
- package/dist/components/DashboardSidebar.d.ts +29 -0
- package/dist/components/DashboardSidebar.js +189 -0
- package/dist/components/DashboardSidebar.js.map +1 -0
- package/dist/components/index.d.ts +10 -0
- package/dist/components/index.js +502 -0
- package/dist/components/index.js.map +1 -0
- package/dist/hooks/dashboard.d.ts +35 -0
- package/dist/hooks/dashboard.js +57 -0
- package/dist/hooks/dashboard.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +57 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +17 -403
- package/dist/index.js +56 -52
- package/dist/index.js.map +1 -1
- package/dist/theme/default.d.ts +18 -0
- package/dist/theme/default.js +52 -0
- package/dist/theme/default.js.map +1 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/index.js +184 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/presets.d.ts +14 -0
- package/dist/theme/presets.js +137 -0
- package/dist/theme/presets.js.map +1 -0
- package/dist/theme/utils.d.ts +22 -0
- package/dist/theme/utils.js +181 -0
- package/dist/theme/utils.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/layout.d.ts +45 -0
- package/dist/types/layout.js +2 -0
- package/dist/types/layout.js.map +1 -0
- package/dist/types/notification.d.ts +20 -0
- package/dist/types/notification.js +2 -0
- package/dist/types/notification.js.map +1 -0
- package/dist/types/sidebar.d.ts +36 -0
- package/dist/types/sidebar.js +2 -0
- package/dist/types/sidebar.js.map +1 -0
- package/dist/types/theme.d.ts +64 -0
- package/dist/types/theme.js +2 -0
- package/dist/types/theme.js.map +1 -0
- package/dist/types/user.d.ts +37 -0
- package/dist/types/user.js +2 -0
- package/dist/types/user.js.map +1 -0
- package/dist/utils/dashboard.d.ts +57 -0
- package/dist/utils/dashboard.js +44 -0
- package/dist/utils/dashboard.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +44 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +19 -23
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/domains/layouts/components/DashboardSidebar.tsx
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { Link, useLocation } from "react-router-dom";
|
|
6
|
+
import { useTranslation } from "react-i18next";
|
|
7
|
+
import { Button } from "@umituz/web-design-system/atoms";
|
|
8
|
+
|
|
9
|
+
// src/domains/layouts/components/BrandLogo.tsx
|
|
10
|
+
import { cn } from "@umituz/web-design-system/utils";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
var BrandLogo = ({ className, size = 32 }) => {
|
|
13
|
+
return /* @__PURE__ */ jsxs(
|
|
14
|
+
"svg",
|
|
15
|
+
{
|
|
16
|
+
width: size,
|
|
17
|
+
height: size,
|
|
18
|
+
viewBox: "0 0 100 100",
|
|
19
|
+
fill: "none",
|
|
20
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
21
|
+
className: cn("shrink-0", className),
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsx(
|
|
24
|
+
"rect",
|
|
25
|
+
{
|
|
26
|
+
x: "15",
|
|
27
|
+
y: "65",
|
|
28
|
+
width: "70",
|
|
29
|
+
height: "15",
|
|
30
|
+
rx: "4",
|
|
31
|
+
fill: "hsl(var(--primary))"
|
|
32
|
+
}
|
|
33
|
+
),
|
|
34
|
+
/* @__PURE__ */ jsx(
|
|
35
|
+
"rect",
|
|
36
|
+
{
|
|
37
|
+
x: "25",
|
|
38
|
+
y: "25",
|
|
39
|
+
width: "12",
|
|
40
|
+
height: "40",
|
|
41
|
+
rx: "2",
|
|
42
|
+
fill: "hsl(var(--primary))"
|
|
43
|
+
}
|
|
44
|
+
),
|
|
45
|
+
/* @__PURE__ */ jsx(
|
|
46
|
+
"rect",
|
|
47
|
+
{
|
|
48
|
+
x: "44",
|
|
49
|
+
y: "35",
|
|
50
|
+
width: "12",
|
|
51
|
+
height: "30",
|
|
52
|
+
rx: "2",
|
|
53
|
+
fill: "hsl(var(--primary))"
|
|
54
|
+
}
|
|
55
|
+
),
|
|
56
|
+
/* @__PURE__ */ jsx(
|
|
57
|
+
"rect",
|
|
58
|
+
{
|
|
59
|
+
x: "63",
|
|
60
|
+
y: "20",
|
|
61
|
+
width: "12",
|
|
62
|
+
height: "45",
|
|
63
|
+
rx: "2",
|
|
64
|
+
fill: "hsl(var(--primary))"
|
|
65
|
+
}
|
|
66
|
+
),
|
|
67
|
+
/* @__PURE__ */ jsx(
|
|
68
|
+
"rect",
|
|
69
|
+
{
|
|
70
|
+
x: "20",
|
|
71
|
+
y: "45",
|
|
72
|
+
width: "60",
|
|
73
|
+
height: "10",
|
|
74
|
+
rx: "2",
|
|
75
|
+
fill: "hsl(var(--secondary))"
|
|
76
|
+
}
|
|
77
|
+
),
|
|
78
|
+
/* @__PURE__ */ jsx(
|
|
79
|
+
"circle",
|
|
80
|
+
{
|
|
81
|
+
cx: "50",
|
|
82
|
+
cy: "20",
|
|
83
|
+
r: "5",
|
|
84
|
+
fill: "hsl(var(--secondary))"
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// src/domains/layouts/components/DashboardSidebar.tsx
|
|
93
|
+
import { PenTool, Menu, ChevronLeft, ChevronDown, ChevronRight } from "lucide-react";
|
|
94
|
+
|
|
95
|
+
// src/domains/layouts/utils/dashboard.ts
|
|
96
|
+
function filterSidebarItems(items, user) {
|
|
97
|
+
return items.filter((item) => {
|
|
98
|
+
if (item.enabled === false) return false;
|
|
99
|
+
if (!item.requiredApp) return true;
|
|
100
|
+
if (item.requiredApp === "mobile") return user?.hasMobileApp ?? false;
|
|
101
|
+
if (item.requiredApp === "web") return user?.hasWebApp ?? false;
|
|
102
|
+
return true;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/domains/layouts/components/DashboardSidebar.tsx
|
|
107
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
108
|
+
var DashboardSidebar = ({
|
|
109
|
+
collapsed,
|
|
110
|
+
setCollapsed,
|
|
111
|
+
sidebarGroups,
|
|
112
|
+
brandName = "App",
|
|
113
|
+
brandTagline = "grow smarter",
|
|
114
|
+
createPostRoute = "/dashboard/create",
|
|
115
|
+
user
|
|
116
|
+
}) => {
|
|
117
|
+
const location = useLocation();
|
|
118
|
+
const { t } = useTranslation();
|
|
119
|
+
const [collapsedGroups, setCollapsedGroups] = useState({});
|
|
120
|
+
const toggleGroup = (title) => {
|
|
121
|
+
setCollapsedGroups((prev) => ({
|
|
122
|
+
...prev,
|
|
123
|
+
[title]: !prev[title]
|
|
124
|
+
}));
|
|
125
|
+
};
|
|
126
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex h-full flex-col", children: [
|
|
127
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex h-16 items-center gap-3 border-b border-sidebar-border px-4 transition-all duration-300", children: [
|
|
128
|
+
/* @__PURE__ */ jsx2(BrandLogo, { size: 32 }),
|
|
129
|
+
!collapsed && /* @__PURE__ */ jsxs2("div", { className: "flex flex-col -gap-1", children: [
|
|
130
|
+
/* @__PURE__ */ jsx2("span", { className: "text-2xl font-black text-sidebar-foreground tracking-tighter leading-none", children: brandName }),
|
|
131
|
+
/* @__PURE__ */ jsx2("span", { className: "text-[11px] font-bold text-primary/70 lowercase tracking-tight mt-2 ml-1 select-none underline decoration-primary/40 underline-offset-[6px] decoration-2", children: brandTagline })
|
|
132
|
+
] })
|
|
133
|
+
] }),
|
|
134
|
+
/* @__PURE__ */ jsx2("div", { className: "px-3 py-4 border-b border-sidebar-border/50", children: /* @__PURE__ */ jsx2(Link, { to: createPostRoute, children: /* @__PURE__ */ jsxs2(
|
|
135
|
+
Button,
|
|
136
|
+
{
|
|
137
|
+
variant: "default",
|
|
138
|
+
className: `w-full gap-3 shadow-glow transition-all active:scale-95 group overflow-hidden rounded-xl ${collapsed ? "px-0 justify-center h-10 w-10 mx-auto" : "justify-start px-4 h-11"}`,
|
|
139
|
+
title: collapsed ? t("sidebar.createPost") : void 0,
|
|
140
|
+
children: [
|
|
141
|
+
/* @__PURE__ */ jsx2(PenTool, { className: `shrink-0 transition-transform duration-300 ${collapsed ? "h-5 w-5" : "h-4 w-4 group-hover:scale-110"}` }),
|
|
142
|
+
!collapsed && /* @__PURE__ */ jsx2("span", { className: "font-bold tracking-tight", children: t("sidebar.createPost") })
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
) }) }),
|
|
146
|
+
/* @__PURE__ */ jsx2("nav", { className: "flex-1 overflow-y-auto px-2 py-3 scrollbar-hide", children: /* @__PURE__ */ jsx2("div", { className: "space-y-6", children: sidebarGroups.map((group) => {
|
|
147
|
+
const filteredItems = filterSidebarItems(group.items, user);
|
|
148
|
+
if (filteredItems.length === 0) return null;
|
|
149
|
+
const isGroupCollapsed = collapsedGroups[group.title];
|
|
150
|
+
return /* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
|
|
151
|
+
!collapsed && /* @__PURE__ */ jsxs2(
|
|
152
|
+
"button",
|
|
153
|
+
{
|
|
154
|
+
onClick: () => toggleGroup(group.title),
|
|
155
|
+
className: "w-full flex items-center justify-between px-3 mb-2 group/header",
|
|
156
|
+
children: [
|
|
157
|
+
/* @__PURE__ */ jsx2("span", { className: "text-[10px] font-bold uppercase tracking-widest text-sidebar-foreground/40 group-hover/header:text-sidebar-foreground/70 transition-colors", children: group.title === "sidebar.ai" ? `${brandName} AI` : t(group.title) }),
|
|
158
|
+
isGroupCollapsed ? /* @__PURE__ */ jsx2(ChevronRight, { className: "h-3 w-3 text-sidebar-foreground/30 flex-shrink-0 group-hover/header:text-sidebar-foreground/50 transition-colors" }) : /* @__PURE__ */ jsx2(ChevronDown, { className: "h-3 w-3 text-sidebar-foreground/30 flex-shrink-0 group-hover/header:text-sidebar-foreground/50 transition-colors" })
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
),
|
|
162
|
+
(!isGroupCollapsed || collapsed) && filteredItems.map((item) => {
|
|
163
|
+
const active = location.pathname === item.path;
|
|
164
|
+
return /* @__PURE__ */ jsxs2(
|
|
165
|
+
Link,
|
|
166
|
+
{
|
|
167
|
+
to: item.path,
|
|
168
|
+
className: `flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-all duration-200 ${active ? "bg-sidebar-accent text-sidebar-accent-foreground shadow-sm" : "text-sidebar-foreground/70 hover:bg-sidebar-accent/40 hover:text-sidebar-foreground"} ${collapsed ? "justify-center" : ""}`,
|
|
169
|
+
title: collapsed ? t(item.label) : void 0,
|
|
170
|
+
children: [
|
|
171
|
+
/* @__PURE__ */ jsx2(item.icon, { className: `h-4 w-4 shrink-0 transition-transform ${active && "scale-110"}` }),
|
|
172
|
+
!collapsed && /* @__PURE__ */ jsx2("span", { children: t(item.label) })
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
item.path
|
|
176
|
+
);
|
|
177
|
+
})
|
|
178
|
+
] }, group.title);
|
|
179
|
+
}) }) }),
|
|
180
|
+
/* @__PURE__ */ jsx2("div", { className: "border-t border-sidebar-border p-3", children: /* @__PURE__ */ jsxs2("div", { className: `flex items-center ${collapsed ? "justify-center" : "justify-between"}`, children: [
|
|
181
|
+
!collapsed && /* @__PURE__ */ jsx2("p", { className: "text-[10px] uppercase tracking-wider text-sidebar-foreground/40 font-bold px-2", children: t("sidebar.system") }),
|
|
182
|
+
/* @__PURE__ */ jsx2(Button, { variant: "ghost", size: "icon", onClick: () => setCollapsed(!collapsed), className: "text-sidebar-foreground/70", children: collapsed ? /* @__PURE__ */ jsx2(Menu, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx2(ChevronLeft, { className: "h-4 w-4" }) })
|
|
183
|
+
] }) })
|
|
184
|
+
] });
|
|
185
|
+
};
|
|
186
|
+
export {
|
|
187
|
+
DashboardSidebar
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=DashboardSidebar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/domains/layouts/components/DashboardSidebar.tsx","../../src/domains/layouts/components/BrandLogo.tsx","../../src/domains/layouts/utils/dashboard.ts"],"sourcesContent":["import { useState } from \"react\";\nimport { Link, useLocation } from \"react-router-dom\";\nimport { useTranslation } from \"react-i18next\";\n\nimport { Button } from \"@umituz/web-design-system/atoms\";\nimport { BrandLogo } from \"./BrandLogo\";\nimport { PenTool, Menu, ChevronLeft, ChevronDown, ChevronRight } from \"lucide-react\";\nimport type { DashboardSidebarProps } from \"../types/layout\";\nimport type { DashboardUser } from \"../types/user\";\nimport type { SidebarGroup } from \"../types/sidebar\";\nimport { filterSidebarItems } from \"../utils/dashboard\";\n\ninterface DashboardSidebarPropsExtended extends DashboardSidebarProps {\n /** Sidebar groups configuration */\n sidebarGroups: SidebarGroup[];\n /** Brand name */\n brandName?: string;\n /** Brand tagline */\n brandTagline?: string;\n /** Create post route */\n createPostRoute?: string;\n /** Auth user */\n user?: DashboardUser;\n}\n\n/**\n * Dashboard Sidebar Component\n *\n * Displays collapsible sidebar with navigation menu items.\n * Supports app-based filtering (mobile/web) and collapsible groups.\n *\n * @param props - Dashboard sidebar props\n */\nexport const DashboardSidebar = ({\n collapsed,\n setCollapsed,\n sidebarGroups,\n brandName = \"App\",\n brandTagline = \"grow smarter\",\n createPostRoute = \"/dashboard/create\",\n user,\n}: DashboardSidebarPropsExtended) => {\n const location = useLocation();\n const { t } = useTranslation();\n const [collapsedGroups, setCollapsedGroups] = useState<Record<string, boolean>>({});\n\n const toggleGroup = (title: string) => {\n setCollapsedGroups(prev => ({\n ...prev,\n [title]: !prev[title]\n }));\n };\n\n return (\n <div className=\"flex h-full flex-col\">\n {/* Brand Section */}\n <div className=\"flex h-16 items-center gap-3 border-b border-sidebar-border px-4 transition-all duration-300\">\n <BrandLogo size={32} />\n {!collapsed && (\n <div className=\"flex flex-col -gap-1\">\n <span className=\"text-2xl font-black text-sidebar-foreground tracking-tighter leading-none\">{brandName}</span>\n <span className=\"text-[11px] font-bold text-primary/70 lowercase tracking-tight mt-2 ml-1 select-none underline decoration-primary/40 underline-offset-[6px] decoration-2\">\n {brandTagline}\n </span>\n </div>\n )}\n </div>\n\n {/* Create Button */}\n <div className=\"px-3 py-4 border-b border-sidebar-border/50\">\n <Link to={createPostRoute}>\n <Button\n variant=\"default\"\n className={`w-full gap-3 shadow-glow transition-all active:scale-95 group overflow-hidden rounded-xl ${\n collapsed ? \"px-0 justify-center h-10 w-10 mx-auto\" : \"justify-start px-4 h-11\"\n }`}\n title={collapsed ? t('sidebar.createPost') : undefined}\n >\n <PenTool className={`shrink-0 transition-transform duration-300 ${collapsed ? \"h-5 w-5\" : \"h-4 w-4 group-hover:scale-110\"}`} />\n {!collapsed && <span className=\"font-bold tracking-tight\">{t('sidebar.createPost')}</span>}\n </Button>\n </Link>\n </div>\n\n {/* Navigation */}\n <nav className=\"flex-1 overflow-y-auto px-2 py-3 scrollbar-hide\">\n <div className=\"space-y-6\">\n {sidebarGroups.map((group) => {\n const filteredItems = filterSidebarItems(group.items, user);\n\n if (filteredItems.length === 0) return null;\n\n const isGroupCollapsed = collapsedGroups[group.title];\n\n return (\n <div key={group.title} className=\"space-y-1\">\n {!collapsed && (\n <button\n onClick={() => toggleGroup(group.title)}\n className=\"w-full flex items-center justify-between px-3 mb-2 group/header\"\n >\n <span className=\"text-[10px] font-bold uppercase tracking-widest text-sidebar-foreground/40 group-hover/header:text-sidebar-foreground/70 transition-colors\">\n {group.title === \"sidebar.ai\" ? `${brandName} AI` : t(group.title)}\n </span>\n {isGroupCollapsed ? (\n <ChevronRight className=\"h-3 w-3 text-sidebar-foreground/30 flex-shrink-0 group-hover/header:text-sidebar-foreground/50 transition-colors\" />\n ) : (\n <ChevronDown className=\"h-3 w-3 text-sidebar-foreground/30 flex-shrink-0 group-hover/header:text-sidebar-foreground/50 transition-colors\" />\n )}\n </button>\n )}\n\n {(!isGroupCollapsed || collapsed) && filteredItems.map((item) => {\n const active = location.pathname === item.path;\n return (\n <Link\n key={item.path}\n to={item.path}\n className={`flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-all duration-200 ${\n active\n ? \"bg-sidebar-accent text-sidebar-accent-foreground shadow-sm\"\n : \"text-sidebar-foreground/70 hover:bg-sidebar-accent/40 hover:text-sidebar-foreground\"\n } ${collapsed ? \"justify-center\" : \"\"}`}\n title={collapsed ? t(item.label) : undefined}\n >\n <item.icon className={`h-4 w-4 shrink-0 transition-transform ${active && \"scale-110\"}`} />\n {!collapsed && <span>{t(item.label)}</span>}\n </Link>\n );\n })}\n </div>\n );\n })}\n </div>\n </nav>\n\n {/* Collapse Toggle */}\n <div className=\"border-t border-sidebar-border p-3\">\n <div className={`flex items-center ${collapsed ? \"justify-center\" : \"justify-between\"}`}>\n {!collapsed && (\n <p className=\"text-[10px] uppercase tracking-wider text-sidebar-foreground/40 font-bold px-2\">\n {t('sidebar.system')}\n </p>\n )}\n <Button variant=\"ghost\" size=\"icon\" onClick={() => setCollapsed(!collapsed)} className=\"text-sidebar-foreground/70\">\n {collapsed ? <Menu className=\"h-4 w-4\" /> : <ChevronLeft className=\"h-4 w-4\" />}\n </Button>\n </div>\n </div>\n </div>\n );\n};\n","import React from \"react\";\nimport { cn } from \"@umituz/web-design-system/utils\";\n\ninterface BrandLogoProps {\n className?: string;\n size?: number;\n}\n\n/**\n * BrandLogo Component\n *\n * Displays the application brand logo as an SVG.\n * Supports custom sizing and styling through className.\n *\n * @param className - Optional CSS classes for styling\n * @param size - Width and height in pixels (default: 32)\n */\nexport const BrandLogo = ({ className, size = 32 }: BrandLogoProps) => {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 100 100\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={cn(\"shrink-0\", className)}\n >\n {/* Solid Foundation / Platform */}\n <rect\n x=\"15\"\n y=\"65\"\n width=\"70\"\n height=\"15\"\n rx=\"4\"\n fill=\"hsl(var(--primary))\"\n />\n\n {/* Assembly Paths / Structure */}\n <rect\n x=\"25\"\n y=\"25\"\n width=\"12\"\n height=\"40\"\n rx=\"2\"\n fill=\"hsl(var(--primary))\"\n />\n <rect\n x=\"44\"\n y=\"35\"\n width=\"12\"\n height=\"30\"\n rx=\"2\"\n fill=\"hsl(var(--primary))\"\n />\n <rect\n x=\"63\"\n y=\"20\"\n width=\"12\"\n height=\"45\"\n rx=\"2\"\n fill=\"hsl(var(--primary))\"\n />\n\n {/* Modern Accent - The 'Assembly' Bridge */}\n <rect\n x=\"20\"\n y=\"45\"\n width=\"60\"\n height=\"10\"\n rx=\"2\"\n fill=\"hsl(var(--secondary))\"\n />\n\n {/* Connection Point / Beacon */}\n <circle\n cx=\"50\"\n cy=\"20\"\n r=\"5\"\n fill=\"hsl(var(--secondary))\"\n />\n </svg>\n );\n};\n","/**\n * Dashboard Utilities\n *\n * Utility functions for dashboard operations\n */\n\n/**\n * Format notification timestamp to relative time\n *\n * @param createdAt - Notification creation timestamp\n * @param t - i18n translation function\n * @returns Formatted time string\n */\nexport function formatNotificationTime(\n createdAt: Date | string | number,\n t: (key: string, params?: Record<string, unknown>) => string\n): string {\n const date = new Date(createdAt);\n const secs = Math.floor((Date.now() - date.getTime()) / 1000);\n\n if (secs < 60) return t(\"dashboard.activityFeed.times.justNow\");\n if (secs < 3600) return t(\"dashboard.activityFeed.times.minutesAgo\", { val: Math.floor(secs / 60) });\n if (secs < 86400) return t(\"dashboard.activityFeed.times.hoursAgo\", { val: Math.floor(secs / 3600) });\n return t(\"dashboard.activityFeed.times.daysAgo\", { val: Math.floor(secs / 86400) });\n}\n\n/**\n * Check if a path is active\n *\n * @param currentPath - Current location pathname\n * @param targetPath - Target path to check\n * @returns True if paths match\n */\nexport function isPathActive(currentPath: string, targetPath: string): boolean {\n return currentPath === targetPath;\n}\n\n/**\n * Get page title from sidebar configuration\n *\n * @param pathname - Current pathname\n * @param sidebarGroups - Sidebar groups configuration\n * @param extraTitleMap - Extra title mappings\n * @returns Page title or null\n */\nexport function getPageTitle(\n pathname: string,\n sidebarGroups: Array<{ items: Array<{ path: string; label: string }> }>,\n extraTitleMap?: Record<string, string>\n): string | null {\n // Search in sidebar groups\n for (const group of sidebarGroups) {\n const item = group.items.find((i) => i.path === pathname);\n if (item) return item.label;\n }\n\n // Search in extra title map\n if (extraTitleMap?.[pathname]) {\n return extraTitleMap[pathname];\n }\n\n return null;\n}\n\n/**\n * Filter sidebar items by app type and enabled status\n *\n * @param items - Sidebar items to filter\n * @param user - Current user object\n * @returns Filtered items\n */\nexport function filterSidebarItems<T extends { enabled?: boolean; requiredApp?: \"mobile\" | \"web\" }>(\n items: T[],\n user?: { hasMobileApp?: boolean; hasWebApp?: boolean }\n): T[] {\n return items.filter((item) => {\n // Skip disabled items\n if (item.enabled === false) return false;\n\n // Skip items that require specific app types\n if (!item.requiredApp) return true;\n if (item.requiredApp === \"mobile\") return user?.hasMobileApp ?? false;\n if (item.requiredApp === \"web\") return user?.hasWebApp ?? false;\n\n return true;\n });\n}\n\n/**\n * Generate notification ID\n *\n * @returns Unique notification ID\n */\nexport function generateNotificationId(): string {\n return crypto.randomUUID();\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { DashboardLayout } from './DashboardLayout.js';
|
|
2
|
+
export { DashboardHeader } from './DashboardHeader.js';
|
|
3
|
+
export { DashboardSidebar } from './DashboardSidebar.js';
|
|
4
|
+
export { BrandLogo } from './BrandLogo.js';
|
|
5
|
+
import 'react/jsx-runtime';
|
|
6
|
+
import '../types/layout.js';
|
|
7
|
+
import '../types/sidebar.js';
|
|
8
|
+
import 'lucide-react';
|
|
9
|
+
import '../types/notification.js';
|
|
10
|
+
import '../types/user.js';
|