@godxjp/ui 5.0.2 → 6.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.
Files changed (298) hide show
  1. package/README.md +101 -142
  2. package/package.json +124 -128
  3. package/scripts/ui-audit.mjs +179 -0
  4. package/src/app/__tests__/app-provider.test.tsx +232 -0
  5. package/src/app/__tests__/date-format-labels.test.ts +36 -0
  6. package/src/app/__tests__/date-formats.test.ts +44 -0
  7. package/src/app/__tests__/timezones.test.ts +65 -0
  8. package/src/app/app-provider.tsx +227 -0
  9. package/src/app/date-format-labels.ts +21 -0
  10. package/src/app/date-formats.ts +30 -0
  11. package/src/app/index.ts +40 -0
  12. package/src/app/locales.ts +32 -0
  13. package/src/app/request-headers.ts +31 -0
  14. package/src/app/storage.ts +44 -0
  15. package/src/app/time-format-labels.ts +19 -0
  16. package/src/app/time-formats.ts +15 -0
  17. package/src/app/timezones.ts +208 -0
  18. package/src/app/types.ts +39 -0
  19. package/src/app/use-formatting.ts +47 -0
  20. package/src/components/__tests__/accessibility-primitives.test.tsx +65 -0
  21. package/src/components/__tests__/docs-parity.test.ts +41 -0
  22. package/src/components/__tests__/shadcn-release-guardrails.test.ts +71 -0
  23. package/src/components/__tests__/theme-axes-integration.test.tsx +242 -0
  24. package/src/components/admin/index.ts +76 -0
  25. package/src/components/data-display/__tests__/card-table.test.tsx +328 -0
  26. package/src/components/data-display/__tests__/data-display.test.tsx +73 -0
  27. package/src/components/data-display/__tests__/data-table.test.tsx +84 -0
  28. package/src/components/data-display/__tests__/popover.test.tsx +92 -0
  29. package/src/components/data-display/__tests__/scroll-area-collapsible.test.tsx +66 -0
  30. package/src/components/data-display/badge.tsx +27 -0
  31. package/src/components/data-display/card.tsx +194 -0
  32. package/src/components/data-display/code-badge.tsx +28 -0
  33. package/src/components/data-display/collapsible.tsx +5 -0
  34. package/src/components/data-display/data-table.tsx +476 -0
  35. package/src/components/data-display/empty-state.tsx +22 -0
  36. package/src/components/data-display/index.ts +41 -0
  37. package/src/components/data-display/key-value-grid.tsx +46 -0
  38. package/src/components/data-display/popover.tsx +62 -0
  39. package/src/components/data-display/progress-meter.tsx +20 -0
  40. package/src/components/data-display/scan-panel.tsx +16 -0
  41. package/src/components/data-display/scroll-area.tsx +42 -0
  42. package/src/components/data-display/status-badge.tsx +83 -0
  43. package/src/components/data-display/table.tsx +59 -0
  44. package/src/components/data-display/timeline.tsx +42 -0
  45. package/src/components/data-display/tree-list.tsx +42 -0
  46. package/src/components/data-entry/__fixtures__/tree-options.ts +80 -0
  47. package/src/components/data-entry/__tests__/cascader-tree-transfer.test.tsx +417 -0
  48. package/src/components/data-entry/__tests__/checkbox-group.test.tsx +40 -0
  49. package/src/components/data-entry/__tests__/checkbox.test.tsx +20 -0
  50. package/src/components/data-entry/__tests__/date-autocomplete.test.tsx +94 -0
  51. package/src/components/data-entry/__tests__/form-field.test.tsx +49 -0
  52. package/src/components/data-entry/__tests__/input-textarea.test.tsx +38 -0
  53. package/src/components/data-entry/__tests__/label-select.test.tsx +62 -0
  54. package/src/components/data-entry/__tests__/pickers.test.tsx +74 -0
  55. package/src/components/data-entry/__tests__/radio.test.tsx +46 -0
  56. package/src/components/data-entry/__tests__/search-input.test.tsx +32 -0
  57. package/src/components/data-entry/__tests__/switch-field.test.tsx +52 -0
  58. package/src/components/data-entry/__tests__/upload.test.tsx +125 -0
  59. package/src/components/data-entry/autocomplete.tsx +91 -0
  60. package/src/components/data-entry/calendar.tsx +90 -0
  61. package/src/components/data-entry/cascader.tsx +305 -0
  62. package/src/components/data-entry/checkbox-group.tsx +90 -0
  63. package/src/components/data-entry/checkbox.tsx +30 -0
  64. package/src/components/data-entry/choice-field.tsx +27 -0
  65. package/src/components/data-entry/choice-option.ts +20 -0
  66. package/src/components/data-entry/color-picker.tsx +75 -0
  67. package/src/components/data-entry/command.tsx +56 -0
  68. package/src/components/data-entry/country-select.tsx +88 -0
  69. package/src/components/data-entry/date-picker.tsx +69 -0
  70. package/src/components/data-entry/date-range-picker.tsx +75 -0
  71. package/src/components/data-entry/form-field.tsx +59 -0
  72. package/src/components/data-entry/index.ts +62 -0
  73. package/src/components/data-entry/input.tsx +26 -0
  74. package/src/components/data-entry/label.tsx +25 -0
  75. package/src/components/data-entry/radio.tsx +109 -0
  76. package/src/components/data-entry/search-input.tsx +103 -0
  77. package/src/components/data-entry/select.tsx +149 -0
  78. package/src/components/data-entry/slider.tsx +38 -0
  79. package/src/components/data-entry/switch-field.tsx +91 -0
  80. package/src/components/data-entry/switch.tsx +24 -0
  81. package/src/components/data-entry/textarea.tsx +12 -0
  82. package/src/components/data-entry/time-picker.tsx +214 -0
  83. package/src/components/data-entry/transfer.tsx +231 -0
  84. package/src/components/data-entry/tree-select-strategy.ts +6 -0
  85. package/src/components/data-entry/tree-select.tsx +279 -0
  86. package/src/components/data-entry/tree-utils.ts +221 -0
  87. package/src/components/data-entry/upload-crop-dialog.tsx +109 -0
  88. package/src/components/data-entry/upload-types.ts +86 -0
  89. package/src/components/data-entry/upload.tsx +498 -0
  90. package/src/components/data-entry/use-upload-draft.ts +93 -0
  91. package/src/components/feedback/__tests__/alert.test.tsx +127 -0
  92. package/src/components/feedback/__tests__/dialog.test.tsx +290 -0
  93. package/src/components/feedback/__tests__/sheet.test.tsx +94 -0
  94. package/src/components/feedback/__tests__/skeleton.test.tsx +25 -0
  95. package/src/components/feedback/__tests__/toast.test.tsx +52 -0
  96. package/src/components/feedback/alert.tsx +167 -0
  97. package/src/components/feedback/dialog.tsx +325 -0
  98. package/src/components/feedback/index.ts +53 -0
  99. package/src/components/feedback/sheet.tsx +130 -0
  100. package/src/components/feedback/skeleton.tsx +95 -0
  101. package/src/components/feedback/sonner.tsx +54 -0
  102. package/src/components/feedback/toaster.tsx +1 -0
  103. package/src/components/feedback/use-toast.ts +62 -0
  104. package/src/components/general/__tests__/button.test.tsx +71 -0
  105. package/src/components/general/button.tsx +61 -0
  106. package/src/components/general/index.ts +2 -0
  107. package/src/components/layout/__tests__/page-container.test.tsx +69 -0
  108. package/src/components/layout/__tests__/page-inset.test.tsx +14 -0
  109. package/src/components/layout/__tests__/stack-inline.test.tsx +39 -0
  110. package/src/components/layout/app-shell.tsx +42 -0
  111. package/src/components/layout/breadcrumb.tsx +35 -0
  112. package/src/components/layout/index.ts +31 -0
  113. package/src/components/layout/inline.tsx +13 -0
  114. package/src/components/layout/menu.tsx +34 -0
  115. package/src/components/layout/mobile-frame.tsx +57 -0
  116. package/src/components/layout/page-container.tsx +81 -0
  117. package/src/components/layout/page-inset.tsx +16 -0
  118. package/src/components/layout/responsive-grid.tsx +14 -0
  119. package/src/components/layout/shell-app.tsx +30 -0
  120. package/src/components/layout/sidebar.tsx +98 -0
  121. package/src/components/layout/split-pane.tsx +16 -0
  122. package/src/components/layout/stack.tsx +13 -0
  123. package/src/components/layout/topbar.tsx +108 -0
  124. package/src/components/navigation/__tests__/app-pickers.test.tsx +118 -0
  125. package/src/components/navigation/__tests__/dropdown-menu.test.tsx +104 -0
  126. package/src/components/navigation/__tests__/navigation.test.tsx +61 -0
  127. package/src/components/navigation/__tests__/pagination-steps-tabs.test.tsx +76 -0
  128. package/src/components/navigation/date-format-picker.tsx +55 -0
  129. package/src/components/navigation/dropdown-menu.tsx +190 -0
  130. package/src/components/navigation/filter-bar.tsx +38 -0
  131. package/src/components/navigation/index.ts +28 -0
  132. package/src/components/navigation/locale-picker.tsx +49 -0
  133. package/src/components/navigation/page-header.tsx +50 -0
  134. package/src/components/navigation/pagination-utils.ts +35 -0
  135. package/src/components/navigation/pagination.tsx +168 -0
  136. package/src/components/navigation/steps.tsx +163 -0
  137. package/src/components/navigation/tabs-items.tsx +69 -0
  138. package/src/components/navigation/tabs.tsx +67 -0
  139. package/src/components/navigation/time-format-picker.tsx +55 -0
  140. package/src/components/navigation/timezone-picker.tsx +63 -0
  141. package/src/components/query/__tests__/data-state.test.tsx +214 -0
  142. package/src/components/query/__tests__/infinite-prefetch.test.tsx +105 -0
  143. package/src/components/query/__tests__/query-helpers.test.tsx +61 -0
  144. package/src/components/query/data-state.tsx +58 -0
  145. package/src/components/query/index.ts +10 -0
  146. package/src/components/query/infinite-query-state.tsx +99 -0
  147. package/src/components/query/mutation-feedback.tsx +31 -0
  148. package/src/components/query/prefetch-link.tsx +45 -0
  149. package/src/components/query/query-refetch-button.tsx +41 -0
  150. package/src/components/ui/alert-dialog.tsx +1 -0
  151. package/src/components/ui/alert.tsx +1 -0
  152. package/src/components/ui/autocomplete.tsx +1 -0
  153. package/src/components/ui/badge.tsx +1 -0
  154. package/src/components/ui/button.tsx +1 -0
  155. package/src/components/ui/calendar.tsx +1 -0
  156. package/src/components/ui/card.tsx +1 -0
  157. package/src/components/ui/checkbox.tsx +1 -0
  158. package/src/components/ui/color-picker.tsx +1 -0
  159. package/src/components/ui/command.tsx +1 -0
  160. package/src/components/ui/date-picker.tsx +1 -0
  161. package/src/components/ui/date-range-picker.tsx +1 -0
  162. package/src/components/ui/dialog.tsx +1 -0
  163. package/src/components/ui/dropdown-menu.tsx +1 -0
  164. package/src/components/ui/index.tsx +31 -0
  165. package/src/components/ui/input.tsx +1 -0
  166. package/src/components/ui/label.tsx +1 -0
  167. package/src/components/ui/pagination.tsx +1 -0
  168. package/src/components/ui/popover.tsx +1 -0
  169. package/src/components/ui/radio.tsx +1 -0
  170. package/src/components/ui/scroll-area.tsx +1 -0
  171. package/src/components/ui/select.tsx +1 -0
  172. package/src/components/ui/sheet.tsx +1 -0
  173. package/src/components/ui/slider.tsx +1 -0
  174. package/src/components/ui/sonner.tsx +1 -0
  175. package/src/components/ui/switch.tsx +1 -0
  176. package/src/components/ui/table.tsx +1 -0
  177. package/src/components/ui/tabs-items.tsx +1 -0
  178. package/src/components/ui/tabs.tsx +1 -0
  179. package/src/components/ui/textarea.tsx +1 -0
  180. package/src/components/ui/time-picker.tsx +1 -0
  181. package/src/components/ui/upload.tsx +1 -0
  182. package/src/form/__tests__/use-zod-form.test.tsx +97 -0
  183. package/src/form/form-field-control.tsx +44 -0
  184. package/src/form/form-root.tsx +29 -0
  185. package/src/form/index.ts +7 -0
  186. package/src/form/use-zod-form.ts +29 -0
  187. package/src/i18n/__tests__/translate.test.ts +23 -0
  188. package/src/i18n/index.ts +9 -0
  189. package/src/i18n/messages/en.json +171 -0
  190. package/src/i18n/messages/ja.json +171 -0
  191. package/src/i18n/messages/vi.json +171 -0
  192. package/src/i18n/translate.ts +74 -0
  193. package/src/i18n/use-translation.ts +53 -0
  194. package/src/index.ts +3 -0
  195. package/src/lib/__tests__/control-styles.test.ts +78 -0
  196. package/src/lib/__tests__/datetime.test.ts +77 -0
  197. package/src/lib/__tests__/format-date.test.ts +97 -0
  198. package/src/lib/__tests__/format.test.ts +62 -0
  199. package/src/lib/__tests__/theme-tokens-audit.test.ts +176 -0
  200. package/src/lib/__tests__/theme-tokens-css.test.ts +118 -0
  201. package/src/lib/__tests__/token-governance.test.ts +191 -0
  202. package/src/lib/__tests__/variants.test.ts +18 -0
  203. package/src/lib/control-styles.ts +33 -0
  204. package/src/lib/datetime/detect.ts +25 -0
  205. package/src/lib/datetime/format-date.ts +100 -0
  206. package/src/lib/datetime/format.ts +140 -0
  207. package/src/lib/datetime/index.ts +25 -0
  208. package/src/lib/datetime/parse.ts +51 -0
  209. package/src/lib/datetime/sync.ts +48 -0
  210. package/src/lib/format.ts +114 -0
  211. package/src/lib/hooks.ts +54 -0
  212. package/src/lib/utils.ts +6 -0
  213. package/src/lib/variants.ts +40 -0
  214. package/src/props/components/app.prop.ts +99 -0
  215. package/src/props/components/data-display.prop.ts +73 -0
  216. package/src/props/components/data-entry.prop.ts +334 -0
  217. package/src/props/components/feedback.prop.ts +80 -0
  218. package/src/props/components/form.prop.ts +46 -0
  219. package/src/props/components/general.prop.ts +18 -0
  220. package/src/props/components/index.ts +99 -0
  221. package/src/props/components/layout.prop.ts +130 -0
  222. package/src/props/components/navigation.prop.ts +88 -0
  223. package/src/props/components/query.prop.ts +94 -0
  224. package/src/props/index.ts +17 -0
  225. package/src/props/registry.ts +603 -0
  226. package/src/props/vocabulary/content.prop.ts +35 -0
  227. package/src/props/vocabulary/data.prop.ts +46 -0
  228. package/src/props/vocabulary/index.ts +73 -0
  229. package/src/props/vocabulary/interaction.prop.ts +42 -0
  230. package/src/props/vocabulary/layout.prop.ts +25 -0
  231. package/src/props/vocabulary/navigation.prop.ts +19 -0
  232. package/src/props/vocabulary/shared.prop.ts +59 -0
  233. package/src/styles/alert-layout.css +191 -0
  234. package/src/styles/badge-layout.css +22 -0
  235. package/src/styles/card-layout.css +373 -0
  236. package/src/styles/control.css +504 -0
  237. package/src/styles/data-display-layout.css +246 -0
  238. package/src/styles/density.css +43 -0
  239. package/src/styles/dialog-layout.css +84 -0
  240. package/src/styles/index.css +105 -0
  241. package/src/styles/layout.css +479 -0
  242. package/src/styles/shell-layout.css +604 -0
  243. package/src/styles/table-layout.css +109 -0
  244. package/src/test/__tests__/render-loop-guard.test.tsx +38 -0
  245. package/src/test/jest-dom.d.ts +4 -0
  246. package/src/test/render-loop-guard.tsx +50 -0
  247. package/src/test/render.tsx +29 -0
  248. package/src/test/theme-globals.test.ts +77 -0
  249. package/src/test/theme-globals.ts +134 -0
  250. package/src/test/theme-test-utils.tsx +67 -0
  251. package/src/theme/example.service.css +37 -0
  252. package/src/tokens/base.css +13 -0
  253. package/src/tokens/foundation.css +151 -0
  254. package/src/tokens/primitives/badge.css +13 -0
  255. package/src/tokens/primitives/card.css +29 -0
  256. package/src/tokens/primitives/control.css +55 -0
  257. package/src/tokens/primitives/feedback.css +17 -0
  258. package/src/tokens/primitives/layout.css +20 -0
  259. package/src/tokens/primitives/navigation.css +13 -0
  260. package/src/tokens/primitives/table.css +10 -0
  261. package/BRAND.md +0 -296
  262. package/CHANGELOG.md +0 -668
  263. package/config/eslint.js +0 -54
  264. package/config/prettier.cjs +0 -20
  265. package/config/tsconfig.base.json +0 -22
  266. package/config/vitest.base.ts +0 -26
  267. package/dist/MiniMonth-YAmPGEpC.d.ts +0 -143
  268. package/dist/Table.types-BbsxoIYE.d.ts +0 -352
  269. package/dist/color-DO0qqUAb.d.ts +0 -38
  270. package/dist/components/composites.d.ts +0 -963
  271. package/dist/components/composites.js +0 -7343
  272. package/dist/components/composites.js.map +0 -1
  273. package/dist/components/primitives.d.ts +0 -2744
  274. package/dist/components/primitives.js +0 -7356
  275. package/dist/components/primitives.js.map +0 -1
  276. package/dist/components/shell.d.ts +0 -182
  277. package/dist/components/shell.js +0 -774
  278. package/dist/components/shell.js.map +0 -1
  279. package/dist/hooks.d.ts +0 -100
  280. package/dist/hooks.js +0 -558
  281. package/dist/hooks.js.map +0 -1
  282. package/dist/i18n.d.ts +0 -61
  283. package/dist/i18n.js +0 -860
  284. package/dist/i18n.js.map +0 -1
  285. package/dist/index.d.ts +0 -33
  286. package/dist/index.js +0 -13062
  287. package/dist/index.js.map +0 -1
  288. package/dist/padding-DY0JV5Ja.d.ts +0 -16
  289. package/dist/preferences.d.ts +0 -132
  290. package/dist/preferences.js +0 -262
  291. package/dist/preferences.js.map +0 -1
  292. package/dist/props.d.ts +0 -86
  293. package/dist/props.js +0 -16
  294. package/dist/props.js.map +0 -1
  295. package/dist/size-CQwNvOWd.d.ts +0 -19
  296. package/dist/types-LTj-2bl-.d.ts +0 -30
  297. package/dist/useTableViews-D5NIAJ7h.d.ts +0 -154
  298. package/src/tokens/tailwind.css +0 -158
@@ -1,774 +0,0 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { ChevronDown, PanelLeftOpen, PanelLeftClose, Search, Bell, SlidersHorizontal, X, Check, Clock } from 'lucide-react';
3
- import { useTranslation } from 'react-i18next';
4
- import { clsx } from 'clsx';
5
- import { twMerge } from 'tailwind-merge';
6
- import * as Dialog from '@radix-ui/react-dialog';
7
- import { useState, useRef, useEffect, useCallback } from 'react';
8
- import i18next from 'i18next';
9
- import 'i18next-browser-languagedetector';
10
- import * as Popover from '@radix-ui/react-popover';
11
- import * as VisuallyHidden from '@radix-ui/react-visually-hidden';
12
- import { Command } from 'cmdk';
13
-
14
- // src/components/shell/AppShell.tsx
15
- function AppShell({
16
- sidebar,
17
- topbar,
18
- topbarLeft,
19
- topbarRight,
20
- logo,
21
- breadcrumb,
22
- footer,
23
- children,
24
- sidebarCollapsed = false
25
- }) {
26
- const resolvedTopbar = topbar !== void 0 ? topbar : /* @__PURE__ */ jsxs("div", { className: "app-topbar-rail", children: [
27
- logo !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-logo", children: logo }),
28
- topbarLeft !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-left", children: topbarLeft }),
29
- /* @__PURE__ */ jsx("div", { className: "app-topbar-spacer" }),
30
- topbarRight !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-right", children: topbarRight })
31
- ] });
32
- return /* @__PURE__ */ jsxs("div", { className: "app-root", "data-collapsed": sidebarCollapsed, children: [
33
- /* @__PURE__ */ jsx("aside", { className: "app-sidebar", children: sidebar }),
34
- /* @__PURE__ */ jsx("header", { className: "app-topbar", children: resolvedTopbar }),
35
- /* @__PURE__ */ jsxs("main", { className: "app-main", children: [
36
- breadcrumb !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-breadcrumb", children: breadcrumb }),
37
- children
38
- ] }),
39
- footer !== void 0 && /* @__PURE__ */ jsx("footer", { className: "app-footer", children: footer })
40
- ] });
41
- }
42
- function cn(...inputs) {
43
- return twMerge(clsx(inputs));
44
- }
45
- function Sidebar({
46
- activeId,
47
- onSelect,
48
- sections,
49
- product,
50
- onProductClick,
51
- brand,
52
- collapsed = false,
53
- footer
54
- }) {
55
- const { t } = useTranslation();
56
- return /* @__PURE__ */ jsxs("div", { className: "sb-root", "data-collapsed": collapsed ? "true" : void 0, style: { display: "contents" }, children: [
57
- brand !== void 0 ? /* @__PURE__ */ jsx("div", { className: "sb-brand", children: brand }) : product ? /* @__PURE__ */ jsxs(
58
- "button",
59
- {
60
- type: "button",
61
- className: "sb-product",
62
- onClick: onProductClick,
63
- "aria-label": product.name,
64
- children: [
65
- /* @__PURE__ */ jsx(
66
- "span",
67
- {
68
- className: "sb-logo-mark",
69
- style: { background: product.color },
70
- children: product.name[0]?.toUpperCase() ?? "?"
71
- }
72
- ),
73
- !collapsed && /* @__PURE__ */ jsxs(
74
- "span",
75
- {
76
- className: "sb-product-meta col flex-1 min-w-0",
77
- style: { display: "flex" },
78
- children: [
79
- /* @__PURE__ */ jsx("span", { className: "sb-product-name", children: product.name }),
80
- /* @__PURE__ */ jsx("span", { className: "sb-product-tenant", children: product.role })
81
- ]
82
- }
83
- ),
84
- !collapsed && /* @__PURE__ */ jsx("span", { className: "sb-product-tenant shrink-0", children: /* @__PURE__ */ jsx(ChevronDown, { size: 14 }) })
85
- ]
86
- }
87
- ) : null,
88
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: sections.map((section, i) => /* @__PURE__ */ jsxs("div", { className: "sb-section", children: [
89
- section.label && !collapsed && /* @__PURE__ */ jsx("div", { className: "sb-section-label", children: section.label }),
90
- /* @__PURE__ */ jsx("div", { className: "sb-nav", role: "navigation", children: section.items.map((item) => {
91
- const Icon = item.icon;
92
- const isActive = item.id === activeId;
93
- return /* @__PURE__ */ jsxs(
94
- "button",
95
- {
96
- type: "button",
97
- className: cn("sb-nav-item"),
98
- "data-active": isActive,
99
- "aria-label": collapsed ? item.label : void 0,
100
- "aria-current": isActive ? "page" : void 0,
101
- "aria-disabled": item.disabled,
102
- title: collapsed ? item.label : void 0,
103
- onClick: () => !item.disabled && onSelect(item.id),
104
- children: [
105
- /* @__PURE__ */ jsx("span", { className: "sb-icon", children: /* @__PURE__ */ jsx(Icon, { size: 16 }) }),
106
- !collapsed && /* @__PURE__ */ jsx("span", { className: "sb-label", children: item.label }),
107
- !collapsed && item.badge !== void 0 && item.badge !== "" && /* @__PURE__ */ jsx("span", { className: "sb-badge", children: item.badge })
108
- ]
109
- },
110
- item.id
111
- );
112
- }) })
113
- ] }, section.label ?? i)) }),
114
- footer && /* @__PURE__ */ jsx("div", { className: "sb-footer", children: footer })
115
- ] });
116
- }
117
- function Topbar({
118
- product,
119
- project,
120
- onProductOpen,
121
- onProjectOpen,
122
- onSearchOpen,
123
- onTweaksOpen,
124
- collapsed = false,
125
- onToggleCollapsed,
126
- rightSlot,
127
- unread = false,
128
- onNotificationsOpen,
129
- user
130
- }) {
131
- const { t } = useTranslation();
132
- return /* @__PURE__ */ jsxs(Fragment, { children: [
133
- onToggleCollapsed && /* @__PURE__ */ jsx(
134
- "button",
135
- {
136
- type: "button",
137
- className: "tb-icon-btn",
138
- "aria-label": t("shell.sidebarCollapse"),
139
- "aria-pressed": collapsed,
140
- onClick: onToggleCollapsed,
141
- children: collapsed ? /* @__PURE__ */ jsx(PanelLeftOpen, { size: 16 }) : /* @__PURE__ */ jsx(PanelLeftClose, { size: 16 })
142
- }
143
- ),
144
- /* @__PURE__ */ jsxs("div", { className: "tb-switcher", children: [
145
- /* @__PURE__ */ jsxs(
146
- "button",
147
- {
148
- type: "button",
149
- className: "tb-chip",
150
- "aria-label": product.name,
151
- onClick: onProductOpen,
152
- children: [
153
- /* @__PURE__ */ jsx(
154
- "span",
155
- {
156
- className: "tb-chip-icon",
157
- style: { background: product.color },
158
- children: product.name[0]?.toUpperCase() ?? "?"
159
- }
160
- ),
161
- /* @__PURE__ */ jsx("span", { className: "tb-chip-label", children: product.name }),
162
- /* @__PURE__ */ jsx("span", { className: "tb-chip-caret", children: /* @__PURE__ */ jsx(ChevronDown, { size: 12 }) })
163
- ]
164
- }
165
- ),
166
- /* @__PURE__ */ jsx("span", { className: "tb-chip-sep", children: "/" }),
167
- /* @__PURE__ */ jsxs(
168
- "button",
169
- {
170
- type: "button",
171
- className: cn("tb-chip", !project && "tb-chip-empty"),
172
- "aria-label": project ? project.name : t("shell.pickProject"),
173
- onClick: onProjectOpen,
174
- children: [
175
- /* @__PURE__ */ jsx("span", { className: "tb-chip-label", children: project ? project.name : t("shell.pickProject") }),
176
- /* @__PURE__ */ jsx("span", { className: "tb-chip-caret", children: /* @__PURE__ */ jsx(ChevronDown, { size: 12 }) })
177
- ]
178
- }
179
- )
180
- ] }),
181
- /* @__PURE__ */ jsxs(
182
- "button",
183
- {
184
- type: "button",
185
- className: "tb-search ml-auto",
186
- onClick: onSearchOpen,
187
- children: [
188
- /* @__PURE__ */ jsx(Search, { size: 14 }),
189
- /* @__PURE__ */ jsxs("span", { children: [
190
- t("common.search"),
191
- "\u2026"
192
- ] }),
193
- /* @__PURE__ */ jsx("kbd", { className: "kbd", children: "\u2318K" })
194
- ]
195
- }
196
- ),
197
- rightSlot,
198
- onNotificationsOpen && /* @__PURE__ */ jsxs(
199
- "button",
200
- {
201
- type: "button",
202
- className: "tb-icon-btn tb-bell",
203
- "aria-label": t("topbar.notifications", { defaultValue: "Notifications" }),
204
- onClick: onNotificationsOpen,
205
- children: [
206
- /* @__PURE__ */ jsx(Bell, { size: 16 }),
207
- unread && /* @__PURE__ */ jsx("span", { className: "tb-bell-dot", "aria-hidden": true })
208
- ]
209
- }
210
- ),
211
- user,
212
- onTweaksOpen && /* @__PURE__ */ jsx(
213
- "button",
214
- {
215
- type: "button",
216
- className: "tb-icon-btn",
217
- "aria-label": t("tweaks.title"),
218
- onClick: onTweaksOpen,
219
- children: /* @__PURE__ */ jsx(SlidersHorizontal, { size: 16 })
220
- }
221
- )
222
- ] });
223
- }
224
- var SUPPORTED_LOCALES = ["ja", "en", "vi", "fil"];
225
- var GODX_LOCALE_STORAGE_KEY = "godx.locale";
226
- var i18n_default = i18next;
227
-
228
- // src/hooks/useTweaks.ts
229
- var STORAGE_KEY = "godx.tweaks";
230
- var DEFAULTS = {
231
- density: "default",
232
- theme: "light",
233
- tenant: "godx",
234
- locale: "ja",
235
- sidebarCollapsed: false
236
- };
237
- function loadInitial() {
238
- if (typeof window === "undefined") return DEFAULTS;
239
- try {
240
- const raw = window.localStorage.getItem(STORAGE_KEY);
241
- const stored = raw ? JSON.parse(raw) : {};
242
- const detected = i18n_default.language?.slice(0, 2) || "ja";
243
- return {
244
- ...DEFAULTS,
245
- ...stored,
246
- locale: stored.locale ?? detected
247
- };
248
- } catch {
249
- return DEFAULTS;
250
- }
251
- }
252
- function useTweaks() {
253
- const [tweaks, setTweaks] = useState(loadInitial);
254
- useEffect(() => {
255
- try {
256
- window.localStorage.setItem(STORAGE_KEY, JSON.stringify(tweaks));
257
- } catch {
258
- }
259
- }, [tweaks]);
260
- useEffect(() => {
261
- const html = document.documentElement;
262
- html.dataset.theme = tweaks.theme;
263
- html.dataset.density = tweaks.density;
264
- html.dataset.tenant = tweaks.tenant;
265
- html.lang = tweaks.locale;
266
- }, [tweaks.theme, tweaks.density, tweaks.tenant, tweaks.locale]);
267
- useEffect(() => {
268
- if (!i18n_default.isInitialized) return;
269
- if (i18n_default.language?.slice(0, 2) !== tweaks.locale) {
270
- void i18n_default.changeLanguage(tweaks.locale);
271
- try {
272
- window.localStorage.setItem(GODX_LOCALE_STORAGE_KEY, tweaks.locale);
273
- } catch {
274
- }
275
- }
276
- }, [tweaks.locale]);
277
- const setTweak = useCallback((key, value) => {
278
- setTweaks((prev) => ({ ...prev, [key]: value }));
279
- }, []);
280
- return { tweaks, setTweak, setTweaks };
281
- }
282
- function TweaksPanel({ open, onOpenChange, products = [] }) {
283
- const { t } = useTranslation();
284
- const { tweaks, setTweak } = useTweaks();
285
- return /* @__PURE__ */ jsx(Dialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [
286
- /* @__PURE__ */ jsx(Dialog.Overlay, { className: "fixed inset-0 z-40 bg-black/30 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" }),
287
- /* @__PURE__ */ jsxs(
288
- Dialog.Content,
289
- {
290
- className: "fixed right-0 top-0 z-50 h-full w-80 bg-popover text-popover-foreground border-l border-border shadow-2xl data-[state=open]:animate-in data-[state=open]:slide-in-from-right",
291
- "aria-describedby": void 0,
292
- children: [
293
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-4 h-12", children: [
294
- /* @__PURE__ */ jsx(Dialog.Title, { className: "font-medium text-sm", children: t("tweaks.title") }),
295
- /* @__PURE__ */ jsx(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx("button", { className: "tb-icon-btn", "aria-label": "Close", children: /* @__PURE__ */ jsx(X, { size: 14 }) }) })
296
- ] }),
297
- /* @__PURE__ */ jsxs("div", { className: "overflow-y-auto h-[calc(100%-3rem)] p-4 flex flex-col gap-6", children: [
298
- /* @__PURE__ */ jsxs(Section, { label: t("tweaks.display"), children: [
299
- /* @__PURE__ */ jsx(
300
- Radio,
301
- {
302
- label: t("tweaks.density"),
303
- value: tweaks.density,
304
- onChange: (v) => setTweak("density", v),
305
- options: [
306
- { value: "compact", label: t("tweaks.densityCompact") },
307
- { value: "default", label: t("tweaks.densityDefault") },
308
- { value: "comfortable", label: t("tweaks.densityComfortable") }
309
- ]
310
- }
311
- ),
312
- /* @__PURE__ */ jsx(
313
- Radio,
314
- {
315
- label: t("tweaks.theme"),
316
- value: tweaks.theme,
317
- onChange: (v) => setTweak("theme", v),
318
- options: [
319
- { value: "light", label: t("tweaks.themeLight") },
320
- { value: "dark", label: t("tweaks.themeDark") }
321
- ]
322
- }
323
- ),
324
- /* @__PURE__ */ jsx(
325
- Toggle,
326
- {
327
- label: t("shell.sidebarCollapse"),
328
- value: tweaks.sidebarCollapsed,
329
- onChange: (v) => setTweak("sidebarCollapsed", v)
330
- }
331
- )
332
- ] }),
333
- products.length > 0 && /* @__PURE__ */ jsx(Section, { label: t("tweaks.product"), children: /* @__PURE__ */ jsx(
334
- Select,
335
- {
336
- label: t("tweaks.product"),
337
- value: tweaks.tenant,
338
- onChange: (v) => setTweak("tenant", v),
339
- options: products.map((p) => ({ value: p.tenant, label: p.name }))
340
- }
341
- ) }),
342
- /* @__PURE__ */ jsx(Section, { label: t("tweaks.locale"), children: /* @__PURE__ */ jsx(
343
- Radio,
344
- {
345
- label: t("tweaks.language"),
346
- value: tweaks.locale,
347
- onChange: (v) => setTweak("locale", v),
348
- options: SUPPORTED_LOCALES.map((code) => ({
349
- value: code,
350
- label: { ja: "\u65E5\u672C\u8A9E", en: "English", vi: "Ti\u1EBFng Vi\u1EC7t", fil: "Filipino" }[code] ?? code
351
- }))
352
- }
353
- ) })
354
- ] })
355
- ]
356
- }
357
- )
358
- ] }) });
359
- }
360
- function Section({ label, children }) {
361
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
362
- /* @__PURE__ */ jsx("div", { className: "text-[10px] font-medium uppercase tracking-wider text-muted-foreground", children: label }),
363
- children
364
- ] });
365
- }
366
- function Radio({
367
- label,
368
- value,
369
- onChange,
370
- options
371
- }) {
372
- return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
373
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: label }),
374
- /* @__PURE__ */ jsx("div", { className: "grid auto-cols-fr grid-flow-col rounded-md border border-border overflow-hidden", children: options.map((opt) => /* @__PURE__ */ jsx(
375
- "button",
376
- {
377
- type: "button",
378
- "data-active": opt.value === value,
379
- onClick: () => onChange(opt.value),
380
- className: "px-2 py-1 text-xs hover:bg-accent/40 data-[active=true]:bg-primary data-[active=true]:text-primary-foreground",
381
- children: opt.label
382
- },
383
- opt.value
384
- )) })
385
- ] });
386
- }
387
- function Toggle({
388
- label,
389
- value,
390
- onChange
391
- }) {
392
- return /* @__PURE__ */ jsxs("label", { className: "flex items-center justify-between gap-2 text-xs", children: [
393
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: label }),
394
- /* @__PURE__ */ jsx(
395
- "button",
396
- {
397
- type: "button",
398
- role: "switch",
399
- "aria-checked": value,
400
- onClick: () => onChange(!value),
401
- className: "relative inline-flex h-5 w-9 items-center rounded-full bg-input data-[on=true]:bg-primary transition-colors",
402
- "data-on": value,
403
- children: /* @__PURE__ */ jsx(
404
- "span",
405
- {
406
- className: "inline-block h-4 w-4 transform rounded-full bg-white shadow-sm transition-transform translate-x-0.5 data-[on=true]:translate-x-4",
407
- "data-on": value
408
- }
409
- )
410
- }
411
- )
412
- ] });
413
- }
414
- function Select({
415
- label,
416
- value,
417
- onChange,
418
- options
419
- }) {
420
- return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
421
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: label }),
422
- /* @__PURE__ */ jsx(
423
- "select",
424
- {
425
- className: "input",
426
- value,
427
- onChange: (e) => onChange(e.target.value),
428
- children: options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
429
- }
430
- )
431
- ] });
432
- }
433
- function ProductSwitcher({
434
- trigger,
435
- activeId,
436
- products = [],
437
- onSelect,
438
- open,
439
- onOpenChange
440
- }) {
441
- const { t } = useTranslation();
442
- const [query, setQuery] = useState("");
443
- const q = query.trim().toLowerCase();
444
- const filtered = q ? products.filter(
445
- (p) => p.name.toLowerCase().includes(q) || p.role.toLowerCase().includes(q)
446
- ) : products;
447
- return /* @__PURE__ */ jsxs(Popover.Root, { open, onOpenChange, children: [
448
- /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: trigger }),
449
- /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(
450
- Popover.Content,
451
- {
452
- align: "start",
453
- sideOffset: 4,
454
- className: "sw-pop",
455
- onOpenAutoFocus: (e) => e.preventDefault(),
456
- children: [
457
- /* @__PURE__ */ jsxs("div", { className: "sw-pop-search", children: [
458
- /* @__PURE__ */ jsx(Search, { size: 14, className: "text-muted-foreground" }),
459
- /* @__PURE__ */ jsx(
460
- "input",
461
- {
462
- autoFocus: true,
463
- value: query,
464
- onChange: (e) => setQuery(e.target.value),
465
- placeholder: t("shell.searchProducts"),
466
- className: "flex-1 bg-transparent outline-none"
467
- }
468
- ),
469
- /* @__PURE__ */ jsx("kbd", { className: "kbd", children: "esc" })
470
- ] }),
471
- /* @__PURE__ */ jsxs("div", { className: "sw-pop-list", children: [
472
- /* @__PURE__ */ jsx("div", { className: "sw-pop-section", children: /* @__PURE__ */ jsxs("span", { children: [
473
- t("nav.products"),
474
- " \xB7 ",
475
- filtered.length
476
- ] }) }),
477
- filtered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "sw-pop-empty", children: "\u2014" }) : filtered.map((p) => {
478
- const isActive = p.id === activeId;
479
- return /* @__PURE__ */ jsxs(
480
- "button",
481
- {
482
- type: "button",
483
- className: cn("sw-pop-item w-full text-left"),
484
- "data-active": isActive,
485
- onClick: () => {
486
- onSelect(p);
487
- setQuery("");
488
- },
489
- children: [
490
- /* @__PURE__ */ jsx(
491
- "span",
492
- {
493
- className: "sb-logo-mark",
494
- style: { background: p.color },
495
- children: p.name[0]?.toUpperCase() ?? "?"
496
- }
497
- ),
498
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
499
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: p.name }),
500
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground truncate", children: p.role })
501
- ] }),
502
- /* @__PURE__ */ jsxs("span", { className: "sw-pop-item-meta", children: [
503
- p.projects.length,
504
- " \xB7 ",
505
- p.devs
506
- ] }),
507
- isActive && /* @__PURE__ */ jsx(Check, { size: 12, className: "text-primary" })
508
- ]
509
- },
510
- p.id
511
- );
512
- })
513
- ] })
514
- ]
515
- }
516
- ) })
517
- ] });
518
- }
519
- function ProjectSwitcher({
520
- trigger,
521
- activeProductId,
522
- activeProjectId,
523
- recent = [],
524
- products = [],
525
- onSelect,
526
- open,
527
- onOpenChange
528
- }) {
529
- const { t } = useTranslation();
530
- const [query, setQuery] = useState("");
531
- const productById = new Map(products.map((p) => [p.id, p]));
532
- const recentResolved = recent.map((r) => {
533
- const product = productById.get(r.productId);
534
- const project = product?.projects.find((p) => p.id === r.projectId);
535
- return product && project ? { product, project } : null;
536
- }).filter((x) => !!x).slice(0, 3);
537
- const q = query.trim().toLowerCase();
538
- const filteredProducts = products.map((product) => ({
539
- product,
540
- projects: q ? product.projects.filter(
541
- (p) => p.name.toLowerCase().includes(q) || p.stack.toLowerCase().includes(q)
542
- ) : product.projects
543
- })).filter((group) => group.projects.length > 0);
544
- return /* @__PURE__ */ jsxs(Popover.Root, { open, onOpenChange, children: [
545
- /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: trigger }),
546
- /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(
547
- Popover.Content,
548
- {
549
- align: "start",
550
- sideOffset: 4,
551
- className: "sw-pop",
552
- style: { width: 420 },
553
- onOpenAutoFocus: (e) => e.preventDefault(),
554
- children: [
555
- /* @__PURE__ */ jsxs("div", { className: "sw-pop-search", children: [
556
- /* @__PURE__ */ jsx(Search, { size: 14, className: "text-muted-foreground" }),
557
- /* @__PURE__ */ jsx(
558
- "input",
559
- {
560
- autoFocus: true,
561
- value: query,
562
- onChange: (e) => setQuery(e.target.value),
563
- placeholder: t("shell.searchProjects"),
564
- className: "flex-1 bg-transparent outline-none"
565
- }
566
- ),
567
- /* @__PURE__ */ jsx("kbd", { className: "kbd", children: "esc" })
568
- ] }),
569
- /* @__PURE__ */ jsxs("div", { className: "sw-pop-list", children: [
570
- !q && recentResolved.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
571
- /* @__PURE__ */ jsx("div", { className: "sw-pop-section", children: /* @__PURE__ */ jsx("span", { children: t("shell.recent") }) }),
572
- recentResolved.map(({ product, project }) => /* @__PURE__ */ jsxs(
573
- "button",
574
- {
575
- type: "button",
576
- className: "sw-pop-item w-full text-left",
577
- onClick: () => onSelect(project, product),
578
- children: [
579
- /* @__PURE__ */ jsx(Clock, { size: 12, className: "text-muted-foreground" }),
580
- /* @__PURE__ */ jsx("span", { className: "flex-1 min-w-0 truncate font-mono text-xs", children: project.name }),
581
- /* @__PURE__ */ jsx("span", { className: "sw-pop-item-meta truncate", children: product.name })
582
- ]
583
- },
584
- `${product.id}:${project.id}`
585
- ))
586
- ] }),
587
- filteredProducts.length === 0 && /* @__PURE__ */ jsx("div", { className: "sw-pop-empty", children: "\u2014" }),
588
- filteredProducts.map(({ product, projects }) => /* @__PURE__ */ jsxs("div", { children: [
589
- /* @__PURE__ */ jsxs("div", { className: "sw-pop-section", children: [
590
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
591
- /* @__PURE__ */ jsx(
592
- "span",
593
- {
594
- className: "sb-logo-mark",
595
- style: { background: product.color, width: 12, height: 12, fontSize: 8 },
596
- children: product.name[0]?.toUpperCase() ?? "?"
597
- }
598
- ),
599
- product.name
600
- ] }),
601
- /* @__PURE__ */ jsx("span", { children: projects.length })
602
- ] }),
603
- projects.map((project) => {
604
- const isActive = product.id === activeProductId && project.id === activeProjectId;
605
- return /* @__PURE__ */ jsxs(
606
- "button",
607
- {
608
- type: "button",
609
- className: cn("sw-pop-item w-full text-left"),
610
- "data-active": isActive,
611
- onClick: () => onSelect(project, product),
612
- children: [
613
- /* @__PURE__ */ jsx("span", { className: "font-mono text-xs truncate flex-1 min-w-0", children: project.name }),
614
- /* @__PURE__ */ jsx("span", { className: "sw-kind-chip", children: project.kind }),
615
- /* @__PURE__ */ jsxs("span", { className: "sw-pop-item-meta", children: [
616
- project.stack,
617
- " \xB7 ",
618
- project.devs,
619
- "d \xB7 ",
620
- project.openIssues,
621
- "\u2197 \xB7",
622
- " ",
623
- project.prs,
624
- "pr"
625
- ] }),
626
- isActive && /* @__PURE__ */ jsx(Check, { size: 12, className: "text-primary" })
627
- ]
628
- },
629
- project.id
630
- );
631
- })
632
- ] }, product.id))
633
- ] }),
634
- /* @__PURE__ */ jsxs("div", { className: "sw-pop-foot", children: [
635
- /* @__PURE__ */ jsx("span", { children: t("shell.browseAllProducts") }),
636
- /* @__PURE__ */ jsxs("span", { className: "ml-auto", children: [
637
- /* @__PURE__ */ jsx("kbd", { className: "kbd", children: "\u2191\u2193" }),
638
- " ",
639
- /* @__PURE__ */ jsx("kbd", { className: "kbd", children: "\u23CE" })
640
- ] })
641
- ] })
642
- ]
643
- }
644
- ) })
645
- ] });
646
- }
647
- function CommandPalette({ open, onOpenChange, commands }) {
648
- const { t } = useTranslation();
649
- const inputRef = useRef(null);
650
- useEffect(() => {
651
- const handler = (e) => {
652
- const isModifier = e.metaKey || e.ctrlKey;
653
- if (isModifier && e.key.toLowerCase() === "k") {
654
- e.preventDefault();
655
- onOpenChange(!open);
656
- } else if (e.key === "Escape" && open) {
657
- onOpenChange(false);
658
- }
659
- };
660
- window.addEventListener("keydown", handler);
661
- return () => window.removeEventListener("keydown", handler);
662
- }, [open, onOpenChange]);
663
- const groups = /* @__PURE__ */ new Map();
664
- for (const cmd of commands) {
665
- const key = cmd.group ?? "";
666
- const arr = groups.get(key) ?? [];
667
- arr.push(cmd);
668
- groups.set(key, arr);
669
- }
670
- return /* @__PURE__ */ jsx(Dialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [
671
- /* @__PURE__ */ jsx(Dialog.Overlay, { className: "fixed inset-0 z-50 bg-black/30 backdrop-blur-sm" }),
672
- /* @__PURE__ */ jsxs(
673
- Dialog.Content,
674
- {
675
- className: "fixed left-1/2 top-[20%] z-50 w-[min(560px,calc(100vw-2rem))] -translate-x-1/2 rounded-lg border border-border bg-popover text-popover-foreground shadow-2xl outline-none",
676
- "aria-describedby": void 0,
677
- children: [
678
- /* @__PURE__ */ jsx(VisuallyHidden.Root, { children: /* @__PURE__ */ jsx(Dialog.Title, { children: t("common.search") }) }),
679
- /* @__PURE__ */ jsxs(Command, { label: "Command palette", className: "flex flex-col", children: [
680
- /* @__PURE__ */ jsx(
681
- Command.Input,
682
- {
683
- ref: inputRef,
684
- autoFocus: true,
685
- placeholder: `${t("common.search")}\u2026`,
686
- className: "w-full border-b border-border bg-transparent px-4 py-3 text-sm outline-none placeholder:text-muted-foreground"
687
- }
688
- ),
689
- /* @__PURE__ */ jsxs(Command.List, { className: "max-h-80 overflow-y-auto p-1", children: [
690
- /* @__PURE__ */ jsx(Command.Empty, { className: "px-3 py-6 text-center text-xs text-muted-foreground", children: "\u2014" }),
691
- [...groups.entries()].map(([groupLabel, items]) => /* @__PURE__ */ jsx(
692
- Command.Group,
693
- {
694
- heading: groupLabel ? /* @__PURE__ */ jsx("span", { className: "px-2 py-1 text-[10px] uppercase tracking-wider text-muted-foreground", children: groupLabel }) : void 0,
695
- children: items.map((cmd) => /* @__PURE__ */ jsxs(
696
- Command.Item,
697
- {
698
- value: cmd.label,
699
- onSelect: () => {
700
- cmd.onSelect();
701
- onOpenChange(false);
702
- },
703
- className: "flex items-center gap-2 rounded-md px-3 py-2 text-sm cursor-pointer data-[selected=true]:bg-accent",
704
- children: [
705
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: cmd.label }),
706
- cmd.hint && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: cmd.hint })
707
- ]
708
- },
709
- cmd.id
710
- ))
711
- },
712
- groupLabel || "default"
713
- ))
714
- ] }),
715
- /* @__PURE__ */ jsxs("div", { className: "border-t border-border px-3 py-2 text-[10px] text-muted-foreground flex items-center gap-3", children: [
716
- /* @__PURE__ */ jsxs("span", { children: [
717
- /* @__PURE__ */ jsx("kbd", { className: "kbd", children: "\u2191\u2193" }),
718
- " navigate"
719
- ] }),
720
- /* @__PURE__ */ jsxs("span", { children: [
721
- /* @__PURE__ */ jsx("kbd", { className: "kbd", children: "\u23CE" }),
722
- " select"
723
- ] }),
724
- /* @__PURE__ */ jsxs("span", { className: "ml-auto", children: [
725
- /* @__PURE__ */ jsx("kbd", { className: "kbd", children: "esc" }),
726
- " close"
727
- ] })
728
- ] })
729
- ] })
730
- ]
731
- }
732
- )
733
- ] }) });
734
- }
735
- function PageContent({
736
- title,
737
- subtitle,
738
- extra,
739
- breadcrumb,
740
- tabs,
741
- children,
742
- footer,
743
- padding = "default",
744
- header = "default",
745
- className
746
- }) {
747
- const showHeader = header !== "none" && (breadcrumb || title || subtitle || extra);
748
- return /* @__PURE__ */ jsxs(
749
- "section",
750
- {
751
- className: cn("page-content", className),
752
- "data-padding": padding,
753
- children: [
754
- showHeader && /* @__PURE__ */ jsxs("header", { className: "page-content-header", children: [
755
- breadcrumb && /* @__PURE__ */ jsx("div", { className: "page-content-breadcrumb", children: breadcrumb }),
756
- /* @__PURE__ */ jsxs("div", { className: "page-content-titlebar", children: [
757
- /* @__PURE__ */ jsxs("div", { className: "page-content-titlegroup", children: [
758
- title && /* @__PURE__ */ jsx("h1", { className: "page-content-title", children: title }),
759
- subtitle && /* @__PURE__ */ jsx("p", { className: "page-content-subtitle", children: subtitle })
760
- ] }),
761
- extra && /* @__PURE__ */ jsx("div", { className: "page-content-extra", children: extra })
762
- ] }),
763
- tabs && /* @__PURE__ */ jsx("div", { className: "page-content-tabs", children: tabs })
764
- ] }),
765
- children !== void 0 && /* @__PURE__ */ jsx("div", { className: "page-content-body", children }),
766
- footer && /* @__PURE__ */ jsx("footer", { className: "page-content-footer", children: footer })
767
- ]
768
- }
769
- );
770
- }
771
-
772
- export { AppShell, CommandPalette, PageContent, ProductSwitcher, ProjectSwitcher, Sidebar, Topbar, TweaksPanel };
773
- //# sourceMappingURL=shell.js.map
774
- //# sourceMappingURL=shell.js.map