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.mjs CHANGED
@@ -1,7 +1,30 @@
1
1
  import { createContext, useState, useEffect, useRef, useCallback, useContext, useId } from 'react';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
 
4
- // src/sidebar/StaffSidebar.tsx
4
+ // #style-inject:#style-inject
5
+ function styleInject(css, { insertAt } = {}) {
6
+ if (typeof document === "undefined") return;
7
+ const head = document.head || document.getElementsByTagName("head")[0];
8
+ const style = document.createElement("style");
9
+ style.type = "text/css";
10
+ if (insertAt === "top") {
11
+ if (head.firstChild) {
12
+ head.insertBefore(style, head.firstChild);
13
+ } else {
14
+ head.appendChild(style);
15
+ }
16
+ } else {
17
+ head.appendChild(style);
18
+ }
19
+ if (style.styleSheet) {
20
+ style.styleSheet.cssText = css;
21
+ } else {
22
+ style.appendChild(document.createTextNode(css));
23
+ }
24
+ }
25
+
26
+ // src/styles.css
27
+ 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");
5
28
  function useDarkMode() {
6
29
  const [isDark, setIsDark] = useState(false);
7
30
  useEffect(() => {
@@ -623,6 +646,25 @@ function ProfileIcon() {
623
646
  }
624
647
  );
625
648
  }
649
+ function AvatarPlaceholder({ size = 40 }) {
650
+ return /* @__PURE__ */ jsx(
651
+ "div",
652
+ {
653
+ style: {
654
+ width: `${size}px`,
655
+ height: `${size}px`,
656
+ borderRadius: "50%",
657
+ backgroundColor: "#f1f5f9",
658
+ display: "flex",
659
+ alignItems: "center",
660
+ justifyContent: "center",
661
+ flexShrink: 0,
662
+ boxShadow: "0 2px 8px rgba(0,0,0,0.05)"
663
+ },
664
+ children: /* @__PURE__ */ jsx("svg", { width: size * 0.6, height: size * 0.6, viewBox: "0 0 24 24", fill: "#94a3b8", children: /* @__PURE__ */ 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" }) })
665
+ }
666
+ );
667
+ }
626
668
  function SidebarUserProfile({
627
669
  user,
628
670
  roleLabel,
@@ -631,6 +673,10 @@ function SidebarUserProfile({
631
673
  onProfile
632
674
  }) {
633
675
  const isDark = useDarkMode();
676
+ const [imgError, setImgError] = useState(false);
677
+ useEffect(() => {
678
+ setImgError(false);
679
+ }, [user?.pictureUrl]);
634
680
  if (!user) return null;
635
681
  const getFullName = () => {
636
682
  if (user.firstName && user.lastName) {
@@ -638,9 +684,6 @@ function SidebarUserProfile({
638
684
  }
639
685
  return user.firstName || user.lastName || "\u0E1C\u0E39\u0E49\u0E43\u0E0A\u0E49";
640
686
  };
641
- const getInitial = () => {
642
- return user.firstName?.charAt(0) || user.lastName?.charAt(0) || "?";
643
- };
644
687
  if (collapsed) {
645
688
  return /* @__PURE__ */ jsxs("div", { style: {
646
689
  padding: "12px 8px",
@@ -656,36 +699,21 @@ function SidebarUserProfile({
656
699
  onClick: onProfile,
657
700
  title: onProfile ? "\u0E14\u0E39\u0E42\u0E1B\u0E23\u0E44\u0E1F\u0E25\u0E4C" : getFullName(),
658
701
  style: { cursor: onProfile ? "pointer" : "default" },
659
- children: user.pictureUrl ? /* @__PURE__ */ jsx(
702
+ children: user.pictureUrl && !imgError ? /* @__PURE__ */ jsx(
660
703
  "img",
661
704
  {
662
705
  src: user.pictureUrl,
663
706
  alt: getFullName(),
707
+ onError: () => setImgError(true),
664
708
  style: {
665
709
  width: "36px",
666
710
  height: "36px",
667
711
  borderRadius: "50%",
668
- objectFit: "cover"
712
+ objectFit: "cover",
713
+ flexShrink: 0
669
714
  }
670
715
  }
671
- ) : /* @__PURE__ */ jsx(
672
- "div",
673
- {
674
- style: {
675
- width: "36px",
676
- height: "36px",
677
- borderRadius: "50%",
678
- background: "var(--color-alias-color-brand-primary, #1e7d55)",
679
- display: "flex",
680
- alignItems: "center",
681
- justifyContent: "center",
682
- color: "#fff",
683
- fontWeight: 700,
684
- fontSize: "14px"
685
- },
686
- children: getInitial()
687
- }
688
- )
716
+ ) : /* @__PURE__ */ jsx(AvatarPlaceholder, { size: 36 })
689
717
  }
690
718
  ),
691
719
  onProfile && /* @__PURE__ */ jsx(
@@ -775,11 +803,12 @@ function SidebarUserProfile({
775
803
  transition: "opacity 0.15s ease"
776
804
  },
777
805
  children: [
778
- user.pictureUrl ? /* @__PURE__ */ jsx(
806
+ user.pictureUrl && !imgError ? /* @__PURE__ */ jsx(
779
807
  "img",
780
808
  {
781
809
  src: user.pictureUrl,
782
810
  alt: getFullName(),
811
+ onError: () => setImgError(true),
783
812
  style: {
784
813
  width: "40px",
785
814
  height: "40px",
@@ -788,25 +817,7 @@ function SidebarUserProfile({
788
817
  flexShrink: 0
789
818
  }
790
819
  }
791
- ) : /* @__PURE__ */ jsx(
792
- "div",
793
- {
794
- style: {
795
- width: "40px",
796
- height: "40px",
797
- borderRadius: "50%",
798
- background: "var(--color-alias-color-brand-primary, #1e7d55)",
799
- display: "flex",
800
- alignItems: "center",
801
- justifyContent: "center",
802
- color: "#fff",
803
- fontWeight: 700,
804
- fontSize: "16px",
805
- flexShrink: 0
806
- },
807
- children: getInitial()
808
- }
809
- ),
820
+ ) : /* @__PURE__ */ jsx(AvatarPlaceholder, { size: 40 }),
810
821
  /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
811
822
  /* @__PURE__ */ jsx("p", { style: {
812
823
  fontWeight: 600,
@@ -944,7 +955,8 @@ function StaffSidebar({
944
955
  collapsible = false,
945
956
  isOpen: controlledIsOpen,
946
957
  onToggle,
947
- onExpandRequest
958
+ onExpandRequest,
959
+ topOffset = 0
948
960
  }) {
949
961
  const isDark = useDarkMode();
950
962
  const [internalOpen, setInternalOpen] = useState(true);
@@ -978,9 +990,9 @@ function StaffSidebar({
978
990
  className,
979
991
  style: {
980
992
  position: "fixed",
981
- top: 0,
993
+ top: topOffset,
982
994
  left: 0,
983
- height: "100vh",
995
+ height: `calc(100vh - ${typeof topOffset === "number" ? topOffset + "px" : topOffset})`,
984
996
  width: currentWidth,
985
997
  background: isDark ? "#1e293b" : "#fff",
986
998
  borderRight: `1px solid ${isDark ? "#374151" : "var(--color-border-colors-neutral, #c8cedd)"}`,
@@ -1053,7 +1065,7 @@ function StaffSidebar({
1053
1065
  title: sidebarOpen ? "\u0E22\u0E48\u0E2D Sidebar" : "\u0E02\u0E22\u0E32\u0E22 Sidebar",
1054
1066
  style: {
1055
1067
  position: "fixed",
1056
- top: "10%",
1068
+ top: `calc(${typeof topOffset === "number" ? topOffset + "px" : topOffset} + 10vh)`,
1057
1069
  left: currentWidth,
1058
1070
  zIndex: 51,
1059
1071
  width: "24px",
@@ -1098,6 +1110,25 @@ function HamburgerIcon() {
1098
1110
  function MessageOutlinedIcon(props) {
1099
1111
  return /* @__PURE__ */ jsx("svg", { focusable: "false", "aria-hidden": "true", viewBox: "0 0 24 24", fill: "currentColor", ...props, children: /* @__PURE__ */ 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" }) });
1100
1112
  }
1113
+ function AvatarPlaceholder2({ size = 44 }) {
1114
+ return /* @__PURE__ */ jsx(
1115
+ "div",
1116
+ {
1117
+ style: {
1118
+ width: `${size}px`,
1119
+ height: `${size}px`,
1120
+ borderRadius: "50%",
1121
+ backgroundColor: "#f1f5f9",
1122
+ display: "flex",
1123
+ alignItems: "center",
1124
+ justifyContent: "center",
1125
+ flexShrink: 0,
1126
+ boxShadow: "0 2px 8px rgba(0,0,0,0.05)"
1127
+ },
1128
+ children: /* @__PURE__ */ jsx("svg", { width: size * 0.6, height: size * 0.6, viewBox: "0 0 24 24", fill: "#94a3b8", children: /* @__PURE__ */ 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" }) })
1129
+ }
1130
+ );
1131
+ }
1101
1132
  function getNotifBg(type) {
1102
1133
  const map = {
1103
1134
  success: "#dcfce7",
@@ -1129,11 +1160,14 @@ function UserHeader({
1129
1160
  className
1130
1161
  }) {
1131
1162
  const displayName = `${user?.firstName || ""} ${user?.lastName || ""}`.trim() || "\u0E1C\u0E39\u0E49\u0E43\u0E0A\u0E49";
1132
- const firstChar = user?.firstName?.charAt(0) || "\u0E1C";
1133
1163
  const [isNotifOpen, setIsNotifOpen] = useState(false);
1134
1164
  const [activeFilter, setActiveFilter] = useState("all");
1135
1165
  const notifRef = useRef(null);
1136
1166
  const isDark = useDarkMode();
1167
+ const [imgError, setImgError] = useState(false);
1168
+ useEffect(() => {
1169
+ setImgError(false);
1170
+ }, [user?.pictureUrl]);
1137
1171
  useEffect(() => {
1138
1172
  const handleClickOutside = (e) => {
1139
1173
  if (notifRef.current && !notifRef.current.contains(e.target)) {
@@ -1196,42 +1230,22 @@ function UserHeader({
1196
1230
  overflow: "hidden"
1197
1231
  },
1198
1232
  children: [
1199
- user?.pictureUrl ? /* @__PURE__ */ jsx(
1233
+ user?.pictureUrl && !imgError ? /* @__PURE__ */ jsx(
1200
1234
  "img",
1201
1235
  {
1202
1236
  src: user.pictureUrl,
1203
1237
  alt: displayName,
1238
+ onError: () => setImgError(true),
1204
1239
  style: {
1205
1240
  width: "44px",
1206
1241
  height: "44px",
1207
1242
  borderRadius: "50%",
1208
1243
  objectFit: "cover",
1209
- border: "2px solid rgba(255,255,255,0.7)"
1210
- }
1211
- }
1212
- ) : /* @__PURE__ */ jsx(
1213
- "div",
1214
- {
1215
- style: {
1216
- width: "44px",
1217
- height: "44px",
1218
- borderRadius: "50%",
1219
- background: "rgba(255,255,255,0.2)",
1220
1244
  border: "2px solid rgba(255,255,255,0.7)",
1221
- display: "flex",
1222
- alignItems: "center",
1223
- justifyContent: "center",
1224
- boxShadow: "0 1px 3px rgba(0,0,0,0.1)"
1225
- },
1226
- children: /* @__PURE__ */ jsx(
1227
- "span",
1228
- {
1229
- style: { color: "#fff", fontSize: "18px", fontWeight: 600 },
1230
- children: firstChar
1231
- }
1232
- )
1245
+ flexShrink: 0
1246
+ }
1233
1247
  }
1234
- ),
1248
+ ) : /* @__PURE__ */ jsx(AvatarPlaceholder2, { size: 44 }),
1235
1249
  /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
1236
1250
  /* @__PURE__ */ jsxs(
1237
1251
  "p",
@@ -1623,6 +1637,25 @@ function ProfileIcon2() {
1623
1637
  /* @__PURE__ */ jsx("circle", { cx: "12", cy: "7", r: "4" })
1624
1638
  ] });
1625
1639
  }
1640
+ function AvatarPlaceholder3({ size = 56 }) {
1641
+ return /* @__PURE__ */ jsx(
1642
+ "div",
1643
+ {
1644
+ style: {
1645
+ width: `${size}px`,
1646
+ height: `${size}px`,
1647
+ borderRadius: "50%",
1648
+ backgroundColor: "#f1f5f9",
1649
+ display: "flex",
1650
+ alignItems: "center",
1651
+ justifyContent: "center",
1652
+ flexShrink: 0,
1653
+ boxShadow: "0 2px 8px rgba(0,0,0,0.05)"
1654
+ },
1655
+ children: /* @__PURE__ */ jsx("svg", { width: size * 0.6, height: size * 0.6, viewBox: "0 0 24 24", fill: "#94a3b8", children: /* @__PURE__ */ 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" }) })
1656
+ }
1657
+ );
1658
+ }
1626
1659
  function UserSidebar({
1627
1660
  user,
1628
1661
  roleLabel,
@@ -1635,6 +1668,10 @@ function UserSidebar({
1635
1668
  onProfile
1636
1669
  }) {
1637
1670
  const isDark = useDarkMode();
1671
+ const [imgError, setImgError] = useState(false);
1672
+ useEffect(() => {
1673
+ setImgError(false);
1674
+ }, [user?.pictureUrl]);
1638
1675
  useEffect(() => {
1639
1676
  if (isOpen) {
1640
1677
  document.body.style.overflow = "hidden";
@@ -1650,10 +1687,6 @@ function UserSidebar({
1650
1687
  if (user.firstName && user.lastName) return `${user.firstName} ${user.lastName}`;
1651
1688
  return user.firstName || user.lastName || "\u0E1C\u0E39\u0E49\u0E43\u0E0A\u0E49";
1652
1689
  };
1653
- const getInitial = () => {
1654
- if (!user) return "?";
1655
- return user.firstName?.charAt(0) || user.lastName?.charAt(0) || "?";
1656
- };
1657
1690
  const handleMenuClick = (path) => {
1658
1691
  onNavigate(path);
1659
1692
  onClose();
@@ -1713,38 +1746,22 @@ function UserSidebar({
1713
1746
  padding: "8px"
1714
1747
  },
1715
1748
  children: [
1716
- user.pictureUrl ? /* @__PURE__ */ jsx(
1749
+ user.pictureUrl && !imgError ? /* @__PURE__ */ jsx(
1717
1750
  "img",
1718
1751
  {
1719
1752
  src: user.pictureUrl,
1720
1753
  alt: getFullName(),
1754
+ onError: () => setImgError(true),
1721
1755
  style: {
1722
1756
  width: "56px",
1723
1757
  height: "56px",
1724
1758
  borderRadius: "50%",
1725
1759
  objectFit: "cover",
1760
+ flexShrink: 0,
1726
1761
  boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
1727
1762
  }
1728
1763
  }
1729
- ) : /* @__PURE__ */ jsx(
1730
- "div",
1731
- {
1732
- style: {
1733
- width: "56px",
1734
- height: "56px",
1735
- borderRadius: "50%",
1736
- background: "linear-gradient(135deg, var(--color-alias-color-brand-secondary, #80d897), var(--color-alias-color-brand-primary, #1e7d55))",
1737
- display: "flex",
1738
- alignItems: "center",
1739
- justifyContent: "center",
1740
- color: "#fff",
1741
- fontWeight: 700,
1742
- fontSize: "20px",
1743
- boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
1744
- },
1745
- children: getInitial()
1746
- }
1747
- ),
1764
+ ) : /* @__PURE__ */ jsx(AvatarPlaceholder3, { size: 56 }),
1748
1765
  /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
1749
1766
  /* @__PURE__ */ jsx(
1750
1767
  "p",