gov-layout 1.3.1 → 1.3.5

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.d.mts CHANGED
@@ -53,7 +53,9 @@ interface StaffSidebarProps {
53
53
  onExpandRequest?: () => void;
54
54
  }
55
55
 
56
- declare function StaffSidebar({ orgLogo, orgName, orgSubtitle, menuItems, bottomMenuItems, user, roleLabel, onNavigate, onLogout, onProfile, currentPath, width, className, collapsible, isOpen: controlledIsOpen, onToggle, onExpandRequest, }: StaffSidebarProps): react_jsx_runtime.JSX.Element;
56
+ declare function StaffSidebar({ orgLogo, orgName, orgSubtitle, menuItems, bottomMenuItems, user, roleLabel, onNavigate, onLogout, onProfile, currentPath, width, className, collapsible, isOpen: controlledIsOpen, onToggle, onExpandRequest, topOffset, }: StaffSidebarProps & {
57
+ topOffset?: number | string;
58
+ }): react_jsx_runtime.JSX.Element;
57
59
 
58
60
  interface SidebarHeaderProps {
59
61
  orgLogo?: string;
package/dist/index.d.ts CHANGED
@@ -53,7 +53,9 @@ interface StaffSidebarProps {
53
53
  onExpandRequest?: () => void;
54
54
  }
55
55
 
56
- declare function StaffSidebar({ orgLogo, orgName, orgSubtitle, menuItems, bottomMenuItems, user, roleLabel, onNavigate, onLogout, onProfile, currentPath, width, className, collapsible, isOpen: controlledIsOpen, onToggle, onExpandRequest, }: StaffSidebarProps): react_jsx_runtime.JSX.Element;
56
+ declare function StaffSidebar({ orgLogo, orgName, orgSubtitle, menuItems, bottomMenuItems, user, roleLabel, onNavigate, onLogout, onProfile, currentPath, width, className, collapsible, isOpen: controlledIsOpen, onToggle, onExpandRequest, topOffset, }: StaffSidebarProps & {
57
+ topOffset?: number | string;
58
+ }): react_jsx_runtime.JSX.Element;
57
59
 
58
60
  interface SidebarHeaderProps {
59
61
  orgLogo?: string;
package/dist/index.js CHANGED
@@ -3,7 +3,30 @@
3
3
  var react = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
 
6
- // src/sidebar/StaffSidebar.tsx
6
+ // #style-inject:#style-inject
7
+ function styleInject(css, { insertAt } = {}) {
8
+ if (typeof document === "undefined") return;
9
+ const head = document.head || document.getElementsByTagName("head")[0];
10
+ const style = document.createElement("style");
11
+ style.type = "text/css";
12
+ if (insertAt === "top") {
13
+ if (head.firstChild) {
14
+ head.insertBefore(style, head.firstChild);
15
+ } else {
16
+ head.appendChild(style);
17
+ }
18
+ } else {
19
+ head.appendChild(style);
20
+ }
21
+ if (style.styleSheet) {
22
+ style.styleSheet.cssText = css;
23
+ } else {
24
+ style.appendChild(document.createTextNode(css));
25
+ }
26
+ }
27
+
28
+ // src/styles.css
29
+ styleInject(".text-primary,\n.text-text-primary {\n color: var(--color-alias-text-colors-primary, #060d26);\n}\n.text-secondary,\n.text-text-secondary {\n color: var(--color-alias-text-colors-secondary, #1e7d55);\n}\n.text-tertiary,\n.text-text-tertiary {\n color: var(--color-alias-text-colors-tertiary, #475272);\n}\n.text-placeholder,\n.text-text-placeholder {\n color: var(--color-alias-text-colors-placeholder, #707993);\n}\n.text-critical,\n.text-text-critical {\n color: var(--color-alias-text-colors-critical, #f21515);\n}\n");
7
30
  function useDarkMode() {
8
31
  const [isDark, setIsDark] = react.useState(false);
9
32
  react.useEffect(() => {
@@ -625,6 +648,25 @@ function ProfileIcon() {
625
648
  }
626
649
  );
627
650
  }
651
+ function AvatarPlaceholder({ size = 40 }) {
652
+ return /* @__PURE__ */ jsxRuntime.jsx(
653
+ "div",
654
+ {
655
+ style: {
656
+ width: `${size}px`,
657
+ height: `${size}px`,
658
+ borderRadius: "50%",
659
+ backgroundColor: "#f1f5f9",
660
+ display: "flex",
661
+ alignItems: "center",
662
+ justifyContent: "center",
663
+ flexShrink: 0,
664
+ boxShadow: "0 2px 8px rgba(0,0,0,0.05)"
665
+ },
666
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: size * 0.6, height: size * 0.6, viewBox: "0 0 24 24", fill: "#94a3b8", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" }) })
667
+ }
668
+ );
669
+ }
628
670
  function SidebarUserProfile({
629
671
  user,
630
672
  roleLabel,
@@ -633,6 +675,10 @@ function SidebarUserProfile({
633
675
  onProfile
634
676
  }) {
635
677
  const isDark = useDarkMode();
678
+ const [imgError, setImgError] = react.useState(false);
679
+ react.useEffect(() => {
680
+ setImgError(false);
681
+ }, [user?.pictureUrl]);
636
682
  if (!user) return null;
637
683
  const getFullName = () => {
638
684
  if (user.firstName && user.lastName) {
@@ -640,9 +686,6 @@ function SidebarUserProfile({
640
686
  }
641
687
  return user.firstName || user.lastName || "\u0E1C\u0E39\u0E49\u0E43\u0E0A\u0E49";
642
688
  };
643
- const getInitial = () => {
644
- return user.firstName?.charAt(0) || user.lastName?.charAt(0) || "?";
645
- };
646
689
  if (collapsed) {
647
690
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
648
691
  padding: "12px 8px",
@@ -658,36 +701,21 @@ function SidebarUserProfile({
658
701
  onClick: onProfile,
659
702
  title: onProfile ? "\u0E14\u0E39\u0E42\u0E1B\u0E23\u0E44\u0E1F\u0E25\u0E4C" : getFullName(),
660
703
  style: { cursor: onProfile ? "pointer" : "default" },
661
- children: user.pictureUrl ? /* @__PURE__ */ jsxRuntime.jsx(
704
+ children: user.pictureUrl && !imgError ? /* @__PURE__ */ jsxRuntime.jsx(
662
705
  "img",
663
706
  {
664
707
  src: user.pictureUrl,
665
708
  alt: getFullName(),
709
+ onError: () => setImgError(true),
666
710
  style: {
667
711
  width: "36px",
668
712
  height: "36px",
669
713
  borderRadius: "50%",
670
- objectFit: "cover"
714
+ objectFit: "cover",
715
+ flexShrink: 0
671
716
  }
672
717
  }
673
- ) : /* @__PURE__ */ jsxRuntime.jsx(
674
- "div",
675
- {
676
- style: {
677
- width: "36px",
678
- height: "36px",
679
- borderRadius: "50%",
680
- background: "var(--color-alias-color-brand-primary, #1e7d55)",
681
- display: "flex",
682
- alignItems: "center",
683
- justifyContent: "center",
684
- color: "#fff",
685
- fontWeight: 700,
686
- fontSize: "14px"
687
- },
688
- children: getInitial()
689
- }
690
- )
718
+ ) : /* @__PURE__ */ jsxRuntime.jsx(AvatarPlaceholder, { size: 36 })
691
719
  }
692
720
  ),
693
721
  onProfile && /* @__PURE__ */ jsxRuntime.jsx(
@@ -777,11 +805,12 @@ function SidebarUserProfile({
777
805
  transition: "opacity 0.15s ease"
778
806
  },
779
807
  children: [
780
- user.pictureUrl ? /* @__PURE__ */ jsxRuntime.jsx(
808
+ user.pictureUrl && !imgError ? /* @__PURE__ */ jsxRuntime.jsx(
781
809
  "img",
782
810
  {
783
811
  src: user.pictureUrl,
784
812
  alt: getFullName(),
813
+ onError: () => setImgError(true),
785
814
  style: {
786
815
  width: "40px",
787
816
  height: "40px",
@@ -790,25 +819,7 @@ function SidebarUserProfile({
790
819
  flexShrink: 0
791
820
  }
792
821
  }
793
- ) : /* @__PURE__ */ jsxRuntime.jsx(
794
- "div",
795
- {
796
- style: {
797
- width: "40px",
798
- height: "40px",
799
- borderRadius: "50%",
800
- background: "var(--color-alias-color-brand-primary, #1e7d55)",
801
- display: "flex",
802
- alignItems: "center",
803
- justifyContent: "center",
804
- color: "#fff",
805
- fontWeight: 700,
806
- fontSize: "16px",
807
- flexShrink: 0
808
- },
809
- children: getInitial()
810
- }
811
- ),
822
+ ) : /* @__PURE__ */ jsxRuntime.jsx(AvatarPlaceholder, { size: 40 }),
812
823
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
813
824
  /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
814
825
  fontWeight: 600,
@@ -946,7 +957,8 @@ function StaffSidebar({
946
957
  collapsible = false,
947
958
  isOpen: controlledIsOpen,
948
959
  onToggle,
949
- onExpandRequest
960
+ onExpandRequest,
961
+ topOffset = 0
950
962
  }) {
951
963
  const isDark = useDarkMode();
952
964
  const [internalOpen, setInternalOpen] = react.useState(true);
@@ -980,9 +992,9 @@ function StaffSidebar({
980
992
  className,
981
993
  style: {
982
994
  position: "fixed",
983
- top: 0,
995
+ top: topOffset,
984
996
  left: 0,
985
- height: "100vh",
997
+ height: `calc(100vh - ${typeof topOffset === "number" ? topOffset + "px" : topOffset})`,
986
998
  width: currentWidth,
987
999
  background: isDark ? "#1e293b" : "#fff",
988
1000
  borderRight: `1px solid ${isDark ? "#374151" : "var(--color-border-colors-neutral, #c8cedd)"}`,
@@ -1055,7 +1067,7 @@ function StaffSidebar({
1055
1067
  title: sidebarOpen ? "\u0E22\u0E48\u0E2D Sidebar" : "\u0E02\u0E22\u0E32\u0E22 Sidebar",
1056
1068
  style: {
1057
1069
  position: "fixed",
1058
- top: "10%",
1070
+ top: `calc(${typeof topOffset === "number" ? topOffset + "px" : topOffset} + 10vh)`,
1059
1071
  left: currentWidth,
1060
1072
  zIndex: 51,
1061
1073
  width: "24px",
@@ -1100,6 +1112,25 @@ function HamburgerIcon() {
1100
1112
  function MessageOutlinedIcon(props) {
1101
1113
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { focusable: "false", "aria-hidden": "true", viewBox: "0 0 24 24", fill: "currentColor", ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 4h16v12H5.17L4 17.17zm0-2c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm2 10h12v2H6zm0-3h12v2H6zm0-3h12v2H6z" }) });
1102
1114
  }
1115
+ function AvatarPlaceholder2({ size = 44 }) {
1116
+ return /* @__PURE__ */ jsxRuntime.jsx(
1117
+ "div",
1118
+ {
1119
+ style: {
1120
+ width: `${size}px`,
1121
+ height: `${size}px`,
1122
+ borderRadius: "50%",
1123
+ backgroundColor: "#f1f5f9",
1124
+ display: "flex",
1125
+ alignItems: "center",
1126
+ justifyContent: "center",
1127
+ flexShrink: 0,
1128
+ boxShadow: "0 2px 8px rgba(0,0,0,0.05)"
1129
+ },
1130
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: size * 0.6, height: size * 0.6, viewBox: "0 0 24 24", fill: "#94a3b8", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" }) })
1131
+ }
1132
+ );
1133
+ }
1103
1134
  function getNotifBg(type) {
1104
1135
  const map = {
1105
1136
  success: "#dcfce7",
@@ -1131,11 +1162,14 @@ function UserHeader({
1131
1162
  className
1132
1163
  }) {
1133
1164
  const displayName = `${user?.firstName || ""} ${user?.lastName || ""}`.trim() || "\u0E1C\u0E39\u0E49\u0E43\u0E0A\u0E49";
1134
- const firstChar = user?.firstName?.charAt(0) || "\u0E1C";
1135
1165
  const [isNotifOpen, setIsNotifOpen] = react.useState(false);
1136
1166
  const [activeFilter, setActiveFilter] = react.useState("all");
1137
1167
  const notifRef = react.useRef(null);
1138
1168
  const isDark = useDarkMode();
1169
+ const [imgError, setImgError] = react.useState(false);
1170
+ react.useEffect(() => {
1171
+ setImgError(false);
1172
+ }, [user?.pictureUrl]);
1139
1173
  react.useEffect(() => {
1140
1174
  const handleClickOutside = (e) => {
1141
1175
  if (notifRef.current && !notifRef.current.contains(e.target)) {
@@ -1198,42 +1232,22 @@ function UserHeader({
1198
1232
  overflow: "hidden"
1199
1233
  },
1200
1234
  children: [
1201
- user?.pictureUrl ? /* @__PURE__ */ jsxRuntime.jsx(
1235
+ user?.pictureUrl && !imgError ? /* @__PURE__ */ jsxRuntime.jsx(
1202
1236
  "img",
1203
1237
  {
1204
1238
  src: user.pictureUrl,
1205
1239
  alt: displayName,
1240
+ onError: () => setImgError(true),
1206
1241
  style: {
1207
1242
  width: "44px",
1208
1243
  height: "44px",
1209
1244
  borderRadius: "50%",
1210
1245
  objectFit: "cover",
1211
- border: "2px solid rgba(255,255,255,0.7)"
1212
- }
1213
- }
1214
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1215
- "div",
1216
- {
1217
- style: {
1218
- width: "44px",
1219
- height: "44px",
1220
- borderRadius: "50%",
1221
- background: "rgba(255,255,255,0.2)",
1222
1246
  border: "2px solid rgba(255,255,255,0.7)",
1223
- display: "flex",
1224
- alignItems: "center",
1225
- justifyContent: "center",
1226
- boxShadow: "0 1px 3px rgba(0,0,0,0.1)"
1227
- },
1228
- children: /* @__PURE__ */ jsxRuntime.jsx(
1229
- "span",
1230
- {
1231
- style: { color: "#fff", fontSize: "18px", fontWeight: 600 },
1232
- children: firstChar
1233
- }
1234
- )
1247
+ flexShrink: 0
1248
+ }
1235
1249
  }
1236
- ),
1250
+ ) : /* @__PURE__ */ jsxRuntime.jsx(AvatarPlaceholder2, { size: 44 }),
1237
1251
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
1238
1252
  /* @__PURE__ */ jsxRuntime.jsxs(
1239
1253
  "p",
@@ -1625,6 +1639,25 @@ function ProfileIcon2() {
1625
1639
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "7", r: "4" })
1626
1640
  ] });
1627
1641
  }
1642
+ function AvatarPlaceholder3({ size = 56 }) {
1643
+ return /* @__PURE__ */ jsxRuntime.jsx(
1644
+ "div",
1645
+ {
1646
+ style: {
1647
+ width: `${size}px`,
1648
+ height: `${size}px`,
1649
+ borderRadius: "50%",
1650
+ backgroundColor: "#f1f5f9",
1651
+ display: "flex",
1652
+ alignItems: "center",
1653
+ justifyContent: "center",
1654
+ flexShrink: 0,
1655
+ boxShadow: "0 2px 8px rgba(0,0,0,0.05)"
1656
+ },
1657
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: size * 0.6, height: size * 0.6, viewBox: "0 0 24 24", fill: "#94a3b8", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" }) })
1658
+ }
1659
+ );
1660
+ }
1628
1661
  function UserSidebar({
1629
1662
  user,
1630
1663
  roleLabel,
@@ -1637,6 +1670,10 @@ function UserSidebar({
1637
1670
  onProfile
1638
1671
  }) {
1639
1672
  const isDark = useDarkMode();
1673
+ const [imgError, setImgError] = react.useState(false);
1674
+ react.useEffect(() => {
1675
+ setImgError(false);
1676
+ }, [user?.pictureUrl]);
1640
1677
  react.useEffect(() => {
1641
1678
  if (isOpen) {
1642
1679
  document.body.style.overflow = "hidden";
@@ -1652,10 +1689,6 @@ function UserSidebar({
1652
1689
  if (user.firstName && user.lastName) return `${user.firstName} ${user.lastName}`;
1653
1690
  return user.firstName || user.lastName || "\u0E1C\u0E39\u0E49\u0E43\u0E0A\u0E49";
1654
1691
  };
1655
- const getInitial = () => {
1656
- if (!user) return "?";
1657
- return user.firstName?.charAt(0) || user.lastName?.charAt(0) || "?";
1658
- };
1659
1692
  const handleMenuClick = (path) => {
1660
1693
  onNavigate(path);
1661
1694
  onClose();
@@ -1715,38 +1748,22 @@ function UserSidebar({
1715
1748
  padding: "8px"
1716
1749
  },
1717
1750
  children: [
1718
- user.pictureUrl ? /* @__PURE__ */ jsxRuntime.jsx(
1751
+ user.pictureUrl && !imgError ? /* @__PURE__ */ jsxRuntime.jsx(
1719
1752
  "img",
1720
1753
  {
1721
1754
  src: user.pictureUrl,
1722
1755
  alt: getFullName(),
1756
+ onError: () => setImgError(true),
1723
1757
  style: {
1724
1758
  width: "56px",
1725
1759
  height: "56px",
1726
1760
  borderRadius: "50%",
1727
1761
  objectFit: "cover",
1762
+ flexShrink: 0,
1728
1763
  boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
1729
1764
  }
1730
1765
  }
1731
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1732
- "div",
1733
- {
1734
- style: {
1735
- width: "56px",
1736
- height: "56px",
1737
- borderRadius: "50%",
1738
- background: "linear-gradient(135deg, var(--color-alias-color-brand-secondary, #80d897), var(--color-alias-color-brand-primary, #1e7d55))",
1739
- display: "flex",
1740
- alignItems: "center",
1741
- justifyContent: "center",
1742
- color: "#fff",
1743
- fontWeight: 700,
1744
- fontSize: "20px",
1745
- boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
1746
- },
1747
- children: getInitial()
1748
- }
1749
- ),
1766
+ ) : /* @__PURE__ */ jsxRuntime.jsx(AvatarPlaceholder3, { size: 56 }),
1750
1767
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
1751
1768
  /* @__PURE__ */ jsxRuntime.jsx(
1752
1769
  "p",