gov-layout 1.0.0 → 1.1.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/index.js CHANGED
@@ -1,10 +1,41 @@
1
1
  'use strict';
2
2
 
3
- var jsxRuntime = require('react/jsx-runtime');
4
3
  var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
5
 
6
- // src/sidebar/SidebarHeader.tsx
7
- function SidebarHeader({ orgLogo, orgName, orgSubtitle }) {
6
+ // src/sidebar/StaffSidebar.tsx
7
+ function SidebarHeader({ orgLogo, orgName, orgSubtitle, collapsed }) {
8
+ if (collapsed) {
9
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
10
+ display: "flex",
11
+ alignItems: "center",
12
+ justifyContent: "center",
13
+ padding: "20px 8px"
14
+ }, children: orgLogo ? /* @__PURE__ */ jsxRuntime.jsx(
15
+ "img",
16
+ {
17
+ src: orgLogo,
18
+ alt: orgName,
19
+ style: {
20
+ width: "36px",
21
+ height: "36px",
22
+ borderRadius: "50%",
23
+ objectFit: "cover"
24
+ }
25
+ }
26
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
27
+ width: "36px",
28
+ height: "36px",
29
+ borderRadius: "50%",
30
+ background: "var(--color-alias-color-brand-primary, #1e7d55)",
31
+ display: "flex",
32
+ alignItems: "center",
33
+ justifyContent: "center",
34
+ color: "#fff",
35
+ fontWeight: 700,
36
+ fontSize: "14px"
37
+ }, children: orgName.charAt(0) }) });
38
+ }
8
39
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
9
40
  display: "flex",
10
41
  alignItems: "center",
@@ -52,8 +83,8 @@ function ChevronDownIcon({ isOpen }) {
52
83
  return /* @__PURE__ */ jsxRuntime.jsx(
53
84
  "svg",
54
85
  {
55
- width: "20",
56
- height: "20",
86
+ width: "16",
87
+ height: "16",
57
88
  viewBox: "0 0 20 20",
58
89
  fill: "none",
59
90
  stroke: "currentColor",
@@ -73,7 +104,8 @@ function MenuItemComponent({
73
104
  item,
74
105
  onItemClick,
75
106
  currentPath,
76
- depth = 0
107
+ depth = 0,
108
+ collapsed = false
77
109
  }) {
78
110
  const [isOpen, setIsOpen] = react.useState(false);
79
111
  const hasChildren = item.children && item.children.length > 0;
@@ -89,20 +121,58 @@ function MenuItemComponent({
89
121
  };
90
122
  const activeColor = "var(--color-alias-color-brand-primary, #1e7d55)";
91
123
  const hoverBg = "var(--color-foundations-fuji-pallet-light, #ebedf5)";
124
+ if (collapsed && depth === 0) {
125
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
126
+ /* @__PURE__ */ jsxRuntime.jsx(
127
+ "button",
128
+ {
129
+ onClick: handleClick,
130
+ title: item.title,
131
+ onMouseEnter: (e) => {
132
+ if (!isActive) e.currentTarget.style.backgroundColor = hoverBg;
133
+ },
134
+ onMouseLeave: (e) => {
135
+ if (!isActive) e.currentTarget.style.backgroundColor = "transparent";
136
+ },
137
+ style: {
138
+ width: "100%",
139
+ display: "flex",
140
+ alignItems: "center",
141
+ justifyContent: "center",
142
+ padding: "12px 0",
143
+ borderRadius: "8px",
144
+ border: "none",
145
+ background: isActive || isChildActive ? `color-mix(in srgb, ${activeColor} 10%, transparent)` : "transparent",
146
+ color: isActive || isChildActive ? activeColor : "var(--color-alias-text-colors-tertiary, #475272)",
147
+ cursor: "pointer",
148
+ transition: "background-color 0.15s ease"
149
+ },
150
+ children: item.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
151
+ width: "24px",
152
+ height: "24px",
153
+ display: "flex",
154
+ alignItems: "center",
155
+ justifyContent: "center"
156
+ }, children: item.icon })
157
+ }
158
+ ),
159
+ item.dividerAfter && /* @__PURE__ */ jsxRuntime.jsx("hr", { style: {
160
+ border: "none",
161
+ borderTop: "1px solid var(--color-border-colors-neutral, #c8cedd)",
162
+ margin: "8px 4px"
163
+ } })
164
+ ] });
165
+ }
92
166
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
93
167
  /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
94
168
  "button",
95
169
  {
96
170
  onClick: handleClick,
97
171
  onMouseEnter: (e) => {
98
- if (!isActive) {
99
- e.currentTarget.style.backgroundColor = hoverBg;
100
- }
172
+ if (!isActive) e.currentTarget.style.backgroundColor = hoverBg;
101
173
  },
102
174
  onMouseLeave: (e) => {
103
- if (!isActive) {
104
- e.currentTarget.style.backgroundColor = "transparent";
105
- }
175
+ if (!isActive) e.currentTarget.style.backgroundColor = "transparent";
106
176
  },
107
177
  style: {
108
178
  width: "100%",
@@ -122,21 +192,15 @@ function MenuItemComponent({
122
192
  lineHeight: "22px"
123
193
  },
124
194
  children: [
125
- item.icon && /* @__PURE__ */ jsxRuntime.jsx(
126
- "span",
127
- {
128
- style: {
129
- width: "24px",
130
- height: "24px",
131
- display: "flex",
132
- alignItems: "center",
133
- justifyContent: "center",
134
- flexShrink: 0,
135
- color: isActive ? activeColor : "var(--color-alias-text-colors-tertiary, #475272)"
136
- },
137
- children: item.icon
138
- }
139
- ),
195
+ item.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
196
+ width: "24px",
197
+ height: "24px",
198
+ display: "flex",
199
+ alignItems: "center",
200
+ justifyContent: "center",
201
+ flexShrink: 0,
202
+ color: isActive ? activeColor : "var(--color-alias-text-colors-tertiary, #475272)"
203
+ }, children: item.icon }),
140
204
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1 }, children: item.title }),
141
205
  hasChildren && /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon, { isOpen: expanded })
142
206
  ]
@@ -152,25 +216,32 @@ function MenuItemComponent({
152
216
  },
153
217
  child.id
154
218
  )) }),
155
- item.dividerAfter && /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
156
- "hr",
157
- {
158
- style: {
159
- border: "none",
160
- borderTop: "1px solid var(--color-border-colors-neutral, #c8cedd)",
161
- margin: "8px 0"
162
- }
163
- }
164
- ) })
219
+ item.dividerAfter && /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("hr", { style: {
220
+ border: "none",
221
+ borderTop: "1px solid var(--color-border-colors-neutral, #c8cedd)",
222
+ margin: "8px 0"
223
+ } }) })
165
224
  ] });
166
225
  }
167
- function SidebarMenu({ menuItems, onItemClick, currentPath }) {
168
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { style: { flex: 1, padding: "8px 12px", overflowY: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "2px" }, children: menuItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
226
+ function SidebarMenu({ menuItems, onItemClick, currentPath, collapsed }) {
227
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { style: {
228
+ flex: collapsed ? void 0 : 1,
229
+ padding: collapsed ? "8px 8px" : "8px 12px",
230
+ overflowY: "auto"
231
+ }, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { style: {
232
+ listStyle: "none",
233
+ margin: 0,
234
+ padding: 0,
235
+ display: "flex",
236
+ flexDirection: "column",
237
+ gap: "2px"
238
+ }, children: menuItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
169
239
  MenuItemComponent,
170
240
  {
171
241
  item,
172
242
  onItemClick,
173
- currentPath
243
+ currentPath,
244
+ collapsed
174
245
  },
175
246
  item.id
176
247
  )) }) });
@@ -198,7 +269,8 @@ function LogoutIcon() {
198
269
  function SidebarUserProfile({
199
270
  user,
200
271
  roleLabel,
201
- onLogout
272
+ onLogout,
273
+ collapsed
202
274
  }) {
203
275
  if (!user) return null;
204
276
  const getFullName = () => {
@@ -210,6 +282,76 @@ function SidebarUserProfile({
210
282
  const getInitial = () => {
211
283
  return user.firstName?.charAt(0) || user.lastName?.charAt(0) || "?";
212
284
  };
285
+ if (collapsed) {
286
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
287
+ padding: "12px 8px",
288
+ borderTop: "1px solid var(--color-border-colors-neutral, #c8cedd)",
289
+ display: "flex",
290
+ flexDirection: "column",
291
+ alignItems: "center",
292
+ gap: "12px"
293
+ }, children: [
294
+ user.pictureUrl ? /* @__PURE__ */ jsxRuntime.jsx(
295
+ "img",
296
+ {
297
+ src: user.pictureUrl,
298
+ alt: getFullName(),
299
+ title: getFullName(),
300
+ style: {
301
+ width: "36px",
302
+ height: "36px",
303
+ borderRadius: "50%",
304
+ objectFit: "cover"
305
+ }
306
+ }
307
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
308
+ "div",
309
+ {
310
+ title: getFullName(),
311
+ style: {
312
+ width: "36px",
313
+ height: "36px",
314
+ borderRadius: "50%",
315
+ background: "var(--color-alias-color-brand-primary, #1e7d55)",
316
+ display: "flex",
317
+ alignItems: "center",
318
+ justifyContent: "center",
319
+ color: "#fff",
320
+ fontWeight: 700,
321
+ fontSize: "14px"
322
+ },
323
+ children: getInitial()
324
+ }
325
+ ),
326
+ /* @__PURE__ */ jsxRuntime.jsx(
327
+ "button",
328
+ {
329
+ onClick: onLogout,
330
+ title: "\u0E2D\u0E2D\u0E01\u0E08\u0E32\u0E01\u0E23\u0E30\u0E1A\u0E1A",
331
+ onMouseEnter: (e) => {
332
+ e.currentTarget.style.backgroundColor = "var(--color-foundations-fuan-pallet-light, #ffd2d2)";
333
+ },
334
+ onMouseLeave: (e) => {
335
+ e.currentTarget.style.backgroundColor = "transparent";
336
+ },
337
+ style: {
338
+ width: "36px",
339
+ height: "36px",
340
+ borderRadius: "8px",
341
+ border: "none",
342
+ background: "transparent",
343
+ color: "var(--color-alias-semantic-critical, #f21515)",
344
+ cursor: "pointer",
345
+ display: "flex",
346
+ alignItems: "center",
347
+ justifyContent: "center",
348
+ transition: "background-color 0.15s ease"
349
+ },
350
+ children: /* @__PURE__ */ jsxRuntime.jsx(LogoutIcon, {})
351
+ }
352
+ )
353
+ ] });
354
+ }
213
355
  return /* @__PURE__ */ jsxRuntime.jsxs(
214
356
  "div",
215
357
  {
@@ -254,34 +396,22 @@ function SidebarUserProfile({
254
396
  }
255
397
  ),
256
398
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
257
- /* @__PURE__ */ jsxRuntime.jsx(
258
- "p",
259
- {
260
- style: {
261
- fontWeight: 600,
262
- fontSize: "14px",
263
- lineHeight: "20px",
264
- color: "var(--color-alias-text-colors-primary, #060d26)",
265
- margin: 0,
266
- overflow: "hidden",
267
- textOverflow: "ellipsis",
268
- whiteSpace: "nowrap"
269
- },
270
- children: getFullName()
271
- }
272
- ),
273
- /* @__PURE__ */ jsxRuntime.jsx(
274
- "p",
275
- {
276
- style: {
277
- fontSize: "12px",
278
- lineHeight: "16px",
279
- color: "var(--color-alias-text-colors-tertiary, #475272)",
280
- margin: 0
281
- },
282
- children: roleLabel
283
- }
284
- )
399
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
400
+ fontWeight: 600,
401
+ fontSize: "14px",
402
+ lineHeight: "20px",
403
+ color: "var(--color-alias-text-colors-primary, #060d26)",
404
+ margin: 0,
405
+ overflow: "hidden",
406
+ textOverflow: "ellipsis",
407
+ whiteSpace: "nowrap"
408
+ }, children: getFullName() }),
409
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
410
+ fontSize: "12px",
411
+ lineHeight: "16px",
412
+ color: "var(--color-alias-text-colors-tertiary, #475272)",
413
+ margin: 0
414
+ }, children: roleLabel })
285
415
  ] }),
286
416
  /* @__PURE__ */ jsxRuntime.jsx(
287
417
  "button",
@@ -317,6 +447,26 @@ function SidebarUserProfile({
317
447
  }
318
448
  );
319
449
  }
450
+ function ToggleIcon({ isOpen }) {
451
+ return /* @__PURE__ */ jsxRuntime.jsx(
452
+ "svg",
453
+ {
454
+ width: "18",
455
+ height: "18",
456
+ viewBox: "0 0 24 24",
457
+ fill: "none",
458
+ stroke: "currentColor",
459
+ strokeWidth: "2",
460
+ strokeLinecap: "round",
461
+ strokeLinejoin: "round",
462
+ style: {
463
+ transition: "transform 0.2s ease",
464
+ transform: isOpen ? "rotate(0deg)" : "rotate(180deg)"
465
+ },
466
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 18l-6-6 6-6" })
467
+ }
468
+ );
469
+ }
320
470
  function StaffSidebar({
321
471
  orgLogo,
322
472
  orgName,
@@ -329,61 +479,117 @@ function StaffSidebar({
329
479
  onLogout,
330
480
  currentPath,
331
481
  width = "280px",
332
- className
482
+ className,
483
+ collapsible = false,
484
+ isOpen: controlledIsOpen,
485
+ onToggle
333
486
  }) {
334
- return /* @__PURE__ */ jsxRuntime.jsxs(
335
- "aside",
336
- {
337
- className,
338
- style: {
339
- position: "fixed",
340
- top: 0,
341
- left: 0,
342
- height: "100vh",
343
- width,
344
- background: "#fff",
345
- borderRight: "1px solid var(--color-border-colors-neutral, #c8cedd)",
346
- display: "flex",
347
- flexDirection: "column",
348
- zIndex: 40,
349
- overflow: "hidden"
350
- },
351
- children: [
352
- /* @__PURE__ */ jsxRuntime.jsx(
353
- SidebarHeader,
354
- {
355
- orgLogo,
356
- orgName,
357
- orgSubtitle
358
- }
359
- ),
360
- /* @__PURE__ */ jsxRuntime.jsx(
361
- SidebarMenu,
362
- {
363
- menuItems,
364
- onItemClick: onNavigate,
365
- currentPath
366
- }
367
- ),
368
- bottomMenuItems && bottomMenuItems.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
369
- SidebarMenu,
370
- {
371
- menuItems: bottomMenuItems,
372
- onItemClick: onNavigate,
373
- currentPath
374
- }
375
- ),
376
- /* @__PURE__ */ jsxRuntime.jsx(
377
- SidebarUserProfile,
378
- {
379
- user,
380
- roleLabel,
381
- onLogout
382
- }
383
- )
384
- ]
487
+ const [internalOpen, setInternalOpen] = react.useState(true);
488
+ const sidebarOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalOpen;
489
+ const collapsed = collapsible && !sidebarOpen;
490
+ const collapsedWidth = "64px";
491
+ const currentWidth = collapsed ? collapsedWidth : width;
492
+ const handleToggle = () => {
493
+ if (onToggle) {
494
+ onToggle();
495
+ } else {
496
+ setInternalOpen(!internalOpen);
385
497
  }
386
- );
498
+ };
499
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
500
+ /* @__PURE__ */ jsxRuntime.jsxs(
501
+ "aside",
502
+ {
503
+ className,
504
+ style: {
505
+ position: "fixed",
506
+ top: 0,
507
+ left: 0,
508
+ height: "100vh",
509
+ width: currentWidth,
510
+ background: "#fff",
511
+ borderRight: "1px solid var(--color-border-colors-neutral, #c8cedd)",
512
+ display: "flex",
513
+ flexDirection: "column",
514
+ zIndex: 40,
515
+ overflow: "hidden",
516
+ transition: "width 0.3s ease"
517
+ },
518
+ children: [
519
+ /* @__PURE__ */ jsxRuntime.jsx(
520
+ SidebarHeader,
521
+ {
522
+ orgLogo,
523
+ orgName,
524
+ orgSubtitle,
525
+ collapsed
526
+ }
527
+ ),
528
+ /* @__PURE__ */ jsxRuntime.jsx(
529
+ SidebarMenu,
530
+ {
531
+ menuItems,
532
+ onItemClick: onNavigate,
533
+ currentPath,
534
+ collapsed
535
+ }
536
+ ),
537
+ bottomMenuItems && bottomMenuItems.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
538
+ SidebarMenu,
539
+ {
540
+ menuItems: bottomMenuItems,
541
+ onItemClick: onNavigate,
542
+ currentPath,
543
+ collapsed
544
+ }
545
+ ),
546
+ /* @__PURE__ */ jsxRuntime.jsx(
547
+ SidebarUserProfile,
548
+ {
549
+ user,
550
+ roleLabel,
551
+ onLogout,
552
+ collapsed
553
+ }
554
+ )
555
+ ]
556
+ }
557
+ ),
558
+ collapsible && /* @__PURE__ */ jsxRuntime.jsx(
559
+ "button",
560
+ {
561
+ onClick: handleToggle,
562
+ title: sidebarOpen ? "\u0E22\u0E48\u0E2D Sidebar" : "\u0E02\u0E22\u0E32\u0E22 Sidebar",
563
+ onMouseEnter: (e) => {
564
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
565
+ },
566
+ onMouseLeave: (e) => {
567
+ e.currentTarget.style.backgroundColor = "#fff";
568
+ },
569
+ style: {
570
+ position: "fixed",
571
+ top: "50%",
572
+ left: currentWidth,
573
+ transform: "translateY(-50%)",
574
+ zIndex: 41,
575
+ width: "24px",
576
+ height: "48px",
577
+ borderRadius: "0 6px 6px 0",
578
+ border: "1px solid var(--color-border-colors-neutral, #c8cedd)",
579
+ borderLeft: "none",
580
+ background: "#fff",
581
+ cursor: "pointer",
582
+ display: "flex",
583
+ alignItems: "center",
584
+ justifyContent: "center",
585
+ boxShadow: "2px 0 8px rgba(0,0,0,0.06)",
586
+ transition: "left 0.3s ease",
587
+ color: "var(--color-alias-text-colors-tertiary, #475272)"
588
+ },
589
+ children: /* @__PURE__ */ jsxRuntime.jsx(ToggleIcon, { isOpen: sidebarOpen })
590
+ }
591
+ )
592
+ ] });
387
593
  }
388
594
  function BellIcon() {
389
595
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "22", height: "24", viewBox: "0 0 22 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -958,64 +1164,13 @@ function UserSidebar({
958
1164
  ] })
959
1165
  }
960
1166
  ),
961
- /* @__PURE__ */ jsxRuntime.jsx("nav", { style: { flex: 1, padding: "20px", overflowY: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "4px" }, children: menuItems.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
962
- /* @__PURE__ */ jsxRuntime.jsxs(
963
- "button",
964
- {
965
- onClick: () => item.path && handleMenuClick(item.path),
966
- onMouseEnter: (e) => {
967
- e.currentTarget.style.backgroundColor = "#f9fafb";
968
- },
969
- onMouseLeave: (e) => {
970
- e.currentTarget.style.backgroundColor = "transparent";
971
- },
972
- style: {
973
- width: "100%",
974
- display: "flex",
975
- alignItems: "center",
976
- gap: "16px",
977
- padding: "14px 16px",
978
- borderRadius: "8px",
979
- border: "none",
980
- background: "transparent",
981
- color: "var(--color-alias-text-colors-primary, #374151)",
982
- cursor: "pointer",
983
- transition: "background-color 0.15s ease",
984
- fontSize: "15px",
985
- fontWeight: 500,
986
- textAlign: "left"
987
- },
988
- children: [
989
- item.icon && /* @__PURE__ */ jsxRuntime.jsx(
990
- "span",
991
- {
992
- style: {
993
- width: "28px",
994
- height: "28px",
995
- display: "flex",
996
- alignItems: "center",
997
- justifyContent: "center",
998
- color: "var(--color-alias-text-colors-tertiary, #6b7280)",
999
- flexShrink: 0
1000
- },
1001
- children: item.icon
1002
- }
1003
- ),
1004
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1 }, children: item.title })
1005
- ]
1006
- }
1007
- ),
1008
- item.dividerAfter && /* @__PURE__ */ jsxRuntime.jsx(
1009
- "hr",
1010
- {
1011
- style: {
1012
- border: "none",
1013
- borderTop: "1px solid var(--color-border-colors-neutral, #e5e7eb)",
1014
- margin: "8px 0"
1015
- }
1016
- }
1017
- )
1018
- ] }, item.id)) }) }),
1167
+ /* @__PURE__ */ jsxRuntime.jsx(
1168
+ SidebarMenu,
1169
+ {
1170
+ menuItems,
1171
+ onItemClick: handleMenuClick
1172
+ }
1173
+ ),
1019
1174
  /* @__PURE__ */ jsxRuntime.jsx(
1020
1175
  "div",
1021
1176
  {