@pablo2410/shared-ui 0.5.0 → 0.6.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.
@@ -1,832 +1,24 @@
1
1
  import {
2
- cn
3
- } from "../chunk-JT3XLKKD.js";
4
- import {
5
- Avatar,
6
- AvatarFallback,
7
- DropdownMenu,
8
- DropdownMenuContent,
9
- DropdownMenuItem,
10
- DropdownMenuSeparator,
11
- DropdownMenuTrigger,
12
- Sidebar,
13
- SidebarContent,
14
- SidebarFooter,
15
- SidebarHeader,
16
- SidebarInset,
17
- SidebarMenu,
18
- SidebarMenuButton,
19
- SidebarMenuItem,
20
- SidebarProvider,
21
- SidebarTrigger,
22
- useIsMobile,
23
- useSidebar
24
- } from "../chunk-LTUYIBMA.js";
25
-
26
- // src/layout/SharedSidebar.tsx
27
- import { useEffect, useRef, useState } from "react";
28
- var ADMIN_ROLES = ["enterprise_admin", "platform_admin", "admin", "superuser"];
29
- function isAdminRole(role) {
30
- return !!role && ADMIN_ROLES.includes(role);
31
- }
32
- function getInitials(name) {
33
- if (!name) return "U";
34
- return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
35
- }
36
- function isMenuItemActive(itemPath, location, basePath) {
37
- if (basePath) {
38
- if (itemPath === basePath) return location === basePath;
39
- return location.startsWith(itemPath);
40
- }
41
- if (itemPath === "/") return location === "/";
42
- return location.startsWith(itemPath);
43
- }
44
- function useSidebarResize(config) {
45
- const [width, setWidth] = useState(() => {
46
- if (typeof window === "undefined") return config.defaultWidth;
47
- const saved = localStorage.getItem(config.storageKey);
48
- return saved ? parseInt(saved, 10) : config.defaultWidth;
49
- });
50
- const [isResizing, setIsResizing] = useState(false);
51
- const startX = useRef(0);
52
- const startWidth = useRef(config.defaultWidth);
53
- useEffect(() => {
54
- localStorage.setItem(config.storageKey, String(width));
55
- }, [width, config.storageKey]);
56
- useEffect(() => {
57
- if (!isResizing) return;
58
- const onMove = (e) => {
59
- const newWidth = Math.min(
60
- config.maxWidth,
61
- Math.max(config.minWidth, startWidth.current + (e.clientX - startX.current))
62
- );
63
- setWidth(newWidth);
64
- };
65
- const onUp = () => {
66
- setIsResizing(false);
67
- };
68
- document.addEventListener("mousemove", onMove);
69
- document.addEventListener("mouseup", onUp);
70
- document.body.style.cursor = "col-resize";
71
- document.body.style.userSelect = "none";
72
- return () => {
73
- document.removeEventListener("mousemove", onMove);
74
- document.removeEventListener("mouseup", onUp);
75
- document.body.style.cursor = "";
76
- document.body.style.userSelect = "";
77
- };
78
- }, [isResizing, config.minWidth, config.maxWidth]);
79
- const startResize = (e) => {
80
- setIsResizing(true);
81
- startX.current = e.clientX;
82
- startWidth.current = width;
83
- };
84
- return { width, isResizing, startResize };
85
- }
86
-
87
- // src/layout/DashboardLayout.tsx
88
- import { ArrowLeft, LogOut, PanelLeft, Settings } from "lucide-react";
89
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
90
- var DEFAULT_SERVICE_HUB_URL = "https://portal.oplytics.digital/app";
91
- var DEFAULT_USER_SETTINGS_URL = "https://portal.oplytics.digital/account";
92
- function UserMenu({
93
- user,
94
- onLogout,
95
- userSettingsUrl = DEFAULT_USER_SETTINGS_URL
96
- }) {
97
- const initials = (user.name || "U").split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
98
- return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
99
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs("button", { className: "flex items-center gap-2 rounded-md px-2 py-1 hover:bg-[#1E2738] transition-colors outline-none focus-visible:ring-1 focus-visible:ring-[#8C34E9]", children: [
100
- /* @__PURE__ */ jsx(Avatar, { className: "h-7 w-7 border border-[#2A2A3E]", children: /* @__PURE__ */ jsx(AvatarFallback, { className: "text-[10px] font-medium bg-[#8C34E9]/20 text-[#C084FC]", children: initials }) }),
101
- /* @__PURE__ */ jsx("span", { className: "hidden md:block text-xs text-[#E2E8F0] truncate max-w-[100px]", children: user.name || "User" })
102
- ] }) }),
103
- /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-48 bg-[#0D1220] border-[#1E2738]", children: [
104
- /* @__PURE__ */ jsxs("div", { className: "px-3 py-2 border-b border-[#1E2738]", children: [
105
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-[#E2E8F0] truncate", children: user.name }),
106
- /* @__PURE__ */ jsx("p", { className: "text-[10px] text-[#596475] truncate", children: user.role })
107
- ] }),
108
- /* @__PURE__ */ jsxs(
109
- DropdownMenuItem,
110
- {
111
- onClick: () => {
112
- window.location.href = userSettingsUrl;
113
- },
114
- className: "text-xs text-[#E2E8F0] hover:bg-[#1E2738] cursor-pointer focus:bg-[#1E2738]",
115
- children: [
116
- /* @__PURE__ */ jsx(Settings, { className: "h-3.5 w-3.5 mr-2 text-[#8890A0]" }),
117
- "User Settings"
118
- ]
119
- }
120
- ),
121
- /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: "bg-[#1E2738]" }),
122
- /* @__PURE__ */ jsxs(
123
- DropdownMenuItem,
124
- {
125
- onClick: () => onLogout?.(),
126
- className: "text-xs text-[#EF4444] hover:bg-[#EF4444]/10 cursor-pointer focus:bg-[#EF4444]/10 focus:text-[#EF4444]",
127
- children: [
128
- /* @__PURE__ */ jsx(LogOut, { className: "h-3.5 w-3.5 mr-2" }),
129
- "Sign Out"
130
- ]
131
- }
132
- )
133
- ] })
134
- ] });
135
- }
136
- function EnterpriseBadge({ enterprise }) {
137
- if (!enterprise) return null;
138
- return /* @__PURE__ */ jsxs("div", { className: "hidden lg:flex items-center gap-1.5 px-2 py-1 rounded-md bg-[#8C34E9]/10 border border-[#8C34E9]/20", children: [
139
- /* @__PURE__ */ jsx("div", { className: "h-4 w-4 rounded-sm bg-[#8C34E9]/30 flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "text-[8px] font-bold text-[#C084FC]", children: enterprise.name.charAt(0).toUpperCase() }) }),
140
- /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-[#C084FC] truncate max-w-[80px]", children: enterprise.code || enterprise.name })
141
- ] });
142
- }
143
- function NavSection({
144
- section,
145
- marginTop,
146
- isCollapsed,
147
- resolveActive,
148
- onNavigate
149
- }) {
150
- const label = section.title ?? section.label;
151
- return /* @__PURE__ */ jsxs(Fragment, { children: [
152
- label && /* @__PURE__ */ jsx("div", { className: cn("px-4 py-2", marginTop && "mt-2"), children: !isCollapsed && /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider", children: label }) }),
153
- /* @__PURE__ */ jsx(SidebarMenu, { className: "px-2 py-1", children: section.items.map((item) => {
154
- const active = resolveActive(item.path);
155
- const Icon = item.icon;
156
- return /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(
157
- SidebarMenuButton,
158
- {
159
- isActive: active,
160
- onClick: () => onNavigate(item.path),
161
- tooltip: item.label,
162
- className: "h-10 transition-all font-normal",
163
- children: [
164
- Icon && /* @__PURE__ */ jsx(Icon, { className: cn("h-4 w-4", active && "text-primary") }),
165
- /* @__PURE__ */ jsx("span", { children: item.label })
166
- ]
167
- }
168
- ) }, item.path);
169
- }) })
170
- ] });
171
- }
172
- function DashboardShell({
173
- serviceName,
174
- serviceIcon,
175
- menuSections,
176
- adminSections,
177
- isAdmin = false,
178
- activePath,
179
- onNavigate,
180
- isActive,
181
- serviceHubUrl = DEFAULT_SERVICE_HUB_URL,
182
- settingsPath,
183
- user,
184
- onLogout,
185
- userSettingsUrl,
186
- hierarchyNavigator,
187
- enterprise,
188
- reportingToolbar,
189
- footer,
190
- children
191
- }) {
192
- const { toggleSidebar, state } = useSidebar();
193
- const isCollapsed = state === "collapsed";
194
- const navigate = onNavigate;
195
- const resolveActive = (path) => isActive ? isActive(path, activePath) : isMenuItemActive(path, activePath);
196
- return /* @__PURE__ */ jsxs(Fragment, { children: [
197
- /* @__PURE__ */ jsxs(Sidebar, { collapsible: "icon", className: "border-r-0", children: [
198
- /* @__PURE__ */ jsx(SidebarHeader, { className: "h-16 justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-2 transition-all w-full", children: [
199
- /* @__PURE__ */ jsx(
200
- "button",
201
- {
202
- onClick: toggleSidebar,
203
- className: "h-8 w-8 flex items-center justify-center hover:bg-accent rounded-lg transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring shrink-0",
204
- "aria-label": "Toggle navigation",
205
- children: /* @__PURE__ */ jsx(PanelLeft, { className: "h-4 w-4 text-muted-foreground" })
206
- }
207
- ),
208
- !isCollapsed ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
209
- serviceIcon && /* @__PURE__ */ jsx("span", { className: "text-[#8C34E9] shrink-0", children: serviceIcon }),
210
- /* @__PURE__ */ jsx("span", { className: "font-semibold tracking-tight truncate", children: serviceName })
211
- ] }) : null
212
- ] }) }),
213
- /* @__PURE__ */ jsxs(SidebarContent, { className: "gap-0", children: [
214
- serviceHubUrl && /* @__PURE__ */ jsx(SidebarMenu, { className: "px-2 pt-2 pb-1", children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(
215
- SidebarMenuButton,
216
- {
217
- onClick: () => {
218
- window.location.href = serviceHubUrl;
219
- },
220
- tooltip: "Back to Service Hub",
221
- className: "h-10 transition-all font-normal text-muted-foreground hover:text-foreground",
222
- children: [
223
- /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" }),
224
- /* @__PURE__ */ jsx("span", { children: "Service Hub" })
225
- ]
226
- }
227
- ) }) }),
228
- menuSections.map((section, i) => /* @__PURE__ */ jsx(
229
- NavSection,
230
- {
231
- section,
232
- isCollapsed,
233
- resolveActive,
234
- onNavigate: navigate
235
- },
236
- section.title ?? section.label ?? `section-${i}`
237
- )),
238
- isAdmin && adminSections?.map((section, i) => /* @__PURE__ */ jsx(
239
- NavSection,
240
- {
241
- section,
242
- marginTop: true,
243
- isCollapsed,
244
- resolveActive,
245
- onNavigate: navigate
246
- },
247
- section.title ?? section.label ?? `admin-${i}`
248
- ))
249
- ] }),
250
- settingsPath && /* @__PURE__ */ jsx(SidebarFooter, { className: "p-2", children: /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(
251
- SidebarMenuButton,
252
- {
253
- onClick: () => navigate(settingsPath),
254
- tooltip: "Settings",
255
- className: "h-10 transition-all font-normal text-muted-foreground hover:text-foreground",
256
- children: [
257
- /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" }),
258
- /* @__PURE__ */ jsx("span", { children: "Settings" })
259
- ]
260
- }
261
- ) }) }) })
262
- ] }),
263
- /* @__PURE__ */ jsxs(SidebarInset, { children: [
264
- /* @__PURE__ */ jsxs(
265
- "header",
266
- {
267
- className: cn(
268
- "flex items-center justify-between h-14 px-4",
269
- "bg-[#0D1220]/95 border-b border-[#1E2738]",
270
- "backdrop-blur supports-[backdrop-filter]:backdrop-blur",
271
- "sticky top-0 z-40"
272
- ),
273
- children: [
274
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [
275
- /* @__PURE__ */ jsx(SidebarTrigger, { className: "h-9 w-9 rounded-lg bg-background shrink-0 md:hidden" }),
276
- serviceIcon && /* @__PURE__ */ jsx("span", { className: "text-[#8C34E9] shrink-0 hidden sm:block", children: serviceIcon }),
277
- hierarchyNavigator && /* @__PURE__ */ jsx("div", { className: "min-w-0 overflow-x-auto scrollbar-none", children: hierarchyNavigator })
278
- ] }),
279
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [
280
- reportingToolbar,
281
- /* @__PURE__ */ jsx(EnterpriseBadge, { enterprise }),
282
- /* @__PURE__ */ jsx("div", { className: "w-px h-6 bg-[#1E2738] hidden md:block" }),
283
- user && /* @__PURE__ */ jsx(UserMenu, { user, onLogout, userSettingsUrl })
284
- ] })
285
- ]
286
- }
287
- ),
288
- /* @__PURE__ */ jsx("main", { className: "flex-1 p-4 md:p-6 pb-14", children })
289
- ] }),
290
- footer
291
- ] });
292
- }
293
- function DashboardLayout(props) {
294
- const isMobile = useIsMobile();
295
- return /* @__PURE__ */ jsx(SidebarProvider, { defaultOpen: props.defaultOpen ?? !isMobile, children: /* @__PURE__ */ jsx(DashboardShell, { ...props }) });
296
- }
297
-
298
- // src/layout/DashboardLayoutSkeleton.tsx
299
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
300
- function Skeleton({ className }) {
301
- return /* @__PURE__ */ jsx2(
302
- "div",
303
- {
304
- className: cn(
305
- "animate-pulse rounded-md bg-[#1E2738]",
306
- className
307
- )
308
- }
309
- );
310
- }
311
- function DashboardLayoutSkeleton({ className }) {
312
- return /* @__PURE__ */ jsxs2("div", { className: cn("flex min-h-screen bg-[#0A0E1A]", className), children: [
313
- /* @__PURE__ */ jsxs2("div", { className: "w-[260px] border-r border-[#1E2738] bg-[#0D1220] p-4 space-y-6", children: [
314
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3 px-2", children: [
315
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-8 w-8 rounded-md" }),
316
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-24" })
317
- ] }),
318
- /* @__PURE__ */ jsxs2("div", { className: "space-y-2 px-2", children: [
319
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-9 w-full rounded-lg" }),
320
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-9 w-full rounded-lg" }),
321
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-9 w-full rounded-lg" }),
322
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-9 w-full rounded-lg" })
323
- ] }),
324
- /* @__PURE__ */ jsxs2("div", { className: "px-2", children: [
325
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-3 w-16 mb-3" }),
326
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-9 w-full rounded-lg" }),
327
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-9 w-full rounded-lg mt-2" })
328
- ] }),
329
- /* @__PURE__ */ jsx2("div", { className: "absolute bottom-4 left-4 right-4", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3 px-1", children: [
330
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-8 w-8 rounded-full" }),
331
- /* @__PURE__ */ jsxs2("div", { className: "flex-1 space-y-2", children: [
332
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-3 w-20" }),
333
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-2 w-32" })
334
- ] })
335
- ] }) })
336
- ] }),
337
- /* @__PURE__ */ jsxs2("div", { className: "flex-1 p-6 space-y-4", children: [
338
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between", children: [
339
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-8 w-48 rounded-lg" }),
340
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-9 w-24 rounded-lg" })
341
- ] }),
342
- /* @__PURE__ */ jsxs2("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4", children: [
343
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-24 rounded-xl" }),
344
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-24 rounded-xl" }),
345
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-24 rounded-xl" }),
346
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-24 rounded-xl" })
347
- ] }),
348
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-64 rounded-xl" }),
349
- /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
350
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-10 w-full rounded-lg" }),
351
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-10 w-full rounded-lg" }),
352
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-10 w-full rounded-lg" })
353
- ] })
354
- ] })
355
- ] });
356
- }
357
-
358
- // src/layout/SharedPageHeader.tsx
359
- import { ChevronLeft } from "lucide-react";
360
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
361
- function SharedPageHeader({
362
- title,
363
- subtitle,
364
- icon,
365
- onBack,
366
- actions,
367
- breadcrumbs,
368
- showBorder = true,
369
- compact = false,
370
- className,
371
- children
372
- }) {
373
- return /* @__PURE__ */ jsxs3(
374
- "div",
375
- {
376
- className: cn(
377
- "w-full",
378
- showBorder && "border-b border-[#1E2738]",
379
- compact ? "px-4 py-3" : "px-6 py-4",
380
- className
381
- ),
382
- children: [
383
- breadcrumbs && /* @__PURE__ */ jsx3("div", { className: cn("mb-2", compact && "mb-1"), children: breadcrumbs }),
384
- /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-4", children: [
385
- /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3 min-w-0", children: [
386
- onBack && /* @__PURE__ */ jsx3(
387
- "button",
388
- {
389
- onClick: onBack,
390
- className: cn(
391
- "shrink-0 p-1.5 rounded-md",
392
- "text-[#8890A0] hover:text-[#E2E8F0] hover:bg-[#1E2738]",
393
- "transition-colors cursor-pointer",
394
- "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[#8C34E9]"
395
- ),
396
- "aria-label": "Go back",
397
- children: /* @__PURE__ */ jsx3(ChevronLeft, { className: compact ? "h-4 w-4" : "h-5 w-5" })
398
- }
399
- ),
400
- icon && /* @__PURE__ */ jsx3("div", { className: "shrink-0 text-[#8C34E9]", children: icon }),
401
- /* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
402
- /* @__PURE__ */ jsx3(
403
- "h1",
404
- {
405
- className: cn(
406
- "font-semibold text-[#E2E8F0] truncate",
407
- "font-[Montserrat,sans-serif]",
408
- compact ? "text-lg" : "text-xl"
409
- ),
410
- children: title
411
- }
412
- ),
413
- subtitle && /* @__PURE__ */ jsx3(
414
- "p",
415
- {
416
- className: cn(
417
- "text-[#8890A0] truncate mt-0.5",
418
- "font-[Space_Grotesk,sans-serif]",
419
- compact ? "text-xs" : "text-sm"
420
- ),
421
- children: subtitle
422
- }
423
- )
424
- ] })
425
- ] }),
426
- actions && /* @__PURE__ */ jsx3("div", { className: "shrink-0 flex items-center gap-2", children: actions })
427
- ] }),
428
- children && /* @__PURE__ */ jsx3("div", { className: cn("mt-3", compact && "mt-2"), children })
429
- ]
430
- }
431
- );
432
- }
433
-
434
- // src/layout/SharedFooter.tsx
435
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
436
- var FOOTER_SERVICES = [
437
- { name: "SQDCP", slug: "sqdcp", localRoute: "/services/sqdcp", externalUrl: "https://sqdcp.oplytics.digital" },
438
- { name: "OEE Manager", slug: "oee-manager", localRoute: "/services/oee-manager", externalUrl: "https://oee.oplytics.digital" },
439
- { name: "Policy Deployment", slug: "policy-deployment", localRoute: "/services/policy-deployment", externalUrl: "https://policy.oplytics.digital" },
440
- { name: "Action Manager", slug: "action-manager", localRoute: "/services/action-manager", externalUrl: "https://actions.oplytics.digital" },
441
- { name: "Safety Manager", slug: "safety-manager", localRoute: "/services/safety-manager" },
442
- { name: "Connect", slug: "connect", localRoute: "/services/connect", externalUrl: "https://connect.oplytics.digital" }
443
- ];
444
- function SharedFooter({
445
- services = FOOTER_SERVICES,
446
- showPricing = true,
447
- showSignIn = true,
448
- onServiceClick,
449
- onPricingClick,
450
- onSignInClick,
451
- children,
452
- className,
453
- useExternalUrls = false,
454
- year
455
- }) {
456
- const currentYear = year ?? (/* @__PURE__ */ new Date()).getFullYear();
457
- return /* @__PURE__ */ jsx4(
458
- "footer",
459
- {
460
- className: cn(
461
- "w-full border-t border-[#1E2738]",
462
- "bg-[#0D1220] text-[#8890A0]",
463
- "font-[Space_Grotesk,sans-serif]",
464
- className
465
- ),
466
- children: /* @__PURE__ */ jsxs4("div", { className: "max-w-7xl mx-auto px-6 py-10", children: [
467
- /* @__PURE__ */ jsxs4("div", { className: "grid grid-cols-1 md:grid-cols-4 gap-8 mb-8", children: [
468
- /* @__PURE__ */ jsxs4("div", { className: "md:col-span-1", children: [
469
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 mb-3", children: [
470
- /* @__PURE__ */ jsx4(
471
- "div",
472
- {
473
- className: "w-7 h-7 rounded-full flex items-center justify-center",
474
- style: { background: "#8C34E9" },
475
- children: /* @__PURE__ */ jsx4("span", { className: "text-white font-bold text-xs", children: "O" })
476
- }
477
- ),
478
- /* @__PURE__ */ jsx4("span", { className: "text-[#E2E8F0] font-semibold text-sm font-[Montserrat,sans-serif]", children: "Oplytics.digital" })
479
- ] }),
480
- /* @__PURE__ */ jsx4("p", { className: "text-xs text-[#596475] leading-relaxed", children: "Operational intelligence platform for manufacturing excellence." })
481
- ] }),
482
- /* @__PURE__ */ jsxs4("div", { children: [
483
- /* @__PURE__ */ jsx4("h4", { className: "text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]", children: "Services" }),
484
- /* @__PURE__ */ jsx4("ul", { className: "space-y-2", children: services.map((service) => /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsx4(
485
- "a",
486
- {
487
- href: useExternalUrls && service.externalUrl ? service.externalUrl : service.localRoute,
488
- onClick: onServiceClick ? (e) => onServiceClick(service, e) : void 0,
489
- className: "text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors",
490
- children: service.name
491
- }
492
- ) }, service.slug)) })
493
- ] }),
494
- /* @__PURE__ */ jsxs4("div", { children: [
495
- /* @__PURE__ */ jsx4("h4", { className: "text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]", children: "Company" }),
496
- /* @__PURE__ */ jsxs4("ul", { className: "space-y-2", children: [
497
- showPricing && /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsx4(
498
- "a",
499
- {
500
- href: "/pricing",
501
- onClick: onPricingClick,
502
- className: "text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors",
503
- children: "Pricing"
504
- }
505
- ) }),
506
- /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsx4(
507
- "a",
508
- {
509
- href: "/about",
510
- className: "text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors",
511
- children: "About"
512
- }
513
- ) }),
514
- /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsx4(
515
- "a",
516
- {
517
- href: "/contact",
518
- className: "text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors",
519
- children: "Contact"
520
- }
521
- ) })
522
- ] })
523
- ] }),
524
- /* @__PURE__ */ jsxs4("div", { children: [
525
- /* @__PURE__ */ jsx4("h4", { className: "text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]", children: "Legal" }),
526
- /* @__PURE__ */ jsxs4("ul", { className: "space-y-2", children: [
527
- /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsx4(
528
- "a",
529
- {
530
- href: "/privacy",
531
- className: "text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors",
532
- children: "Privacy Policy"
533
- }
534
- ) }),
535
- /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsx4(
536
- "a",
537
- {
538
- href: "/terms",
539
- className: "text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors",
540
- children: "Terms of Service"
541
- }
542
- ) })
543
- ] }),
544
- showSignIn && /* @__PURE__ */ jsx4("div", { className: "mt-4", children: /* @__PURE__ */ jsx4(
545
- "a",
546
- {
547
- href: "/login",
548
- onClick: onSignInClick,
549
- className: "text-xs text-[#8C34E9] hover:text-[#A855F7] transition-colors font-medium",
550
- children: "Sign In"
551
- }
552
- ) })
553
- ] })
554
- ] }),
555
- children,
556
- /* @__PURE__ */ jsxs4("div", { className: "pt-6 border-t border-[#1E2738] flex flex-col sm:flex-row items-center justify-between gap-3", children: [
557
- /* @__PURE__ */ jsxs4("p", { className: "text-xs text-[#596475]", children: [
558
- "\xA9 ",
559
- currentYear,
560
- " Oplytics.digital. All rights reserved."
561
- ] }),
562
- /* @__PURE__ */ jsx4("p", { className: "text-xs text-[#3E4A5C]", children: "Built for manufacturing excellence" }),
563
- typeof __APP_VERSION__ !== "undefined" && /* @__PURE__ */ jsxs4("p", { className: "text-xs text-[#3E4A5C]", children: [
564
- "Platform v",
565
- __APP_VERSION__
566
- ] })
567
- ] })
568
- ] })
569
- }
570
- );
571
- }
572
-
573
- // src/layout/ServiceFooter.tsx
574
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
575
- var ENV_LABELS = {
576
- production: { label: "prod", color: "#10b981" },
577
- staging: { label: "stg", color: "#f59e0b" },
578
- development: { label: "dev", color: "#8C34E9" }
579
- };
580
- function ServiceFooter({
581
- enterpriseId,
582
- enterpriseName,
583
- userRole,
584
- userEmail,
585
- environment,
586
- buildVersion,
587
- showHealthMonitor = false,
588
- className
589
- }) {
590
- const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
591
- const env = environment ? ENV_LABELS[environment] : null;
592
- const version = buildVersion ?? (typeof __APP_VERSION__ !== "undefined" ? __APP_VERSION__ : void 0);
593
- return /* @__PURE__ */ jsxs5(
594
- "footer",
595
- {
596
- className: cn(
597
- "w-full border-t border-[#1E2738] bg-[#0D1220]",
598
- "flex items-center justify-between px-4",
599
- "h-9 min-h-[36px] shrink-0",
600
- "font-[Montserrat,sans-serif]",
601
- className
602
- ),
603
- children: [
604
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 min-w-0", children: [
605
- /* @__PURE__ */ jsx5(
606
- "div",
607
- {
608
- className: "w-5 h-5 rounded-full flex items-center justify-center shrink-0",
609
- style: { background: "#8C34E9" },
610
- children: /* @__PURE__ */ jsx5("span", { className: "text-white font-bold", style: { fontSize: 9 }, children: "O" })
611
- }
612
- ),
613
- /* @__PURE__ */ jsx5("span", { className: "text-[10px] text-[#596475] whitespace-nowrap hidden sm:inline", children: "Operational Excellence. One Digital Platform." })
614
- ] }),
615
- showHealthMonitor && /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1.5 text-[10px] text-[#3E4A5C] min-w-0 overflow-hidden", children: [
616
- enterpriseName && /* @__PURE__ */ jsxs5(Fragment2, { children: [
617
- /* @__PURE__ */ jsxs5("span", { className: "whitespace-nowrap", children: [
618
- /* @__PURE__ */ jsx5("span", { className: "text-[#596475]", children: enterpriseName }),
619
- enterpriseId != null && /* @__PURE__ */ jsxs5("span", { className: "text-[#3E4A5C]", children: [
620
- " (",
621
- enterpriseId,
622
- ")"
623
- ] })
624
- ] }),
625
- /* @__PURE__ */ jsx5(Separator, {})
626
- ] }),
627
- userEmail && /* @__PURE__ */ jsxs5(Fragment2, { children: [
628
- /* @__PURE__ */ jsx5("span", { className: "whitespace-nowrap text-[#596475]", children: userEmail }),
629
- userRole && /* @__PURE__ */ jsxs5("span", { className: "text-[#3E4A5C]", children: [
630
- " (",
631
- userRole,
632
- ")"
633
- ] }),
634
- /* @__PURE__ */ jsx5(Separator, {})
635
- ] }),
636
- env && /* @__PURE__ */ jsxs5(Fragment2, { children: [
637
- /* @__PURE__ */ jsxs5("span", { className: "whitespace-nowrap", children: [
638
- "ENV:",
639
- " ",
640
- /* @__PURE__ */ jsx5("span", { style: { color: env.color }, className: "font-semibold", children: env.label })
641
- ] }),
642
- /* @__PURE__ */ jsx5(Separator, {})
643
- ] }),
644
- version && /* @__PURE__ */ jsxs5("span", { className: "whitespace-nowrap text-[#3E4A5C] font-mono", children: [
645
- "v.",
646
- version
647
- ] })
648
- ] }),
649
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 text-[10px] text-[#3E4A5C] whitespace-nowrap shrink-0", children: [
650
- /* @__PURE__ */ jsxs5("span", { children: [
651
- "\xA9 ",
652
- currentYear,
653
- " Oplytics.digital"
654
- ] }),
655
- !showHealthMonitor && version && /* @__PURE__ */ jsxs5(Fragment2, { children: [
656
- /* @__PURE__ */ jsx5(Separator, {}),
657
- /* @__PURE__ */ jsxs5("span", { className: "font-mono", children: [
658
- "v.",
659
- version
660
- ] })
661
- ] })
662
- ] })
663
- ]
664
- }
665
- );
666
- }
667
- function Separator() {
668
- return /* @__PURE__ */ jsx5("span", { className: "text-[#1E2738] select-none", "aria-hidden": true, children: "|" });
669
- }
670
-
671
- // src/layout/createServiceLayout.tsx
672
- function defineServiceLayout(config) {
673
- return {
674
- defaultWidth: 260,
675
- minWidth: 200,
676
- maxWidth: 480,
677
- showPageHeader: true,
678
- showReportingToolbar: false,
679
- wrapHierarchyProvider: false,
680
- showAuthGate: true,
681
- ...config,
682
- storageKeyPrefix: config.storageKeyPrefix || config.serviceName.toLowerCase().replace(/\s+/g, "-")
683
- };
684
- }
685
-
686
- // src/layout/serviceConfigs.ts
687
- var sqdcpConfig = {
688
- serviceName: "SQDCP",
689
- serviceAbbreviation: "S",
690
- serviceIconName: "BarChart3",
691
- menuSections: [
692
- {
693
- items: [
694
- { iconName: "LayoutDashboard", label: "Dashboard", path: "/" },
695
- { iconName: "PenLine", label: "Data Entry", path: "/entry" },
696
- { iconName: "ClipboardList", label: "Action Tracker", path: "/actions" },
697
- { iconName: "FileText", label: "Reports", path: "/reports" },
698
- { iconName: "Settings", label: "Admin", path: "/admin" }
699
- ]
700
- }
701
- ],
702
- showPageHeader: true,
703
- showReportingToolbar: true,
704
- reportingModuleName: "SQDCP",
705
- wrapHierarchyProvider: false,
706
- showAuthGate: false,
707
- storageKeyPrefix: "sqdcp-sidebar",
708
- defaultWidth: 260,
709
- minWidth: 200,
710
- maxWidth: 480
711
- };
712
- var oeeManagerConfig = {
713
- serviceName: "OEE Manager",
714
- serviceAbbreviation: "o",
715
- serviceIconName: "BarChart3",
716
- menuSections: [
717
- {
718
- items: [
719
- { iconName: "BarChart3", label: "Dashboard", path: "/" },
720
- { iconName: "Database", label: "Data Input", path: "/data-input" },
721
- { iconName: "Clock", label: "Downtime", path: "/downtime" },
722
- { iconName: "Settings", label: "Settings", path: "/settings" }
723
- ]
724
- }
725
- ],
726
- backLink: {
727
- label: "Back to Portal",
728
- path: "https://portal.oplytics.digital"
729
- },
730
- showPageHeader: true,
731
- showReportingToolbar: true,
732
- reportingModuleName: "OEE Enterprise Manager",
733
- wrapHierarchyProvider: false,
734
- showAuthGate: false,
735
- storageKeyPrefix: "oee-sidebar",
736
- defaultWidth: 240,
737
- minWidth: 200,
738
- maxWidth: 400
739
- };
740
- var actionManagerConfig = {
741
- serviceName: "Action Manager",
742
- serviceAbbreviation: "A",
743
- serviceIconName: "LayoutDashboard",
744
- menuSections: [
745
- {
746
- items: [
747
- { iconName: "LayoutDashboard", label: "Dashboard", path: "/" },
748
- { iconName: "Users", label: "Teams", path: "/teams" }
749
- ]
750
- }
751
- ],
752
- showPageHeader: true,
753
- showReportingToolbar: false,
754
- reportingModuleName: "Action Manager",
755
- wrapHierarchyProvider: false,
756
- showAuthGate: true,
757
- storageKeyPrefix: "actionmanager-sidebar",
758
- defaultWidth: 280,
759
- minWidth: 200,
760
- maxWidth: 480
761
- };
762
- var businessHubConfig = {
763
- serviceName: "Business Hub",
764
- serviceAbbreviation: "B",
765
- serviceIconName: "LayoutDashboard",
766
- menuSections: [
767
- {
768
- items: [
769
- { iconName: "LayoutDashboard", label: "Dashboard", path: "/" },
770
- { iconName: "Users", label: "Analytics", path: "/analytics" }
771
- ]
772
- }
773
- ],
774
- showPageHeader: true,
775
- showReportingToolbar: false,
776
- reportingModuleName: "Business Hub",
777
- wrapHierarchyProvider: false,
778
- showAuthGate: true,
779
- storageKeyPrefix: "businesshub-sidebar",
780
- defaultWidth: 280,
781
- minWidth: 200,
782
- maxWidth: 480
783
- };
784
- var policyDeploymentConfig = {
785
- serviceName: "Policy Deployment",
786
- serviceAbbreviation: "PD",
787
- serviceIconName: "FileStack",
788
- menuSections: [
789
- {
790
- label: "Analysis",
791
- items: [
792
- { iconName: "LayoutGrid", label: "Dashboard", path: "/app/policy-deployment" },
793
- { iconName: "Grid3X3", label: "X-Matrix", path: "/app/policy-deployment/xmatrix" },
794
- { iconName: "BarChart3", label: "Bowling Chart", path: "/app/policy-deployment/bowling" },
795
- { iconName: "FolderKanban", label: "Action Plans", path: "/app/policy-deployment/actions" },
796
- { iconName: "GitBranchPlus", label: "Catchball", path: "/app/policy-deployment/catchball" },
797
- { iconName: "Target", label: "Deployments", path: "/app/policy-deployment/deployments" }
798
- ]
799
- },
800
- {
801
- label: "Administration",
802
- adminOnly: true,
803
- items: [
804
- { iconName: "Settings", label: "Manage Policy", path: "/app/policy-deployment/manage" },
805
- { iconName: "Plug", label: "Integrations", path: "/app/policy-deployment/integrations" }
806
- ]
807
- }
808
- ],
809
- backLink: {
810
- label: "Service Hub",
811
- path: "/app"
812
- },
813
- showPageHeader: true,
814
- showReportingToolbar: true,
815
- reportingModuleName: "Policy Deployment",
816
- wrapHierarchyProvider: true,
817
- showAuthGate: true,
818
- storageKeyPrefix: "policy-sidebar",
819
- defaultWidth: 260,
820
- minWidth: 200,
821
- maxWidth: 480
822
- };
823
- var SERVICE_CONFIGS = {
824
- sqdcp: sqdcpConfig,
825
- oeeManager: oeeManagerConfig,
826
- actionManager: actionManagerConfig,
827
- businessHub: businessHubConfig,
828
- policyDeployment: policyDeploymentConfig
829
- };
2
+ DashboardLayout,
3
+ DashboardLayoutSkeleton,
4
+ FOOTER_SERVICES,
5
+ SERVICE_CONFIGS,
6
+ ServiceFooter,
7
+ SharedFooter,
8
+ SharedPageHeader,
9
+ actionManagerConfig,
10
+ businessHubConfig,
11
+ defineServiceLayout,
12
+ getInitials,
13
+ isAdminRole,
14
+ isMenuItemActive,
15
+ oeeManagerConfig,
16
+ policyDeploymentConfig,
17
+ sqdcpConfig,
18
+ useSidebarResize
19
+ } from "../chunk-MAKRKBBI.js";
20
+ import "../chunk-JT3XLKKD.js";
21
+ import "../chunk-LTUYIBMA.js";
830
22
  export {
831
23
  DashboardLayout,
832
24
  DashboardLayoutSkeleton,