@umituz/web-dashboard 1.0.7 → 2.0.0
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/{index.js → components/DashboardLayout.js} +3 -254
- 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/hooks/dashboard.d.ts +35 -0
- package/dist/hooks/dashboard.js +57 -0
- package/dist/hooks/dashboard.js.map +1 -0
- 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/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/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/package.json +51 -23
- package/dist/index.d.ts +0 -403
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface BrandLogoProps {
|
|
4
|
+
className?: string;
|
|
5
|
+
size?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* BrandLogo Component
|
|
9
|
+
*
|
|
10
|
+
* Displays the application brand logo as an SVG.
|
|
11
|
+
* Supports custom sizing and styling through className.
|
|
12
|
+
*
|
|
13
|
+
* @param className - Optional CSS classes for styling
|
|
14
|
+
* @param size - Width and height in pixels (default: 32)
|
|
15
|
+
*/
|
|
16
|
+
declare const BrandLogo: ({ className, size }: BrandLogoProps) => react_jsx_runtime.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { BrandLogo };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/domains/layouts/components/BrandLogo.tsx
|
|
4
|
+
import { cn } from "@umituz/web-design-system/utils";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
var BrandLogo = ({ className, size = 32 }) => {
|
|
7
|
+
return /* @__PURE__ */ jsxs(
|
|
8
|
+
"svg",
|
|
9
|
+
{
|
|
10
|
+
width: size,
|
|
11
|
+
height: size,
|
|
12
|
+
viewBox: "0 0 100 100",
|
|
13
|
+
fill: "none",
|
|
14
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
15
|
+
className: cn("shrink-0", className),
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ jsx(
|
|
18
|
+
"rect",
|
|
19
|
+
{
|
|
20
|
+
x: "15",
|
|
21
|
+
y: "65",
|
|
22
|
+
width: "70",
|
|
23
|
+
height: "15",
|
|
24
|
+
rx: "4",
|
|
25
|
+
fill: "hsl(var(--primary))"
|
|
26
|
+
}
|
|
27
|
+
),
|
|
28
|
+
/* @__PURE__ */ jsx(
|
|
29
|
+
"rect",
|
|
30
|
+
{
|
|
31
|
+
x: "25",
|
|
32
|
+
y: "25",
|
|
33
|
+
width: "12",
|
|
34
|
+
height: "40",
|
|
35
|
+
rx: "2",
|
|
36
|
+
fill: "hsl(var(--primary))"
|
|
37
|
+
}
|
|
38
|
+
),
|
|
39
|
+
/* @__PURE__ */ jsx(
|
|
40
|
+
"rect",
|
|
41
|
+
{
|
|
42
|
+
x: "44",
|
|
43
|
+
y: "35",
|
|
44
|
+
width: "12",
|
|
45
|
+
height: "30",
|
|
46
|
+
rx: "2",
|
|
47
|
+
fill: "hsl(var(--primary))"
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
/* @__PURE__ */ jsx(
|
|
51
|
+
"rect",
|
|
52
|
+
{
|
|
53
|
+
x: "63",
|
|
54
|
+
y: "20",
|
|
55
|
+
width: "12",
|
|
56
|
+
height: "45",
|
|
57
|
+
rx: "2",
|
|
58
|
+
fill: "hsl(var(--primary))"
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
/* @__PURE__ */ jsx(
|
|
62
|
+
"rect",
|
|
63
|
+
{
|
|
64
|
+
x: "20",
|
|
65
|
+
y: "45",
|
|
66
|
+
width: "60",
|
|
67
|
+
height: "10",
|
|
68
|
+
rx: "2",
|
|
69
|
+
fill: "hsl(var(--secondary))"
|
|
70
|
+
}
|
|
71
|
+
),
|
|
72
|
+
/* @__PURE__ */ jsx(
|
|
73
|
+
"circle",
|
|
74
|
+
{
|
|
75
|
+
cx: "50",
|
|
76
|
+
cy: "20",
|
|
77
|
+
r: "5",
|
|
78
|
+
fill: "hsl(var(--secondary))"
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
export {
|
|
86
|
+
BrandLogo
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=BrandLogo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/domains/layouts/components/BrandLogo.tsx"],"sourcesContent":["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"],"mappings":";;;AACA,SAAS,UAAU;AAkBf,SASE,KATF;AAFG,IAAM,YAAY,CAAC,EAAE,WAAW,OAAO,GAAG,MAAsB;AACrE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,WAAW,GAAG,YAAY,SAAS;AAAA,MAGnC;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,GAAE;AAAA,YACF,OAAM;AAAA,YACN,QAAO;AAAA,YACP,IAAG;AAAA,YACH,MAAK;AAAA;AAAA,QACP;AAAA,QAGA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,GAAE;AAAA,YACF,OAAM;AAAA,YACN,QAAO;AAAA,YACP,IAAG;AAAA,YACH,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,GAAE;AAAA,YACF,OAAM;AAAA,YACN,QAAO;AAAA,YACP,IAAG;AAAA,YACH,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,GAAE;AAAA,YACF,OAAM;AAAA,YACN,QAAO;AAAA,YACP,IAAG;AAAA,YACH,MAAK;AAAA;AAAA,QACP;AAAA,QAGA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,GAAE;AAAA,YACF,OAAM;AAAA,YACN,QAAO;AAAA,YACP,IAAG;AAAA,YACH,MAAK;AAAA;AAAA,QACP;AAAA,QAGA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,IAAG;AAAA,YACH,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { DashboardHeaderProps } from '../types/layout.js';
|
|
3
|
+
import { DashboardNotification } from '../types/notification.js';
|
|
4
|
+
import { DashboardUser } from '../types/user.js';
|
|
5
|
+
import '../types/sidebar.js';
|
|
6
|
+
import 'lucide-react';
|
|
7
|
+
|
|
8
|
+
interface DashboardHeaderPropsExtended extends DashboardHeaderProps {
|
|
9
|
+
/** Auth user */
|
|
10
|
+
user?: DashboardUser;
|
|
11
|
+
/** Notifications */
|
|
12
|
+
notifications?: DashboardNotification[];
|
|
13
|
+
/** Logout function */
|
|
14
|
+
onLogout?: () => Promise<void>;
|
|
15
|
+
/** Mark all as read function */
|
|
16
|
+
onMarkAllRead?: () => void;
|
|
17
|
+
/** Dismiss notification function */
|
|
18
|
+
onDismissNotification?: (id: string) => void;
|
|
19
|
+
/** Settings route */
|
|
20
|
+
settingsRoute?: string;
|
|
21
|
+
/** Profile route */
|
|
22
|
+
profileRoute?: string;
|
|
23
|
+
/** Billing route */
|
|
24
|
+
billingRoute?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Dashboard Header Component
|
|
28
|
+
*
|
|
29
|
+
* Displays top navigation bar with theme toggle, notifications,
|
|
30
|
+
* user menu, and organisation selector.
|
|
31
|
+
*
|
|
32
|
+
* @param props - Dashboard header props
|
|
33
|
+
*/
|
|
34
|
+
declare const DashboardHeader: ({ collapsed, setCollapsed, setMobileOpen, title, user, notifications, onLogout, onMarkAllRead, onDismissNotification, settingsRoute, profileRoute, billingRoute, }: DashboardHeaderPropsExtended) => react_jsx_runtime.JSX.Element;
|
|
35
|
+
|
|
36
|
+
export { DashboardHeader };
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/domains/layouts/components/DashboardHeader.tsx
|
|
4
|
+
import React, { useState } from "react";
|
|
5
|
+
import {
|
|
6
|
+
Bell,
|
|
7
|
+
X,
|
|
8
|
+
Sun,
|
|
9
|
+
Moon,
|
|
10
|
+
Menu,
|
|
11
|
+
User,
|
|
12
|
+
Settings,
|
|
13
|
+
LogOut,
|
|
14
|
+
ChevronDown,
|
|
15
|
+
CreditCard
|
|
16
|
+
} from "lucide-react";
|
|
17
|
+
import { Button } from "@umituz/web-design-system/atoms";
|
|
18
|
+
import { useNavigate } from "react-router-dom";
|
|
19
|
+
import { useTranslation } from "react-i18next";
|
|
20
|
+
|
|
21
|
+
// src/domains/layouts/utils/dashboard.ts
|
|
22
|
+
function formatNotificationTime(createdAt, t) {
|
|
23
|
+
const date = new Date(createdAt);
|
|
24
|
+
const secs = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
25
|
+
if (secs < 60) return t("dashboard.activityFeed.times.justNow");
|
|
26
|
+
if (secs < 3600) return t("dashboard.activityFeed.times.minutesAgo", { val: Math.floor(secs / 60) });
|
|
27
|
+
if (secs < 86400) return t("dashboard.activityFeed.times.hoursAgo", { val: Math.floor(secs / 3600) });
|
|
28
|
+
return t("dashboard.activityFeed.times.daysAgo", { val: Math.floor(secs / 86400) });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/domains/layouts/components/DashboardHeader.tsx
|
|
32
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
33
|
+
var DashboardHeader = ({
|
|
34
|
+
collapsed,
|
|
35
|
+
setCollapsed,
|
|
36
|
+
setMobileOpen,
|
|
37
|
+
title,
|
|
38
|
+
user,
|
|
39
|
+
notifications = [],
|
|
40
|
+
onLogout,
|
|
41
|
+
onMarkAllRead,
|
|
42
|
+
onDismissNotification,
|
|
43
|
+
settingsRoute = "/dashboard/settings",
|
|
44
|
+
profileRoute = "/dashboard/profile",
|
|
45
|
+
billingRoute = "/dashboard/billing"
|
|
46
|
+
}) => {
|
|
47
|
+
const navigate = useNavigate();
|
|
48
|
+
const { t } = useTranslation();
|
|
49
|
+
const [notifOpen, setNotifOpen] = useState(false);
|
|
50
|
+
const [profileOpen, setProfileOpen] = useState(false);
|
|
51
|
+
const unreadCount = notifications.filter((n) => !n.read).length;
|
|
52
|
+
const markAllRead = () => {
|
|
53
|
+
onMarkAllRead?.();
|
|
54
|
+
};
|
|
55
|
+
const handleLogout = async () => {
|
|
56
|
+
try {
|
|
57
|
+
await onLogout?.();
|
|
58
|
+
navigate("/login");
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const ThemeToggle = () => {
|
|
63
|
+
const [resolvedTheme, setResolvedTheme] = React.useState("light");
|
|
64
|
+
return /* @__PURE__ */ jsx(
|
|
65
|
+
Button,
|
|
66
|
+
{
|
|
67
|
+
variant: "ghost",
|
|
68
|
+
size: "icon",
|
|
69
|
+
onClick: () => setResolvedTheme(resolvedTheme === "light" ? "dark" : "light"),
|
|
70
|
+
className: "text-muted-foreground h-9 w-9",
|
|
71
|
+
title: resolvedTheme === "dark" ? t("common.tooltips.switchLight") : t("common.tooltips.switchDark"),
|
|
72
|
+
children: resolvedTheme === "dark" ? /* @__PURE__ */ jsx(Sun, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Moon, { className: "h-4 w-4" })
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
return /* @__PURE__ */ jsxs("header", { className: "flex h-14 items-center justify-between border-b border-border bg-card/50 backdrop-blur-md px-4 shrink-0 z-30", children: [
|
|
77
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
78
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "md:hidden", onClick: () => setMobileOpen(true), children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" }) }),
|
|
79
|
+
collapsed && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "hidden md:inline-flex", onClick: () => setCollapsed(false), children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" }) }),
|
|
80
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-foreground", children: title })
|
|
81
|
+
] }),
|
|
82
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
83
|
+
/* @__PURE__ */ jsx(ThemeToggle, {}),
|
|
84
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
85
|
+
/* @__PURE__ */ jsxs(
|
|
86
|
+
Button,
|
|
87
|
+
{
|
|
88
|
+
variant: "ghost",
|
|
89
|
+
size: "icon",
|
|
90
|
+
className: "text-muted-foreground relative h-9 w-9",
|
|
91
|
+
onClick: () => {
|
|
92
|
+
setNotifOpen(!notifOpen);
|
|
93
|
+
setProfileOpen(false);
|
|
94
|
+
},
|
|
95
|
+
children: [
|
|
96
|
+
/* @__PURE__ */ jsx(Bell, { className: "h-4 w-4" }),
|
|
97
|
+
unreadCount > 0 && /* @__PURE__ */ jsxs("span", { className: "absolute top-2 right-2 flex h-2 w-2", children: [
|
|
98
|
+
/* @__PURE__ */ jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-destructive opacity-75" }),
|
|
99
|
+
/* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-destructive" })
|
|
100
|
+
] })
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
),
|
|
104
|
+
notifOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
105
|
+
/* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-40", onClick: () => setNotifOpen(false) }),
|
|
106
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute top-12 right-0 w-80 bg-popover border border-border rounded-xl shadow-xl z-50 overflow-hidden animate-in fade-in zoom-in-95 duration-200", children: [
|
|
107
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border bg-muted/50", children: [
|
|
108
|
+
/* @__PURE__ */ jsx("h3", { className: "text-xs font-bold uppercase tracking-wider text-foreground", children: t("dashboard.notifications.title") }),
|
|
109
|
+
unreadCount > 0 && /* @__PURE__ */ jsx("button", { onClick: markAllRead, className: "text-[10px] font-bold text-primary hover:underline uppercase", children: t("dashboard.notifications.markAllRead") })
|
|
110
|
+
] }),
|
|
111
|
+
/* @__PURE__ */ jsxs("div", { className: "max-h-[400px] overflow-y-auto", children: [
|
|
112
|
+
notifications.map((n) => /* @__PURE__ */ jsxs("div", { className: `px-4 py-3 border-b border-border last:border-0 flex items-start gap-3 transition-colors hover:bg-muted/30 ${!n.read ? "bg-primary/5" : ""}`, children: [
|
|
113
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
114
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-foreground leading-snug", children: n.text }),
|
|
115
|
+
/* @__PURE__ */ jsxs("p", { className: "text-[10px] text-muted-foreground mt-1 flex items-center gap-1", children: [
|
|
116
|
+
/* @__PURE__ */ jsx("span", { className: "inline-block w-1 h-1 rounded-full bg-muted-foreground/30" }),
|
|
117
|
+
formatNotificationTime(n.createdAt, t)
|
|
118
|
+
] })
|
|
119
|
+
] }),
|
|
120
|
+
/* @__PURE__ */ jsx(
|
|
121
|
+
"button",
|
|
122
|
+
{
|
|
123
|
+
onClick: () => onDismissNotification?.(n.id),
|
|
124
|
+
className: "text-muted-foreground/50 hover:text-foreground shrink-0 transition-colors",
|
|
125
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
] }, n.id)),
|
|
129
|
+
notifications.length === 0 && /* @__PURE__ */ jsxs("div", { className: "px-4 py-10 text-center", children: [
|
|
130
|
+
/* @__PURE__ */ jsx("div", { className: "mx-auto w-10 h-10 rounded-full bg-muted flex items-center justify-center mb-3", children: /* @__PURE__ */ jsx(Bell, { className: "h-5 w-5 text-muted-foreground/50" }) }),
|
|
131
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("dashboard.notifications.none") })
|
|
132
|
+
] })
|
|
133
|
+
] })
|
|
134
|
+
] })
|
|
135
|
+
] })
|
|
136
|
+
] }),
|
|
137
|
+
/* @__PURE__ */ jsx("div", { className: "h-6 w-px bg-border mx-1" }),
|
|
138
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
139
|
+
/* @__PURE__ */ jsxs(
|
|
140
|
+
"button",
|
|
141
|
+
{
|
|
142
|
+
onClick: () => {
|
|
143
|
+
setProfileOpen(!profileOpen);
|
|
144
|
+
setNotifOpen(false);
|
|
145
|
+
},
|
|
146
|
+
className: "flex items-center gap-2 p-1 pl-1 rounded-full hover:bg-muted transition-colors group",
|
|
147
|
+
children: [
|
|
148
|
+
/* @__PURE__ */ jsx("div", { className: "w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-[10px] font-bold text-primary overflow-hidden border border-primary/20 ring-primary/20 group-hover:ring-4 transition-all", children: user?.avatar && /* @__PURE__ */ jsx("img", { src: user.avatar, alt: "User", className: "w-full h-full object-cover" }) }),
|
|
149
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: `h-4 w-4 text-muted-foreground transition-transform duration-200 ${profileOpen && "rotate-180"}` })
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
),
|
|
153
|
+
profileOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
154
|
+
/* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-40", onClick: () => setProfileOpen(false) }),
|
|
155
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute top-12 right-0 w-56 bg-popover border border-border rounded-xl shadow-xl z-50 overflow-hidden animate-in fade-in zoom-in-95 duration-200 p-1.5", children: [
|
|
156
|
+
/* @__PURE__ */ jsxs("div", { className: "px-3 py-2 border-b border-border/50 mb-1", children: [
|
|
157
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-bold text-foreground", children: user?.name || t("common.roles.user") }),
|
|
158
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate", children: user?.email })
|
|
159
|
+
] }),
|
|
160
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
|
|
161
|
+
/* @__PURE__ */ jsxs(
|
|
162
|
+
"button",
|
|
163
|
+
{
|
|
164
|
+
onClick: () => {
|
|
165
|
+
navigate(profileRoute);
|
|
166
|
+
setProfileOpen(false);
|
|
167
|
+
},
|
|
168
|
+
className: "flex w-full items-center gap-2.5 px-3 py-2 text-sm text-foreground hover:bg-muted rounded-lg transition-colors",
|
|
169
|
+
children: [
|
|
170
|
+
/* @__PURE__ */ jsx(User, { className: "h-4 w-4 text-muted-foreground" }),
|
|
171
|
+
t("common.profile")
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
),
|
|
175
|
+
/* @__PURE__ */ jsxs(
|
|
176
|
+
"button",
|
|
177
|
+
{
|
|
178
|
+
onClick: () => {
|
|
179
|
+
navigate(billingRoute);
|
|
180
|
+
setProfileOpen(false);
|
|
181
|
+
},
|
|
182
|
+
className: "flex w-full items-center gap-2.5 px-3 py-2 text-sm text-foreground hover:bg-muted rounded-lg transition-colors",
|
|
183
|
+
children: [
|
|
184
|
+
/* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4 text-muted-foreground" }),
|
|
185
|
+
t("common.billing")
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
),
|
|
189
|
+
/* @__PURE__ */ jsxs(
|
|
190
|
+
"button",
|
|
191
|
+
{
|
|
192
|
+
onClick: () => {
|
|
193
|
+
navigate(settingsRoute);
|
|
194
|
+
setProfileOpen(false);
|
|
195
|
+
},
|
|
196
|
+
className: "flex w-full items-center gap-2.5 px-3 py-2 text-sm text-foreground hover:bg-muted rounded-lg transition-colors",
|
|
197
|
+
children: [
|
|
198
|
+
/* @__PURE__ */ jsx(Settings, { className: "h-4 w-4 text-muted-foreground" }),
|
|
199
|
+
t("common.settings")
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
] }),
|
|
204
|
+
/* @__PURE__ */ jsx("div", { className: "h-px bg-border my-1.5" }),
|
|
205
|
+
/* @__PURE__ */ jsxs(
|
|
206
|
+
"button",
|
|
207
|
+
{
|
|
208
|
+
onClick: handleLogout,
|
|
209
|
+
className: "flex w-full items-center gap-2.5 px-3 py-2 text-sm text-destructive hover:bg-destructive/10 rounded-lg transition-colors font-medium",
|
|
210
|
+
children: [
|
|
211
|
+
/* @__PURE__ */ jsx(LogOut, { className: "h-4 w-4" }),
|
|
212
|
+
t("common.logout")
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
] })
|
|
217
|
+
] })
|
|
218
|
+
] })
|
|
219
|
+
] })
|
|
220
|
+
] });
|
|
221
|
+
};
|
|
222
|
+
export {
|
|
223
|
+
DashboardHeader
|
|
224
|
+
};
|
|
225
|
+
//# sourceMappingURL=DashboardHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/domains/layouts/components/DashboardHeader.tsx","../../src/domains/layouts/utils/dashboard.ts"],"sourcesContent":["import React, { useState } from \"react\";\nimport {\n Bell, X, Sun, Moon, Menu, User, Settings, LogOut,\n ChevronDown, CreditCard\n} from \"lucide-react\";\nimport { Button } from \"@umituz/web-design-system/atoms\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useTranslation } from \"react-i18next\";\nimport type { DashboardHeaderProps } from \"../types/layout\";\nimport type { DashboardNotification } from \"../types/notification\";\nimport type { DashboardUser } from \"../types/user\";\nimport { formatNotificationTime } from \"../utils/dashboard\";\n\ninterface DashboardHeaderPropsExtended extends DashboardHeaderProps {\n /** Auth user */\n user?: DashboardUser;\n /** Notifications */\n notifications?: DashboardNotification[];\n /** Logout function */\n onLogout?: () => Promise<void>;\n /** Mark all as read function */\n onMarkAllRead?: () => void;\n /** Dismiss notification function */\n onDismissNotification?: (id: string) => void;\n /** Settings route */\n settingsRoute?: string;\n /** Profile route */\n profileRoute?: string;\n /** Billing route */\n billingRoute?: string;\n}\n\n/**\n * Dashboard Header Component\n *\n * Displays top navigation bar with theme toggle, notifications,\n * user menu, and organisation selector.\n *\n * @param props - Dashboard header props\n */\nexport const DashboardHeader = ({\n collapsed,\n setCollapsed,\n setMobileOpen,\n title,\n user,\n notifications = [],\n onLogout,\n onMarkAllRead,\n onDismissNotification,\n settingsRoute = \"/dashboard/settings\",\n profileRoute = \"/dashboard/profile\",\n billingRoute = \"/dashboard/billing\",\n}: DashboardHeaderPropsExtended) => {\n const navigate = useNavigate();\n const { t } = useTranslation();\n const [notifOpen, setNotifOpen] = useState(false);\n const [profileOpen, setProfileOpen] = useState(false);\n\n const unreadCount = notifications.filter((n) => !n.read).length;\n\n const markAllRead = () => {\n onMarkAllRead?.();\n };\n\n const handleLogout = async () => {\n try {\n await onLogout?.();\n navigate(\"/login\");\n } catch {\n // Error handling can be added by parent component\n }\n };\n\n // Placeholder components - these should be provided by the consuming app\n const ThemeToggle = () => {\n const [resolvedTheme, setResolvedTheme] = React.useState<\"light\" | \"dark\">(\"light\");\n\n return (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setResolvedTheme(resolvedTheme === \"light\" ? \"dark\" : \"light\")}\n className=\"text-muted-foreground h-9 w-9\"\n title={resolvedTheme === \"dark\" ? t('common.tooltips.switchLight') : t('common.tooltips.switchDark')}\n >\n {resolvedTheme === \"dark\" ? <Sun className=\"h-4 w-4\" /> : <Moon className=\"h-4 w-4\" />}\n </Button>\n );\n };\n\n return (\n <header className=\"flex h-14 items-center justify-between border-b border-border bg-card/50 backdrop-blur-md px-4 shrink-0 z-30\">\n <div className=\"flex items-center gap-3\">\n <Button variant=\"ghost\" size=\"icon\" className=\"md:hidden\" onClick={() => setMobileOpen(true)}>\n <Menu className=\"h-5 w-5\" />\n </Button>\n {collapsed && (\n <Button variant=\"ghost\" size=\"icon\" className=\"hidden md:inline-flex\" onClick={() => setCollapsed(false)}>\n <Menu className=\"h-5 w-5\" />\n </Button>\n )}\n <h2 className=\"text-sm font-semibold text-foreground\">\n {title}\n </h2>\n </div>\n\n <div className=\"flex items-center gap-2\">\n {/* Theme Toggle */}\n <ThemeToggle />\n\n {/* Notifications */}\n <div className=\"relative\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"text-muted-foreground relative h-9 w-9\"\n onClick={() => {\n setNotifOpen(!notifOpen);\n setProfileOpen(false);\n }}\n >\n <Bell className=\"h-4 w-4\" />\n {unreadCount > 0 && (\n <span className=\"absolute top-2 right-2 flex h-2 w-2\">\n <span className=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-destructive opacity-75\"></span>\n <span className=\"relative inline-flex rounded-full h-2 w-2 bg-destructive\"></span>\n </span>\n )}\n </Button>\n\n {notifOpen && (\n <>\n <div className=\"fixed inset-0 z-40\" onClick={() => setNotifOpen(false)} />\n <div className=\"absolute top-12 right-0 w-80 bg-popover border border-border rounded-xl shadow-xl z-50 overflow-hidden animate-in fade-in zoom-in-95 duration-200\">\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border bg-muted/50\">\n <h3 className=\"text-xs font-bold uppercase tracking-wider text-foreground\">{t('dashboard.notifications.title')}</h3>\n {unreadCount > 0 && (\n <button onClick={markAllRead} className=\"text-[10px] font-bold text-primary hover:underline uppercase\">{t('dashboard.notifications.markAllRead')}</button>\n )}\n </div>\n\n <div className=\"max-h-[400px] overflow-y-auto\">\n {notifications.map((n) => (\n <div key={n.id} className={`px-4 py-3 border-b border-border last:border-0 flex items-start gap-3 transition-colors hover:bg-muted/30 ${!n.read ? \"bg-primary/5\" : \"\"}`}>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm text-foreground leading-snug\">{n.text}</p>\n <p className=\"text-[10px] text-muted-foreground mt-1 flex items-center gap-1\">\n <span className=\"inline-block w-1 h-1 rounded-full bg-muted-foreground/30\" />\n {formatNotificationTime(n.createdAt, t)}\n </p>\n </div>\n <button\n onClick={() => onDismissNotification?.(n.id)}\n className=\"text-muted-foreground/50 hover:text-foreground shrink-0 transition-colors\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n </div>\n ))}\n {notifications.length === 0 && (\n <div className=\"px-4 py-10 text-center\">\n <div className=\"mx-auto w-10 h-10 rounded-full bg-muted flex items-center justify-center mb-3\">\n <Bell className=\"h-5 w-5 text-muted-foreground/50\" />\n </div>\n <p className=\"text-sm text-muted-foreground\">{t('dashboard.notifications.none')}</p>\n </div>\n )}\n </div>\n </div>\n </>\n )}\n </div>\n\n <div className=\"h-6 w-px bg-border mx-1\" />\n\n <div className=\"relative\">\n <button\n onClick={() => {\n setProfileOpen(!profileOpen);\n setNotifOpen(false);\n }}\n className=\"flex items-center gap-2 p-1 pl-1 rounded-full hover:bg-muted transition-colors group\"\n >\n <div className=\"w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-[10px] font-bold text-primary overflow-hidden border border-primary/20 ring-primary/20 group-hover:ring-4 transition-all\">\n {user?.avatar && <img src={user.avatar} alt=\"User\" className=\"w-full h-full object-cover\" />}\n </div>\n <ChevronDown className={`h-4 w-4 text-muted-foreground transition-transform duration-200 ${profileOpen && \"rotate-180\"}`} />\n </button>\n\n {profileOpen && (\n <>\n <div className=\"fixed inset-0 z-40\" onClick={() => setProfileOpen(false)} />\n <div className=\"absolute top-12 right-0 w-56 bg-popover border border-border rounded-xl shadow-xl z-50 overflow-hidden animate-in fade-in zoom-in-95 duration-200 p-1.5\">\n <div className=\"px-3 py-2 border-b border-border/50 mb-1\">\n <p className=\"text-sm font-bold text-foreground\">{user?.name || t(\"common.roles.user\")}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{user?.email}</p>\n </div>\n\n <div className=\"space-y-0.5\">\n <button\n onClick={() => { navigate(profileRoute); setProfileOpen(false); }}\n className=\"flex w-full items-center gap-2.5 px-3 py-2 text-sm text-foreground hover:bg-muted rounded-lg transition-colors\"\n >\n <User className=\"h-4 w-4 text-muted-foreground\" />\n {t('common.profile')}\n </button>\n <button\n onClick={() => { navigate(billingRoute); setProfileOpen(false); }}\n className=\"flex w-full items-center gap-2.5 px-3 py-2 text-sm text-foreground hover:bg-muted rounded-lg transition-colors\"\n >\n <CreditCard className=\"h-4 w-4 text-muted-foreground\" />\n {t('common.billing')}\n </button>\n <button\n onClick={() => { navigate(settingsRoute); setProfileOpen(false); }}\n className=\"flex w-full items-center gap-2.5 px-3 py-2 text-sm text-foreground hover:bg-muted rounded-lg transition-colors\"\n >\n <Settings className=\"h-4 w-4 text-muted-foreground\" />\n {t('common.settings')}\n </button>\n </div>\n\n <div className=\"h-px bg-border my-1.5\" />\n\n <button\n onClick={handleLogout}\n className=\"flex w-full items-center gap-2.5 px-3 py-2 text-sm text-destructive hover:bg-destructive/10 rounded-lg transition-colors font-medium\"\n >\n <LogOut className=\"h-4 w-4\" />\n {t('common.logout')}\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n </header>\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":[]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { DashboardLayoutConfig } from '../types/layout.js';
|
|
3
|
+
import { DashboardNotification } from '../types/notification.js';
|
|
4
|
+
import { DashboardUser } from '../types/user.js';
|
|
5
|
+
import '../types/sidebar.js';
|
|
6
|
+
import 'lucide-react';
|
|
7
|
+
|
|
8
|
+
interface DashboardLayoutProps {
|
|
9
|
+
/** Layout configuration */
|
|
10
|
+
config: DashboardLayoutConfig;
|
|
11
|
+
/** Auth user */
|
|
12
|
+
user?: DashboardUser;
|
|
13
|
+
/** Auth loading state */
|
|
14
|
+
authLoading?: boolean;
|
|
15
|
+
/** Authenticated state */
|
|
16
|
+
isAuthenticated?: boolean;
|
|
17
|
+
/** Notifications */
|
|
18
|
+
notifications?: DashboardNotification[];
|
|
19
|
+
/** Logout function */
|
|
20
|
+
onLogout?: () => Promise<void>;
|
|
21
|
+
/** Mark all as read function */
|
|
22
|
+
onMarkAllRead?: () => void;
|
|
23
|
+
/** Dismiss notification function */
|
|
24
|
+
onDismissNotification?: (id: string) => void;
|
|
25
|
+
/** Login route for redirect */
|
|
26
|
+
loginRoute?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Dashboard Layout Component
|
|
30
|
+
*
|
|
31
|
+
* Main layout wrapper for dashboard pages.
|
|
32
|
+
* Provides sidebar, header, and content area with responsive design.
|
|
33
|
+
*
|
|
34
|
+
* Features:
|
|
35
|
+
* - Collapsible sidebar
|
|
36
|
+
* - Mobile menu overlay
|
|
37
|
+
* - Breadcrumb page titles
|
|
38
|
+
* - Loading skeletons
|
|
39
|
+
* - Auth protection
|
|
40
|
+
*
|
|
41
|
+
* @param props - Dashboard layout props
|
|
42
|
+
*/
|
|
43
|
+
declare const DashboardLayout: ({ config, user, authLoading, isAuthenticated, notifications, onLogout, onMarkAllRead, onDismissNotification, loginRoute, }: DashboardLayoutProps) => react_jsx_runtime.JSX.Element | null;
|
|
44
|
+
|
|
45
|
+
export { DashboardLayout, DashboardLayout as default };
|