gov-layout 1.2.15 → 1.2.17

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/README.md CHANGED
@@ -233,7 +233,11 @@ Header ด้านบนพร้อม notification bell
233
233
  import { UserHeader } from 'gov-layout';
234
234
 
235
235
  <UserHeader
236
- user={{ firstName: 'สมหญิง', pictureUrl: '/avatar.jpg' }}
236
+ user={{
237
+ firstName: 'ชนธัญ',
238
+ pictureUrl: '/avatar.jpg',
239
+ subtitle: 'ผู้สูงอายุ', // แสดงใต้ข้อความทักทาย (optional)
240
+ }}
237
241
  notifications={[
238
242
  {
239
243
  id: 1,
@@ -247,15 +251,35 @@ import { UserHeader } from 'gov-layout';
247
251
  onToggleSidebar={() => setOpen(true)}
248
252
  onMarkAllRead={() => markAllRead()}
249
253
  onViewAll={() => router.push('/notifications')}
254
+ onNotificationClick={(notif) => router.push(`/notifications/${notif.id}`)}
250
255
  onProfile={() => router.push('/profile')}
251
256
  />
252
257
  ```
253
258
 
259
+ ### Props
260
+
261
+ | Prop | Type | Default | คำอธิบาย |
262
+ |------|------|---------|----------|
263
+ | `user.firstName` | `string?` | - | ชื่อ |
264
+ | `user.lastName` | `string?` | - | นามสกุล |
265
+ | `user.pictureUrl` | `string?` | - | URL รูปโปรไฟล์ |
266
+ | `user.subtitle` | `string?` | - | ข้อความใต้ชื่อ เช่น "ผู้สูงอายุ" |
267
+ | `notifications` | `NotificationItem[]?` | `[]` | รายการแจ้งเตือน |
268
+ | `onToggleSidebar` | `() => void?` | - | callback เปิด sidebar |
269
+ | `onMarkAllRead` | `() => void?` | - | callback อ่านทั้งหมดแล้ว |
270
+ | `onViewAll` | `() => void?` | - | callback ดูทั้งหมด |
271
+ | `onNotificationClick` | `(notification) => void?` | - | callback เมื่อกดแจ้งเตือนแต่ละรายการ |
272
+ | `onProfile` | `() => void?` | - | callback เมื่อกดโปรไฟล์ |
273
+ | `notificationBell` | `ReactNode?` | - | custom bell icon |
274
+ | `className` | `string?` | - | className เพิ่มเติม |
275
+
254
276
  ### Features
255
277
 
256
278
  - ✅ Notification bell พร้อม badge (99+ เมื่อเกิน)
257
279
  - ✅ ไม่มีแจ้งเตือน → ไม่แสดง badge
258
280
  - ✅ Notification dropdown แบบ scroll
281
+ - ✅ กดแจ้งเตือนแต่ละรายการ → `onNotificationClick`
282
+ - ✅ Subtitle ใต้ข้อความทักทาย (เช่น "ผู้สูงอายุ")
259
283
  - ✅ ปุ่มเปิด sidebar (☰)
260
284
  - ✅ กดโปรไฟล์ผู้ใช้ (avatar + ชื่อ) → `onProfile`
261
285
 
@@ -476,9 +500,10 @@ export default function UserLayout({ children }) {
476
500
  return (
477
501
  <>
478
502
  <UserHeader
479
- user={user}
503
+ user={{ ...user, subtitle: 'ผู้สูงอายุ' }}
480
504
  notifications={notifications}
481
505
  onToggleSidebar={() => setOpen(true)}
506
+ onNotificationClick={(notif) => setCurrentPath(`/notifications/${notif.id}`)}
482
507
  onProfile={() => setCurrentPath('/profile')}
483
508
  />
484
509
  <UserSidebar
package/dist/index.d.mts CHANGED
@@ -95,6 +95,8 @@ interface UserHeaderProps {
95
95
  firstName?: string;
96
96
  lastName?: string;
97
97
  pictureUrl?: string;
98
+ /** เช่น 'ผู้สูงอายุ', 'เจ้าหน้าที่' */
99
+ subtitle?: string;
98
100
  };
99
101
  notifications?: NotificationItem[];
100
102
  onToggleSidebar?: () => void;
@@ -102,11 +104,13 @@ interface UserHeaderProps {
102
104
  notificationBell?: React.ReactNode;
103
105
  onMarkAllRead?: () => void;
104
106
  onViewAll?: () => void;
107
+ /** Callback เมื่อกดการแจ้งเตือนแต่ละรายการ */
108
+ onNotificationClick?: (notification: NotificationItem) => void;
105
109
  /** Callback เมื่อกดโปรไฟล์ผู้ใช้ */
106
110
  onProfile?: () => void;
107
111
  className?: string;
108
112
  }
109
- declare function UserHeader({ user, notifications, onToggleSidebar, notificationBell, onMarkAllRead, onViewAll, onProfile, className, }: UserHeaderProps): react_jsx_runtime.JSX.Element;
113
+ declare function UserHeader({ user, notifications, onToggleSidebar, notificationBell, onMarkAllRead, onViewAll, onNotificationClick, onProfile, className, }: UserHeaderProps): react_jsx_runtime.JSX.Element;
110
114
 
111
115
  interface UserSidebarProps {
112
116
  user: User | null;
@@ -122,6 +126,20 @@ interface UserSidebarProps {
122
126
  }
123
127
  declare function UserSidebar({ user, roleLabel, menuItems, onNavigate, onLogout, isOpen, onClose, roleColor, onProfile, }: UserSidebarProps): react_jsx_runtime.JSX.Element;
124
128
 
129
+ interface BottomBarProps {
130
+ /** Content inside the bottom bar (pagination, buttons, etc.) */
131
+ children: React.ReactNode;
132
+ /** Left offset to account for sidebar width (default: '280px') */
133
+ sidebarWidth?: string;
134
+ /** Height of the bottom bar (default: '73px') */
135
+ height?: string;
136
+ /** Additional CSS class */
137
+ className?: string;
138
+ /** Custom inline styles */
139
+ style?: React.CSSProperties;
140
+ }
141
+ declare function BottomBar({ children, sidebarWidth, height, className, style, }: BottomBarProps): react_jsx_runtime.JSX.Element;
142
+
125
143
  type Theme = 'light' | 'dark';
126
144
  type FontSizeKey = 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
127
145
  interface FontSizeOption {
@@ -245,4 +263,4 @@ declare const Icons: {
245
263
  readonly Trash: typeof TrashIcon;
246
264
  };
247
265
 
248
- export { AlertTriangleIcon, BarChartIcon, BellIcon, BuildingIcon, CalendarIcon, CheckCircleIcon, ClipboardIcon, DatabaseIcon, DownloadIcon, EditIcon, EyeIcon, FONT_SIZE_OPTIONS, FileTextIcon, FolderIcon, type FontSizeKey, type FontSizeOption, FontSizeSettings, GearIcon, HeartIcon, HelpCircleIcon, HistoryIcon, HomeIcon, type IconProps, Icons, LogOutIcon, MailIcon, MapPinIcon, type MenuItem, type NotificationItem, PhoneIcon, PlusCircleIcon, PrinterIcon, SearchIcon, SettingsPanel, SettingsProvider, ShieldIcon, SidebarHeader, SidebarMenu, SidebarUserProfile, StaffSidebar, type StaffSidebarProps, StarIcon, type Theme, ThemeSettings, TrashIcon, UploadIcon, type User, UserHeader, UserIcon, UserSidebar, UsersIcon, WrenchIcon, XCircleIcon, useDarkMode, useSettings };
266
+ export { AlertTriangleIcon, BarChartIcon, BellIcon, BottomBar, type BottomBarProps, BuildingIcon, CalendarIcon, CheckCircleIcon, ClipboardIcon, DatabaseIcon, DownloadIcon, EditIcon, EyeIcon, FONT_SIZE_OPTIONS, FileTextIcon, FolderIcon, type FontSizeKey, type FontSizeOption, FontSizeSettings, GearIcon, HeartIcon, HelpCircleIcon, HistoryIcon, HomeIcon, type IconProps, Icons, LogOutIcon, MailIcon, MapPinIcon, type MenuItem, type NotificationItem, PhoneIcon, PlusCircleIcon, PrinterIcon, SearchIcon, SettingsPanel, SettingsProvider, ShieldIcon, SidebarHeader, SidebarMenu, SidebarUserProfile, StaffSidebar, type StaffSidebarProps, StarIcon, type Theme, ThemeSettings, TrashIcon, UploadIcon, type User, UserHeader, UserIcon, UserSidebar, UsersIcon, WrenchIcon, XCircleIcon, useDarkMode, useSettings };
package/dist/index.d.ts CHANGED
@@ -95,6 +95,8 @@ interface UserHeaderProps {
95
95
  firstName?: string;
96
96
  lastName?: string;
97
97
  pictureUrl?: string;
98
+ /** เช่น 'ผู้สูงอายุ', 'เจ้าหน้าที่' */
99
+ subtitle?: string;
98
100
  };
99
101
  notifications?: NotificationItem[];
100
102
  onToggleSidebar?: () => void;
@@ -102,11 +104,13 @@ interface UserHeaderProps {
102
104
  notificationBell?: React.ReactNode;
103
105
  onMarkAllRead?: () => void;
104
106
  onViewAll?: () => void;
107
+ /** Callback เมื่อกดการแจ้งเตือนแต่ละรายการ */
108
+ onNotificationClick?: (notification: NotificationItem) => void;
105
109
  /** Callback เมื่อกดโปรไฟล์ผู้ใช้ */
106
110
  onProfile?: () => void;
107
111
  className?: string;
108
112
  }
109
- declare function UserHeader({ user, notifications, onToggleSidebar, notificationBell, onMarkAllRead, onViewAll, onProfile, className, }: UserHeaderProps): react_jsx_runtime.JSX.Element;
113
+ declare function UserHeader({ user, notifications, onToggleSidebar, notificationBell, onMarkAllRead, onViewAll, onNotificationClick, onProfile, className, }: UserHeaderProps): react_jsx_runtime.JSX.Element;
110
114
 
111
115
  interface UserSidebarProps {
112
116
  user: User | null;
@@ -122,6 +126,20 @@ interface UserSidebarProps {
122
126
  }
123
127
  declare function UserSidebar({ user, roleLabel, menuItems, onNavigate, onLogout, isOpen, onClose, roleColor, onProfile, }: UserSidebarProps): react_jsx_runtime.JSX.Element;
124
128
 
129
+ interface BottomBarProps {
130
+ /** Content inside the bottom bar (pagination, buttons, etc.) */
131
+ children: React.ReactNode;
132
+ /** Left offset to account for sidebar width (default: '280px') */
133
+ sidebarWidth?: string;
134
+ /** Height of the bottom bar (default: '73px') */
135
+ height?: string;
136
+ /** Additional CSS class */
137
+ className?: string;
138
+ /** Custom inline styles */
139
+ style?: React.CSSProperties;
140
+ }
141
+ declare function BottomBar({ children, sidebarWidth, height, className, style, }: BottomBarProps): react_jsx_runtime.JSX.Element;
142
+
125
143
  type Theme = 'light' | 'dark';
126
144
  type FontSizeKey = 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
127
145
  interface FontSizeOption {
@@ -245,4 +263,4 @@ declare const Icons: {
245
263
  readonly Trash: typeof TrashIcon;
246
264
  };
247
265
 
248
- export { AlertTriangleIcon, BarChartIcon, BellIcon, BuildingIcon, CalendarIcon, CheckCircleIcon, ClipboardIcon, DatabaseIcon, DownloadIcon, EditIcon, EyeIcon, FONT_SIZE_OPTIONS, FileTextIcon, FolderIcon, type FontSizeKey, type FontSizeOption, FontSizeSettings, GearIcon, HeartIcon, HelpCircleIcon, HistoryIcon, HomeIcon, type IconProps, Icons, LogOutIcon, MailIcon, MapPinIcon, type MenuItem, type NotificationItem, PhoneIcon, PlusCircleIcon, PrinterIcon, SearchIcon, SettingsPanel, SettingsProvider, ShieldIcon, SidebarHeader, SidebarMenu, SidebarUserProfile, StaffSidebar, type StaffSidebarProps, StarIcon, type Theme, ThemeSettings, TrashIcon, UploadIcon, type User, UserHeader, UserIcon, UserSidebar, UsersIcon, WrenchIcon, XCircleIcon, useDarkMode, useSettings };
266
+ export { AlertTriangleIcon, BarChartIcon, BellIcon, BottomBar, type BottomBarProps, BuildingIcon, CalendarIcon, CheckCircleIcon, ClipboardIcon, DatabaseIcon, DownloadIcon, EditIcon, EyeIcon, FONT_SIZE_OPTIONS, FileTextIcon, FolderIcon, type FontSizeKey, type FontSizeOption, FontSizeSettings, GearIcon, HeartIcon, HelpCircleIcon, HistoryIcon, HomeIcon, type IconProps, Icons, LogOutIcon, MailIcon, MapPinIcon, type MenuItem, type NotificationItem, PhoneIcon, PlusCircleIcon, PrinterIcon, SearchIcon, SettingsPanel, SettingsProvider, ShieldIcon, SidebarHeader, SidebarMenu, SidebarUserProfile, StaffSidebar, type StaffSidebarProps, StarIcon, type Theme, ThemeSettings, TrashIcon, UploadIcon, type User, UserHeader, UserIcon, UserSidebar, UsersIcon, WrenchIcon, XCircleIcon, useDarkMode, useSettings };
package/dist/index.js CHANGED
@@ -696,7 +696,7 @@ function SidebarUserProfile({
696
696
  onClick: onProfile,
697
697
  title: "\u0E42\u0E1B\u0E23\u0E44\u0E1F\u0E25\u0E4C\u0E02\u0E2D\u0E07\u0E09\u0E31\u0E19",
698
698
  onMouseEnter: (e) => {
699
- e.currentTarget.style.backgroundColor = isDark ? "#334155" : "var(--color-alias-color-brand-surface, #f0fdf4)";
699
+ e.currentTarget.style.backgroundColor = isDark ? "#334155" : "var(--color-alias-color-brand-surface, #faf9e5)";
700
700
  },
701
701
  onMouseLeave: (e) => {
702
702
  e.currentTarget.style.backgroundColor = "transparent";
@@ -836,7 +836,7 @@ function SidebarUserProfile({
836
836
  onClick: onProfile,
837
837
  title: "\u0E42\u0E1B\u0E23\u0E44\u0E1F\u0E25\u0E4C\u0E02\u0E2D\u0E07\u0E09\u0E31\u0E19",
838
838
  onMouseEnter: (e) => {
839
- e.currentTarget.style.backgroundColor = isDark ? "#334155" : "var(--color-alias-color-brand-surface, #f0fdf4)";
839
+ e.currentTarget.style.backgroundColor = isDark ? "#334155" : "var(--color-alias-color-brand-surface, #faf9e5)";
840
840
  },
841
841
  onMouseLeave: (e) => {
842
842
  e.currentTarget.style.backgroundColor = "transparent";
@@ -1124,6 +1124,7 @@ function UserHeader({
1124
1124
  notificationBell,
1125
1125
  onMarkAllRead,
1126
1126
  onViewAll,
1127
+ onNotificationClick,
1127
1128
  onProfile,
1128
1129
  className
1129
1130
  }) {
@@ -1220,30 +1221,44 @@ function UserHeader({
1220
1221
  )
1221
1222
  }
1222
1223
  ),
1223
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(
1224
- "p",
1225
- {
1226
- style: {
1227
- fontSize: "15px",
1228
- fontWeight: 600,
1229
- color: "#ffffff",
1230
- margin: 0
1231
- },
1232
- children: [
1233
- "\u0E2A\u0E27\u0E31\u0E2A\u0E14\u0E35,",
1234
- " ",
1235
- /* @__PURE__ */ jsxRuntime.jsx(
1236
- "span",
1237
- {
1238
- style: {
1239
- color: "#ffffff"
1240
- },
1241
- children: displayName
1242
- }
1243
- )
1244
- ]
1245
- }
1246
- ) })
1224
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1225
+ /* @__PURE__ */ jsxRuntime.jsxs(
1226
+ "p",
1227
+ {
1228
+ style: {
1229
+ fontSize: "15px",
1230
+ fontWeight: 600,
1231
+ color: "#ffffff",
1232
+ margin: 0
1233
+ },
1234
+ children: [
1235
+ "\u0E2A\u0E27\u0E31\u0E2A\u0E14\u0E35,",
1236
+ " ",
1237
+ /* @__PURE__ */ jsxRuntime.jsx(
1238
+ "span",
1239
+ {
1240
+ style: {
1241
+ color: "#ffffff"
1242
+ },
1243
+ children: displayName
1244
+ }
1245
+ )
1246
+ ]
1247
+ }
1248
+ ),
1249
+ user?.subtitle && /* @__PURE__ */ jsxRuntime.jsx(
1250
+ "p",
1251
+ {
1252
+ style: {
1253
+ fontSize: "12px",
1254
+ color: "rgba(255,255,255,0.75)",
1255
+ margin: "2px 0 0",
1256
+ fontWeight: 400
1257
+ },
1258
+ children: user.subtitle
1259
+ }
1260
+ )
1261
+ ] })
1247
1262
  ]
1248
1263
  }
1249
1264
  ),
@@ -1361,6 +1376,7 @@ function UserHeader({
1361
1376
  ) : notifications.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
1362
1377
  "div",
1363
1378
  {
1379
+ onClick: () => onNotificationClick?.(item),
1364
1380
  style: {
1365
1381
  padding: "12px 16px",
1366
1382
  borderBottom: "1px solid #f9fafb",
@@ -1607,7 +1623,7 @@ function UserSidebar({
1607
1623
  {
1608
1624
  style: {
1609
1625
  padding: "20px",
1610
- borderBottom: `1px solid ${isDark ? "#374151" : "var(--color-border-colors-neutral, #e5e7eb)"}`
1626
+ borderBottom: `1px solid ${isDark ? "#374151" : "var(--color-border-colors-neutral, #c8cedd)"}`
1611
1627
  },
1612
1628
  children: /* @__PURE__ */ jsxRuntime.jsxs(
1613
1629
  "div",
@@ -1672,7 +1688,7 @@ function UserSidebar({
1672
1688
  {
1673
1689
  style: {
1674
1690
  fontSize: "13px",
1675
- color: isDark ? "#e2e8f0" : "var(--color-alias-text-colors-tertiary, #6b7280)",
1691
+ color: isDark ? "#e2e8f0" : "var(--color-alias-text-colors-tertiary, #475272)",
1676
1692
  margin: "2px 0 0",
1677
1693
  display: "flex",
1678
1694
  alignItems: "center",
@@ -1720,7 +1736,7 @@ function UserSidebar({
1720
1736
  {
1721
1737
  style: {
1722
1738
  padding: "20px",
1723
- borderTop: `1px solid ${isDark ? "#374151" : "var(--color-border-colors-neutral, #e5e7eb)"}`
1739
+ borderTop: `1px solid ${isDark ? "#374151" : "var(--color-border-colors-neutral, #c8cedd)"}`
1724
1740
  },
1725
1741
  children: /* @__PURE__ */ jsxRuntime.jsxs(
1726
1742
  "button",
@@ -1741,7 +1757,7 @@ function UserSidebar({
1741
1757
  borderRadius: "8px",
1742
1758
  border: "none",
1743
1759
  background: "transparent",
1744
- color: "var(--color-alias-semantic-critical, #ef4444)",
1760
+ color: "var(--color-alias-semantic-critical, #f21515)",
1745
1761
  cursor: "pointer",
1746
1762
  transition: "background-color 0.15s ease",
1747
1763
  fontSize: "15px",
@@ -1760,6 +1776,38 @@ function UserSidebar({
1760
1776
  )
1761
1777
  ] });
1762
1778
  }
1779
+ function BottomBar({
1780
+ children,
1781
+ sidebarWidth = "280px",
1782
+ height = "73px",
1783
+ className,
1784
+ style
1785
+ }) {
1786
+ const isDark = useDarkMode();
1787
+ return /* @__PURE__ */ jsxRuntime.jsx(
1788
+ "div",
1789
+ {
1790
+ className,
1791
+ style: {
1792
+ position: "fixed",
1793
+ bottom: 0,
1794
+ left: sidebarWidth,
1795
+ right: 0,
1796
+ height,
1797
+ background: isDark ? "#111827" : "#ffffff",
1798
+ borderTop: `1px solid ${isDark ? "#374151" : "var(--color-border-colors-neutral, #c8cedd)"}`,
1799
+ display: "flex",
1800
+ alignItems: "center",
1801
+ justifyContent: "space-between",
1802
+ padding: "16px 24px",
1803
+ zIndex: 30,
1804
+ transition: "left 0.3s ease",
1805
+ ...style
1806
+ },
1807
+ children
1808
+ }
1809
+ );
1810
+ }
1763
1811
  var FONT_SIZE_OPTIONS = [
1764
1812
  { key: "xsmall", label: "\u0E40\u0E25\u0E47\u0E01\u0E21\u0E32\u0E01", scale: 0.8 },
1765
1813
  { key: "small", label: "\u0E40\u0E25\u0E47\u0E01", scale: 0.9 },
@@ -1967,7 +2015,7 @@ function FontSizeSettings({ onBack }) {
1967
2015
  margin: "8px 16px",
1968
2016
  padding: "16px",
1969
2017
  borderRadius: 10,
1970
- background: "var(--color-foundations-fuji-pallet-light, #f5f6fa)",
2018
+ background: "var(--color-foundations-fuji-pallet-light, #ebedf5)",
1971
2019
  textAlign: "center"
1972
2020
  }, children: [
1973
2021
  /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
@@ -2070,7 +2118,7 @@ function SettingsPanel({ className, showTheme = true }) {
2070
2118
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
2071
2119
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2072
2120
  padding: "16px",
2073
- borderBottom: "1px solid var(--color-border-colors-neutral, #e5e7eb)"
2121
+ borderBottom: "1px solid var(--color-border-colors-neutral, #c8cedd)"
2074
2122
  }, children: /* @__PURE__ */ jsxRuntime.jsx("h3", { style: {
2075
2123
  fontSize: 16,
2076
2124
  fontWeight: 700,
@@ -2173,6 +2221,7 @@ var Icons = {
2173
2221
  exports.AlertTriangleIcon = AlertTriangleIcon;
2174
2222
  exports.BarChartIcon = BarChartIcon;
2175
2223
  exports.BellIcon = BellIcon;
2224
+ exports.BottomBar = BottomBar;
2176
2225
  exports.BuildingIcon = BuildingIcon;
2177
2226
  exports.CalendarIcon = CalendarIcon;
2178
2227
  exports.CheckCircleIcon = CheckCircleIcon;