@suphark/ui 0.10.0 → 0.11.1

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/CHANGELOG.md CHANGED
@@ -2,12 +2,25 @@
2
2
 
3
3
  รูปแบบตาม [Keep a Changelog](https://keepachangelog.com/) · semver: patch = หน้าตา/บั๊ก, minor = component/prop ใหม่, major = เปลี่ยน/ลบ props
4
4
 
5
+ ## [0.11.1] — 2026-09-22
6
+
7
+ ### Changed
8
+
9
+ - `SubNav` (AppShell layout top): หัวกลุ่มกับรายการเคยเป็นสี muted เท่ากันจนแยกไม่ออก (ผู้ใช้ Pi Auth ชี้ในหน้า Settings) → หัวกลุ่มเป็น `text-[0.7rem] font-semibold uppercase tracking-wider text-muted-foreground/70`, รายการที่ไม่ active เป็น `text-foreground/80` (hover `text-foreground`), กลุ่มที่ 2 ขึ้นไปมีเส้นคั่น `border-t border-border/60` + `pt-3`; active และ `<select>` บนจอแคบคงเดิม — ไม่มี prop ใหม่ (ขอจาก Pi Auth)
10
+
11
+ ## [0.11.0] — 2026-09-21
12
+
13
+ ### Added
14
+
15
+ - `AppShell` (layout sidebar): slot **`sidebarContentBefore`** / **`sidebarContentAfter`** วางใน `SidebarContent` ก่อน/หลังเมนู — เลื่อนไปกับเมนู (ต่างจาก `sidebarHeader` ที่ตรึงบน) ซ่อนอัตโนมัติเมื่อยุบเป็นไอคอน; สำหรับต้นไม้โฟลเดอร์ + ถังขยะ + มิเตอร์พื้นที่แบบ Google Drive (ขอจาก Pi Files — เดิมต้องยัดใน `sidebarHeader` แล้วจำกัด max-h เอง)
16
+ - showcase: `/shell` ใส่ `TreeView` + `ProgressBar` ใน `sidebarContentAfter` เป็นตัวอย่าง (`app/shell/sidebar-drive.tsx`)
17
+
5
18
  ## [0.10.0] — 2026-09-21
6
19
 
7
20
  ### Added
8
21
 
9
22
  - **`SectionNav`** (`@suphark/ui/next`, สเปกจาก Pi Auth — ชิ้นสุดท้ายที่แอปยังประกอบเอง) — หัวหมวด + แถบแท็บย่อยใต้หัวข้อสำหรับ layout ของหมวดที่มีหลายหน้า (directory/access/security/integrations): `title`/`description`/`actions` ส่งต่อ `PageHeader`, `tabs[{ href? | slug?, label, exact?, badge? }]` (href หรือ `${base}/${slug}`), แต่ละแท็บเป็น `NavLink` (`-mb-px border-b-2` ไฮไลต์ `border-primary` ตาม pathname, `aria-current=page`), badge ต่อท้าย label, `navLabel` (ค่าเริ่มต้น `UiText.sectionNav.tabs` — "แท็บย่อย"/"Section tabs"), ไม่มี tabs = ไม่มี nav; ไม่มี state ใช้จาก server component ได้ (เฉพาะแถบ `<nav>` เป็น client component เล็ก ๆ เพื่ออ่าน UiText); types `SectionNavProps`, `SectionNavTab`; `UiText.sectionNav` (optional)
10
- - showcase: หน้า `section-nav` — 97 หน้า; tests 3 กรณี (รวม 126)
23
+ - showcase: หน้า `section-nav` (แท็บชี้หน้าจริงในหมวดนำทาง — Link prefetch จะไม่ 404) — 97 หน้า; tests 3 กรณี (รวม 126)
11
24
 
12
25
  ## [0.9.0] — 2026-09-21
13
26
 
package/README.md CHANGED
@@ -129,6 +129,7 @@ export default async function Layout({ children }) {
129
129
  - `header={false}` ไม่มี header · `collapsible="offcanvas"` ซ่อนทั้งแผง (supplychain) · `contentMaxWidth="max-w-5xl"` จำกัดความกว้าง (Pi Auth)
130
130
  - `pin={{ pinnedHrefs, onTogglePin }}` เปิดปุ่มปักหมุดเมนู (แอปเก็บ state เอง) · `header.center` วาง pinned menus
131
131
  - `sidebarHeader` ซ่อนอัตโนมัติเมื่อยุบเป็นไอคอน — ใส่ `sidebarHeaderCollapsed` ถ้าต้องการไอคอนแทน (เช่นปุ่ม ⌘K)
132
+ - ของที่ต้องเลื่อนไปกับเมนู (ต้นไม้โฟลเดอร์ยาว, มิเตอร์พื้นที่) ใส่ `sidebarContentBefore` / `sidebarContentAfter` (อยู่ใน SidebarContent) — `sidebarHeader` ตรึงอยู่บนไม่เลื่อน
132
133
  - `header.breadcrumbs.labels` รับฟังก์ชัน `(segment, href) => ReactNode` ได้ (ใส่ `t()` ของ next-intl) — **แต่ฟังก์ชันส่งจาก server layout ไม่ได้** (React error "Functions cannot be passed directly to Client Components") ให้ทำ client component ที่เรียก `<HeaderBreadcrumbs labels={…} />` แล้วส่งเป็น `breadcrumbs: <MyBreadcrumbs />` (ดู `apps/showcase/src/app/shell/breadcrumbs.tsx`)
133
134
  - `<UserMenu>` children คือรายการเมนู: `ThemeMenuItems` มี `DropdownMenuGroup` + หัว "ธีม" ในตัวแล้ว (ปรับข้อความด้วย `label`/`labels`) ไม่ต้องห่อเพิ่ม; รายการอื่นใส่ `DropdownMenuItem`/`DropdownMenuGroup` เอง
134
135
  - ตัวอย่างรันได้ที่ `apps/showcase/src/app/shell`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suphark/ui",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Design system กลางของ Suphark apps: shadcn/ui (base-nova, Base UI, Tailwind v4) + shared components + token/ฟอนต์ Noto Sans Thai Looped — ส่งเป็น source ให้แอป Next transpile เอง",
@@ -65,6 +65,12 @@ export interface AppShellProps {
65
65
  sidebarHeader?: ReactNode;
66
66
  /** สิ่งที่แสดงแทน `sidebarHeader` ตอนยุบเป็นไอคอน (เช่นปุ่มไอคอน ⌘K) — ไม่ส่ง = ไม่แสดงอะไร */
67
67
  sidebarHeaderCollapsed?: ReactNode;
68
+ /**
69
+ * ส่วนเพิ่มใน `SidebarContent` ก่อน/หลังเมนู — เลื่อนไปกับเมนู (ต่างจาก `sidebarHeader` ที่ตรึงอยู่บน)
70
+ * เช่น ต้นไม้โฟลเดอร์ + มิเตอร์พื้นที่แบบ Drive (Pi Files); ซ่อนอัตโนมัติเมื่อยุบเป็นไอคอน
71
+ */
72
+ sidebarContentBefore?: ReactNode;
73
+ sidebarContentAfter?: ReactNode;
68
74
  /** ท้าย sidebar — ปกติคือ `<UserMenu variant="sidebar" />` */
69
75
  sidebarFooter?: ReactNode;
70
76
  /**
@@ -137,6 +143,8 @@ function SidebarShell({
137
143
  pin,
138
144
  sidebarHeader,
139
145
  sidebarHeaderCollapsed,
146
+ sidebarContentBefore,
147
+ sidebarContentAfter,
140
148
  sidebarFooter,
141
149
  header = true,
142
150
  brandColor,
@@ -176,6 +184,8 @@ function SidebarShell({
176
184
  pin={pin}
177
185
  sidebarHeader={sidebarHeader}
178
186
  sidebarHeaderCollapsed={sidebarHeaderCollapsed}
187
+ sidebarContentBefore={sidebarContentBefore}
188
+ sidebarContentAfter={sidebarContentAfter}
179
189
  sidebarFooter={sidebarFooter}
180
190
  collapsible={collapsible}
181
191
  />
@@ -344,6 +354,8 @@ function ShellSidebar({
344
354
  pin,
345
355
  sidebarHeader,
346
356
  sidebarHeaderCollapsed,
357
+ sidebarContentBefore,
358
+ sidebarContentAfter,
347
359
  sidebarFooter,
348
360
  collapsible,
349
361
  }: Pick<
@@ -355,6 +367,8 @@ function ShellSidebar({
355
367
  | "pin"
356
368
  | "sidebarHeader"
357
369
  | "sidebarHeaderCollapsed"
370
+ | "sidebarContentBefore"
371
+ | "sidebarContentAfter"
358
372
  | "sidebarFooter"
359
373
  | "collapsible"
360
374
  >) {
@@ -407,7 +421,13 @@ function ShellSidebar({
407
421
  )}
408
422
  </SidebarHeader>
409
423
  <SidebarContent>
424
+ {sidebarContentBefore && (
425
+ <div className="px-2 group-data-[collapsible=icon]:hidden">{sidebarContentBefore}</div>
426
+ )}
410
427
  <AppNav nav={visibleNav} pin={pin} forceOpen={searching} />
428
+ {sidebarContentAfter && (
429
+ <div className="px-2 group-data-[collapsible=icon]:hidden">{sidebarContentAfter}</div>
430
+ )}
411
431
  </SidebarContent>
412
432
  {sidebarFooter && <SidebarFooter>{sidebarFooter}</SidebarFooter>}
413
433
  {collapsible !== "none" && <SidebarRail />}
@@ -106,9 +106,13 @@ export function SubNav({
106
106
  )}
107
107
  {sections.map((s, si) => (
108
108
  // biome-ignore lint/suspicious/noArrayIndexKey: กลุ่มคงที่
109
- <div key={si} className="flex flex-col gap-0.5">
109
+ <div
110
+ key={si}
111
+ className={cn("flex flex-col gap-0.5", si > 0 && "border-border/60 border-t pt-3")}
112
+ >
113
+ {/* หัวกลุ่มแบบ Clerk/Linear — ตัวเล็ก uppercase จางกว่ารายการ ให้แยกจากรายการได้ชัด (ขอจาก Pi Auth) */}
110
114
  {s.title && (
111
- <p className="px-2 pt-1 pb-0.5 font-medium text-muted-foreground text-xs">
115
+ <p className="px-2 pt-1 pb-1 font-semibold text-[0.7rem] text-muted-foreground/70 uppercase tracking-wider">
112
116
  {s.title}
113
117
  </p>
114
118
  )}
@@ -123,7 +127,7 @@ export function SubNav({
123
127
  "flex items-center gap-2 rounded-md px-2 py-1.5 text-sm no-underline outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring/50 [&_svg:not([class*='size-'])]:size-4",
124
128
  active
125
129
  ? "bg-accent font-medium text-accent-foreground"
126
- : "text-muted-foreground hover:bg-accent/60 hover:text-foreground",
130
+ : "text-foreground/80 hover:bg-accent/60 hover:text-foreground",
127
131
  )}
128
132
  >
129
133
  {i.icon}