hermium 0.1.2 → 0.1.4

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 (150) hide show
  1. package/bin/hermium.mjs +184 -145
  2. package/dist/server/index.mjs +65 -65
  3. package/dist/web-server/__23tanstack-start-plugin-adapters-Cwee5PKy.mjs +6 -0
  4. package/dist/web-server/_chunks/ssr-renderer.mjs +22 -0
  5. package/dist/web-server/_libs/babel__runtime.mjs +237 -0
  6. package/dist/web-server/_libs/bail.mjs +8 -0
  7. package/dist/web-server/_libs/base-ui__react.mjs +9554 -0
  8. package/dist/web-server/_libs/base-ui__utils.mjs +1101 -0
  9. package/dist/web-server/_libs/ccount.mjs +16 -0
  10. package/dist/web-server/_libs/character-entities-legacy.mjs +111 -0
  11. package/dist/web-server/_libs/character-entities.mjs +2130 -0
  12. package/dist/web-server/_libs/character-reference-invalid.mjs +33 -0
  13. package/dist/web-server/_libs/class-variance-authority.mjs +44 -0
  14. package/dist/web-server/_libs/clsx.mjs +16 -0
  15. package/dist/web-server/_libs/comma-separated-tokens.mjs +31 -0
  16. package/dist/web-server/_libs/cookie-es.mjs +44 -0
  17. package/dist/web-server/_libs/croner.mjs +1 -0
  18. package/dist/web-server/_libs/crossws.mjs +1 -0
  19. package/dist/web-server/_libs/decode-named-character-reference+[...].mjs +8 -0
  20. package/dist/web-server/_libs/devlop.mjs +8 -0
  21. package/dist/web-server/_libs/escape-string-regexp.mjs +9 -0
  22. package/dist/web-server/_libs/estree-util-is-identifier-name.mjs +11 -0
  23. package/dist/web-server/_libs/extend.mjs +97 -0
  24. package/dist/web-server/_libs/fault.mjs +1 -0
  25. package/dist/web-server/_libs/floating-ui__core.mjs +663 -0
  26. package/dist/web-server/_libs/floating-ui__dom.mjs +624 -0
  27. package/dist/web-server/_libs/floating-ui__react-dom.mjs +279 -0
  28. package/dist/web-server/_libs/floating-ui__utils.mjs +322 -0
  29. package/dist/web-server/_libs/format.mjs +1 -0
  30. package/dist/web-server/_libs/h3.mjs +408 -0
  31. package/dist/web-server/_libs/hast-util-parse-selector.mjs +39 -0
  32. package/dist/web-server/_libs/hast-util-to-jsx-runtime.mjs +388 -0
  33. package/dist/web-server/_libs/hast-util-whitespace.mjs +10 -0
  34. package/dist/web-server/_libs/hastscript.mjs +200 -0
  35. package/dist/web-server/_libs/highlight.js.mjs +1 -0
  36. package/dist/web-server/_libs/hookable.mjs +1 -0
  37. package/dist/web-server/_libs/html-url-attributes.mjs +26 -0
  38. package/dist/web-server/_libs/inline-style-parser.mjs +142 -0
  39. package/dist/web-server/_libs/is-alphabetical.mjs +7 -0
  40. package/dist/web-server/_libs/is-alphanumerical.mjs +8 -0
  41. package/dist/web-server/_libs/is-decimal.mjs +7 -0
  42. package/dist/web-server/_libs/is-hexadecimal.mjs +7 -0
  43. package/dist/web-server/_libs/is-plain-obj.mjs +10 -0
  44. package/dist/web-server/_libs/isbot.mjs +21 -0
  45. package/dist/web-server/_libs/longest-streak.mjs +25 -0
  46. package/dist/web-server/_libs/lowlight.mjs +1 -0
  47. package/dist/web-server/_libs/markdown-table.mjs +142 -0
  48. package/dist/web-server/_libs/mdast-util-find-and-replace.mjs +109 -0
  49. package/dist/web-server/_libs/mdast-util-from-markdown.mjs +717 -0
  50. package/dist/web-server/_libs/mdast-util-gfm-autolink-literal+[...].mjs +156 -0
  51. package/dist/web-server/_libs/mdast-util-gfm-footnote.mjs +117 -0
  52. package/dist/web-server/_libs/mdast-util-gfm-strikethrough.mjs +54 -0
  53. package/dist/web-server/_libs/mdast-util-gfm-table.mjs +157 -0
  54. package/dist/web-server/_libs/mdast-util-gfm-task-list-item.mjs +77 -0
  55. package/dist/web-server/_libs/mdast-util-gfm.mjs +29 -0
  56. package/dist/web-server/_libs/mdast-util-phrasing.mjs +30 -0
  57. package/dist/web-server/_libs/mdast-util-to-hast.mjs +710 -0
  58. package/dist/web-server/_libs/mdast-util-to-markdown.mjs +798 -0
  59. package/dist/web-server/_libs/mdast-util-to-string.mjs +38 -0
  60. package/dist/web-server/_libs/micromark-core-commonmark.mjs +2259 -0
  61. package/dist/web-server/_libs/micromark-extension-gfm-autolink-literal+[...].mjs +344 -0
  62. package/dist/web-server/_libs/micromark-extension-gfm-footnote+[...].mjs +279 -0
  63. package/dist/web-server/_libs/micromark-extension-gfm-strikethrough+[...].mjs +98 -0
  64. package/dist/web-server/_libs/micromark-extension-gfm-table.mjs +491 -0
  65. package/dist/web-server/_libs/micromark-extension-gfm-tagfilter+[...].mjs +1 -0
  66. package/dist/web-server/_libs/micromark-extension-gfm-task-list-item+[...].mjs +77 -0
  67. package/dist/web-server/_libs/micromark-extension-gfm.mjs +18 -0
  68. package/dist/web-server/_libs/micromark-factory-destination.mjs +94 -0
  69. package/dist/web-server/_libs/micromark-factory-label.mjs +63 -0
  70. package/dist/web-server/_libs/micromark-factory-space.mjs +24 -0
  71. package/dist/web-server/_libs/micromark-factory-title.mjs +65 -0
  72. package/dist/web-server/_libs/micromark-factory-whitespace.mjs +22 -0
  73. package/dist/web-server/_libs/micromark-util-character.mjs +44 -0
  74. package/dist/web-server/_libs/micromark-util-chunked.mjs +36 -0
  75. package/dist/web-server/_libs/micromark-util-classify-character+[...].mjs +12 -0
  76. package/dist/web-server/_libs/micromark-util-combine-extensions+[...].mjs +41 -0
  77. package/dist/web-server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +19 -0
  78. package/dist/web-server/_libs/micromark-util-decode-string.mjs +21 -0
  79. package/dist/web-server/_libs/micromark-util-encode.mjs +1 -0
  80. package/dist/web-server/_libs/micromark-util-html-tag-name.mjs +69 -0
  81. package/dist/web-server/_libs/micromark-util-normalize-identifier+[...].mjs +6 -0
  82. package/dist/web-server/_libs/micromark-util-resolve-all.mjs +15 -0
  83. package/dist/web-server/_libs/micromark-util-sanitize-uri.mjs +41 -0
  84. package/dist/web-server/_libs/micromark-util-subtokenize.mjs +346 -0
  85. package/dist/web-server/_libs/micromark.mjs +906 -0
  86. package/dist/web-server/_libs/ocache.mjs +1 -0
  87. package/dist/web-server/_libs/ohash.mjs +1 -0
  88. package/dist/web-server/_libs/parse-entities.mjs +245 -0
  89. package/dist/web-server/_libs/property-information.mjs +1210 -0
  90. package/dist/web-server/_libs/react-dom.mjs +10779 -0
  91. package/dist/web-server/_libs/react-markdown.mjs +147 -0
  92. package/dist/web-server/_libs/react-syntax-highlighter.mjs +941 -0
  93. package/dist/web-server/_libs/react.mjs +513 -0
  94. package/dist/web-server/_libs/refractor.mjs +2425 -0
  95. package/dist/web-server/_libs/remark-gfm.mjs +20 -0
  96. package/dist/web-server/_libs/remark-parse.mjs +19 -0
  97. package/dist/web-server/_libs/remark-rehype.mjs +21 -0
  98. package/dist/web-server/_libs/reselect.mjs +1 -0
  99. package/dist/web-server/_libs/rou3.mjs +8 -0
  100. package/dist/web-server/_libs/seroval-plugins.mjs +58 -0
  101. package/dist/web-server/_libs/seroval.mjs +1775 -0
  102. package/dist/web-server/_libs/space-separated-tokens.mjs +11 -0
  103. package/dist/web-server/_libs/srvx.mjs +781 -0
  104. package/dist/web-server/_libs/style-to-js.mjs +72 -0
  105. package/dist/web-server/_libs/style-to-object.mjs +38 -0
  106. package/dist/web-server/_libs/tabler__icons-react.mjs +224 -0
  107. package/dist/web-server/_libs/tanstack__history.mjs +204 -0
  108. package/dist/web-server/_libs/tanstack__query-core.mjs +2552 -0
  109. package/dist/web-server/_libs/tanstack__react-query.mjs +190 -0
  110. package/dist/web-server/_libs/tanstack__react-router.mjs +1120 -0
  111. package/dist/web-server/_libs/tanstack__react-store.mjs +2 -0
  112. package/dist/web-server/_libs/tanstack__router-core.mjs +4288 -0
  113. package/dist/web-server/_libs/tanstack__store.mjs +1 -0
  114. package/dist/web-server/_libs/trim-lines.mjs +41 -0
  115. package/dist/web-server/_libs/trough.mjs +85 -0
  116. package/dist/web-server/_libs/ufo.mjs +54 -0
  117. package/dist/web-server/_libs/unctx.mjs +1 -0
  118. package/dist/web-server/_libs/ungap__structured-clone.mjs +224 -0
  119. package/dist/web-server/_libs/unified.mjs +661 -0
  120. package/dist/web-server/_libs/unist-util-is.mjs +100 -0
  121. package/dist/web-server/_libs/unist-util-position.mjs +27 -0
  122. package/dist/web-server/_libs/unist-util-stringify-position.mjs +27 -0
  123. package/dist/web-server/_libs/unist-util-visit-parents.mjs +83 -0
  124. package/dist/web-server/_libs/unist-util-visit.mjs +24 -0
  125. package/dist/web-server/_libs/unstorage.mjs +1 -0
  126. package/dist/web-server/_libs/use-sync-external-store.mjs +139 -0
  127. package/dist/web-server/_libs/vfile-message.mjs +138 -0
  128. package/dist/web-server/_libs/vfile.mjs +467 -0
  129. package/dist/web-server/_libs/zod.mjs +3915 -0
  130. package/dist/web-server/_libs/zustand.mjs +343 -0
  131. package/dist/web-server/_libs/zwitch.mjs +1 -0
  132. package/dist/web-server/_ssr/index-BLK6uN4p.mjs +612 -0
  133. package/dist/web-server/_ssr/index-BkkxTg0a.mjs +1855 -0
  134. package/dist/web-server/_ssr/index-Bp9a_nTf.mjs +66 -0
  135. package/dist/web-server/_ssr/index-C8t8AZQG.mjs +513 -0
  136. package/dist/web-server/_ssr/index-DSIu0x-q.mjs +449 -0
  137. package/dist/web-server/_ssr/index-DqFrn6kj.mjs +278 -0
  138. package/dist/web-server/_ssr/index-EKE8NFy_.mjs +189 -0
  139. package/dist/web-server/_ssr/index-JzLhPyir.mjs +213 -0
  140. package/dist/web-server/_ssr/index-wTy_4MhH.mjs +369 -0
  141. package/dist/web-server/_ssr/index.mjs +1558 -0
  142. package/dist/web-server/_ssr/input-BQFduUUo.mjs +20 -0
  143. package/dist/web-server/_ssr/router-59cN5lqo.mjs +1998 -0
  144. package/dist/web-server/_ssr/start-HYkvq4Ni.mjs +4 -0
  145. package/dist/web-server/_ssr/switch-Bim4kX8N.mjs +33 -0
  146. package/dist/web-server/_ssr/syntax-highlighter-5vezNTce.mjs +62 -0
  147. package/dist/web-server/_ssr/textarea-CK0ROhfF.mjs +18 -0
  148. package/dist/web-server/_tanstack-start-manifest_v-DLw6M7p4.mjs +4 -0
  149. package/dist/web-server/index.mjs +611 -0
  150. package/package.json +1 -1
@@ -0,0 +1,1998 @@
1
+ import { c as createRouter, a as createRootRoute, b as createFileRoute, l as lazyRouteComponent, H as HeadContent, S as Scripts, u as useLocation, L as Link } from "../_libs/tanstack__react-router.mjs";
2
+ import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
3
+ import { b as QueryClient } from "../_libs/tanstack__query-core.mjs";
4
+ import { Q as QueryClientProvider, u as useQueryClient } from "../_libs/tanstack__react-query.mjs";
5
+ import { c as clsx } from "../_libs/clsx.mjs";
6
+ import { c as cva } from "../_libs/class-variance-authority.mjs";
7
+ import { c as create, d as devtools } from "../_libs/zustand.mjs";
8
+ import { I as IconSearch, a as IconX, b as IconSettings, c as IconSun, d as IconMoon, e as IconUser, f as IconPaint, g as IconBell, h as IconKey, i as IconLanguage, j as IconArrowLeft, k as IconLayoutSidebar, l as IconChevronUp, m as IconChevronDown, n as IconCirclePlus, o as IconBrain, p as IconPuzzle, q as IconRobot, r as IconHash, s as IconChartBar, t as IconPin, u as IconDots, v as IconPencil, w as IconPinnedOff, x as IconCopy, y as IconTrash } from "../_libs/tabler__icons-react.mjs";
9
+ import { T as TooltipProvider$1, u as useRender, m as mergeProps, B as Button$1, D as DialogRoot, a as DialogPopup, b as DialogClose, c as DialogTitle, d as DialogDescription, C as CollapsibleRoot, e as CollapsibleTrigger$1, f as CollapsiblePanel, M as MenuRoot, g as MenuTrigger, h as MenuPortal, i as MenuPositioner, j as MenuPopup, k as MenuItem, l as DialogPortal, n as DialogBackdrop, o as TooltipRoot, p as TooltipPortal, q as TooltipPositioner, r as TooltipPopup, s as TooltipArrow, t as TooltipTrigger$1 } from "../_libs/base-ui__react.mjs";
10
+ import { o as object, s as string } from "../_libs/zod.mjs";
11
+ import "../_libs/tanstack__router-core.mjs";
12
+ import "../_libs/tanstack__history.mjs";
13
+ import "../_libs/cookie-es.mjs";
14
+ import "../_libs/seroval.mjs";
15
+ import "../_libs/seroval-plugins.mjs";
16
+ import "node:stream/web";
17
+ import "node:stream";
18
+ import "../_libs/react-dom.mjs";
19
+ import "util";
20
+ import "crypto";
21
+ import "async_hooks";
22
+ import "stream";
23
+ import "../_libs/isbot.mjs";
24
+ import "../_libs/base-ui__utils.mjs";
25
+ import "../_libs/use-sync-external-store.mjs";
26
+ import "../_libs/floating-ui__utils.mjs";
27
+ import "../_libs/floating-ui__react-dom.mjs";
28
+ import "../_libs/floating-ui__dom.mjs";
29
+ import "../_libs/floating-ui__core.mjs";
30
+ const queryClient = new QueryClient({
31
+ defaultOptions: {
32
+ queries: {
33
+ staleTime: 3e4,
34
+ // 30s before re-fetch
35
+ gcTime: 5 * 6e4,
36
+ // 5min garbage collection
37
+ retry: 1,
38
+ refetchOnWindowFocus: false
39
+ },
40
+ mutations: {
41
+ retry: 0
42
+ }
43
+ }
44
+ });
45
+ const CONFLICT_PREFIXES = /* @__PURE__ */ new Set([
46
+ "p-",
47
+ "px-",
48
+ "py-",
49
+ "pt-",
50
+ "pr-",
51
+ "pb-",
52
+ "pl-",
53
+ "m-",
54
+ "mx-",
55
+ "my-",
56
+ "mt-",
57
+ "mr-",
58
+ "mb-",
59
+ "ml-",
60
+ "w-",
61
+ "h-",
62
+ "min-w-",
63
+ "min-h-",
64
+ "max-w-",
65
+ "max-h-",
66
+ "gap-",
67
+ "gap-x-",
68
+ "gap-y-",
69
+ "inset-",
70
+ "inset-x-",
71
+ "inset-y-",
72
+ "top-",
73
+ "right-",
74
+ "bottom-",
75
+ "left-",
76
+ "z-",
77
+ "bg-",
78
+ "text-",
79
+ "border-",
80
+ "ring-",
81
+ "shadow-",
82
+ "rounded-",
83
+ "rounded-t-",
84
+ "rounded-r-",
85
+ "rounded-b-",
86
+ "rounded-l-",
87
+ "rounded-tl-",
88
+ "rounded-tr-",
89
+ "rounded-br-",
90
+ "rounded-bl-",
91
+ "font-",
92
+ "leading-",
93
+ "tracking-",
94
+ "opacity-",
95
+ "scale-",
96
+ "rotate-",
97
+ "translate-x-",
98
+ "translate-y-",
99
+ "skew-x-",
100
+ "skew-y-",
101
+ "divide-x-",
102
+ "divide-y-",
103
+ "space-x-",
104
+ "space-y-",
105
+ "flex-",
106
+ "grid-cols-",
107
+ "grid-rows-",
108
+ "col-",
109
+ "col-start-",
110
+ "col-end-",
111
+ "row-",
112
+ "row-start-",
113
+ "row-end-",
114
+ "order-",
115
+ "duration-",
116
+ "delay-",
117
+ "ease-",
118
+ "size-",
119
+ "blur-",
120
+ "brightness-",
121
+ "contrast-",
122
+ "grayscale-"
123
+ ]);
124
+ function getPrefix(cls) {
125
+ for (let i = cls.length; i > 0; i--) {
126
+ const prefix = cls.slice(0, i);
127
+ if (CONFLICT_PREFIXES.has(prefix)) return prefix;
128
+ }
129
+ return null;
130
+ }
131
+ function cn(...inputs) {
132
+ const classes = clsx(inputs);
133
+ if (!classes) return "";
134
+ const seen = /* @__PURE__ */ new Map();
135
+ const result = [];
136
+ for (const cls of classes.split(" ")) {
137
+ if (!cls) continue;
138
+ const prefix = getPrefix(cls);
139
+ if (prefix) {
140
+ if (seen.has(prefix)) {
141
+ const prevIdx = result.indexOf(seen.get(prefix));
142
+ if (prevIdx >= 0) {
143
+ result[prevIdx] = cls;
144
+ }
145
+ } else {
146
+ seen.set(prefix, cls);
147
+ result.push(cls);
148
+ }
149
+ } else {
150
+ result.push(cls);
151
+ }
152
+ }
153
+ return result.join(" ");
154
+ }
155
+ function TooltipProvider({
156
+ delay = 0,
157
+ ...props
158
+ }) {
159
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
160
+ TooltipProvider$1,
161
+ {
162
+ "data-slot": "tooltip-provider",
163
+ delay,
164
+ ...props
165
+ }
166
+ );
167
+ }
168
+ function Tooltip({ ...props }) {
169
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipRoot, { "data-slot": "tooltip", ...props });
170
+ }
171
+ function TooltipTrigger({ ...props }) {
172
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger$1, { "data-slot": "tooltip-trigger", ...props });
173
+ }
174
+ function TooltipContent({
175
+ className,
176
+ side = "top",
177
+ sideOffset = 4,
178
+ align = "center",
179
+ alignOffset = 0,
180
+ children,
181
+ ...props
182
+ }) {
183
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipPortal, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
184
+ TooltipPositioner,
185
+ {
186
+ align,
187
+ alignOffset,
188
+ side,
189
+ sideOffset,
190
+ className: "isolate z-50",
191
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
192
+ TooltipPopup,
193
+ {
194
+ "data-slot": "tooltip-content",
195
+ className: cn(
196
+ "z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
197
+ className
198
+ ),
199
+ ...props,
200
+ children: [
201
+ children,
202
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipArrow, { className: "z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" })
203
+ ]
204
+ }
205
+ )
206
+ }
207
+ ) });
208
+ }
209
+ const THEME_KEY = "hermium-theme";
210
+ function getStoredTheme() {
211
+ try {
212
+ const stored = localStorage.getItem(THEME_KEY);
213
+ if (stored === "light" || stored === "dark" || stored === "system") return stored;
214
+ } catch {
215
+ }
216
+ return "system";
217
+ }
218
+ function setStoredTheme(theme) {
219
+ try {
220
+ localStorage.setItem(THEME_KEY, theme);
221
+ } catch {
222
+ }
223
+ }
224
+ function getSystemTheme() {
225
+ if (typeof window === "undefined") return "light";
226
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
227
+ }
228
+ function applyTheme(theme) {
229
+ const root = document.documentElement;
230
+ const resolved = theme === "system" ? getSystemTheme() : theme;
231
+ root.classList.toggle("dark", resolved === "dark");
232
+ }
233
+ const ThemeContext = reactExports.createContext({
234
+ theme: "system",
235
+ resolvedTheme: "light",
236
+ setTheme: () => {
237
+ }
238
+ });
239
+ function ThemeProvider({ children }) {
240
+ const [theme, setThemeState] = reactExports.useState("system");
241
+ const [resolved, setResolved] = reactExports.useState("light");
242
+ const [mounted, setMounted] = reactExports.useState(false);
243
+ reactExports.useEffect(() => {
244
+ setMounted(true);
245
+ const stored = getStoredTheme();
246
+ setThemeState(stored);
247
+ const isDark = stored === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches : stored === "dark";
248
+ setResolved(isDark ? "dark" : "light");
249
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
250
+ const handler = (e) => {
251
+ const t = getStoredTheme();
252
+ if (t === "system") {
253
+ applyTheme("system");
254
+ setResolved(e.matches ? "dark" : "light");
255
+ }
256
+ };
257
+ mq.addEventListener("change", handler);
258
+ return () => mq.removeEventListener("change", handler);
259
+ }, []);
260
+ const setTheme = reactExports.useCallback((t) => {
261
+ setThemeState(t);
262
+ setStoredTheme(t);
263
+ applyTheme(t);
264
+ const isDark = t === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches : t === "dark";
265
+ setResolved(isDark ? "dark" : "light");
266
+ }, []);
267
+ if (!mounted) {
268
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
269
+ ThemeContext.Provider,
270
+ {
271
+ value: { theme: "system", resolvedTheme: "light", setTheme: () => {
272
+ } },
273
+ children
274
+ }
275
+ );
276
+ }
277
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(ThemeContext.Provider, { value: { theme, resolvedTheme: resolved, setTheme }, children });
278
+ }
279
+ function useTheme() {
280
+ return reactExports.useContext(ThemeContext);
281
+ }
282
+ const MOBILE_BREAKPOINT = 768;
283
+ function useIsMobile() {
284
+ const [isMobile, setIsMobile] = reactExports.useState(void 0);
285
+ reactExports.useEffect(() => {
286
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
287
+ const onChange = () => {
288
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
289
+ };
290
+ mql.addEventListener("change", onChange);
291
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
292
+ return () => mql.removeEventListener("change", onChange);
293
+ }, []);
294
+ return !!isMobile;
295
+ }
296
+ const buttonVariants = cva(
297
+ "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
298
+ {
299
+ variants: {
300
+ variant: {
301
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
302
+ outline: "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
303
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
304
+ ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
305
+ destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
306
+ link: "text-primary underline-offset-4 hover:underline"
307
+ },
308
+ size: {
309
+ default: "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
310
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
311
+ sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
312
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
313
+ icon: "size-8",
314
+ "icon-xs": "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
315
+ "icon-sm": "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
316
+ "icon-lg": "size-9"
317
+ }
318
+ },
319
+ defaultVariants: {
320
+ variant: "default",
321
+ size: "default"
322
+ }
323
+ }
324
+ );
325
+ function Button({
326
+ className,
327
+ variant = "default",
328
+ size = "default",
329
+ ...props
330
+ }) {
331
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
332
+ Button$1,
333
+ {
334
+ "data-slot": "button",
335
+ className: cn(buttonVariants({ variant, size, className })),
336
+ ...props
337
+ }
338
+ );
339
+ }
340
+ function Sheet({ ...props }) {
341
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(DialogRoot, { "data-slot": "sheet", ...props });
342
+ }
343
+ function SheetPortal({ ...props }) {
344
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(DialogPortal, { "data-slot": "sheet-portal", ...props });
345
+ }
346
+ function SheetOverlay({ className, ...props }) {
347
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
348
+ DialogBackdrop,
349
+ {
350
+ "data-slot": "sheet-overlay",
351
+ className: cn(
352
+ "fixed inset-0 z-50 bg-black/10 transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs",
353
+ className
354
+ ),
355
+ ...props
356
+ }
357
+ );
358
+ }
359
+ function SheetContent({
360
+ className,
361
+ children,
362
+ side = "right",
363
+ showCloseButton = true,
364
+ ...props
365
+ }) {
366
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(SheetPortal, { children: [
367
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SheetOverlay, {}),
368
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
369
+ DialogPopup,
370
+ {
371
+ "data-slot": "sheet-content",
372
+ "data-side": side,
373
+ className: cn(
374
+ "fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
375
+ className
376
+ ),
377
+ ...props,
378
+ children: [
379
+ children,
380
+ showCloseButton && /* @__PURE__ */ jsxRuntimeExports.jsxs(
381
+ DialogClose,
382
+ {
383
+ "data-slot": "sheet-close",
384
+ render: /* @__PURE__ */ jsxRuntimeExports.jsx(
385
+ Button,
386
+ {
387
+ variant: "ghost",
388
+ className: "absolute top-3 right-3",
389
+ size: "icon-sm"
390
+ }
391
+ ),
392
+ children: [
393
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
394
+ IconX,
395
+ {}
396
+ ),
397
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Close" })
398
+ ]
399
+ }
400
+ )
401
+ ]
402
+ }
403
+ )
404
+ ] });
405
+ }
406
+ function SheetHeader({ className, ...props }) {
407
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
408
+ "div",
409
+ {
410
+ "data-slot": "sheet-header",
411
+ className: cn("flex flex-col gap-0.5 p-4", className),
412
+ ...props
413
+ }
414
+ );
415
+ }
416
+ function SheetTitle({ className, ...props }) {
417
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
418
+ DialogTitle,
419
+ {
420
+ "data-slot": "sheet-title",
421
+ className: cn(
422
+ "font-heading text-base font-medium text-foreground",
423
+ className
424
+ ),
425
+ ...props
426
+ }
427
+ );
428
+ }
429
+ function SheetDescription({
430
+ className,
431
+ ...props
432
+ }) {
433
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
434
+ DialogDescription,
435
+ {
436
+ "data-slot": "sheet-description",
437
+ className: cn("text-sm text-muted-foreground", className),
438
+ ...props
439
+ }
440
+ );
441
+ }
442
+ const SIDEBAR_COOKIE_NAME = "sidebar_state";
443
+ const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
444
+ const SIDEBAR_WIDTH = "16rem";
445
+ const SIDEBAR_WIDTH_MOBILE = "18rem";
446
+ const SIDEBAR_WIDTH_ICON = "3rem";
447
+ const SIDEBAR_KEYBOARD_SHORTCUT = "b";
448
+ const SidebarContext = reactExports.createContext(null);
449
+ function useSidebar() {
450
+ const context = reactExports.useContext(SidebarContext);
451
+ if (!context) {
452
+ throw new Error("useSidebar must be used within a SidebarProvider.");
453
+ }
454
+ return context;
455
+ }
456
+ function SidebarProvider({
457
+ defaultOpen = true,
458
+ open: openProp,
459
+ onOpenChange: setOpenProp,
460
+ className,
461
+ style,
462
+ children,
463
+ ...props
464
+ }) {
465
+ const isMobile = useIsMobile();
466
+ const [openMobile, setOpenMobile] = reactExports.useState(false);
467
+ const [_open, _setOpen] = reactExports.useState(defaultOpen);
468
+ const open = openProp ?? _open;
469
+ const setOpen = reactExports.useCallback(
470
+ (value) => {
471
+ const openState = typeof value === "function" ? value(open) : value;
472
+ if (setOpenProp) {
473
+ setOpenProp(openState);
474
+ } else {
475
+ _setOpen(openState);
476
+ }
477
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
478
+ },
479
+ [setOpenProp, open]
480
+ );
481
+ const toggleSidebar = reactExports.useCallback(() => {
482
+ return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
483
+ }, [isMobile, setOpen, setOpenMobile]);
484
+ reactExports.useEffect(() => {
485
+ const handleKeyDown = (event) => {
486
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
487
+ event.preventDefault();
488
+ toggleSidebar();
489
+ }
490
+ };
491
+ window.addEventListener("keydown", handleKeyDown);
492
+ return () => window.removeEventListener("keydown", handleKeyDown);
493
+ }, [toggleSidebar]);
494
+ const state = open ? "expanded" : "collapsed";
495
+ const contextValue = reactExports.useMemo(
496
+ () => ({
497
+ state,
498
+ open,
499
+ setOpen,
500
+ isMobile,
501
+ openMobile,
502
+ setOpenMobile,
503
+ toggleSidebar
504
+ }),
505
+ [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
506
+ );
507
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
508
+ "div",
509
+ {
510
+ "data-slot": "sidebar-wrapper",
511
+ style: {
512
+ "--sidebar-width": SIDEBAR_WIDTH,
513
+ "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
514
+ ...style
515
+ },
516
+ className: cn(
517
+ "group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar",
518
+ className
519
+ ),
520
+ ...props,
521
+ children
522
+ }
523
+ ) });
524
+ }
525
+ function Sidebar({
526
+ side = "left",
527
+ variant = "sidebar",
528
+ collapsible = "offcanvas",
529
+ className,
530
+ children,
531
+ dir,
532
+ ...props
533
+ }) {
534
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
535
+ if (collapsible === "none") {
536
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
537
+ "div",
538
+ {
539
+ "data-slot": "sidebar",
540
+ className: cn(
541
+ "flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground",
542
+ className
543
+ ),
544
+ ...props,
545
+ children
546
+ }
547
+ );
548
+ }
549
+ if (isMobile) {
550
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Sheet, { open: openMobile, onOpenChange: setOpenMobile, ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
551
+ SheetContent,
552
+ {
553
+ dir,
554
+ "data-sidebar": "sidebar",
555
+ "data-slot": "sidebar",
556
+ "data-mobile": "true",
557
+ className: "w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden",
558
+ style: {
559
+ "--sidebar-width": SIDEBAR_WIDTH_MOBILE
560
+ },
561
+ side,
562
+ children: [
563
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SheetHeader, { className: "sr-only", children: [
564
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SheetTitle, { children: "Sidebar" }),
565
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SheetDescription, { children: "Displays the mobile sidebar." })
566
+ ] }),
567
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full w-full flex-col", children })
568
+ ]
569
+ }
570
+ ) });
571
+ }
572
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
573
+ "div",
574
+ {
575
+ className: "group peer hidden text-sidebar-foreground md:block",
576
+ "data-state": state,
577
+ "data-collapsible": state === "collapsed" ? collapsible : "",
578
+ "data-variant": variant,
579
+ "data-side": side,
580
+ "data-slot": "sidebar",
581
+ children: [
582
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
583
+ "div",
584
+ {
585
+ "data-slot": "sidebar-gap",
586
+ className: cn(
587
+ "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
588
+ "group-data-[collapsible=offcanvas]:w-0",
589
+ "group-data-[side=right]:rotate-180",
590
+ variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
591
+ )
592
+ }
593
+ ),
594
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
595
+ "div",
596
+ {
597
+ "data-slot": "sidebar-container",
598
+ "data-side": side,
599
+ className: cn(
600
+ "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] md:flex",
601
+ // Adjust the padding for floating and inset variants.
602
+ variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
603
+ className
604
+ ),
605
+ ...props,
606
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
607
+ "div",
608
+ {
609
+ "data-sidebar": "sidebar",
610
+ "data-slot": "sidebar-inner",
611
+ className: "flex size-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 group-data-[variant=floating]:ring-sidebar-border",
612
+ children
613
+ }
614
+ )
615
+ }
616
+ )
617
+ ]
618
+ }
619
+ );
620
+ }
621
+ function SidebarTrigger({
622
+ className,
623
+ onClick,
624
+ ...props
625
+ }) {
626
+ const { toggleSidebar } = useSidebar();
627
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
628
+ Button,
629
+ {
630
+ "data-sidebar": "trigger",
631
+ "data-slot": "sidebar-trigger",
632
+ variant: "ghost",
633
+ size: "icon-sm",
634
+ className: cn(className),
635
+ onClick: (event) => {
636
+ onClick?.(event);
637
+ toggleSidebar();
638
+ },
639
+ ...props,
640
+ children: [
641
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconLayoutSidebar, {}),
642
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Toggle Sidebar" })
643
+ ]
644
+ }
645
+ );
646
+ }
647
+ function SidebarInset({ className, ...props }) {
648
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
649
+ "main",
650
+ {
651
+ "data-slot": "sidebar-inset",
652
+ className: cn(
653
+ "relative flex w-full flex-1 flex-col bg-background md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
654
+ className
655
+ ),
656
+ ...props
657
+ }
658
+ );
659
+ }
660
+ function SidebarHeader({ className, ...props }) {
661
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
662
+ "div",
663
+ {
664
+ "data-slot": "sidebar-header",
665
+ "data-sidebar": "header",
666
+ className: cn("flex flex-col gap-2 p-2", className),
667
+ ...props
668
+ }
669
+ );
670
+ }
671
+ function SidebarContent({ className, ...props }) {
672
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
673
+ "div",
674
+ {
675
+ "data-slot": "sidebar-content",
676
+ "data-sidebar": "content",
677
+ className: cn(
678
+ "no-scrollbar flex min-h-0 flex-1 flex-col gap-0 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
679
+ className
680
+ ),
681
+ ...props
682
+ }
683
+ );
684
+ }
685
+ function SidebarGroup({ className, ...props }) {
686
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
687
+ "div",
688
+ {
689
+ "data-slot": "sidebar-group",
690
+ "data-sidebar": "group",
691
+ className: cn("relative flex w-full min-w-0 flex-col p-2", className),
692
+ ...props
693
+ }
694
+ );
695
+ }
696
+ function SidebarGroupLabel({
697
+ className,
698
+ render,
699
+ ...props
700
+ }) {
701
+ return useRender({
702
+ defaultTagName: "div",
703
+ props: mergeProps(
704
+ {
705
+ className: cn(
706
+ "flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
707
+ className
708
+ )
709
+ },
710
+ props
711
+ ),
712
+ render,
713
+ state: {
714
+ slot: "sidebar-group-label",
715
+ sidebar: "group-label"
716
+ }
717
+ });
718
+ }
719
+ function SidebarMenu({ className, ...props }) {
720
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
721
+ "ul",
722
+ {
723
+ "data-slot": "sidebar-menu",
724
+ "data-sidebar": "menu",
725
+ className: cn("flex w-full min-w-0 flex-col gap-0", className),
726
+ ...props
727
+ }
728
+ );
729
+ }
730
+ function SidebarMenuItem({ className, ...props }) {
731
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
732
+ "li",
733
+ {
734
+ "data-slot": "sidebar-menu-item",
735
+ "data-sidebar": "menu-item",
736
+ className: cn("group/menu-item relative", className),
737
+ ...props
738
+ }
739
+ );
740
+ }
741
+ const sidebarMenuButtonVariants = cva(
742
+ "peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
743
+ {
744
+ variants: {
745
+ variant: {
746
+ default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
747
+ outline: "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]"
748
+ },
749
+ size: {
750
+ default: "h-8 text-sm",
751
+ sm: "h-7 text-xs",
752
+ lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!"
753
+ }
754
+ },
755
+ defaultVariants: {
756
+ variant: "default",
757
+ size: "default"
758
+ }
759
+ }
760
+ );
761
+ function SidebarMenuButton({
762
+ render,
763
+ isActive = false,
764
+ variant = "default",
765
+ size = "default",
766
+ tooltip,
767
+ className,
768
+ ...props
769
+ }) {
770
+ const { isMobile, state } = useSidebar();
771
+ const comp = useRender({
772
+ defaultTagName: "button",
773
+ props: mergeProps(
774
+ {
775
+ className: cn(sidebarMenuButtonVariants({ variant, size }), className)
776
+ },
777
+ props
778
+ ),
779
+ render: !tooltip ? render : /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { render }),
780
+ state: {
781
+ slot: "sidebar-menu-button",
782
+ sidebar: "menu-button",
783
+ size,
784
+ active: isActive
785
+ }
786
+ });
787
+ if (!tooltip) {
788
+ return comp;
789
+ }
790
+ if (typeof tooltip === "string") {
791
+ tooltip = {
792
+ children: tooltip
793
+ };
794
+ }
795
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
796
+ comp,
797
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
798
+ TooltipContent,
799
+ {
800
+ side: "right",
801
+ align: "center",
802
+ hidden: state !== "collapsed" || isMobile,
803
+ ...tooltip
804
+ }
805
+ )
806
+ ] });
807
+ }
808
+ function SidebarMenuSub({ className, ...props }) {
809
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
810
+ "ul",
811
+ {
812
+ "data-slot": "sidebar-menu-sub",
813
+ "data-sidebar": "menu-sub",
814
+ className: cn(
815
+ "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5 group-data-[collapsible=icon]:hidden",
816
+ className
817
+ ),
818
+ ...props
819
+ }
820
+ );
821
+ }
822
+ function SidebarMenuSubButton({
823
+ render,
824
+ size = "md",
825
+ isActive = false,
826
+ className,
827
+ ...props
828
+ }) {
829
+ return useRender({
830
+ defaultTagName: "a",
831
+ props: mergeProps(
832
+ {
833
+ className: cn(
834
+ "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground ring-sidebar-ring outline-hidden group-data-[collapsible=icon]:hidden hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[size=md]:text-sm data-[size=sm]:text-xs data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground",
835
+ className
836
+ )
837
+ },
838
+ props
839
+ ),
840
+ render,
841
+ state: {
842
+ slot: "sidebar-menu-sub-button",
843
+ sidebar: "menu-sub-button",
844
+ size,
845
+ active: isActive
846
+ }
847
+ });
848
+ }
849
+ function Collapsible({ ...props }) {
850
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleRoot, { "data-slot": "collapsible", ...props });
851
+ }
852
+ function CollapsibleTrigger({ ...props }) {
853
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleTrigger$1, { "data-slot": "collapsible-trigger", ...props });
854
+ }
855
+ function CollapsibleContent({ ...props }) {
856
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CollapsiblePanel, { "data-slot": "collapsible-content", ...props });
857
+ }
858
+ function isRouteActive(pathname, link) {
859
+ if (pathname === link) return true;
860
+ if (link !== "/" && pathname.startsWith(link)) return true;
861
+ return false;
862
+ }
863
+ function DashboardNavigation({ routes }) {
864
+ const { state } = useSidebar();
865
+ const isCollapsed = state === "collapsed";
866
+ const [openCollapsible, setOpenCollapsible] = reactExports.useState(null);
867
+ const location = useLocation();
868
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarMenu, { children: routes.map((route) => {
869
+ const isOpen = !isCollapsed && openCollapsible === route.id;
870
+ const hasSubRoutes = !!route.subs?.length;
871
+ const isActive = isRouteActive(location.pathname, route.link) || route.subs?.some((sub) => isRouteActive(location.pathname, sub.link));
872
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarMenuItem, { children: hasSubRoutes ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
873
+ Collapsible,
874
+ {
875
+ open: isOpen,
876
+ onOpenChange: (open) => setOpenCollapsible(open ? route.id : null),
877
+ className: "w-full",
878
+ children: [
879
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
880
+ CollapsibleTrigger,
881
+ {
882
+ render: /* @__PURE__ */ jsxRuntimeExports.jsx(
883
+ SidebarMenuButton,
884
+ {
885
+ className: cn(
886
+ "flex w-full items-center rounded-lg px-2 transition-colors",
887
+ isOpen || isActive ? "bg-sidebar-muted text-foreground" : "text-muted-foreground hover:bg-sidebar-muted hover:text-foreground",
888
+ isCollapsed && "justify-center"
889
+ )
890
+ }
891
+ ),
892
+ children: [
893
+ route.icon,
894
+ !isCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-2 flex-1 text-sm font-medium", children: route.title }),
895
+ !isCollapsed && hasSubRoutes && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-auto", children: isOpen ? /* @__PURE__ */ jsxRuntimeExports.jsx(IconChevronUp, { className: "size-4" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(IconChevronDown, { className: "size-4" }) })
896
+ ]
897
+ }
898
+ ),
899
+ !isCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarMenuSub, { className: "my-1 ml-3.5", children: route.subs?.map((subRoute) => {
900
+ const isSubActive = isRouteActive(location.pathname, subRoute.link);
901
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
902
+ SidebarMenuItem,
903
+ {
904
+ className: "h-auto",
905
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
906
+ SidebarMenuSubButton,
907
+ {
908
+ render: /* @__PURE__ */ jsxRuntimeExports.jsx(
909
+ Link,
910
+ {
911
+ to: subRoute.link,
912
+ className: cn(
913
+ "flex items-center rounded-md px-4 py-1.5 text-sm font-medium",
914
+ isSubActive ? "bg-sidebar-muted text-foreground" : "text-muted-foreground hover:bg-sidebar-muted hover:text-foreground"
915
+ )
916
+ }
917
+ ),
918
+ children: subRoute.title
919
+ }
920
+ )
921
+ },
922
+ `${route.id}-${subRoute.title}`
923
+ );
924
+ }) }) })
925
+ ]
926
+ }
927
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
928
+ SidebarMenuButton,
929
+ {
930
+ tooltip: route.title,
931
+ render: /* @__PURE__ */ jsxRuntimeExports.jsx(
932
+ Link,
933
+ {
934
+ to: route.link,
935
+ className: cn(
936
+ "flex items-center rounded-lg px-2 transition-colors",
937
+ isActive ? "bg-sidebar-muted text-foreground" : "text-muted-foreground hover:bg-sidebar-muted hover:text-foreground",
938
+ isCollapsed && "justify-center"
939
+ )
940
+ }
941
+ ),
942
+ children: [
943
+ route.icon,
944
+ !isCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-2 text-sm font-medium", children: route.title })
945
+ ]
946
+ }
947
+ ) }, route.id);
948
+ }) });
949
+ }
950
+ function DropdownMenu({ ...props }) {
951
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(MenuRoot, { "data-slot": "dropdown-menu", ...props });
952
+ }
953
+ function DropdownMenuTrigger({ ...props }) {
954
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(MenuTrigger, { "data-slot": "dropdown-menu-trigger", ...props });
955
+ }
956
+ function DropdownMenuContent({
957
+ align = "start",
958
+ alignOffset = 0,
959
+ side = "bottom",
960
+ sideOffset = 4,
961
+ className,
962
+ ...props
963
+ }) {
964
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(MenuPortal, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
965
+ MenuPositioner,
966
+ {
967
+ className: "isolate z-50 outline-none",
968
+ align,
969
+ alignOffset,
970
+ side,
971
+ sideOffset,
972
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
973
+ MenuPopup,
974
+ {
975
+ "data-slot": "dropdown-menu-content",
976
+ className: cn("z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95 animate-none! relative bg-popover/70 before:pointer-events-none before:absolute before:inset-0 before:-z-1 before:rounded-[inherit] before:backdrop-blur-2xl before:backdrop-saturate-150 **:data-[slot$=-item]:focus:bg-foreground/10 **:data-[slot$=-item]:data-highlighted:bg-foreground/10 **:data-[slot$=-separator]:bg-foreground/5 **:data-[slot$=-trigger]:focus:bg-foreground/10 **:data-[slot$=-trigger]:aria-expanded:bg-foreground/10! **:data-[variant=destructive]:focus:bg-foreground/10! **:data-[variant=destructive]:text-accent-foreground! **:data-[variant=destructive]:**:text-accent-foreground!", className),
977
+ ...props
978
+ }
979
+ )
980
+ }
981
+ ) });
982
+ }
983
+ function DropdownMenuItem({
984
+ className,
985
+ inset,
986
+ variant = "default",
987
+ ...props
988
+ }) {
989
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
990
+ MenuItem,
991
+ {
992
+ "data-slot": "dropdown-menu-item",
993
+ "data-inset": inset,
994
+ "data-variant": variant,
995
+ className: cn(
996
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
997
+ className
998
+ ),
999
+ ...props
1000
+ }
1001
+ );
1002
+ }
1003
+ const BASE_URL = "http://localhost:8788";
1004
+ class ApiError extends Error {
1005
+ constructor(message, status, code) {
1006
+ super(message);
1007
+ this.status = status;
1008
+ this.code = code;
1009
+ this.name = "ApiError";
1010
+ }
1011
+ status;
1012
+ code;
1013
+ }
1014
+ async function handleResponse(res) {
1015
+ if (!res.ok) {
1016
+ let body = null;
1017
+ try {
1018
+ body = await res.json();
1019
+ } catch {
1020
+ }
1021
+ throw new ApiError(
1022
+ (body && typeof body.error === "string" ? body.error : res.statusText) ?? "Unknown error",
1023
+ res.status,
1024
+ typeof body?.code === "string" ? body.code : void 0
1025
+ );
1026
+ }
1027
+ return res.json();
1028
+ }
1029
+ async function get(path, params) {
1030
+ const url = new URL(`${BASE_URL}${path}`);
1031
+ const res = await fetch(url, { credentials: "include", cache: "no-store" });
1032
+ return handleResponse(res);
1033
+ }
1034
+ async function post(path, body) {
1035
+ const res = await fetch(`${BASE_URL}${path}`, {
1036
+ method: "POST",
1037
+ headers: { "Content-Type": "application/json" },
1038
+ credentials: "include",
1039
+ body: body != null ? JSON.stringify(body) : void 0
1040
+ });
1041
+ return handleResponse(res);
1042
+ }
1043
+ async function put(path, body) {
1044
+ const res = await fetch(`${BASE_URL}${path}`, {
1045
+ method: "PUT",
1046
+ headers: { "Content-Type": "application/json" },
1047
+ credentials: "include",
1048
+ body: body != null ? JSON.stringify(body) : void 0
1049
+ });
1050
+ return handleResponse(res);
1051
+ }
1052
+ async function patch(path, body) {
1053
+ const res = await fetch(`${BASE_URL}${path}`, {
1054
+ method: "PATCH",
1055
+ headers: { "Content-Type": "application/json" },
1056
+ credentials: "include",
1057
+ body: body != null ? JSON.stringify(body) : void 0
1058
+ });
1059
+ return handleResponse(res);
1060
+ }
1061
+ async function del(path) {
1062
+ const res = await fetch(`${BASE_URL}${path}`, {
1063
+ method: "DELETE",
1064
+ credentials: "include"
1065
+ });
1066
+ return handleResponse(res);
1067
+ }
1068
+ function uid() {
1069
+ return Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
1070
+ }
1071
+ const ACTIVE_SESSION_KEY = "hermium_active_session";
1072
+ const PINNED_SESSIONS_KEY = "hermium_pinned_sessions";
1073
+ function loadPinnedSessions() {
1074
+ try {
1075
+ const raw = localStorage.getItem(PINNED_SESSIONS_KEY);
1076
+ return raw ? JSON.parse(raw) : [];
1077
+ } catch {
1078
+ return [];
1079
+ }
1080
+ }
1081
+ function savePinnedSessions(ids) {
1082
+ localStorage.setItem(PINNED_SESSIONS_KEY, JSON.stringify(ids));
1083
+ }
1084
+ const initialState = {
1085
+ sessions: [],
1086
+ activeSessionId: null,
1087
+ streamingSessions: /* @__PURE__ */ new Set(),
1088
+ isLoadingSessions: false,
1089
+ isLoadingMessages: false,
1090
+ sessionsLoaded: false,
1091
+ pinnedSessionIds: loadPinnedSessions()
1092
+ };
1093
+ let _loadingSessionId = null;
1094
+ const useChatStore = create()(
1095
+ devtools(
1096
+ (set, get$1) => ({
1097
+ ...initialState,
1098
+ getSession: (id) => get$1().sessions.find((s) => s.id === id),
1099
+ activeSession: () => {
1100
+ const st = get$1();
1101
+ return st.sessions.find((s) => s.id === st.activeSessionId) || null;
1102
+ },
1103
+ messages: () => {
1104
+ const st = get$1();
1105
+ const session = st.sessions.find((s) => s.id === st.activeSessionId);
1106
+ return session?.messages || [];
1107
+ },
1108
+ updateSession: (id, update) => {
1109
+ set((s) => ({
1110
+ sessions: s.sessions.map(
1111
+ (sx) => sx.id === id ? { ...sx, ...update } : sx
1112
+ )
1113
+ }));
1114
+ },
1115
+ loadSessions: async () => {
1116
+ try {
1117
+ set({ isLoadingSessions: true });
1118
+ const data = await get("/api/sessions");
1119
+ const apiSessions = (data.sessions || []).map((s) => {
1120
+ const startedAt = s.started_at ? s.started_at < 1e12 ? s.started_at * 1e3 : s.started_at : Date.now();
1121
+ return {
1122
+ id: String(s.id),
1123
+ title: s.title || "Untitled",
1124
+ model: s.model || "",
1125
+ source: s.source || "webui",
1126
+ messages: [],
1127
+ createdAt: startedAt,
1128
+ updatedAt: s.ended_at ? s.ended_at < 1e12 ? s.ended_at * 1e3 : s.ended_at : startedAt,
1129
+ messageCount: s.message_count ?? 0,
1130
+ inputTokens: s.input_tokens ?? 0,
1131
+ outputTokens: s.output_tokens ?? 0
1132
+ };
1133
+ });
1134
+ const deduped = /* @__PURE__ */ new Map();
1135
+ for (const s of apiSessions) deduped.set(s.id, s);
1136
+ const apiSessionsDeduped = [...deduped.values()];
1137
+ const preservedLocals = get$1().sessions.filter(
1138
+ (local) => !apiSessionsDeduped.some((api) => api.id === local.id) && (local.messages.length > 0 || local.id === get$1().activeSessionId)
1139
+ );
1140
+ const merged = [...preservedLocals, ...apiSessionsDeduped];
1141
+ set({ sessions: merged, sessionsLoaded: true, streamingSessions: /* @__PURE__ */ new Set() });
1142
+ const currentActive = get$1().activeSessionId;
1143
+ if (!currentActive) {
1144
+ const savedId = localStorage.getItem(ACTIVE_SESSION_KEY);
1145
+ if (savedId && apiSessionsDeduped.some((s) => s.id === savedId)) {
1146
+ get$1().switchSession(savedId);
1147
+ }
1148
+ }
1149
+ } catch (err) {
1150
+ console.error("Failed to load sessions:", err);
1151
+ } finally {
1152
+ set({ isLoadingSessions: false });
1153
+ }
1154
+ },
1155
+ switchSession: (id) => {
1156
+ const current = get$1().activeSessionId;
1157
+ if (current === id) return;
1158
+ set({ activeSessionId: id });
1159
+ localStorage.setItem(ACTIVE_SESSION_KEY, id);
1160
+ },
1161
+ loadSessionMessages: async (id) => {
1162
+ _loadingSessionId = id;
1163
+ try {
1164
+ set({ isLoadingMessages: true });
1165
+ const data = await get(`/api/sessions/${id}`);
1166
+ if (_loadingSessionId !== id) return;
1167
+ const rawMessages = data.messages || [];
1168
+ const msgs = rawMessages.map((m, idx) => ({
1169
+ id: String(m.id || `${id}-${idx}`),
1170
+ role: m.role,
1171
+ content: typeof m.content === "string" ? m.content : "",
1172
+ timestamp: m.timestamp ? Number(m.timestamp) * (m.timestamp < 1e12 ? 1e3 : 1) : Date.now(),
1173
+ toolCalls: m.tool_calls ? m.tool_calls.map((tc) => ({
1174
+ name: tc.function?.name || tc.name || "tool",
1175
+ preview: "",
1176
+ status: "done",
1177
+ callId: tc.id || void 0,
1178
+ output: void 0
1179
+ })) : void 0,
1180
+ reasoning: m.reasoning || m.reasoning_content || void 0
1181
+ }));
1182
+ const title = data.title || msgs.find((m) => m.role === "user")?.content?.slice(0, 64) || "Untitled";
1183
+ set((s) => {
1184
+ const existing = s.sessions.find((sx) => sx.id === id);
1185
+ if (existing) {
1186
+ const mergedMessages = msgs.length === 0 && existing.messages.length > 0 ? existing.messages : msgs;
1187
+ return {
1188
+ sessions: s.sessions.map(
1189
+ (sx) => sx.id === id ? {
1190
+ ...sx,
1191
+ messages: mergedMessages,
1192
+ title,
1193
+ model: sx.model || data.model || "",
1194
+ messageCount: data.message_count ?? sx.messageCount ?? msgs.length,
1195
+ inputTokens: data.input_tokens ?? sx.inputTokens ?? 0,
1196
+ outputTokens: data.output_tokens ?? sx.outputTokens ?? 0,
1197
+ reasoningTokens: data.reasoning_tokens ?? sx.reasoningTokens ?? 0
1198
+ } : sx
1199
+ )
1200
+ };
1201
+ }
1202
+ return {
1203
+ sessions: [
1204
+ ...s.sessions,
1205
+ {
1206
+ id,
1207
+ title,
1208
+ model: data.model || "",
1209
+ source: data.source || "webui",
1210
+ messages: msgs,
1211
+ createdAt: data.started_at ? data.started_at < 1e12 ? data.started_at * 1e3 : data.started_at : Date.now(),
1212
+ updatedAt: data.ended_at ? data.ended_at < 1e12 ? data.ended_at * 1e3 : data.ended_at : Date.now(),
1213
+ messageCount: data.message_count ?? msgs.length,
1214
+ inputTokens: data.input_tokens ?? 0,
1215
+ outputTokens: data.output_tokens ?? 0,
1216
+ reasoningTokens: data.reasoning_tokens ?? 0
1217
+ }
1218
+ ]
1219
+ };
1220
+ });
1221
+ } finally {
1222
+ if (_loadingSessionId === id) _loadingSessionId = null;
1223
+ set({ isLoadingMessages: false });
1224
+ }
1225
+ },
1226
+ deleteSession: (id) => {
1227
+ set((s) => ({
1228
+ sessions: s.sessions.filter((sx) => sx.id !== id)
1229
+ }));
1230
+ },
1231
+ newChat: async (model) => {
1232
+ const sessionId = uid();
1233
+ const now = Date.now();
1234
+ const session = {
1235
+ id: sessionId,
1236
+ title: "New Conversation",
1237
+ model: model || "",
1238
+ messages: [],
1239
+ createdAt: now,
1240
+ updatedAt: now
1241
+ };
1242
+ set((s) => ({
1243
+ sessions: [session, ...s.sessions],
1244
+ activeSessionId: session.id
1245
+ }));
1246
+ localStorage.setItem(ACTIVE_SESSION_KEY, session.id);
1247
+ return session.id;
1248
+ },
1249
+ addOrUpdateSession: (session) => {
1250
+ set((s) => {
1251
+ const idx = s.sessions.findIndex((sx) => sx.id === session.id);
1252
+ if (idx >= 0) {
1253
+ const updated = [...s.sessions];
1254
+ updated[idx] = { ...updated[idx], ...session };
1255
+ return { sessions: updated };
1256
+ }
1257
+ return { sessions: [session, ...s.sessions] };
1258
+ });
1259
+ },
1260
+ togglePin: (sessionId) => {
1261
+ set((s) => {
1262
+ const isPinned = s.pinnedSessionIds.includes(sessionId);
1263
+ const next = isPinned ? s.pinnedSessionIds.filter((id) => id !== sessionId) : [...s.pinnedSessionIds, sessionId];
1264
+ savePinnedSessions(next);
1265
+ return { pinnedSessionIds: next };
1266
+ });
1267
+ },
1268
+ isSessionStreaming: (id) => {
1269
+ return get$1().streamingSessions.has(id);
1270
+ }
1271
+ }),
1272
+ { name: "chat", enabled: false }
1273
+ )
1274
+ );
1275
+ async function createSession(params) {
1276
+ const data = await post("/api/sessions", { model: params?.model });
1277
+ return {
1278
+ id: data.id,
1279
+ session_id: data.id,
1280
+ title: data.title || "New Conversation",
1281
+ workspace: params?.workspace || "",
1282
+ model: data.model || "",
1283
+ source: data.source || "webui",
1284
+ message_count: data.message_count ?? 0,
1285
+ started_at: data.started_at,
1286
+ ended_at: null,
1287
+ created_at: data.started_at,
1288
+ updated_at: data.started_at,
1289
+ input_tokens: data.input_tokens ?? 0,
1290
+ output_tokens: data.output_tokens ?? 0
1291
+ };
1292
+ }
1293
+ async function renameSession(sessionId, title) {
1294
+ return patch(`/api/sessions/${sessionId}`, { title });
1295
+ }
1296
+ async function deleteSessionApi(sessionId) {
1297
+ return del(`/api/sessions/${sessionId}`);
1298
+ }
1299
+ async function fetchModels() {
1300
+ return get("/api/config/models");
1301
+ }
1302
+ async function respondApproval(params) {
1303
+ return post("/api/approval/respond", params);
1304
+ }
1305
+ function normalizeContent(raw) {
1306
+ if (typeof raw === "string") return raw;
1307
+ if (Array.isArray(raw)) {
1308
+ return raw.map((p) => typeof p === "object" && p.text ? p.text : "").join(" ");
1309
+ }
1310
+ return "";
1311
+ }
1312
+ function transformMessage(m, sessionId, index) {
1313
+ const role = m.role;
1314
+ const content = normalizeContent(m.content);
1315
+ const reasoning = m.reasoning || m.reasoning_content || "";
1316
+ const toolCalls = [];
1317
+ if (Array.isArray(m.tool_calls)) {
1318
+ for (const tc of m.tool_calls) {
1319
+ const fn = tc.function;
1320
+ const tcName = fn?.name || tc.name;
1321
+ if (tcName) {
1322
+ toolCalls.push({ name: tcName, preview: "", status: "done" });
1323
+ }
1324
+ }
1325
+ }
1326
+ let displayRole = "assistant";
1327
+ if (role === "user") displayRole = "user";
1328
+ if (role === "tool") displayRole = "tool";
1329
+ return {
1330
+ id: `${sessionId}-${index}`,
1331
+ role: displayRole,
1332
+ content,
1333
+ timestamp: m.timestamp ? Number(m.timestamp) * (m.timestamp < 1e12 ? 1e3 : 1) : Date.now(),
1334
+ reasoning: reasoning || void 0,
1335
+ toolName: m.name || void 0,
1336
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0
1337
+ };
1338
+ }
1339
+ const sessionMsgKeys = {
1340
+ all: ["session-messages"],
1341
+ detail: (id) => [...sessionMsgKeys.all, id]
1342
+ };
1343
+ function prefetchSessionMessages(queryClient2, sessionId) {
1344
+ return queryClient2.prefetchQuery({
1345
+ queryKey: sessionMsgKeys.detail(sessionId),
1346
+ queryFn: async () => {
1347
+ const data = await get(
1348
+ `/api/sessions/${sessionId}`
1349
+ );
1350
+ const msgs = [];
1351
+ let derivedTitle = data.title || "";
1352
+ for (const m of data.messages ?? []) {
1353
+ const msg = transformMessage(m, sessionId, msgs.length);
1354
+ msgs.push(msg);
1355
+ if (!derivedTitle && m.role === "user" && msg.content.trim()) {
1356
+ derivedTitle = msg.content.trim();
1357
+ }
1358
+ }
1359
+ return { messages: msgs, title: derivedTitle || "Conversation" };
1360
+ },
1361
+ staleTime: 3e4,
1362
+ gcTime: 3e5
1363
+ });
1364
+ }
1365
+ const dashboardRoutes = [
1366
+ {
1367
+ id: "dashboard",
1368
+ title: "New Chat",
1369
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconCirclePlus, { className: "size-4" }),
1370
+ link: "/"
1371
+ },
1372
+ {
1373
+ id: "memory",
1374
+ title: "Memory",
1375
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconBrain, { className: "size-4" }),
1376
+ link: "/memory"
1377
+ },
1378
+ {
1379
+ id: "skills",
1380
+ title: "Skills",
1381
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconPuzzle, { className: "size-4" }),
1382
+ link: "/skills"
1383
+ },
1384
+ {
1385
+ id: "automations",
1386
+ title: "Automations",
1387
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconRobot, { className: "size-4" }),
1388
+ link: "/automations"
1389
+ },
1390
+ {
1391
+ id: "channels",
1392
+ title: "Channels",
1393
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconHash, { className: "size-4" }),
1394
+ link: "/channels"
1395
+ },
1396
+ {
1397
+ id: "usage",
1398
+ title: "Usage",
1399
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconChartBar, { className: "size-4" }),
1400
+ link: "/usage"
1401
+ }
1402
+ ];
1403
+ function isSettingsPath(pathname) {
1404
+ return pathname.startsWith("/settings");
1405
+ }
1406
+ function DashboardSidebar() {
1407
+ const { state } = useSidebar();
1408
+ const isCollapsed = state === "collapsed";
1409
+ const { resolvedTheme, setTheme } = useTheme();
1410
+ const queryClient2 = useQueryClient();
1411
+ const sessions = useChatStore((s) => s.sessions);
1412
+ const loadSessions = useChatStore((s) => s.loadSessions);
1413
+ const activeSessionId = useChatStore((s) => s.activeSessionId);
1414
+ const deleteStoreSession = useChatStore((s) => s.deleteSession);
1415
+ const sessionsLoaded = useChatStore((s) => s.sessionsLoaded);
1416
+ const pinnedIds = useChatStore((s) => s.pinnedSessionIds);
1417
+ const togglePin = useChatStore((s) => s.togglePin);
1418
+ const prefetchSession = reactExports.useCallback(
1419
+ (sid) => prefetchSessionMessages(queryClient2, sid),
1420
+ [queryClient2]
1421
+ );
1422
+ const location = useLocation();
1423
+ const currentSection = new URLSearchParams(location.search).get("section") || "profile";
1424
+ const [searchQuery, setSearchQuery] = reactExports.useState("");
1425
+ const [isSearchOpen, setIsSearchOpen] = reactExports.useState(false);
1426
+ const [activePanel, setActivePanel] = reactExports.useState(
1427
+ isSettingsPath(location.pathname) ? "settings" : "main"
1428
+ );
1429
+ const searchRef = reactExports.useRef(null);
1430
+ reactExports.useEffect(() => {
1431
+ setActivePanel(isSettingsPath(location.pathname) ? "settings" : "main");
1432
+ }, [location.pathname]);
1433
+ reactExports.useEffect(() => {
1434
+ console.log("[Sidebar] mount effect, sessionsLoaded=", sessionsLoaded);
1435
+ if (!sessionsLoaded) {
1436
+ loadSessions();
1437
+ }
1438
+ }, [sessionsLoaded, loadSessions]);
1439
+ const [editingSessionId, setEditingSessionId] = reactExports.useState(null);
1440
+ const [editTitle, setEditTitle] = reactExports.useState("");
1441
+ const renameInputRef = reactExports.useRef(null);
1442
+ const handleDeleteSession = async (sid) => {
1443
+ try {
1444
+ await deleteSessionApi(sid);
1445
+ deleteStoreSession(sid);
1446
+ } catch {
1447
+ }
1448
+ };
1449
+ const handleRename = async (sid) => {
1450
+ const trimmed = editTitle.trim();
1451
+ if (!trimmed) {
1452
+ setEditingSessionId(null);
1453
+ return;
1454
+ }
1455
+ try {
1456
+ await renameSession(sid, trimmed);
1457
+ useChatStore.getState().updateSession(sid, { title: trimmed });
1458
+ } catch {
1459
+ }
1460
+ setEditingSessionId(null);
1461
+ };
1462
+ const handleCopyId = (sid) => {
1463
+ navigator.clipboard.writeText(sid).catch(() => {
1464
+ });
1465
+ };
1466
+ const startRename = (s) => {
1467
+ setEditingSessionId(s.id);
1468
+ setEditTitle(s.title);
1469
+ setTimeout(() => renameInputRef.current?.focus(), 0);
1470
+ };
1471
+ const visibleSessions = sessions.filter(
1472
+ (s) => s.messages.length > 0 || (s.messageCount ?? 0) > 0 || s.id === activeSessionId
1473
+ );
1474
+ const filteredSessions = searchQuery ? visibleSessions.filter(
1475
+ (s) => s.title.toLowerCase().includes(searchQuery.toLowerCase())
1476
+ ) : visibleSessions;
1477
+ const pinnedSessions = filteredSessions.filter((s) => pinnedIds.includes(s.id));
1478
+ const unpinnedSessions = filteredSessions.filter((s) => !pinnedIds.includes(s.id));
1479
+ const openSearch = () => {
1480
+ setIsSearchOpen(true);
1481
+ setTimeout(() => searchRef.current?.focus(), 0);
1482
+ };
1483
+ const closeSearch = () => {
1484
+ setIsSearchOpen(false);
1485
+ setSearchQuery("");
1486
+ };
1487
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Sidebar, { variant: "inset", collapsible: "icon", children: [
1488
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1489
+ SidebarHeader,
1490
+ {
1491
+ className: cn(
1492
+ "flex px-0.5 md:pt-3.5",
1493
+ isCollapsed ? "flex-row items-center justify-between gap-y-4 md:flex-col md:items-start md:justify-start" : "flex-row items-center justify-between"
1494
+ ),
1495
+ children: [
1496
+ /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "/", className: "flex items-center px-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: "/nous-logo.png", alt: "Nous", className: "h-6 w-6 rounded object-cover shrink-0" }) }),
1497
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("flex items-center gap-2", isCollapsed ? "flex-row md:flex-col-reverse" : "flex-row"), children: /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarTrigger, {}) })
1498
+ ]
1499
+ }
1500
+ ),
1501
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative flex flex-col flex-1 min-h-0 gap-1 px-0.5 py-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
1502
+ "div",
1503
+ {
1504
+ className: "flex h-full transition-transform duration-150 ease-out",
1505
+ style: {
1506
+ width: "200%",
1507
+ transform: activePanel === "settings" ? "translateX(-50%)" : "translateX(0)"
1508
+ },
1509
+ children: [
1510
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1 h-full justify-between w-1/2", children: [
1511
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1 flex-1 min-h-0", children: [
1512
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DashboardNavigation, { routes: dashboardRoutes }),
1513
+ !isCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsxs(SidebarGroup, { className: "px-0 flex flex-col min-h-0", children: [
1514
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "group/search flex items-center justify-between px-0.5 pb-0.5 shrink-0", children: isSearchOpen ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex w-full items-center gap-1 min-w-0", children: [
1515
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconSearch, { className: "size-3.5 shrink-0 text-muted-foreground" }),
1516
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1517
+ "input",
1518
+ {
1519
+ ref: searchRef,
1520
+ value: searchQuery,
1521
+ onChange: (e) => setSearchQuery(e.target.value),
1522
+ onKeyDown: (e) => {
1523
+ if (e.key === "Escape") closeSearch();
1524
+ },
1525
+ placeholder: "Search...",
1526
+ className: "flex-1 min-w-0 bg-transparent border-none outline-none text-xs text-foreground placeholder:text-muted-foreground/50"
1527
+ }
1528
+ ),
1529
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1530
+ "button",
1531
+ {
1532
+ onClick: closeSearch,
1533
+ className: "flex shrink-0 items-center justify-center rounded-md p-1 text-muted-foreground hover:text-foreground hover:bg-sidebar-muted transition-colors",
1534
+ "aria-label": "Close search",
1535
+ title: "Close search",
1536
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(IconX, { className: "size-4" })
1537
+ }
1538
+ )
1539
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1540
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarGroupLabel, { className: "!text-[11px] !font-normal text-muted-foreground/60", children: "Chats" }),
1541
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1542
+ "button",
1543
+ {
1544
+ onClick: openSearch,
1545
+ className: "flex shrink-0 items-center justify-center rounded p-0.5 text-muted-foreground opacity-0 hover:text-foreground group-hover/search:opacity-100 transition-opacity",
1546
+ "aria-label": "Search chats",
1547
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(IconSearch, { className: "size-3.5" })
1548
+ }
1549
+ )
1550
+ ] }) }),
1551
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(SidebarMenu, { children: [
1552
+ filteredSessions.length === 0 && searchQuery && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "px-2 py-4 text-xs text-muted-foreground", children: [
1553
+ 'No chats match "',
1554
+ searchQuery,
1555
+ '"'
1556
+ ] }),
1557
+ filteredSessions.length === 0 && !searchQuery && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "px-2 py-4 text-xs text-muted-foreground", children: "No conversations yet. Start chatting!" }),
1558
+ pinnedSessions.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(
1559
+ SessionItem,
1560
+ {
1561
+ session: s,
1562
+ isActive: activeSessionId === s.id,
1563
+ isEditing: editingSessionId === s.id,
1564
+ editTitle,
1565
+ setEditTitle,
1566
+ renameInputRef,
1567
+ onRename: (sid) => handleRename(sid),
1568
+ onCancelRename: () => setEditingSessionId(null),
1569
+ onPrefetch: () => prefetchSession(s.id),
1570
+ onStartRename: () => startRename(s),
1571
+ onTogglePin: () => togglePin(s.id),
1572
+ onCopyId: () => handleCopyId(s.id),
1573
+ onDelete: () => handleDeleteSession(s.id),
1574
+ isPinned: true
1575
+ },
1576
+ s.id
1577
+ )),
1578
+ unpinnedSessions.slice(0, 20).map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(
1579
+ SessionItem,
1580
+ {
1581
+ session: s,
1582
+ isActive: activeSessionId === s.id,
1583
+ isEditing: editingSessionId === s.id,
1584
+ editTitle,
1585
+ setEditTitle,
1586
+ renameInputRef,
1587
+ onRename: (sid) => handleRename(sid),
1588
+ onCancelRename: () => setEditingSessionId(null),
1589
+ onPrefetch: () => prefetchSession(s.id),
1590
+ onStartRename: () => startRename(s),
1591
+ onTogglePin: () => togglePin(s.id),
1592
+ onCopyId: () => handleCopyId(s.id),
1593
+ onDelete: () => handleDeleteSession(s.id)
1594
+ },
1595
+ s.id
1596
+ ))
1597
+ ] }) })
1598
+ ] })
1599
+ ] }),
1600
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn("flex items-center", isCollapsed ? "flex-col gap-1" : "flex-row gap-1"), children: [
1601
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1602
+ Link,
1603
+ {
1604
+ to: "/settings",
1605
+ className: cn(
1606
+ "flex items-center gap-1.5 rounded-md text-xs font-medium text-muted-foreground hover:bg-sidebar-muted hover:text-foreground transition-colors",
1607
+ isCollapsed ? "justify-center p-1.5 w-full" : "flex-1 px-2 py-1"
1608
+ ),
1609
+ "aria-label": "Settings",
1610
+ title: isCollapsed ? "Settings" : void 0,
1611
+ children: [
1612
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconSettings, { className: "size-3.5 shrink-0" }),
1613
+ !isCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Settings" })
1614
+ ]
1615
+ }
1616
+ ),
1617
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1618
+ "button",
1619
+ {
1620
+ onClick: () => setTheme(resolvedTheme === "dark" ? "light" : "dark"),
1621
+ className: cn(
1622
+ "flex items-center justify-center rounded-md text-muted-foreground hover:bg-sidebar-muted hover:text-foreground transition-colors",
1623
+ isCollapsed ? "p-1.5 w-full" : "p-1.5"
1624
+ ),
1625
+ "aria-label": "Toggle theme",
1626
+ title: isCollapsed ? resolvedTheme === "dark" ? "Light mode" : "Dark mode" : void 0,
1627
+ children: [
1628
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconSun, { className: "size-3.5 dark:hidden" }),
1629
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconMoon, { className: "size-3.5 hidden dark:block" })
1630
+ ]
1631
+ }
1632
+ )
1633
+ ] }) })
1634
+ ] }),
1635
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full justify-between w-1/2", children: [
1636
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [
1637
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-1 pb-1.5 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: "Settings" }) }),
1638
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto min-h-0 space-y-0.5 px-0.5", children: [
1639
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1640
+ SettingsGroup,
1641
+ {
1642
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconUser, { className: "size-4" }),
1643
+ title: "Profile",
1644
+ section: "profile",
1645
+ activeSection: currentSection
1646
+ }
1647
+ ),
1648
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1649
+ SettingsGroup,
1650
+ {
1651
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconPaint, { className: "size-4" }),
1652
+ title: "Appearance",
1653
+ section: "appearance",
1654
+ activeSection: currentSection
1655
+ }
1656
+ ),
1657
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1658
+ SettingsGroup,
1659
+ {
1660
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconBell, { className: "size-4" }),
1661
+ title: "Notifications",
1662
+ section: "notifications",
1663
+ activeSection: currentSection
1664
+ }
1665
+ ),
1666
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1667
+ SettingsGroup,
1668
+ {
1669
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconKey, { className: "size-4" }),
1670
+ title: "API Keys",
1671
+ section: "api-keys",
1672
+ activeSection: currentSection
1673
+ }
1674
+ ),
1675
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1676
+ SettingsGroup,
1677
+ {
1678
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(IconLanguage, { className: "size-4" }),
1679
+ title: "Language & Region",
1680
+ section: "language",
1681
+ activeSection: currentSection
1682
+ }
1683
+ )
1684
+ ] })
1685
+ ] }),
1686
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 px-0.5 pb-1", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
1687
+ Link,
1688
+ {
1689
+ to: "/",
1690
+ className: "flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-sm text-muted-foreground hover:bg-sidebar-muted hover:text-foreground transition-colors",
1691
+ children: [
1692
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconArrowLeft, { className: "size-4 shrink-0" }),
1693
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Back to app" })
1694
+ ]
1695
+ }
1696
+ ) })
1697
+ ] })
1698
+ ]
1699
+ }
1700
+ ) }) }) })
1701
+ ] });
1702
+ }
1703
+ function SettingsGroup({
1704
+ icon,
1705
+ title,
1706
+ section,
1707
+ activeSection
1708
+ }) {
1709
+ const isActive = activeSection === section;
1710
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1711
+ Link,
1712
+ {
1713
+ to: "/settings",
1714
+ search: { section },
1715
+ className: cn(
1716
+ "flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-sm transition-colors",
1717
+ isActive ? "bg-sidebar-muted text-foreground font-medium" : "text-muted-foreground hover:bg-sidebar-muted hover:text-foreground"
1718
+ ),
1719
+ children: [
1720
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex shrink-0 items-center justify-center", children: icon }),
1721
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: title })
1722
+ ]
1723
+ }
1724
+ );
1725
+ }
1726
+ function SessionItem({
1727
+ session,
1728
+ isActive,
1729
+ isEditing,
1730
+ editTitle,
1731
+ setEditTitle,
1732
+ renameInputRef,
1733
+ onRename,
1734
+ onCancelRename,
1735
+ onPrefetch,
1736
+ onStartRename,
1737
+ onTogglePin,
1738
+ onCopyId,
1739
+ onDelete,
1740
+ isPinned = false
1741
+ }) {
1742
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarMenuItem, { className: "group/chat", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative", children: isEditing ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1743
+ "input",
1744
+ {
1745
+ ref: renameInputRef,
1746
+ value: editTitle,
1747
+ onChange: (e) => setEditTitle(e.target.value),
1748
+ onKeyDown: (e) => {
1749
+ if (e.key === "Enter") onRename(session.id);
1750
+ if (e.key === "Escape") onCancelRename();
1751
+ },
1752
+ onBlur: () => onCancelRename(),
1753
+ className: "w-full px-2 py-1 text-xs font-medium bg-transparent border-b border-sidebar-ring text-foreground outline-none"
1754
+ }
1755
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1756
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1757
+ SidebarMenuButton,
1758
+ {
1759
+ isActive,
1760
+ className: "px-2 py-1 pr-8 text-xs font-medium text-muted-foreground hover:text-foreground data-[active=true]:bg-sidebar-muted data-[active=true]:text-foreground",
1761
+ onDoubleClick: onStartRename,
1762
+ render: /* @__PURE__ */ jsxRuntimeExports.jsx(
1763
+ Link,
1764
+ {
1765
+ to: `/chat/${session.id}`,
1766
+ className: "flex items-center gap-1.5",
1767
+ onPointerEnter: onPrefetch
1768
+ }
1769
+ ),
1770
+ children: [
1771
+ isPinned && /* @__PURE__ */ jsxRuntimeExports.jsx(IconPin, { className: "size-3 shrink-0 text-amber-500" }),
1772
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: session.title })
1773
+ ]
1774
+ }
1775
+ ),
1776
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenu, { children: [
1777
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1778
+ DropdownMenuTrigger,
1779
+ {
1780
+ render: /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "absolute right-0 top-1/2 -translate-y-1/2 z-10 flex items-center justify-center rounded-md p-1 text-muted-foreground opacity-0 hover:bg-sidebar-muted hover:text-foreground group-hover/chat:opacity-100 transition-opacity" }),
1781
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(IconDots, { className: "size-4" })
1782
+ }
1783
+ ),
1784
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenuContent, { align: "end", side: "right", sideOffset: 4, children: [
1785
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenuItem, { className: "gap-2", onClick: onStartRename, children: [
1786
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconPencil, { className: "size-3.5" }),
1787
+ "Rename"
1788
+ ] }),
1789
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownMenuItem, { className: "gap-2", onClick: onTogglePin, children: isPinned ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1790
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconPinnedOff, { className: "size-3.5" }),
1791
+ "Unpin"
1792
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1793
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconPin, { className: "size-3.5" }),
1794
+ "Pin"
1795
+ ] }) }),
1796
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenuItem, { className: "gap-2", onClick: onCopyId, children: [
1797
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconCopy, { className: "size-3.5" }),
1798
+ "Copy ID"
1799
+ ] }),
1800
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1801
+ DropdownMenuItem,
1802
+ {
1803
+ className: "gap-2 text-destructive",
1804
+ onClick: onDelete,
1805
+ children: [
1806
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconTrash, { className: "size-3.5" }),
1807
+ "Delete"
1808
+ ]
1809
+ }
1810
+ )
1811
+ ] })
1812
+ ] })
1813
+ ] }) }) });
1814
+ }
1815
+ function DashboardLayout({ children }) {
1816
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarProvider, { style: { "--sidebar-width-icon": "2.5rem" }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative flex h-dvh w-full", children: [
1817
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DashboardSidebar, {}),
1818
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarInset, { className: "flex flex-col min-w-0", children })
1819
+ ] }) });
1820
+ }
1821
+ const appCss = "/assets/styles-C9Ypt703.css";
1822
+ const themeScript = `
1823
+ (function() {
1824
+ try {
1825
+ var theme = localStorage.getItem('hermium-theme') || 'system';
1826
+ var resolved = theme === 'system'
1827
+ ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
1828
+ : theme;
1829
+ document.documentElement.classList.toggle('dark', resolved === 'dark');
1830
+ } catch (e) {}
1831
+ })();
1832
+ `;
1833
+ const Route$9 = createRootRoute({
1834
+ head: () => ({
1835
+ meta: [
1836
+ { charSet: "utf-8" },
1837
+ {
1838
+ name: "viewport",
1839
+ content: "width=device-width, initial-scale=1"
1840
+ },
1841
+ { title: "Hermium" }
1842
+ ],
1843
+ links: [
1844
+ { rel: "stylesheet", href: appCss },
1845
+ { rel: "icon", type: "image/x-icon", href: "/favicon.ico" },
1846
+ { rel: "icon", type: "image/png", href: "/favicon.png" }
1847
+ ],
1848
+ scripts: [{ type: "text/javascript", children: themeScript }]
1849
+ }),
1850
+ notFoundComponent: () => /* @__PURE__ */ jsxRuntimeExports.jsxs("main", { className: "container mx-auto p-4 pt-16", children: [
1851
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { children: "404" }),
1852
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "The requested page could not be found." })
1853
+ ] }),
1854
+ shellComponent: RootDocument
1855
+ });
1856
+ function RootDocument({ children }) {
1857
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("html", { lang: "en", suppressHydrationWarning: true, children: [
1858
+ /* @__PURE__ */ jsxRuntimeExports.jsx("head", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(HeadContent, {}) }),
1859
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("body", { children: [
1860
+ /* @__PURE__ */ jsxRuntimeExports.jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ThemeProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(DashboardLayout, { children }) }) }) }),
1861
+ false,
1862
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Scripts, {})
1863
+ ] })
1864
+ ] });
1865
+ }
1866
+ const $$splitComponentImporter$8 = () => import("./index-DqFrn6kj.mjs");
1867
+ const Route$8 = createFileRoute("/")({
1868
+ component: lazyRouteComponent($$splitComponentImporter$8, "component")
1869
+ });
1870
+ const $$splitComponentImporter$7 = () => import("./index-JzLhPyir.mjs");
1871
+ const Route$7 = createFileRoute("/usage/")({
1872
+ component: lazyRouteComponent($$splitComponentImporter$7, "component")
1873
+ });
1874
+ const $$splitComponentImporter$6 = () => import("./index-DSIu0x-q.mjs");
1875
+ const Route$6 = createFileRoute("/skills/")({
1876
+ component: lazyRouteComponent($$splitComponentImporter$6, "component")
1877
+ });
1878
+ const $$splitComponentImporter$5 = () => import("./index-EKE8NFy_.mjs");
1879
+ const settingsSearchSchema = object({
1880
+ section: string().optional().default("profile")
1881
+ });
1882
+ const Route$5 = createFileRoute("/settings/")({
1883
+ component: lazyRouteComponent($$splitComponentImporter$5, "component"),
1884
+ validateSearch: (search) => settingsSearchSchema.parse(search)
1885
+ });
1886
+ const $$splitComponentImporter$4 = () => import("./index-wTy_4MhH.mjs");
1887
+ const Route$4 = createFileRoute("/memory/")({
1888
+ component: lazyRouteComponent($$splitComponentImporter$4, "component")
1889
+ });
1890
+ const $$splitComponentImporter$3 = () => import("./index-Bp9a_nTf.mjs");
1891
+ const Route$3 = createFileRoute("/chat/")({
1892
+ component: lazyRouteComponent($$splitComponentImporter$3, "component")
1893
+ });
1894
+ const $$splitComponentImporter$2 = () => import("./index-C8t8AZQG.mjs");
1895
+ const Route$2 = createFileRoute("/channels/")({
1896
+ component: lazyRouteComponent($$splitComponentImporter$2, "component")
1897
+ });
1898
+ const $$splitComponentImporter$1 = () => import("./index-BLK6uN4p.mjs");
1899
+ const Route$1 = createFileRoute("/automations/")({
1900
+ component: lazyRouteComponent($$splitComponentImporter$1, "component")
1901
+ });
1902
+ const $$splitComponentImporter = () => import("./index-BkkxTg0a.mjs");
1903
+ const Route = createFileRoute("/chat/$sessionId/")({
1904
+ component: lazyRouteComponent($$splitComponentImporter, "component")
1905
+ });
1906
+ const IndexRoute = Route$8.update({
1907
+ id: "/",
1908
+ path: "/",
1909
+ getParentRoute: () => Route$9
1910
+ });
1911
+ const UsageIndexRoute = Route$7.update({
1912
+ id: "/usage/",
1913
+ path: "/usage/",
1914
+ getParentRoute: () => Route$9
1915
+ });
1916
+ const SkillsIndexRoute = Route$6.update({
1917
+ id: "/skills/",
1918
+ path: "/skills/",
1919
+ getParentRoute: () => Route$9
1920
+ });
1921
+ const SettingsIndexRoute = Route$5.update({
1922
+ id: "/settings/",
1923
+ path: "/settings/",
1924
+ getParentRoute: () => Route$9
1925
+ });
1926
+ const MemoryIndexRoute = Route$4.update({
1927
+ id: "/memory/",
1928
+ path: "/memory/",
1929
+ getParentRoute: () => Route$9
1930
+ });
1931
+ const ChatIndexRoute = Route$3.update({
1932
+ id: "/chat/",
1933
+ path: "/chat/",
1934
+ getParentRoute: () => Route$9
1935
+ });
1936
+ const ChannelsIndexRoute = Route$2.update({
1937
+ id: "/channels/",
1938
+ path: "/channels/",
1939
+ getParentRoute: () => Route$9
1940
+ });
1941
+ const AutomationsIndexRoute = Route$1.update({
1942
+ id: "/automations/",
1943
+ path: "/automations/",
1944
+ getParentRoute: () => Route$9
1945
+ });
1946
+ const ChatSessionIdIndexRoute = Route.update({
1947
+ id: "/chat/$sessionId/",
1948
+ path: "/chat/$sessionId/",
1949
+ getParentRoute: () => Route$9
1950
+ });
1951
+ const rootRouteChildren = {
1952
+ IndexRoute,
1953
+ AutomationsIndexRoute,
1954
+ ChannelsIndexRoute,
1955
+ ChatIndexRoute,
1956
+ MemoryIndexRoute,
1957
+ SettingsIndexRoute,
1958
+ SkillsIndexRoute,
1959
+ UsageIndexRoute,
1960
+ ChatSessionIdIndexRoute
1961
+ };
1962
+ const routeTree = Route$9._addFileChildren(rootRouteChildren)._addFileTypes();
1963
+ function getRouter() {
1964
+ const router2 = createRouter({
1965
+ routeTree,
1966
+ scrollRestoration: true,
1967
+ defaultPreload: "intent",
1968
+ defaultPreloadStaleTime: 0
1969
+ });
1970
+ return router2;
1971
+ }
1972
+ const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1973
+ __proto__: null,
1974
+ getRouter
1975
+ }, Symbol.toStringTag, { value: "Module" }));
1976
+ export {
1977
+ Button as B,
1978
+ DropdownMenu as D,
1979
+ Route$5 as R,
1980
+ cn as a,
1981
+ useChatStore as b,
1982
+ createSession as c,
1983
+ put as d,
1984
+ patch as e,
1985
+ del as f,
1986
+ get as g,
1987
+ fetchModels as h,
1988
+ DropdownMenuTrigger as i,
1989
+ DropdownMenuContent as j,
1990
+ DropdownMenuItem as k,
1991
+ deleteSessionApi as l,
1992
+ respondApproval as m,
1993
+ Route as n,
1994
+ router as o,
1995
+ post as p,
1996
+ renameSession as r,
1997
+ useTheme as u
1998
+ };