gov-layout 1.1.8 → 1.1.10

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
@@ -1,28 +1,49 @@
1
1
  # gov-layout
2
2
 
3
- Government Layout Components — Staff Sidebar + User Header/Sidebar + Settings Panel
3
+ Government Layout Components สำหรับเว็บแอปพลิเคชันภาครัฐ
4
4
 
5
5
  > ใช้คู่กับ `gov-token-css` เพื่อให้สีตรงตาม Design System
6
6
 
7
- ## Installation
7
+ ---
8
+
9
+ ## 📥 Installation
8
10
 
9
11
  ```bash
10
12
  npm install gov-layout gov-token-css
11
13
  ```
12
14
 
15
+ ```css
16
+ /* ใน globals.css */
17
+ @import "gov-token-css";
18
+ ```
19
+
20
+ ---
21
+
22
+ ## 📦 Components ทั้งหมด
23
+
24
+ | Component | ใช้สำหรับ | import |
25
+ |-----------|----------|--------|
26
+ | `StaffSidebar` | Sidebar เจ้าหน้าที่ | `import { StaffSidebar } from 'gov-layout'` |
27
+ | `UserHeader` | Header ผู้ใช้ทั่วไป | `import { UserHeader } from 'gov-layout'` |
28
+ | `UserSidebar` | Sidebar ผู้ใช้ (slide-in) | `import { UserSidebar } from 'gov-layout'` |
29
+ | `SettingsPanel` | หน้าตั้งค่า (font + theme) | `import { SettingsPanel } from 'gov-layout'` |
30
+ | `SettingsProvider` | Context wrapper | `import { SettingsProvider } from 'gov-layout'` |
31
+ | `useSettings` | Hook อ่าน/เปลี่ยนค่า | `import { useSettings } from 'gov-layout'` |
32
+
13
33
  ---
14
34
 
15
- ## 📦 Components
35
+ ## 1. StaffSidebar (เจ้าหน้าที่)
16
36
 
17
- ### 1. StaffSidebar (เจ้าหน้าที่)
37
+ Sidebar ฝั่งซ้ายแบบ fixed — รองรับพับ/กาง (collapsible)
18
38
 
19
- Sidebar ฝั่งซ้ายแบบ fixed สำหรับหน้า admin — รองรับพับ/กาง (collapsible)
39
+ ### ตัวอย่างใช้งาน
20
40
 
21
41
  ```tsx
22
42
  import { StaffSidebar } from 'gov-layout';
23
43
  import type { MenuItem } from 'gov-layout';
24
44
 
25
45
  const menuItems: MenuItem[] = [
46
+ // === Dropdown (มี children) ===
26
47
  {
27
48
  id: 'services',
28
49
  title: 'งานบริการ',
@@ -30,19 +51,13 @@ const menuItems: MenuItem[] = [
30
51
  children: [
31
52
  { id: 'water', title: 'ประปา', path: '/services/water' },
32
53
  { id: 'tax', title: 'ภาษี', path: '/services/tax' },
54
+ { id: 'civil', title: 'ทะเบียน', path: '/services/civil' },
33
55
  ],
56
+ dividerAfter: true, // เส้นคั่นหลังเมนูนี้
34
57
  },
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' },
58
+ // === เมนูเดี่ยว (ไม่มี children) ===
59
+ { id: 'users', title: 'จัดการผู้ใช้', icon: <UserIcon />, path: '/users' },
60
+ { id: 'reports', title: 'รายงาน', icon: <ChartIcon />, path: '/reports' },
46
61
  ];
47
62
 
48
63
  <StaffSidebar
@@ -50,39 +65,96 @@ const bottomMenu: MenuItem[] = [
50
65
  orgName="เทศบาลตำบลหลักเมือง"
51
66
  orgSubtitle="จังหวัดราชบุรี"
52
67
  menuItems={menuItems}
53
- bottomMenuItems={bottomMenu}
54
- user={{ firstName: 'Kaimuk', lastName: 'Jakprim' }}
68
+ user={{ firstName: 'สมชาย', lastName: 'ใจดี' }}
55
69
  roleLabel="เจ้าหน้าที่"
56
70
  currentPath="/services/water"
57
71
  onNavigate={(path) => router.push(path)}
58
72
  onLogout={() => signOut()}
59
- collapsible // ← เปิดโหมดพับ/กาง
73
+ collapsible
60
74
  />
61
75
  ```
62
76
 
63
- **Features:**
64
- - Dropdown submenu (พับ/กาง)
77
+ > **💡 ข้อมูลองค์กร (`orgLogo`, `orgName`, `orgSubtitle`) มาจากไหนก็ได้:**
78
+ > - ดึงจาก **ตัวกลาง SSO** หลังล็อกอิน (แนะนำ) เช่น `useSSOAuth().organization`
79
+ > - ดึงจาก **API** เช่น `fetchOrgInfo()`
80
+ > - **Fix ค่า** ตรงๆ ก็ได้ ถ้าใช้ระบบเดียว
81
+ >
82
+ > Library ไม่ผูกกับแหล่งข้อมูลใดๆ — แค่รับ props แล้วแสดงผล
83
+
84
+ ### Default Bottom Menu
85
+
86
+ ไม่ต้องตั้งค่าเอง — มี **ตั้งค่าระบบ** + **ช่วยเหลือ** อยู่ด้านล่างอัตโนมัติ
87
+
88
+ ```
89
+ งานบริการ ▽
90
+ ประปา / ภาษี / ทะเบียน
91
+ ──────────────
92
+ จัดการผู้ใช้
93
+ รายงาน
94
+ ตั้งค่าระบบ ← default (ไม่ต้องส่ง)
95
+ ช่วยเหลือ ← default (ไม่ต้องส่ง)
96
+ ↕ spacer
97
+ โปรไฟล์ + ออกจากระบบ
98
+ ```
99
+
100
+ ถ้าอยากเปลี่ยน bottom menu เอง:
101
+
102
+ ```tsx
103
+ <StaffSidebar
104
+ bottomMenuItems={[
105
+ { id: 'settings', title: 'ตั้งค่า', icon: <GearIcon />, path: '/settings' },
106
+ ]}
107
+ ...
108
+ />
109
+ ```
110
+
111
+ ถ้าไม่อยากมี bottom menu:
112
+
113
+ ```tsx
114
+ <StaffSidebar bottomMenuItems={[]} ... />
115
+ ```
116
+
117
+ ### Props ทั้งหมด
118
+
119
+ | Prop | Type | Default | คำอธิบาย |
120
+ |------|------|---------|----------|
121
+ | `orgLogo` | `string?` | - | URL รูปตราองค์กร |
122
+ | `orgName` | `string` | **required** | ชื่อองค์กร |
123
+ | `orgSubtitle` | `string?` | - | ชื่อรอง เช่น จังหวัด |
124
+ | `menuItems` | `MenuItem[]` | **required** | เมนูหลัก |
125
+ | `bottomMenuItems` | `MenuItem[]?` | ตั้งค่าระบบ + ช่วยเหลือ | เมนูด้านล่าง |
126
+ | `user` | `User \| null` | **required** | ข้อมูลผู้ใช้ |
127
+ | `roleLabel` | `string` | **required** | ป้ายตำแหน่ง เช่น "เจ้าหน้าที่" |
128
+ | `onNavigate` | `(path) => void` | **required** | callback เมื่อคลิกเมนู |
129
+ | `onLogout` | `() => void` | **required** | callback ออกจากระบบ |
130
+ | `currentPath` | `string?` | - | path ปัจจุบัน (highlight active) |
131
+ | `width` | `string?` | `'280px'` | ความกว้าง sidebar |
132
+ | `collapsible` | `boolean?` | `false` | เปิดโหมดพับ/กาง |
133
+ | `isOpen` | `boolean?` | - | controlled open/close |
134
+ | `onToggle` | `() => void?` | - | callback เมื่อกดพับ/กาง |
135
+
136
+ ### Features
137
+
138
+ - ✅ Dropdown submenu (พับ/กางอัตโนมัติ)
65
139
  - ✅ Auto-expand เมื่อ child active
66
140
  - ✅ Active item highlight
67
- - ✅ Bottom menu (ตั้งค่าระบบ)
68
- - ✅ User profile + logout ข้างล่าง
69
- - ✅ **Collapsible** พับเป็น icon-only 64px, กางเป็น 280px
70
- - ปุ่ม toggle อยู่ขอบขวาบน (10%) ของ sidebar
71
- - Tooltip แสดงชื่อเมนูเมื่อพับ
141
+ - ✅ Collapsible พับเป็น icon-only 64px, กางเป็น 280px
142
+ - ✅ Tooltip เมื่อพับ
143
+ - ✅ Default ตั้งค่าระบบ + ช่วยเหลือ (override ได้)
144
+ - โปรไฟล์ + ออกจากระบบ ล่างสุดเสมอ
145
+ - `dividerAfter` เส้นคั่นระหว่างกลุ่ม
72
146
 
73
147
  ---
74
148
 
75
- ### 2. UserHeader (ผู้ใช้ทั่วไป)
149
+ ## 2. UserHeader (ผู้ใช้ทั่วไป)
76
150
 
77
- Header ด้านบนพร้อม notification bell — badge แสดง 99+ เมื่อเกิน 99
151
+ Header ด้านบนพร้อม notification bell
78
152
 
79
153
  ```tsx
80
154
  import { UserHeader } from 'gov-layout';
81
155
 
82
- const [isSidebarOpen, setIsSidebarOpen] = useState(false);
83
-
84
156
  <UserHeader
85
- user={{ firstName: 'Kaimuk', pictureUrl: '/avatar.jpg' }}
157
+ user={{ firstName: 'สมหญิง', pictureUrl: '/avatar.jpg' }}
86
158
  notifications={[
87
159
  {
88
160
  id: 1,
@@ -93,22 +165,24 @@ const [isSidebarOpen, setIsSidebarOpen] = useState(false);
93
165
  isRead: false,
94
166
  },
95
167
  ]}
96
- onToggleSidebar={() => setIsSidebarOpen(true)}
168
+ onToggleSidebar={() => setOpen(true)}
97
169
  onMarkAllRead={() => markAllRead()}
98
170
  onViewAll={() => router.push('/notifications')}
99
171
  />
100
172
  ```
101
173
 
102
- **Features:**
103
- - ✅ Notification bell พร้อม badge (แสดง 99+ เมื่อเกิน 99)
104
- - ✅ Notification dropdown แบบ scroll ได้
105
- - ✅ ปุ่มเปิด sidebar
174
+ ### Features
175
+
176
+ - ✅ Notification bell พร้อม badge (99+ เมื่อเกิน)
177
+ - ✅ ไม่มีแจ้งเตือน → ไม่แสดง badge
178
+ - ✅ Notification dropdown แบบ scroll
179
+ - ✅ ปุ่มเปิด sidebar (☰)
106
180
 
107
181
  ---
108
182
 
109
- ### 3. UserSidebar (ผู้ใช้ทั่วไป)
183
+ ## 3. UserSidebar (ผู้ใช้ทั่วไป)
110
184
 
111
- Sidebar ฝั่งขวาแบบ slide-in
185
+ Sidebar ฝั่งขวาแบบ slide-in + overlay
112
186
 
113
187
  ```tsx
114
188
  import { UserSidebar } from 'gov-layout';
@@ -116,39 +190,39 @@ import { UserSidebar } from 'gov-layout';
116
190
  <UserSidebar
117
191
  isOpen={isSidebarOpen}
118
192
  onClose={() => setIsSidebarOpen(false)}
119
- user={{ firstName: 'Kaimuk', lastName: 'Jakprim', pictureUrl: '/avatar.jpg' }}
120
- roleLabel="ผู้สูงอายุ" // ← กำหนดตาม role ของแต่ละระบบ
193
+ user={{ firstName: 'สมหญิง', lastName: 'ใจดี', pictureUrl: '/avatar.jpg' }}
194
+ roleLabel="ผู้สูงอายุ"
121
195
  menuItems={[
122
196
  { id: 'profile', title: 'ข้อมูลส่วนตัว', icon: <UserIcon />, path: '/profile' },
123
197
  { id: 'services', title: 'บริการหลัก', icon: <HomeIcon />, path: '/services' },
124
- { id: 'settings', title: 'ตั้งค่าระบบ', icon: <SettingsIcon />, path: '/settings' },
198
+ { id: 'settings', title: 'ตั้งค่าระบบ', icon: <GearIcon />, path: '/settings' },
125
199
  ]}
126
200
  onNavigate={(path) => router.push(path)}
127
201
  onLogout={() => signOut()}
128
202
  />
129
203
  ```
130
204
 
131
- > **หมายเหตุ:** `roleLabel` ไม่ได้ fix ไว้ แต่ละระบบส่งค่าเองได้ เช่น "ผู้สูงอายุ", "ผู้ใช้ปกติ", "อาสาสมัคร"
205
+ > **หมายเหตุ:** `roleLabel` แต่ละระบบส่งค่าเองได้ เช่น "ผู้สูงอายุ", "ผู้ใช้ปกติ", "อาสาสมัคร"
132
206
 
133
207
  ---
134
208
 
135
- ### 4. SettingsPanel (ตั้งค่าระบบ) 🆕
209
+ ## 4. SettingsPanel (ตั้งค่าระบบ) 🆕
136
210
 
137
- หน้าตั้งค่าพร้อมปรับขนาดตัวอักษร (5 ระดับ) + โหมดสว่าง/มืด
211
+ ปรับขนาดตัวอักษร (5 ระดับ) + โหมดสว่าง/มืด — ค่าจำใน localStorage
138
212
 
139
- #### ขั้นตอนการใช้งาน
140
-
141
- **1) ครอบ `SettingsProvider` ที่ root layout:**
213
+ ### ขั้นตอนที่ 1: ครอบ SettingsProvider
142
214
 
143
215
  ```tsx
144
- // app/providers.tsx ต้องเป็น 'use client'
216
+ // app/providers.tsx ต้องเป็น 'use client'
145
217
  'use client';
146
218
  import { SettingsProvider } from 'gov-layout';
147
219
 
148
220
  export default function Providers({ children }: { children: React.ReactNode }) {
149
221
  return <SettingsProvider>{children}</SettingsProvider>;
150
222
  }
223
+ ```
151
224
 
225
+ ```tsx
152
226
  // app/layout.tsx
153
227
  import Providers from './providers';
154
228
 
@@ -163,97 +237,87 @@ export default function RootLayout({ children }) {
163
237
  }
164
238
  ```
165
239
 
166
- **2) วาง `SettingsPanel` ในหน้าตั้งค่า:**
240
+ ### ขั้นตอนที่ 2: วาง SettingsPanel
167
241
 
168
242
  ```tsx
169
243
  import { SettingsPanel } from 'gov-layout';
170
244
 
171
- // ผู้ใช้ทั่วไป ได้ทั้ง font + theme
245
+ // ผู้ใช้ทั่วไป ทั้ง font + theme
172
246
  <SettingsPanel />
173
247
 
174
- // เจ้าหน้าที่ แค่ปรับขนาดฟอนต์
248
+ // เจ้าหน้าที่ แค่ปรับขนาดฟอนต์
175
249
  <SettingsPanel showTheme={false} />
176
250
  ```
177
251
 
178
- **3) ใช้ `useSettings()` hook ถ้าอยากอ่าน/เปลี่ยนค่าเอง:**
252
+ | Prop | Type | Default | คำอธิบาย |
253
+ |------|------|---------|----------|
254
+ | `showTheme` | `boolean?` | `true` | แสดงตัวเลือกโหมดสว่าง/มืด |
255
+ | `className` | `string?` | - | className เพิ่มเติม |
256
+
257
+ ### ขั้นตอนที่ 3: ใช้ useSettings() hook (ถ้าต้องการ)
179
258
 
180
259
  ```tsx
181
260
  import { useSettings } from 'gov-layout';
182
261
 
183
262
  function MyComponent() {
184
- const { theme, toggleTheme, fontSize, setFontSize } = useSettings();
185
- return <p>ธีม: {theme} | ฟอนต์: {fontSize}</p>;
186
- }
187
- ```
188
-
189
- #### ขนาดตัวอักษร (5 ระดับ)
190
-
191
- | ค่า | Label | Scale |
192
- |-----|-------|-------|
193
- | `xsmall` | เล็กมาก | ×0.8 |
194
- | `small` | เล็ก | ×0.9 |
195
- | `medium` | กลาง (default) | ×1.0 |
196
- | `large` | ใหญ่ | ×1.2 |
197
- | `xlarge` | ใหญ่มาก | ×1.4 |
198
-
199
- #### หลักการทำงาน
200
-
201
- - **Theme** — เพิ่ม/ลบ class `dark` บน `<html>` → ใช้ CSS `html.dark` selector จัดสี
202
- - **Font size** — ปรับ `body.style.zoom`, `root.style.fontSize`, design token CSS variables ตาม scale
203
- - ค่าเก็บใน **localStorage** (`app-theme`, `app-font-size`) จำค่าได้เมื่อ reload
204
-
205
- #### Dark mode CSS ที่ต้องเพิ่มในโปรเจกต์
263
+ const { theme, toggleTheme, fontSize, setFontSize, fontSizeOption } = useSettings();
206
264
 
207
- ```css
208
- /* globals.css */
209
- html.dark body { background-color: #0f172a; color: #f1f5f9; }
210
- html.dark aside { background-color: #1e293b !important; }
211
- html.dark header { background-color: #1e293b !important; }
212
- html.dark h1, html.dark h2, html.dark h3 { color: #f1f5f9 !important; }
213
- html.dark p { color: #94a3b8 !important; }
265
+ return (
266
+ <div>
267
+ <p>ธีม: {theme}</p>
268
+ <p>ฟอนต์: {fontSize} {fontSizeOption.scale})</p>
269
+ <button onClick={toggleTheme}>สลับธีม</button>
270
+ <button onClick={() => setFontSize('large')}>ฟอนต์ใหญ่</button>
271
+ </div>
272
+ );
273
+ }
214
274
  ```
215
275
 
216
- ---
276
+ ### ขนาดตัวอักษร (5 ระดับ)
217
277
 
218
- ## 🔧 Sub-Components
219
-
220
- ใช้แยกกันได้ถ้าต้องการ customize
221
-
222
- ```tsx
223
- import {
224
- SidebarHeader, // logo + ชื่อองค์กร
225
- SidebarMenu, // เมนู dropdown
226
- SidebarUserProfile // avatar + logout
227
- } from 'gov-layout';
228
- ```
278
+ | ค่า | Label | Scale | ผลลัพธ์ |
279
+ |-----|-------|-------|---------|
280
+ | `xsmall` | เล็กมาก | ×0.8 | ย่อทุกอย่าง 80% |
281
+ | `small` | เล็ก | ×0.9 | ย่อเล็กน้อย |
282
+ | `medium` | กลาง | ×1.0 | ค่าเริ่มต้น |
283
+ | `large` | ใหญ่ | ×1.2 | ขยาย 120% |
284
+ | `xlarge` | ใหญ่มาก | ×1.4 | ขยาย 140% |
229
285
 
230
- ---
286
+ ### หลักการทำงาน
231
287
 
232
- ## 🎨 Styling
288
+ - **Theme** — เพิ่ม/ลบ class `dark` บน `<html>` ➜ ใช้ CSS `html.dark` จัดสี
289
+ - **Font size** — ปรับ `body.style.zoom` + CSS variables ตาม scale
290
+ - **Persistence** — เก็บใน localStorage (`app-theme`, `app-font-size`)
233
291
 
234
- Components ใช้ **inline styles** + CSS variables จาก `gov-token-css`:
292
+ ### Dark mode CSS ที่ต้องเพิ่ม
235
293
 
236
294
  ```css
237
- /* ใน globals.css */
238
- @import "gov-token-css";
295
+ /* globals.css — เพิ่มสำหรับ dark mode */
296
+ html.dark body { background-color: #0f172a; color: #f1f5f9; }
297
+ html.dark aside { background-color: #1e293b !important; }
298
+ html.dark header { background-color: #1e293b !important; }
299
+ html.dark h1,
300
+ html.dark h2,
301
+ html.dark h3 { color: #f1f5f9 !important; }
302
+ html.dark p { color: #94a3b8 !important; }
239
303
  ```
240
304
 
241
- ถ้าไม่ได้ import `gov-token-css` จะใช้สี fallback อัตโนมัติ
242
-
243
305
  ---
244
306
 
245
307
  ## 📐 Types
246
308
 
247
309
  ```ts
310
+ // เมนู
248
311
  interface MenuItem {
249
312
  id: string;
250
313
  title: string;
251
- path?: string;
252
- icon?: React.ReactNode;
253
- children?: MenuItem[]; // submenu
254
- dividerAfter?: boolean; // เส้นคั่น
314
+ path?: string; // path สำหรับ navigate
315
+ icon?: React.ReactNode; // icon component
316
+ children?: MenuItem[]; // submenu → แสดงเป็น dropdown
317
+ dividerAfter?: boolean; // เส้นคั่นด้านล่าง
255
318
  }
256
319
 
320
+ // ผู้ใช้
257
321
  interface User {
258
322
  id?: string | number;
259
323
  firstName?: string;
@@ -262,6 +326,7 @@ interface User {
262
326
  role?: string;
263
327
  }
264
328
 
329
+ // การแจ้งเตือน
265
330
  interface NotificationItem {
266
331
  id: string | number;
267
332
  title: string;
@@ -271,36 +336,109 @@ interface NotificationItem {
271
336
  isRead: boolean;
272
337
  }
273
338
 
339
+ // ตั้งค่า
274
340
  type Theme = 'light' | 'dark';
275
341
  type FontSizeKey = 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
276
342
  ```
277
343
 
278
344
  ---
279
345
 
280
- ## 📁 Layout Example
346
+ ## 📁 Layout Examples
347
+
348
+ ### Staff Layout (เจ้าหน้าที่)
281
349
 
282
350
  ```tsx
283
- // Staff Layout (เจ้าหน้าที่)
351
+ 'use client';
352
+ import { StaffSidebar, SettingsPanel } from 'gov-layout';
353
+
284
354
  export default function AdminLayout({ children }) {
355
+ const [currentPath, setCurrentPath] = useState('/');
356
+
285
357
  return (
286
358
  <div style={{ display: 'flex' }}>
287
- <StaffSidebar collapsible ... />
288
- <main style={{ marginLeft: '280px', flex: 1 }}>
289
- {children}
359
+ <StaffSidebar
360
+ orgLogo="/logo.png"
361
+ orgName="เทศบาลตำบลหลักเมือง"
362
+ orgSubtitle="จังหวัดราชบุรี"
363
+ menuItems={menuItems}
364
+ user={user}
365
+ roleLabel="เจ้าหน้าที่"
366
+ currentPath={currentPath}
367
+ onNavigate={(path) => setCurrentPath(path)}
368
+ onLogout={() => signOut()}
369
+ collapsible
370
+ />
371
+ <main style={{ marginLeft: 280, flex: 1, padding: 32 }}>
372
+ {currentPath === '/settings' ? (
373
+ <SettingsPanel showTheme={false} />
374
+ ) : (
375
+ children
376
+ )}
290
377
  </main>
291
378
  </div>
292
379
  );
293
380
  }
381
+ ```
382
+
383
+ ### User Layout (ผู้ใช้ทั่วไป)
384
+
385
+ ```tsx
386
+ 'use client';
387
+ import { UserHeader, UserSidebar, SettingsPanel } from 'gov-layout';
294
388
 
295
- // User Layout (ผู้ใช้ทั่วไป)
296
389
  export default function UserLayout({ children }) {
297
390
  const [open, setOpen] = useState(false);
391
+ const [currentPath, setCurrentPath] = useState('/');
392
+
298
393
  return (
299
394
  <>
300
- <UserHeader onToggleSidebar={() => setOpen(true)} ... />
301
- <UserSidebar isOpen={open} onClose={() => setOpen(false)} ... />
302
- <main>{children}</main>
395
+ <UserHeader
396
+ user={user}
397
+ notifications={notifications}
398
+ onToggleSidebar={() => setOpen(true)}
399
+ />
400
+ <UserSidebar
401
+ isOpen={open}
402
+ onClose={() => setOpen(false)}
403
+ user={user}
404
+ roleLabel="ผู้ใช้ทั่วไป"
405
+ menuItems={menuItems}
406
+ onNavigate={(path) => setCurrentPath(path)}
407
+ onLogout={() => signOut()}
408
+ />
409
+ <main style={{ padding: 32 }}>
410
+ {currentPath === '/settings' ? (
411
+ <SettingsPanel showTheme={true} />
412
+ ) : (
413
+ children
414
+ )}
415
+ </main>
303
416
  </>
304
417
  );
305
418
  }
306
419
  ```
420
+
421
+ ---
422
+
423
+ ## 🔧 Sub-Components
424
+
425
+ ใช้แยกกันได้ถ้าต้องการ customize เฉพาะส่วน
426
+
427
+ ```tsx
428
+ import {
429
+ SidebarHeader, // logo + ชื่อองค์กร
430
+ SidebarMenu, // เมนู dropdown
431
+ SidebarUserProfile, // avatar + logout
432
+ ThemeSettings, // UI เลือก theme อย่างเดียว
433
+ FontSizeSettings, // UI เลือก font size อย่างเดียว
434
+ } from 'gov-layout';
435
+ ```
436
+
437
+ ---
438
+
439
+ ## 🎨 Styling
440
+
441
+ - Components ใช้ **inline styles** + CSS variables จาก `gov-token-css`
442
+ - ถ้าไม่ได้ import `gov-token-css` จะใช้สี **fallback** อัตโนมัติ
443
+ - Dark mode ต้องเพิ่ม CSS เอง (ดู section Dark mode CSS ด้านบน)
444
+ - Font size ใช้ `body.style.zoom` → scale ทุกอย่างรวมถึง inline `px`
package/dist/index.js CHANGED
@@ -227,7 +227,6 @@ function MenuItemComponent({
227
227
  }
228
228
  function SidebarMenu({ menuItems, onItemClick, currentPath, collapsed }) {
229
229
  return /* @__PURE__ */ jsxRuntime.jsx("nav", { style: {
230
- flex: collapsed ? void 0 : 1,
231
230
  padding: collapsed ? "8px 8px" : "8px 12px",
232
231
  overflowY: "auto"
233
232
  }, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { style: {
@@ -563,6 +562,7 @@ function StaffSidebar({
563
562
  collapsed
564
563
  }
565
564
  ),
565
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1 } }),
566
566
  /* @__PURE__ */ jsxRuntime.jsx(
567
567
  SidebarUserProfile,
568
568
  {