gov-layout 1.0.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/README.md +210 -0
- package/dist/index.d.mts +104 -0
- package/dist/index.d.ts +104 -0
- package/dist/index.js +1072 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1065 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# gov-layout
|
|
2
|
+
|
|
3
|
+
Government Layout Components — Staff Sidebar + User Header/Sidebar
|
|
4
|
+
|
|
5
|
+
> ใช้คู่กับ `gov-token-css` เพื่อให้สีตรงตาม Design System
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install gov-layout gov-token-css
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 📦 Components
|
|
16
|
+
|
|
17
|
+
### 1. StaffSidebar (เจ้าหน้าที่)
|
|
18
|
+
|
|
19
|
+
Sidebar ฝั่งซ้ายแบบ fixed สำหรับหน้า admin
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { StaffSidebar } from 'gov-layout';
|
|
23
|
+
import type { MenuItem } from 'gov-layout';
|
|
24
|
+
|
|
25
|
+
const menuItems: MenuItem[] = [
|
|
26
|
+
{
|
|
27
|
+
id: 'services',
|
|
28
|
+
title: 'งานบริการ',
|
|
29
|
+
icon: <FolderIcon />,
|
|
30
|
+
children: [
|
|
31
|
+
{ id: 'water', title: 'ประปา', path: '/services/water' },
|
|
32
|
+
{ id: 'tax', title: 'ภาษี', path: '/services/tax' },
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'help',
|
|
37
|
+
title: 'ช่วยเหลือ',
|
|
38
|
+
icon: <HelpIcon />,
|
|
39
|
+
path: '/help',
|
|
40
|
+
dividerAfter: true,
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const bottomMenu: MenuItem[] = [
|
|
45
|
+
{ id: 'settings', title: 'ตั้งค่าระบบ', icon: <SettingsIcon />, path: '/settings' },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
<StaffSidebar
|
|
49
|
+
orgLogo="/logo.png"
|
|
50
|
+
orgName="เทศบาลตำบลหลักเมือง"
|
|
51
|
+
orgSubtitle="จังหวัดราชบุรี"
|
|
52
|
+
menuItems={menuItems}
|
|
53
|
+
bottomMenuItems={bottomMenu}
|
|
54
|
+
user={{ firstName: 'Kaimuk', lastName: 'Jakprim' }}
|
|
55
|
+
roleLabel="เจ้าหน้าที่"
|
|
56
|
+
currentPath="/services/water"
|
|
57
|
+
onNavigate={(path) => router.push(path)}
|
|
58
|
+
onLogout={() => signOut()}
|
|
59
|
+
width="280px"
|
|
60
|
+
/>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Features:**
|
|
64
|
+
- ✅ Dropdown submenu (พับ/กาง)
|
|
65
|
+
- ✅ Auto-expand เมื่อ child active
|
|
66
|
+
- ✅ Active item highlight
|
|
67
|
+
- ✅ Bottom menu (ตั้งค่าระบบ)
|
|
68
|
+
- ✅ User profile + logout ข้างล่าง
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### 2. UserHeader (ผู้ใช้ทั่วไป)
|
|
73
|
+
|
|
74
|
+
Header ด้านบนพร้อม notification bell
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { UserHeader } from 'gov-layout';
|
|
78
|
+
|
|
79
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
|
80
|
+
|
|
81
|
+
<UserHeader
|
|
82
|
+
user={{ firstName: 'Kaimuk', pictureUrl: '/avatar.jpg' }}
|
|
83
|
+
notifications={[
|
|
84
|
+
{
|
|
85
|
+
id: 1,
|
|
86
|
+
title: 'คำร้องได้รับการอนุมัติ',
|
|
87
|
+
description: 'คำร้องหมายเลข #1234',
|
|
88
|
+
date: '2 ชม. ที่แล้ว',
|
|
89
|
+
type: 'success',
|
|
90
|
+
isRead: false,
|
|
91
|
+
},
|
|
92
|
+
]}
|
|
93
|
+
onToggleSidebar={() => setIsSidebarOpen(true)}
|
|
94
|
+
onMarkAllRead={() => markAllRead()}
|
|
95
|
+
onViewAll={() => router.push('/notifications')}
|
|
96
|
+
/>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### 3. UserSidebar (ผู้ใช้ทั่วไป)
|
|
102
|
+
|
|
103
|
+
Sidebar ฝั่งขวาแบบ slide-in
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
import { UserSidebar } from 'gov-layout';
|
|
107
|
+
|
|
108
|
+
<UserSidebar
|
|
109
|
+
isOpen={isSidebarOpen}
|
|
110
|
+
onClose={() => setIsSidebarOpen(false)}
|
|
111
|
+
user={{ firstName: 'Kaimuk', lastName: 'Jakprim', pictureUrl: '/avatar.jpg' }}
|
|
112
|
+
roleLabel="ผู้สูงอายุ"
|
|
113
|
+
menuItems={[
|
|
114
|
+
{ id: 'profile', title: 'ข้อมูลส่วนตัว', icon: <UserIcon />, path: '/profile' },
|
|
115
|
+
{ id: 'services', title: 'บริการหลัก', icon: <HomeIcon />, path: '/services' },
|
|
116
|
+
{ id: 'settings', title: 'ตั้งค่าระบบ', icon: <SettingsIcon />, path: '/settings' },
|
|
117
|
+
]}
|
|
118
|
+
onNavigate={(path) => router.push(path)}
|
|
119
|
+
onLogout={() => signOut()}
|
|
120
|
+
/>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 🔧 Sub-Components
|
|
126
|
+
|
|
127
|
+
ใช้แยกกันได้ถ้าต้องการ customize
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import {
|
|
131
|
+
SidebarHeader, // logo + ชื่อองค์กร
|
|
132
|
+
SidebarMenu, // เมนู dropdown
|
|
133
|
+
SidebarUserProfile // avatar + logout
|
|
134
|
+
} from 'gov-layout';
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 🎨 Styling
|
|
140
|
+
|
|
141
|
+
Components ใช้ **inline styles** + CSS variables จาก `gov-token-css`:
|
|
142
|
+
|
|
143
|
+
```css
|
|
144
|
+
/* ใน globals.css */
|
|
145
|
+
@import "gov-token-css";
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
ถ้าไม่ได้ import `gov-token-css` จะใช้สี fallback อัตโนมัติ
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 📐 Types
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
interface MenuItem {
|
|
156
|
+
id: string;
|
|
157
|
+
title: string;
|
|
158
|
+
path?: string;
|
|
159
|
+
icon?: React.ReactNode;
|
|
160
|
+
children?: MenuItem[]; // submenu
|
|
161
|
+
dividerAfter?: boolean; // เส้นคั่น
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface User {
|
|
165
|
+
id?: string | number;
|
|
166
|
+
firstName?: string;
|
|
167
|
+
lastName?: string;
|
|
168
|
+
pictureUrl?: string;
|
|
169
|
+
role?: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
interface NotificationItem {
|
|
173
|
+
id: string | number;
|
|
174
|
+
title: string;
|
|
175
|
+
description: string;
|
|
176
|
+
date: string;
|
|
177
|
+
type: 'info' | 'success' | 'warning' | 'error' | 'reminder';
|
|
178
|
+
isRead: boolean;
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 📁 Layout Example
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
// Staff Layout (เจ้าหน้าที่)
|
|
188
|
+
export default function AdminLayout({ children }) {
|
|
189
|
+
return (
|
|
190
|
+
<div style={{ display: 'flex' }}>
|
|
191
|
+
<StaffSidebar ... />
|
|
192
|
+
<main style={{ marginLeft: '280px', flex: 1 }}>
|
|
193
|
+
{children}
|
|
194
|
+
</main>
|
|
195
|
+
</div>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// User Layout (ผู้ใช้ทั่วไป)
|
|
200
|
+
export default function UserLayout({ children }) {
|
|
201
|
+
const [open, setOpen] = useState(false);
|
|
202
|
+
return (
|
|
203
|
+
<>
|
|
204
|
+
<UserHeader onToggleSidebar={() => setOpen(true)} ... />
|
|
205
|
+
<UserSidebar isOpen={open} onClose={() => setOpen(false)} ... />
|
|
206
|
+
<main>{children}</main>
|
|
207
|
+
</>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface User {
|
|
4
|
+
id?: string | number;
|
|
5
|
+
firstName?: string;
|
|
6
|
+
lastName?: string;
|
|
7
|
+
pictureUrl?: string;
|
|
8
|
+
role?: string;
|
|
9
|
+
}
|
|
10
|
+
interface MenuItem {
|
|
11
|
+
id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
path?: string;
|
|
14
|
+
icon?: React.ReactNode;
|
|
15
|
+
children?: MenuItem[];
|
|
16
|
+
dividerAfter?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface StaffSidebarProps {
|
|
19
|
+
/** URL รูปตราองค์กร */
|
|
20
|
+
orgLogo?: string;
|
|
21
|
+
/** ชื่อองค์กร */
|
|
22
|
+
orgName: string;
|
|
23
|
+
/** ชื่อรอง เช่น จังหวัด */
|
|
24
|
+
orgSubtitle?: string;
|
|
25
|
+
/** เมนูหลัก */
|
|
26
|
+
menuItems: MenuItem[];
|
|
27
|
+
/** เมนูล่าง เช่น ตั้งค่าระบบ */
|
|
28
|
+
bottomMenuItems?: MenuItem[];
|
|
29
|
+
/** ข้อมูลผู้ใช้ */
|
|
30
|
+
user: User | null;
|
|
31
|
+
/** ป้ายแสดงตำแหน่ง เช่น "เจ้าหน้าที่" */
|
|
32
|
+
roleLabel: string;
|
|
33
|
+
/** callback เมื่อคลิกเมนู */
|
|
34
|
+
onNavigate: (path: string) => void;
|
|
35
|
+
/** callback เมื่อกดออกจากระบบ */
|
|
36
|
+
onLogout: () => void;
|
|
37
|
+
/** path ปัจจุบันเพื่อ highlight active menu */
|
|
38
|
+
currentPath?: string;
|
|
39
|
+
/** ความกว้าง sidebar */
|
|
40
|
+
width?: string;
|
|
41
|
+
/** className เพิ่มเติม */
|
|
42
|
+
className?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
declare function StaffSidebar({ orgLogo, orgName, orgSubtitle, menuItems, bottomMenuItems, user, roleLabel, onNavigate, onLogout, currentPath, width, className, }: StaffSidebarProps): react_jsx_runtime.JSX.Element;
|
|
46
|
+
|
|
47
|
+
interface SidebarHeaderProps {
|
|
48
|
+
orgLogo?: string;
|
|
49
|
+
orgName: string;
|
|
50
|
+
orgSubtitle?: string;
|
|
51
|
+
}
|
|
52
|
+
declare function SidebarHeader({ orgLogo, orgName, orgSubtitle }: SidebarHeaderProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
|
|
54
|
+
interface SidebarMenuProps {
|
|
55
|
+
menuItems: MenuItem[];
|
|
56
|
+
onItemClick: (path: string) => void;
|
|
57
|
+
currentPath?: string;
|
|
58
|
+
}
|
|
59
|
+
declare function SidebarMenu({ menuItems, onItemClick, currentPath }: SidebarMenuProps): react_jsx_runtime.JSX.Element;
|
|
60
|
+
|
|
61
|
+
interface SidebarUserProfileProps {
|
|
62
|
+
user: User | null;
|
|
63
|
+
roleLabel: string;
|
|
64
|
+
onLogout: () => void;
|
|
65
|
+
}
|
|
66
|
+
declare function SidebarUserProfile({ user, roleLabel, onLogout, }: SidebarUserProfileProps): react_jsx_runtime.JSX.Element | null;
|
|
67
|
+
|
|
68
|
+
interface NotificationItem {
|
|
69
|
+
id: string | number;
|
|
70
|
+
title: string;
|
|
71
|
+
description: string;
|
|
72
|
+
date: string;
|
|
73
|
+
type: 'info' | 'success' | 'warning' | 'error' | 'reminder';
|
|
74
|
+
isRead: boolean;
|
|
75
|
+
}
|
|
76
|
+
interface UserHeaderProps {
|
|
77
|
+
user?: {
|
|
78
|
+
firstName?: string;
|
|
79
|
+
lastName?: string;
|
|
80
|
+
pictureUrl?: string;
|
|
81
|
+
};
|
|
82
|
+
notifications?: NotificationItem[];
|
|
83
|
+
onToggleSidebar?: () => void;
|
|
84
|
+
/** Custom bell icon */
|
|
85
|
+
notificationBell?: React.ReactNode;
|
|
86
|
+
onMarkAllRead?: () => void;
|
|
87
|
+
onViewAll?: () => void;
|
|
88
|
+
className?: string;
|
|
89
|
+
}
|
|
90
|
+
declare function UserHeader({ user, notifications, onToggleSidebar, notificationBell, onMarkAllRead, onViewAll, className, }: UserHeaderProps): react_jsx_runtime.JSX.Element;
|
|
91
|
+
|
|
92
|
+
interface UserSidebarProps {
|
|
93
|
+
user: User | null;
|
|
94
|
+
roleLabel: string;
|
|
95
|
+
menuItems: MenuItem[];
|
|
96
|
+
onNavigate: (path: string) => void;
|
|
97
|
+
onLogout: () => void;
|
|
98
|
+
isOpen: boolean;
|
|
99
|
+
onClose: () => void;
|
|
100
|
+
roleColor?: string;
|
|
101
|
+
}
|
|
102
|
+
declare function UserSidebar({ user, roleLabel, menuItems, onNavigate, onLogout, isOpen, onClose, roleColor, }: UserSidebarProps): react_jsx_runtime.JSX.Element;
|
|
103
|
+
|
|
104
|
+
export { type MenuItem, type NotificationItem, SidebarHeader, SidebarMenu, SidebarUserProfile, StaffSidebar, type StaffSidebarProps, type User, UserHeader, UserSidebar };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface User {
|
|
4
|
+
id?: string | number;
|
|
5
|
+
firstName?: string;
|
|
6
|
+
lastName?: string;
|
|
7
|
+
pictureUrl?: string;
|
|
8
|
+
role?: string;
|
|
9
|
+
}
|
|
10
|
+
interface MenuItem {
|
|
11
|
+
id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
path?: string;
|
|
14
|
+
icon?: React.ReactNode;
|
|
15
|
+
children?: MenuItem[];
|
|
16
|
+
dividerAfter?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface StaffSidebarProps {
|
|
19
|
+
/** URL รูปตราองค์กร */
|
|
20
|
+
orgLogo?: string;
|
|
21
|
+
/** ชื่อองค์กร */
|
|
22
|
+
orgName: string;
|
|
23
|
+
/** ชื่อรอง เช่น จังหวัด */
|
|
24
|
+
orgSubtitle?: string;
|
|
25
|
+
/** เมนูหลัก */
|
|
26
|
+
menuItems: MenuItem[];
|
|
27
|
+
/** เมนูล่าง เช่น ตั้งค่าระบบ */
|
|
28
|
+
bottomMenuItems?: MenuItem[];
|
|
29
|
+
/** ข้อมูลผู้ใช้ */
|
|
30
|
+
user: User | null;
|
|
31
|
+
/** ป้ายแสดงตำแหน่ง เช่น "เจ้าหน้าที่" */
|
|
32
|
+
roleLabel: string;
|
|
33
|
+
/** callback เมื่อคลิกเมนู */
|
|
34
|
+
onNavigate: (path: string) => void;
|
|
35
|
+
/** callback เมื่อกดออกจากระบบ */
|
|
36
|
+
onLogout: () => void;
|
|
37
|
+
/** path ปัจจุบันเพื่อ highlight active menu */
|
|
38
|
+
currentPath?: string;
|
|
39
|
+
/** ความกว้าง sidebar */
|
|
40
|
+
width?: string;
|
|
41
|
+
/** className เพิ่มเติม */
|
|
42
|
+
className?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
declare function StaffSidebar({ orgLogo, orgName, orgSubtitle, menuItems, bottomMenuItems, user, roleLabel, onNavigate, onLogout, currentPath, width, className, }: StaffSidebarProps): react_jsx_runtime.JSX.Element;
|
|
46
|
+
|
|
47
|
+
interface SidebarHeaderProps {
|
|
48
|
+
orgLogo?: string;
|
|
49
|
+
orgName: string;
|
|
50
|
+
orgSubtitle?: string;
|
|
51
|
+
}
|
|
52
|
+
declare function SidebarHeader({ orgLogo, orgName, orgSubtitle }: SidebarHeaderProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
|
|
54
|
+
interface SidebarMenuProps {
|
|
55
|
+
menuItems: MenuItem[];
|
|
56
|
+
onItemClick: (path: string) => void;
|
|
57
|
+
currentPath?: string;
|
|
58
|
+
}
|
|
59
|
+
declare function SidebarMenu({ menuItems, onItemClick, currentPath }: SidebarMenuProps): react_jsx_runtime.JSX.Element;
|
|
60
|
+
|
|
61
|
+
interface SidebarUserProfileProps {
|
|
62
|
+
user: User | null;
|
|
63
|
+
roleLabel: string;
|
|
64
|
+
onLogout: () => void;
|
|
65
|
+
}
|
|
66
|
+
declare function SidebarUserProfile({ user, roleLabel, onLogout, }: SidebarUserProfileProps): react_jsx_runtime.JSX.Element | null;
|
|
67
|
+
|
|
68
|
+
interface NotificationItem {
|
|
69
|
+
id: string | number;
|
|
70
|
+
title: string;
|
|
71
|
+
description: string;
|
|
72
|
+
date: string;
|
|
73
|
+
type: 'info' | 'success' | 'warning' | 'error' | 'reminder';
|
|
74
|
+
isRead: boolean;
|
|
75
|
+
}
|
|
76
|
+
interface UserHeaderProps {
|
|
77
|
+
user?: {
|
|
78
|
+
firstName?: string;
|
|
79
|
+
lastName?: string;
|
|
80
|
+
pictureUrl?: string;
|
|
81
|
+
};
|
|
82
|
+
notifications?: NotificationItem[];
|
|
83
|
+
onToggleSidebar?: () => void;
|
|
84
|
+
/** Custom bell icon */
|
|
85
|
+
notificationBell?: React.ReactNode;
|
|
86
|
+
onMarkAllRead?: () => void;
|
|
87
|
+
onViewAll?: () => void;
|
|
88
|
+
className?: string;
|
|
89
|
+
}
|
|
90
|
+
declare function UserHeader({ user, notifications, onToggleSidebar, notificationBell, onMarkAllRead, onViewAll, className, }: UserHeaderProps): react_jsx_runtime.JSX.Element;
|
|
91
|
+
|
|
92
|
+
interface UserSidebarProps {
|
|
93
|
+
user: User | null;
|
|
94
|
+
roleLabel: string;
|
|
95
|
+
menuItems: MenuItem[];
|
|
96
|
+
onNavigate: (path: string) => void;
|
|
97
|
+
onLogout: () => void;
|
|
98
|
+
isOpen: boolean;
|
|
99
|
+
onClose: () => void;
|
|
100
|
+
roleColor?: string;
|
|
101
|
+
}
|
|
102
|
+
declare function UserSidebar({ user, roleLabel, menuItems, onNavigate, onLogout, isOpen, onClose, roleColor, }: UserSidebarProps): react_jsx_runtime.JSX.Element;
|
|
103
|
+
|
|
104
|
+
export { type MenuItem, type NotificationItem, SidebarHeader, SidebarMenu, SidebarUserProfile, StaffSidebar, type StaffSidebarProps, type User, UserHeader, UserSidebar };
|