@aaas-pro/library 0.0.0-stage → 0.1.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 (247) hide show
  1. package/README.md +107 -2
  2. package/dist/components/address-picker.d.ts +18 -0
  3. package/dist/components/address-picker.js +46 -0
  4. package/dist/components/card-date-filter.d.ts +12 -0
  5. package/dist/components/card-date-filter.js +95 -0
  6. package/dist/components/date-time-picker.d.ts +12 -0
  7. package/dist/components/date-time-picker.js +96 -0
  8. package/dist/components/detail-dialog.d.ts +48 -0
  9. package/dist/components/detail-dialog.js +97 -0
  10. package/dist/components/document-links.d.ts +13 -0
  11. package/dist/components/document-links.js +19 -0
  12. package/dist/components/draft-row-actions.d.ts +14 -0
  13. package/dist/components/draft-row-actions.js +70 -0
  14. package/dist/components/error-boundary.d.ts +14 -0
  15. package/dist/components/error-boundary.js +35 -0
  16. package/dist/components/glow-card.d.ts +13 -0
  17. package/dist/components/glow-card.js +48 -0
  18. package/dist/components/org-picker.d.ts +17 -0
  19. package/dist/components/org-picker.js +56 -0
  20. package/dist/components/overflow-row-actions.d.ts +29 -0
  21. package/dist/components/overflow-row-actions.js +135 -0
  22. package/dist/components/page-header.d.ts +21 -0
  23. package/dist/components/page-header.js +21 -0
  24. package/dist/components/permission-button.d.ts +4 -0
  25. package/dist/components/permission-button.js +17 -0
  26. package/dist/components/permission-context.d.ts +12 -0
  27. package/dist/components/permission-context.js +17 -0
  28. package/dist/components/person-picker.d.ts +20 -0
  29. package/dist/components/person-picker.js +38 -0
  30. package/dist/components/process-flow-bar.d.ts +15 -0
  31. package/dist/components/process-flow-bar.js +19 -0
  32. package/dist/components/product-picker.d.ts +19 -0
  33. package/dist/components/product-picker.js +155 -0
  34. package/dist/components/ref-doc-picker.d.ts +24 -0
  35. package/dist/components/ref-doc-picker.js +139 -0
  36. package/dist/components/scroll-to-top.d.ts +1 -0
  37. package/dist/components/scroll-to-top.js +20 -0
  38. package/dist/components/state-view.d.ts +26 -0
  39. package/dist/components/state-view.js +75 -0
  40. package/dist/components/theme-switcher.d.ts +27 -0
  41. package/dist/components/theme-switcher.js +77 -0
  42. package/dist/components/time-filter.d.ts +7 -0
  43. package/dist/components/time-filter.js +65 -0
  44. package/dist/components/ui/accordion.d.ts +7 -0
  45. package/dist/components/ui/accordion.js +64 -0
  46. package/dist/components/ui/alert-dialog.d.ts +15 -0
  47. package/dist/components/ui/alert-dialog.js +160 -0
  48. package/dist/components/ui/alert.d.ts +12 -0
  49. package/dist/components/ui/alert.js +66 -0
  50. package/dist/components/ui/aspect-ratio.d.ts +3 -0
  51. package/dist/components/ui/aspect-ratio.js +10 -0
  52. package/dist/components/ui/avatar.d.ts +6 -0
  53. package/dist/components/ui/avatar.js +53 -0
  54. package/dist/components/ui/badge.d.ts +12 -0
  55. package/dist/components/ui/badge.js +44 -0
  56. package/dist/components/ui/breadcrumb.d.ts +11 -0
  57. package/dist/components/ui/breadcrumb.js +103 -0
  58. package/dist/components/ui/button-group.d.ts +14 -0
  59. package/dist/components/ui/button-group.js +76 -0
  60. package/dist/components/ui/button.d.ts +20 -0
  61. package/dist/components/ui/button.js +93 -0
  62. package/dist/components/ui/calendar.d.ts +73 -0
  63. package/dist/components/ui/calendar.js +103 -0
  64. package/dist/components/ui/card.d.ts +9 -0
  65. package/dist/components/ui/card.js +90 -0
  66. package/dist/components/ui/carousel.d.ts +14 -0
  67. package/dist/components/ui/carousel.js +200 -0
  68. package/dist/components/ui/chart.d.ts +43 -0
  69. package/dist/components/ui/chart.js +252 -0
  70. package/dist/components/ui/checkbox.d.ts +4 -0
  71. package/dist/components/ui/checkbox.js +31 -0
  72. package/dist/components/ui/collapsible.d.ts +5 -0
  73. package/dist/components/ui/collapsible.js +34 -0
  74. package/dist/components/ui/command.d.ts +18 -0
  75. package/dist/components/ui/command.js +170 -0
  76. package/dist/components/ui/context-menu.d.ts +26 -0
  77. package/dist/components/ui/context-menu.js +237 -0
  78. package/dist/components/ui/dialog.d.ts +17 -0
  79. package/dist/components/ui/dialog.js +139 -0
  80. package/dist/components/ui/drawer.d.ts +13 -0
  81. package/dist/components/ui/drawer.js +129 -0
  82. package/dist/components/ui/dropdown-menu.d.ts +26 -0
  83. package/dist/components/ui/dropdown-menu.js +245 -0
  84. package/dist/components/ui/empty.d.ts +14 -0
  85. package/dist/components/ui/empty.js +102 -0
  86. package/dist/components/ui/field.d.ts +27 -0
  87. package/dist/components/ui/field.js +229 -0
  88. package/dist/components/ui/form.d.ts +26 -0
  89. package/dist/components/ui/form.js +118 -0
  90. package/dist/components/ui/hover-card.d.ts +6 -0
  91. package/dist/components/ui/hover-card.js +39 -0
  92. package/dist/components/ui/input-group.d.ts +22 -0
  93. package/dist/components/ui/input-group.js +156 -0
  94. package/dist/components/ui/input-otp.d.ts +11 -0
  95. package/dist/components/ui/input-otp.js +66 -0
  96. package/dist/components/ui/input.d.ts +3 -0
  97. package/dist/components/ui/input.js +21 -0
  98. package/dist/components/ui/item.d.ts +29 -0
  99. package/dist/components/ui/item.js +187 -0
  100. package/dist/components/ui/kbd.d.ts +3 -0
  101. package/dist/components/ui/kbd.js +31 -0
  102. package/dist/components/ui/label.d.ts +4 -0
  103. package/dist/components/ui/label.js +22 -0
  104. package/dist/components/ui/menubar.d.ts +26 -0
  105. package/dist/components/ui/menubar.js +252 -0
  106. package/dist/components/ui/navigation-menu.d.ts +17 -0
  107. package/dist/components/ui/navigation-menu.js +170 -0
  108. package/dist/components/ui/pagination.d.ts +13 -0
  109. package/dist/components/ui/pagination.js +118 -0
  110. package/dist/components/ui/popover.d.ts +8 -0
  111. package/dist/components/ui/popover.js +47 -0
  112. package/dist/components/ui/progress.d.ts +4 -0
  113. package/dist/components/ui/progress.js +34 -0
  114. package/dist/components/ui/radio-group.d.ts +5 -0
  115. package/dist/components/ui/radio-group.js +45 -0
  116. package/dist/components/ui/resizable.d.ts +7 -0
  117. package/dist/components/ui/resizable.js +49 -0
  118. package/dist/components/ui/scroll-area.d.ts +5 -0
  119. package/dist/components/ui/scroll-area.js +60 -0
  120. package/dist/components/ui/select.d.ts +17 -0
  121. package/dist/components/ui/select.js +215 -0
  122. package/dist/components/ui/separator.d.ts +4 -0
  123. package/dist/components/ui/separator.js +26 -0
  124. package/dist/components/ui/sheet.d.ts +13 -0
  125. package/dist/components/ui/sheet.js +127 -0
  126. package/dist/components/ui/sidebar.d.ts +72 -0
  127. package/dist/components/ui/sidebar.js +656 -0
  128. package/dist/components/ui/skeleton.d.ts +2 -0
  129. package/dist/components/ui/skeleton.js +15 -0
  130. package/dist/components/ui/slider.d.ts +4 -0
  131. package/dist/components/ui/slider.js +63 -0
  132. package/dist/components/ui/sonner.d.ts +4 -0
  133. package/dist/components/ui/sonner.js +34 -0
  134. package/dist/components/ui/spinner.d.ts +2 -0
  135. package/dist/components/ui/spinner.js +17 -0
  136. package/dist/components/ui/switch.d.ts +4 -0
  137. package/dist/components/ui/switch.js +31 -0
  138. package/dist/components/ui/table.d.ts +10 -0
  139. package/dist/components/ui/table.js +114 -0
  140. package/dist/components/ui/tabs.d.ts +7 -0
  141. package/dist/components/ui/tabs.js +67 -0
  142. package/dist/components/ui/textarea.d.ts +3 -0
  143. package/dist/components/ui/textarea.js +18 -0
  144. package/dist/components/ui/toggle-group.d.ts +9 -0
  145. package/dist/components/ui/toggle-group.js +68 -0
  146. package/dist/components/ui/toggle.d.ts +12 -0
  147. package/dist/components/ui/toggle.js +43 -0
  148. package/dist/components/ui/tooltip.d.ts +7 -0
  149. package/dist/components/ui/tooltip.js +56 -0
  150. package/dist/hooks/use-mobile.d.ts +1 -0
  151. package/dist/hooks/use-mobile.js +18 -0
  152. package/dist/icons/index.d.ts +57 -0
  153. package/dist/icons/index.js +115 -0
  154. package/dist/icons/paths.d.ts +556 -0
  155. package/dist/icons/paths.js +231 -0
  156. package/dist/index.d.ts +68 -0
  157. package/dist/index.js +399 -0
  158. package/dist/internal/selection-base.d.ts +37 -0
  159. package/dist/internal/selection-base.js +40 -0
  160. package/dist/lib/class-names.d.ts +6 -0
  161. package/dist/lib/class-names.js +159 -0
  162. package/dist/lib/utils.d.ts +3 -0
  163. package/dist/lib/utils.js +7 -0
  164. package/dist/lib/variants.d.ts +21 -0
  165. package/dist/lib/variants.js +21 -0
  166. package/dist/primitives/accordion.d.ts +29 -0
  167. package/dist/primitives/accordion.js +49 -0
  168. package/dist/primitives/alert-dialog.d.ts +10 -0
  169. package/dist/primitives/alert-dialog.js +22 -0
  170. package/dist/primitives/aspect-ratio.d.ts +4 -0
  171. package/dist/primitives/aspect-ratio.js +7 -0
  172. package/dist/primitives/avatar.d.ts +8 -0
  173. package/dist/primitives/avatar.js +45 -0
  174. package/dist/primitives/carousel.d.ts +22 -0
  175. package/dist/primitives/carousel.js +78 -0
  176. package/dist/primitives/chart.d.ts +71 -0
  177. package/dist/primitives/chart.js +125 -0
  178. package/dist/primitives/checkbox.d.ts +13 -0
  179. package/dist/primitives/checkbox.js +24 -0
  180. package/dist/primitives/collapsible.d.ts +14 -0
  181. package/dist/primitives/collapsible.js +29 -0
  182. package/dist/primitives/command.d.ts +43 -0
  183. package/dist/primitives/command.js +98 -0
  184. package/dist/primitives/context-menu.d.ts +24 -0
  185. package/dist/primitives/context-menu.js +19 -0
  186. package/dist/primitives/core.d.ts +25 -0
  187. package/dist/primitives/core.js +89 -0
  188. package/dist/primitives/dialog.d.ts +7 -0
  189. package/dist/primitives/dialog.js +15 -0
  190. package/dist/primitives/drawer.d.ts +30 -0
  191. package/dist/primitives/drawer.js +39 -0
  192. package/dist/primitives/dropdown-menu.d.ts +24 -0
  193. package/dist/primitives/dropdown-menu.js +19 -0
  194. package/dist/primitives/form.d.ts +154 -0
  195. package/dist/primitives/form.js +139 -0
  196. package/dist/primitives/hover-card.d.ts +4 -0
  197. package/dist/primitives/hover-card.js +8 -0
  198. package/dist/primitives/input-otp.d.ts +21 -0
  199. package/dist/primitives/input-otp.js +78 -0
  200. package/dist/primitives/label.d.ts +2 -0
  201. package/dist/primitives/label.js +7 -0
  202. package/dist/primitives/layer.d.ts +84 -0
  203. package/dist/primitives/layer.js +300 -0
  204. package/dist/primitives/menu.d.ts +56 -0
  205. package/dist/primitives/menu.js +126 -0
  206. package/dist/primitives/menubar.d.ts +91 -0
  207. package/dist/primitives/menubar.js +44 -0
  208. package/dist/primitives/navigation-menu.d.ts +32 -0
  209. package/dist/primitives/navigation-menu.js +121 -0
  210. package/dist/primitives/popover.d.ts +4 -0
  211. package/dist/primitives/popover.js +12 -0
  212. package/dist/primitives/progress.d.ts +7 -0
  213. package/dist/primitives/progress.js +13 -0
  214. package/dist/primitives/radio-group.d.ts +18 -0
  215. package/dist/primitives/radio-group.js +36 -0
  216. package/dist/primitives/resizable.d.ts +19 -0
  217. package/dist/primitives/resizable.js +91 -0
  218. package/dist/primitives/scroll-area.d.ts +12 -0
  219. package/dist/primitives/scroll-area.js +26 -0
  220. package/dist/primitives/select.d.ts +42 -0
  221. package/dist/primitives/select.js +167 -0
  222. package/dist/primitives/separator.d.ts +5 -0
  223. package/dist/primitives/separator.js +7 -0
  224. package/dist/primitives/slider.d.ts +25 -0
  225. package/dist/primitives/slider.js +98 -0
  226. package/dist/primitives/slot.d.ts +1 -0
  227. package/dist/primitives/slot.js +4 -0
  228. package/dist/primitives/switch.d.ts +11 -0
  229. package/dist/primitives/switch.js +22 -0
  230. package/dist/primitives/tabs.d.ts +23 -0
  231. package/dist/primitives/tabs.js +38 -0
  232. package/dist/primitives/toast.d.ts +55 -0
  233. package/dist/primitives/toast.js +86 -0
  234. package/dist/primitives/toggle-group.d.ts +24 -0
  235. package/dist/primitives/toggle-group.js +33 -0
  236. package/dist/primitives/toggle.d.ts +7 -0
  237. package/dist/primitives/toggle.js +13 -0
  238. package/dist/primitives/tooltip.d.ts +7 -0
  239. package/dist/primitives/tooltip.js +10 -0
  240. package/dist/style-entry.d.ts +1 -0
  241. package/dist/style-entry.js +1 -0
  242. package/dist/styles.css +7016 -0
  243. package/dist/styles.js +1 -0
  244. package/dist/theme/index.d.ts +110 -0
  245. package/dist/theme/index.js +199 -0
  246. package/licenses/Lucide.txt +15 -0
  247. package/package.json +67 -4
@@ -0,0 +1,19 @@
1
+ export interface ProductOption {
2
+ code: string;
3
+ name: string;
4
+ category: string;
5
+ spec: string;
6
+ unitGroup: string;
7
+ price: string | number;
8
+ }
9
+ export declare function ProductPickerDialog<T extends ProductOption>({ products, exists, initialSelected, onConfirm, onClose, }: {
10
+ /** 商品库(商品主数据) */
11
+ products: T[];
12
+ /** 不允许选择的商品编码,默认 []。 */
13
+ exists?: string[];
14
+ /** 初始勾选的商品编码(编辑/回显已选) */
15
+ initialSelected?: string[];
16
+ /** 确认添加:返回勾选的商品行(含初始勾选的累计结果) */
17
+ onConfirm: (picked: T[]) => void;
18
+ onClose: () => void;
19
+ }): import("react").JSX.Element;
@@ -0,0 +1,155 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState, useMemo } from "react";
3
+ import { Button } from "./ui/button.js";
4
+ import { Input } from "./ui/input.js";
5
+ import { Badge } from "./ui/badge.js";
6
+ import { Checkbox } from "./ui/checkbox.js";
7
+ import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "./ui/table.js";
8
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "./ui/dialog.js";
9
+ import { PackagePlus, Search } from "../icons/index.js";
10
+ import { cn } from "../lib/utils.js";
11
+ function ProductPickerDialog({
12
+ products,
13
+ exists = [],
14
+ initialSelected,
15
+ onConfirm,
16
+ onClose
17
+ }) {
18
+ const [q, setQ] = useState("");
19
+ const [cat, setCat] = useState("全部分类");
20
+ const [selected, setSelected] = useState((initialSelected || []).filter((id) => !exists.includes(id) && products.some((p) => p.code === id)));
21
+ const existsSet = useMemo(() => new Set(exists), [exists]);
22
+ const selectedSet = useMemo(() => new Set(selected), [selected]);
23
+ const [position, setPosition] = useState({ filter: "", page: 1 });
24
+ const filterKey = `${q}\0${cat}`;
25
+ const categoryCounts = useMemo(() => {
26
+ const counts = /* @__PURE__ */ new Map();
27
+ for (const p of products) if (p.category) counts.set(p.category, (counts.get(p.category) ?? 0) + 1);
28
+ return counts;
29
+ }, [products]);
30
+ const cats = useMemo(() => ["全部分类", ...categoryCounts.keys()], [categoryCounts]);
31
+ const filtered = useMemo(() => {
32
+ const kw = q.trim().toLowerCase();
33
+ return products.filter((p) => (cat === "全部分类" || p.category === cat) && (!kw || p.name.toLowerCase().includes(kw) || p.code.toLowerCase().includes(kw) || p.spec.toLowerCase().includes(kw)));
34
+ }, [products, q, cat]);
35
+ const pageSize = 50;
36
+ const pages = Math.max(1, Math.ceil(filtered.length / pageSize));
37
+ const page = position.filter === filterKey ? Math.min(position.page, pages) : 1;
38
+ const visibleProducts = filtered.slice((page - 1) * pageSize, page * pageSize);
39
+ const selectable = useMemo(() => filtered.filter((p) => !existsSet.has(p.code)).map((p) => p.code), [filtered, existsSet]);
40
+ const allSelected = selectable.length > 0 && selectable.every((c) => selectedSet.has(c));
41
+ function toggle(code) {
42
+ setSelected((prev) => prev.includes(code) ? prev.filter((x) => x !== code) : [...prev, code]);
43
+ }
44
+ function toggleAll() {
45
+ const selectableSet = new Set(selectable);
46
+ setSelected((prev) => allSelected ? prev.filter((id) => !selectableSet.has(id)) : [.../* @__PURE__ */ new Set([...prev, ...selectable])]);
47
+ }
48
+ function confirm() {
49
+ const picked = products.filter((p) => selectedSet.has(p.code) && !existsSet.has(p.code));
50
+ if (picked.length === 0) {
51
+ return;
52
+ }
53
+ onConfirm(picked);
54
+ }
55
+ return /* @__PURE__ */ jsx(Dialog, { open: true, onOpenChange: (v) => !v && onClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-[96vw] sm:max-w-6xl h-[88vh] flex flex-col", children: [
56
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2 text-base", children: [
57
+ /* @__PURE__ */ jsx(PackagePlus, { className: "w-4 h-4 text-primary" }),
58
+ "添加商品",
59
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-normal text-muted-foreground", children: "从商品库按分类 + 名称 / 编码 / 规格快速搜索,勾选后返回给应用" })
60
+ ] }) }),
61
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
62
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
63
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
64
+ /* @__PURE__ */ jsx(Search, { className: "w-4 h-4 text-muted-foreground absolute left-2.5 top-1/2 -translate-y-1/2" }),
65
+ /* @__PURE__ */ jsx(Input, { value: q, onChange: (e) => setQ(e.target.value), placeholder: "搜索商品名称 / 编码 / 规格...", className: "h-9 text-sm bg-card pl-8", autoFocus: true })
66
+ ] }),
67
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", className: "h-9 text-xs shrink-0", onClick: toggleAll, disabled: selectable.length === 0, children: allSelected ? "清空勾选" : "全选结果" })
68
+ ] }),
69
+ /* @__PURE__ */ jsx("div", { className: "flex max-h-24 overflow-y-auto items-center gap-1.5 flex-wrap", children: cats.map((c) => /* @__PURE__ */ jsxs(
70
+ "button",
71
+ {
72
+ type: "button",
73
+ "aria-label": c,
74
+ onClick: () => setCat(c),
75
+ className: cn(
76
+ "px-3 py-1.5 rounded-full text-xs font-medium transition-colors border",
77
+ cat === c ? "bg-primary text-white border-primary" : "bg-card border-border text-muted-foreground hover:border-primary hover:text-primary"
78
+ ),
79
+ children: [
80
+ c,
81
+ c !== "全部分类" && /* @__PURE__ */ jsxs("span", { className: cn("ml-1", cat === c ? "text-blue-100" : "text-muted-foreground"), children: [
82
+ "(",
83
+ categoryCounts.get(c),
84
+ ")"
85
+ ] })
86
+ ]
87
+ },
88
+ c
89
+ )) })
90
+ ] }),
91
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs(Table, { children: [
92
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
93
+ /* @__PURE__ */ jsx(TableHead, { className: "w-9" }),
94
+ /* @__PURE__ */ jsx(TableHead, { children: "商品" }),
95
+ /* @__PURE__ */ jsx(TableHead, { children: "分类" }),
96
+ /* @__PURE__ */ jsx(TableHead, { children: "规格" }),
97
+ /* @__PURE__ */ jsx(TableHead, { children: "单位" }),
98
+ /* @__PURE__ */ jsx(TableHead, { className: "text-right", children: "参考价格" })
99
+ ] }) }),
100
+ /* @__PURE__ */ jsxs(TableBody, { children: [
101
+ visibleProducts.map((p) => {
102
+ const inScheme = existsSet.has(p.code);
103
+ const on = selectedSet.has(p.code);
104
+ return /* @__PURE__ */ jsxs(TableRow, { className: cn(inScheme && "opacity-55"), children: [
105
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Checkbox, { "aria-label": `选择${p.name}`, checked: inScheme || on, disabled: inScheme, onCheckedChange: () => toggle(p.code) }) }),
106
+ /* @__PURE__ */ jsxs(TableCell, { className: "text-sm", children: [
107
+ p.name,
108
+ /* @__PURE__ */ jsx("span", { className: "ml-1.5 font-mono text-[10px] text-slate-300", children: p.code }),
109
+ inScheme && /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "ml-1.5 text-[10px] bg-muted text-muted-foreground border-border", children: "不可选择" })
110
+ ] }),
111
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "text-[10px] bg-muted text-muted-foreground border-border", children: p.category }) }),
112
+ /* @__PURE__ */ jsx(TableCell, { className: "text-xs text-muted-foreground", children: p.spec }),
113
+ /* @__PURE__ */ jsx(TableCell, { className: "text-xs text-muted-foreground", children: p.unitGroup }),
114
+ /* @__PURE__ */ jsx(TableCell, { className: "text-right text-xs tabular-nums text-muted-foreground", children: p.price })
115
+ ] }, p.code);
116
+ }),
117
+ filtered.length === 0 && /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: 6, className: "text-center text-xs text-muted-foreground py-6", children: "当前分类下未搜到匹配商品,换个分类或关键词试试" }) })
118
+ ] })
119
+ ] }) }),
120
+ /* @__PURE__ */ jsxs("nav", { "aria-label": "商品分页", className: "flex items-center justify-between gap-2 text-xs text-muted-foreground", children: [
121
+ /* @__PURE__ */ jsxs("span", { children: [
122
+ "共 ",
123
+ filtered.length,
124
+ " 个商品 · 第 ",
125
+ page,
126
+ "/",
127
+ pages,
128
+ " 页 · 每页 ",
129
+ pageSize,
130
+ " 个"
131
+ ] }),
132
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
133
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", "aria-label": "上一页商品", disabled: page <= 1, onClick: () => setPosition({ filter: filterKey, page: page - 1 }), children: "上一页" }),
134
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", "aria-label": "下一页商品", disabled: page >= pages, onClick: () => setPosition({ filter: filterKey, page: page + 1 }), children: "下一页" })
135
+ ] })
136
+ ] }),
137
+ /* @__PURE__ */ jsxs(DialogFooter, { className: "gap-2", children: [
138
+ /* @__PURE__ */ jsxs("span", { className: "mr-auto text-xs text-muted-foreground", children: [
139
+ "共勾选 ",
140
+ selected.length,
141
+ " 个商品",
142
+ cat !== "全部分类" && ` · 当前分类 ${cat}`
143
+ ] }),
144
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: "h-8 text-xs", onClick: onClose, children: "取消" }),
145
+ /* @__PURE__ */ jsxs(Button, { size: "sm", className: "h-8 text-xs", disabled: selected.length === 0, onClick: confirm, children: [
146
+ "添加选中(",
147
+ selected.length,
148
+ ")"
149
+ ] })
150
+ ] })
151
+ ] }) });
152
+ }
153
+ export {
154
+ ProductPickerDialog
155
+ };
@@ -0,0 +1,24 @@
1
+ import { type ReactNode } from 'react';
2
+ export interface RefDocItem {
3
+ id: string;
4
+ label: string;
5
+ sub?: string;
6
+ }
7
+ export declare function RefDocPicker({ label, items, value, editable, onPick, onRemove, renderDetail, onOpenDoc, closeOnPick, hint, compact, }: {
8
+ label: string;
9
+ items: RefDocItem[];
10
+ value: string[];
11
+ editable: boolean;
12
+ onPick?: (id: string) => void;
13
+ onRemove?: (id: string) => void;
14
+ renderDetail?: (id: string) => ReactNode;
15
+ /** 给了就=点关联单据直接开它的原生表单(优先于摘要弹窗) */
16
+ onOpenDoc?: (id: string) => void;
17
+ closeOnPick?: boolean;
18
+ hint?: string;
19
+ compact?: boolean;
20
+ }): import("react").JSX.Element;
21
+ export declare function DetailRow({ label: k, children }: {
22
+ label: string;
23
+ children: ReactNode;
24
+ }): import("react").JSX.Element;
@@ -0,0 +1,139 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "./ui/dialog.js";
4
+ import { Button } from "./ui/button.js";
5
+ import { FileText, X, Search, FileDown } from "../icons/index.js";
6
+ import { cn } from "../lib/utils.js";
7
+ function RefDocPicker({
8
+ label,
9
+ items,
10
+ value,
11
+ editable,
12
+ onPick,
13
+ onRemove,
14
+ renderDetail,
15
+ onOpenDoc,
16
+ closeOnPick = true,
17
+ hint,
18
+ compact = false
19
+ }) {
20
+ const [pickOpen, setPickOpen] = useState(false);
21
+ const [detailId, setDetailId] = useState(null);
22
+ const labelOf = (id) => items.find((i) => i.id === id)?.label || id;
23
+ const candidates = items.filter((i) => !value.includes(i.id));
24
+ const openDetail = (id) => {
25
+ if (onOpenDoc) onOpenDoc(id);
26
+ else setDetailId(id);
27
+ };
28
+ return /* @__PURE__ */ jsxs("div", { className: compact ? "flex items-center gap-1.5 flex-wrap" : "space-y-1.5", children: [
29
+ compact ? /* @__PURE__ */ jsxs(Fragment, { children: [
30
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground shrink-0", children: label }),
31
+ value.length === 0 && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "未关联" }),
32
+ value.map((id) => /* @__PURE__ */ jsxs("span", { className: cn(
33
+ "inline-flex items-center gap-1 px-2 py-1 rounded-md border text-xs max-w-56",
34
+ "bg-card border-border text-primary hover:border-primary"
35
+ ), children: [
36
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "truncate underline-offset-2 hover:underline", onClick: () => openDetail(id), title: onOpenDoc ? "打开原生表单" : "查看摘要", children: [
37
+ /* @__PURE__ */ jsx(FileText, { className: "w-3 h-3 inline mr-0.5 -mt-0.5 text-primary" }),
38
+ labelOf(id)
39
+ ] }),
40
+ editable && onRemove && /* @__PURE__ */ jsx("button", { type: "button", className: "text-slate-300 hover:text-red-500 shrink-0", "aria-label": `移除${labelOf(id)}`, onClick: () => onRemove(id), children: /* @__PURE__ */ jsx(X, { className: "w-3 h-3" }) })
41
+ ] }, id)),
42
+ editable && onPick && items.length > 0 && /* @__PURE__ */ jsxs(
43
+ "button",
44
+ {
45
+ type: "button",
46
+ onClick: () => setPickOpen(true),
47
+ className: "inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs font-medium text-primary hover:bg-primary/5 border border-dashed border-border",
48
+ children: [
49
+ /* @__PURE__ */ jsx(Search, { className: "w-3 h-3" }),
50
+ "选择"
51
+ ]
52
+ }
53
+ )
54
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
55
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2.5", children: [
56
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground w-[84px] shrink-0 text-right pt-1.5", children: label }),
57
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex items-center gap-1.5 flex-wrap min-h-8", children: [
58
+ value.length === 0 && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: items.length > 0 ? "未关联" : "—" }),
59
+ value.map((id) => /* @__PURE__ */ jsxs("span", { className: cn(
60
+ "inline-flex items-center gap-1 px-2 py-1 rounded-md border text-xs max-w-72",
61
+ "bg-card border-border text-primary hover:border-primary"
62
+ ), children: [
63
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "truncate underline-offset-2 hover:underline", onClick: () => openDetail(id), title: onOpenDoc ? "打开原生表单" : "查看摘要", children: [
64
+ /* @__PURE__ */ jsx(FileText, { className: "w-3 h-3 inline mr-0.5 -mt-0.5 text-primary" }),
65
+ labelOf(id)
66
+ ] }),
67
+ editable && onRemove && /* @__PURE__ */ jsx("button", { type: "button", className: "text-slate-300 hover:text-red-500 shrink-0", "aria-label": `移除${labelOf(id)}`, onClick: () => onRemove(id), children: /* @__PURE__ */ jsx(X, { className: "w-3 h-3" }) })
68
+ ] }, id)),
69
+ editable && onPick && items.length > 0 && /* @__PURE__ */ jsxs(
70
+ "button",
71
+ {
72
+ type: "button",
73
+ onClick: () => setPickOpen(true),
74
+ className: "inline-flex items-center gap-1 px-2.5 py-1 rounded-md text-xs font-medium text-primary hover:bg-primary/5 border border-dashed border-border",
75
+ children: [
76
+ /* @__PURE__ */ jsx(Search, { className: "w-3 h-3" }),
77
+ "选择关联"
78
+ ]
79
+ }
80
+ )
81
+ ] })
82
+ ] }),
83
+ hint && /* @__PURE__ */ jsx("div", { className: "text-[11px] text-muted-foreground pl-[92px]", children: hint })
84
+ ] }),
85
+ /* @__PURE__ */ jsx(Dialog, { open: pickOpen, onOpenChange: setPickOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-xl", children: [
86
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
87
+ /* @__PURE__ */ jsx(FileDown, { className: "w-4 h-4 text-rose-400" }),
88
+ "选择关联",
89
+ label
90
+ ] }) }),
91
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 max-h-[50vh] overflow-y-auto", children: [
92
+ items.map((it) => {
93
+ const picked = value.includes(it.id);
94
+ return /* @__PURE__ */ jsxs("div", { className: cn(
95
+ "flex items-center gap-2 rounded border px-3 py-2 text-xs transition-colors",
96
+ picked ? "border-border bg-muted" : "border-border hover:border-primary hover:bg-primary/5"
97
+ ), children: [
98
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground w-36 truncate", children: it.id }),
99
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground flex-1 truncate", children: it.sub || it.label }),
100
+ picked ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "已关联" }) : /* @__PURE__ */ jsx(Button, { size: "sm", className: "h-7 text-xs bg-primary hover:bg-primary/90", onClick: () => {
101
+ onPick?.(it.id);
102
+ if (closeOnPick) setPickOpen(false);
103
+ }, children: "选择" })
104
+ ] }, it.id);
105
+ }),
106
+ items.length === 0 && /* @__PURE__ */ jsxs("div", { className: "text-center text-xs text-muted-foreground py-8", children: [
107
+ "暂无可关联的",
108
+ label
109
+ ] }),
110
+ candidates.length === 0 && items.length > 0 && /* @__PURE__ */ jsxs("div", { className: "text-center text-xs text-muted-foreground py-8", children: [
111
+ "可关联的",
112
+ label,
113
+ "均已关联"
114
+ ] })
115
+ ] })
116
+ ] }) }),
117
+ /* @__PURE__ */ jsx(Dialog, { open: !!detailId, onOpenChange: (v) => {
118
+ if (!v) setDetailId(null);
119
+ }, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-md", children: [
120
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
121
+ /* @__PURE__ */ jsx(FileText, { className: "w-4 h-4 text-primary" }),
122
+ label,
123
+ "详情 · ",
124
+ detailId
125
+ ] }) }),
126
+ detailId && /* @__PURE__ */ jsx("div", { className: "text-xs space-y-3", children: renderDetail ? renderDetail(detailId) : /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: "暂无摘要数据源" }) })
127
+ ] }) })
128
+ ] });
129
+ }
130
+ function DetailRow({ label: k, children }) {
131
+ return /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-4 border-b border-dashed border-border pb-1.5", children: [
132
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground shrink-0", children: k }),
133
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground text-right", children })
134
+ ] });
135
+ }
136
+ export {
137
+ DetailRow,
138
+ RefDocPicker
139
+ };
@@ -0,0 +1 @@
1
+ export declare function ScrollToTop(): null;
@@ -0,0 +1,20 @@
1
+ import { useEffect } from "react";
2
+ import { useLocation } from "react-router-dom";
3
+ function ScrollToTop() {
4
+ const pathname = useLocation().pathname;
5
+ useEffect(() => {
6
+ const container = document.getElementById("main-scroll-container");
7
+ if (container && typeof container.scrollTo === "function") {
8
+ container.scrollTo(0, 0);
9
+ } else if (container) {
10
+ try {
11
+ container.scrollTop = 0;
12
+ } catch {
13
+ }
14
+ }
15
+ }, [pathname]);
16
+ return null;
17
+ }
18
+ export {
19
+ ScrollToTop
20
+ };
@@ -0,0 +1,26 @@
1
+ import type { ReactNode } from 'react';
2
+ export type StateViewKind = 'loading' | 'empty' | 'error' | 'forbidden' | 'not-found' | 'offline';
3
+ export interface StateViewProps {
4
+ kind: StateViewKind;
5
+ /** 覆盖默认标题。 */
6
+ title?: ReactNode;
7
+ /** 覆盖默认说明。 */
8
+ description?: ReactNode;
9
+ /** 提供时显示“重试”按钮(error / offline 默认文案)。 */
10
+ onRetry?: () => void;
11
+ /** 额外操作,如“新建”。显示在重试按钮之后。 */
12
+ action?: ReactNode;
13
+ /** 服务端请求 ID,便于用户反馈问题时定位日志。 */
14
+ requestId?: string;
15
+ /** page:页面级(居中、留白大);section:卡片/表格内(紧凑)。默认 section。 */
16
+ size?: 'page' | 'section';
17
+ /** loading 时以骨架行代替旋转图标,适合表格与列表。 */
18
+ skeletonRows?: number;
19
+ className?: string;
20
+ }
21
+ /**
22
+ * 统一的数据状态视图:加载、空、失败、无权限、不存在、离线。
23
+ * 各状态使用不同图标、语义色与文案,避免把“无权限”“服务异常”都显示为“暂无数据”。
24
+ * 数据请求与重试逻辑由宿主负责,本组件只负责呈现。
25
+ */
26
+ export declare function StateView({ kind, title, description, onRetry, action, requestId, size, skeletonRows, className }: StateViewProps): import("react").JSX.Element;
@@ -0,0 +1,75 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { RotateCcw, WifiOff, FileQuestion, Lock, AlertTriangle, Inbox } from "../icons/index.js";
3
+ import { cn } from "../lib/utils.js";
4
+ import { Button } from "./ui/button.js";
5
+ import { Skeleton } from "./ui/skeleton.js";
6
+ import { Spinner } from "./ui/spinner.js";
7
+ const presets = {
8
+ loading: { icon: /* @__PURE__ */ jsx(Spinner, {}), title: "加载中…", description: "", tone: "text-primary" },
9
+ empty: { icon: /* @__PURE__ */ jsx(Inbox, {}), title: "暂无数据", description: "当前条件下没有记录,可调整筛选条件后重试。", tone: "text-muted-foreground" },
10
+ error: { icon: /* @__PURE__ */ jsx(AlertTriangle, {}), title: "加载失败", description: "服务暂时不可用,请稍后重试。", tone: "text-destructive" },
11
+ forbidden: { icon: /* @__PURE__ */ jsx(Lock, {}), title: "没有访问权限", description: "当前账号或单位无权查看此内容,如需开通请联系管理员。", tone: "text-warning" },
12
+ "not-found": { icon: /* @__PURE__ */ jsx(FileQuestion, {}), title: "内容不存在", description: "记录可能已被删除,或不在当前单位的可见范围内。", tone: "text-muted-foreground" },
13
+ offline: { icon: /* @__PURE__ */ jsx(WifiOff, {}), title: "网络连接中断", description: "请检查网络后重试。", tone: "text-muted-foreground" }
14
+ };
15
+ function StateView({ kind, title, description, onRetry, action, requestId, size = "section", skeletonRows, className }) {
16
+ const preset = presets[kind];
17
+ const isError = kind === "error" || kind === "offline";
18
+ if (kind === "loading" && skeletonRows) {
19
+ return /* @__PURE__ */ jsx("div", { role: "status", "aria-label": "加载中", "aria-busy": true, className: cn("flex flex-col gap-3 p-4", className), "data-slot": "state-view", "data-kind": kind, children: Array.from({ length: skeletonRows }, (_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-full", style: { opacity: 1 - i * (0.6 / skeletonRows) } }, i)) });
20
+ }
21
+ if (kind === "loading") {
22
+ return /* @__PURE__ */ jsxs(
23
+ "div",
24
+ {
25
+ role: "status",
26
+ "aria-label": "加载中",
27
+ "aria-busy": true,
28
+ "data-slot": "state-view",
29
+ "data-kind": kind,
30
+ className: cn(
31
+ "flex flex-col items-center justify-center text-center text-balance",
32
+ size === "page" ? "min-h-[50vh] gap-4 px-6 py-16" : "gap-3 px-4 py-10",
33
+ className
34
+ ),
35
+ children: [
36
+ /* @__PURE__ */ jsx(Spinner, { className: cn("text-primary motion-reduce:animate-none", size === "page" ? "size-8" : "size-7") }),
37
+ /* @__PURE__ */ jsxs("div", { className: "flex max-w-sm flex-col gap-1.5", children: [
38
+ /* @__PURE__ */ jsx("p", { className: cn("font-medium text-foreground/90", size === "page" ? "text-base" : "text-sm"), children: title ?? preset.title }),
39
+ description && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
40
+ ] })
41
+ ]
42
+ }
43
+ );
44
+ }
45
+ return /* @__PURE__ */ jsxs(
46
+ "div",
47
+ {
48
+ role: isError ? "alert" : "status",
49
+ "data-slot": "state-view",
50
+ "data-kind": kind,
51
+ className: cn("flex flex-col items-center justify-center gap-3 text-center text-balance", size === "page" ? "min-h-[50vh] px-6 py-16" : "px-4 py-10", className),
52
+ children: [
53
+ /* @__PURE__ */ jsx("div", { className: cn("grid size-12 place-items-center rounded-xl bg-muted ring-1 ring-border [&_svg:not([class*=size-])]:size-6", preset.tone), children: preset.icon }),
54
+ /* @__PURE__ */ jsxs("div", { className: "flex max-w-sm flex-col gap-1", children: [
55
+ /* @__PURE__ */ jsx("p", { className: cn("font-semibold text-foreground", size === "page" ? "text-lg" : "text-base"), children: title ?? preset.title }),
56
+ (description ?? preset.description) && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description ?? preset.description }),
57
+ requestId && /* @__PURE__ */ jsxs("p", { className: "mt-1 font-mono text-xs text-muted-foreground/80", children: [
58
+ "请求 ID:",
59
+ requestId
60
+ ] })
61
+ ] }),
62
+ (onRetry || action) && /* @__PURE__ */ jsxs("div", { className: "mt-1 flex flex-wrap items-center justify-center gap-2", children: [
63
+ onRetry && /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onRetry, children: [
64
+ /* @__PURE__ */ jsx(RotateCcw, {}),
65
+ "重试"
66
+ ] }),
67
+ action
68
+ ] })
69
+ ]
70
+ }
71
+ );
72
+ }
73
+ export {
74
+ StateView
75
+ };
@@ -0,0 +1,27 @@
1
+ import type { ReactNode } from 'react';
2
+ import { type ThemeName } from '../theme';
3
+ export interface ThemeSwitcherProps {
4
+ /** 自定义触发器(会被 asChild 包裹);不传时使用幽灵图标按钮。 */
5
+ children?: ReactNode;
6
+ /** 默认触发器是否显示当前主题名称。 */
7
+ showLabel?: boolean;
8
+ /** 菜单对齐方式与方向,默认 end / bottom。 */
9
+ align?: 'start' | 'center' | 'end';
10
+ side?: 'top' | 'right' | 'bottom' | 'left';
11
+ /** 菜单标题,默认「界面主题」。 */
12
+ title?: ReactNode;
13
+ /** 是否显示导航栏外观(浅色 / 深色)切换,默认显示。 */
14
+ showNavStyle?: boolean;
15
+ className?: string;
16
+ contentClassName?: string;
17
+ }
18
+ /** 主题色样:外圈页面底色、内圆主色,让用户一眼区分明暗与品牌色。 */
19
+ export declare function ThemeSwatch({ theme, className }: {
20
+ theme: ThemeName;
21
+ className?: string;
22
+ }): import("react").JSX.Element;
23
+ /**
24
+ * 主题切换器:色彩预设以色样网格呈现,下方可切换导航栏外观;选中即时生效并写入本地记忆。
25
+ * 须位于 ThemeProvider 内;在深色导航栏中使用时请通过 children 传入与导航配色一致的触发器。
26
+ */
27
+ export declare function ThemeSwitcher({ children, showLabel, align, side, title, showNavStyle, className, contentClassName }: ThemeSwitcherProps): import("react").JSX.Element;
@@ -0,0 +1,77 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { themePresets, useTheme, themeDescriptions, navStyleLabels } from "../theme/index.js";
3
+ import { Button } from "./ui/button.js";
4
+ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator } from "./ui/dropdown-menu.js";
5
+ import { Moon, Sun, Palette } from "../icons/index.js";
6
+ import { cn } from "../lib/utils.js";
7
+ function ThemeSwatch({ theme, className }) {
8
+ const t = themePresets[theme];
9
+ return /* @__PURE__ */ jsx(
10
+ "span",
11
+ {
12
+ "aria-hidden": true,
13
+ "data-slot": "theme-swatch",
14
+ className: cn("relative inline-grid size-5 shrink-0 place-items-center rounded-full border", className),
15
+ style: { background: t.colorBackground, borderColor: t.colorBorder },
16
+ children: /* @__PURE__ */ jsx("span", { className: "size-2.5 rounded-full", style: { background: t.colorPrimary } })
17
+ }
18
+ );
19
+ }
20
+ function NavStylePreview({ style, theme }) {
21
+ const t = themePresets[theme];
22
+ const nav = style === "dark" ? "#14212e" : t.colorSurface;
23
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "inline-flex h-5 w-7 shrink-0 overflow-hidden rounded-[4px] border", style: { borderColor: t.colorBorder, background: t.colorBackground }, children: /* @__PURE__ */ jsx("span", { className: "h-full w-2.5", style: { background: nav } }) });
24
+ }
25
+ function ThemeSwitcher({ children, showLabel = false, align = "end", side = "bottom", title = "界面主题", showNavStyle = true, className, contentClassName }) {
26
+ const { theme, setTheme, themes, labels, navStyle, setNavStyle } = useTheme();
27
+ const CurrentIcon = theme === "dark" ? Moon : themes.includes("dark") && themes.length === 2 ? Sun : Palette;
28
+ const navLocked = theme === "dark";
29
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
30
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: children ?? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", color: "default", size: showLabel ? "sm" : "icon-sm", "aria-label": showLabel ? void 0 : `切换主题(当前:${labels[theme]})`, title: showLabel ? void 0 : `切换主题(当前:${labels[theme]})`, className: cn("text-muted-foreground hover:text-foreground", className), children: [
31
+ /* @__PURE__ */ jsx(CurrentIcon, {}),
32
+ showLabel && /* @__PURE__ */ jsx("span", { children: labels[theme] })
33
+ ] }) }),
34
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align, side, className: cn("w-[19rem] p-2", contentClassName), children: [
35
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "px-1 pb-1.5 pt-0.5 text-xs font-medium text-muted-foreground", children: title }),
36
+ /* @__PURE__ */ jsx(DropdownMenuRadioGroup, { value: theme, onValueChange: (v) => setTheme(v), className: "grid grid-cols-3 gap-1", children: themes.map((name) => /* @__PURE__ */ jsxs(
37
+ DropdownMenuRadioItem,
38
+ {
39
+ value: name,
40
+ "data-theme-option": name,
41
+ title: themeDescriptions[name],
42
+ className: "flex-col items-start gap-1.5 rounded-md border border-transparent px-2 py-2 pl-2 data-[state=checked]:border-primary data-[state=checked]:bg-secondary [&>span:first-child]:hidden",
43
+ children: [
44
+ /* @__PURE__ */ jsx(ThemeSwatch, { theme: name, className: "size-6" }),
45
+ /* @__PURE__ */ jsx("span", { className: "text-xs leading-none", children: labels[name] })
46
+ ]
47
+ },
48
+ name
49
+ )) }),
50
+ showNavStyle && /* @__PURE__ */ jsxs(Fragment, { children: [
51
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: "my-2" }),
52
+ /* @__PURE__ */ jsxs(DropdownMenuLabel, { className: "px-1 pb-1.5 pt-0 text-xs font-medium text-muted-foreground", children: [
53
+ "导航栏",
54
+ navLocked && /* @__PURE__ */ jsx("span", { className: "ml-1 font-normal", children: "(深色主题下固定为深色)" })
55
+ ] }),
56
+ /* @__PURE__ */ jsx(DropdownMenuRadioGroup, { value: navStyle, onValueChange: (v) => setNavStyle(v), className: "grid grid-cols-2 gap-1", children: ["light", "dark"].map((style) => /* @__PURE__ */ jsxs(
57
+ DropdownMenuRadioItem,
58
+ {
59
+ value: style,
60
+ disabled: navLocked,
61
+ "data-nav-option": style,
62
+ className: "gap-2 rounded-md border border-transparent px-2 py-1.5 pl-2 data-[state=checked]:border-primary data-[state=checked]:bg-secondary [&>span:first-child]:hidden",
63
+ children: [
64
+ /* @__PURE__ */ jsx(NavStylePreview, { style, theme }),
65
+ /* @__PURE__ */ jsx("span", { className: "text-xs", children: navStyleLabels[style] })
66
+ ]
67
+ },
68
+ style
69
+ )) })
70
+ ] })
71
+ ] })
72
+ ] });
73
+ }
74
+ export {
75
+ ThemeSwatch,
76
+ ThemeSwitcher
77
+ };
@@ -0,0 +1,7 @@
1
+ export type TimeRange = 'today' | 'week' | 'month' | 'quarter' | 'year' | 'custom';
2
+ interface TimeFilterProps {
3
+ value: TimeRange;
4
+ onChange: (value: TimeRange) => void;
5
+ }
6
+ export declare function TimeFilter({ value, onChange }: TimeFilterProps): import("react").JSX.Element;
7
+ export {};