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.
- package/bin/hermium.mjs +184 -145
- package/dist/server/index.mjs +65 -65
- package/dist/web-server/__23tanstack-start-plugin-adapters-Cwee5PKy.mjs +6 -0
- package/dist/web-server/_chunks/ssr-renderer.mjs +22 -0
- package/dist/web-server/_libs/babel__runtime.mjs +237 -0
- package/dist/web-server/_libs/bail.mjs +8 -0
- package/dist/web-server/_libs/base-ui__react.mjs +9554 -0
- package/dist/web-server/_libs/base-ui__utils.mjs +1101 -0
- package/dist/web-server/_libs/ccount.mjs +16 -0
- package/dist/web-server/_libs/character-entities-legacy.mjs +111 -0
- package/dist/web-server/_libs/character-entities.mjs +2130 -0
- package/dist/web-server/_libs/character-reference-invalid.mjs +33 -0
- package/dist/web-server/_libs/class-variance-authority.mjs +44 -0
- package/dist/web-server/_libs/clsx.mjs +16 -0
- package/dist/web-server/_libs/comma-separated-tokens.mjs +31 -0
- package/dist/web-server/_libs/cookie-es.mjs +44 -0
- package/dist/web-server/_libs/croner.mjs +1 -0
- package/dist/web-server/_libs/crossws.mjs +1 -0
- package/dist/web-server/_libs/decode-named-character-reference+[...].mjs +8 -0
- package/dist/web-server/_libs/devlop.mjs +8 -0
- package/dist/web-server/_libs/escape-string-regexp.mjs +9 -0
- package/dist/web-server/_libs/estree-util-is-identifier-name.mjs +11 -0
- package/dist/web-server/_libs/extend.mjs +97 -0
- package/dist/web-server/_libs/fault.mjs +1 -0
- package/dist/web-server/_libs/floating-ui__core.mjs +663 -0
- package/dist/web-server/_libs/floating-ui__dom.mjs +624 -0
- package/dist/web-server/_libs/floating-ui__react-dom.mjs +279 -0
- package/dist/web-server/_libs/floating-ui__utils.mjs +322 -0
- package/dist/web-server/_libs/format.mjs +1 -0
- package/dist/web-server/_libs/h3.mjs +408 -0
- package/dist/web-server/_libs/hast-util-parse-selector.mjs +39 -0
- package/dist/web-server/_libs/hast-util-to-jsx-runtime.mjs +388 -0
- package/dist/web-server/_libs/hast-util-whitespace.mjs +10 -0
- package/dist/web-server/_libs/hastscript.mjs +200 -0
- package/dist/web-server/_libs/highlight.js.mjs +1 -0
- package/dist/web-server/_libs/hookable.mjs +1 -0
- package/dist/web-server/_libs/html-url-attributes.mjs +26 -0
- package/dist/web-server/_libs/inline-style-parser.mjs +142 -0
- package/dist/web-server/_libs/is-alphabetical.mjs +7 -0
- package/dist/web-server/_libs/is-alphanumerical.mjs +8 -0
- package/dist/web-server/_libs/is-decimal.mjs +7 -0
- package/dist/web-server/_libs/is-hexadecimal.mjs +7 -0
- package/dist/web-server/_libs/is-plain-obj.mjs +10 -0
- package/dist/web-server/_libs/isbot.mjs +21 -0
- package/dist/web-server/_libs/longest-streak.mjs +25 -0
- package/dist/web-server/_libs/lowlight.mjs +1 -0
- package/dist/web-server/_libs/markdown-table.mjs +142 -0
- package/dist/web-server/_libs/mdast-util-find-and-replace.mjs +109 -0
- package/dist/web-server/_libs/mdast-util-from-markdown.mjs +717 -0
- package/dist/web-server/_libs/mdast-util-gfm-autolink-literal+[...].mjs +156 -0
- package/dist/web-server/_libs/mdast-util-gfm-footnote.mjs +117 -0
- package/dist/web-server/_libs/mdast-util-gfm-strikethrough.mjs +54 -0
- package/dist/web-server/_libs/mdast-util-gfm-table.mjs +157 -0
- package/dist/web-server/_libs/mdast-util-gfm-task-list-item.mjs +77 -0
- package/dist/web-server/_libs/mdast-util-gfm.mjs +29 -0
- package/dist/web-server/_libs/mdast-util-phrasing.mjs +30 -0
- package/dist/web-server/_libs/mdast-util-to-hast.mjs +710 -0
- package/dist/web-server/_libs/mdast-util-to-markdown.mjs +798 -0
- package/dist/web-server/_libs/mdast-util-to-string.mjs +38 -0
- package/dist/web-server/_libs/micromark-core-commonmark.mjs +2259 -0
- package/dist/web-server/_libs/micromark-extension-gfm-autolink-literal+[...].mjs +344 -0
- package/dist/web-server/_libs/micromark-extension-gfm-footnote+[...].mjs +279 -0
- package/dist/web-server/_libs/micromark-extension-gfm-strikethrough+[...].mjs +98 -0
- package/dist/web-server/_libs/micromark-extension-gfm-table.mjs +491 -0
- package/dist/web-server/_libs/micromark-extension-gfm-tagfilter+[...].mjs +1 -0
- package/dist/web-server/_libs/micromark-extension-gfm-task-list-item+[...].mjs +77 -0
- package/dist/web-server/_libs/micromark-extension-gfm.mjs +18 -0
- package/dist/web-server/_libs/micromark-factory-destination.mjs +94 -0
- package/dist/web-server/_libs/micromark-factory-label.mjs +63 -0
- package/dist/web-server/_libs/micromark-factory-space.mjs +24 -0
- package/dist/web-server/_libs/micromark-factory-title.mjs +65 -0
- package/dist/web-server/_libs/micromark-factory-whitespace.mjs +22 -0
- package/dist/web-server/_libs/micromark-util-character.mjs +44 -0
- package/dist/web-server/_libs/micromark-util-chunked.mjs +36 -0
- package/dist/web-server/_libs/micromark-util-classify-character+[...].mjs +12 -0
- package/dist/web-server/_libs/micromark-util-combine-extensions+[...].mjs +41 -0
- package/dist/web-server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +19 -0
- package/dist/web-server/_libs/micromark-util-decode-string.mjs +21 -0
- package/dist/web-server/_libs/micromark-util-encode.mjs +1 -0
- package/dist/web-server/_libs/micromark-util-html-tag-name.mjs +69 -0
- package/dist/web-server/_libs/micromark-util-normalize-identifier+[...].mjs +6 -0
- package/dist/web-server/_libs/micromark-util-resolve-all.mjs +15 -0
- package/dist/web-server/_libs/micromark-util-sanitize-uri.mjs +41 -0
- package/dist/web-server/_libs/micromark-util-subtokenize.mjs +346 -0
- package/dist/web-server/_libs/micromark.mjs +906 -0
- package/dist/web-server/_libs/ocache.mjs +1 -0
- package/dist/web-server/_libs/ohash.mjs +1 -0
- package/dist/web-server/_libs/parse-entities.mjs +245 -0
- package/dist/web-server/_libs/property-information.mjs +1210 -0
- package/dist/web-server/_libs/react-dom.mjs +10779 -0
- package/dist/web-server/_libs/react-markdown.mjs +147 -0
- package/dist/web-server/_libs/react-syntax-highlighter.mjs +941 -0
- package/dist/web-server/_libs/react.mjs +513 -0
- package/dist/web-server/_libs/refractor.mjs +2425 -0
- package/dist/web-server/_libs/remark-gfm.mjs +20 -0
- package/dist/web-server/_libs/remark-parse.mjs +19 -0
- package/dist/web-server/_libs/remark-rehype.mjs +21 -0
- package/dist/web-server/_libs/reselect.mjs +1 -0
- package/dist/web-server/_libs/rou3.mjs +8 -0
- package/dist/web-server/_libs/seroval-plugins.mjs +58 -0
- package/dist/web-server/_libs/seroval.mjs +1775 -0
- package/dist/web-server/_libs/space-separated-tokens.mjs +11 -0
- package/dist/web-server/_libs/srvx.mjs +781 -0
- package/dist/web-server/_libs/style-to-js.mjs +72 -0
- package/dist/web-server/_libs/style-to-object.mjs +38 -0
- package/dist/web-server/_libs/tabler__icons-react.mjs +224 -0
- package/dist/web-server/_libs/tanstack__history.mjs +204 -0
- package/dist/web-server/_libs/tanstack__query-core.mjs +2552 -0
- package/dist/web-server/_libs/tanstack__react-query.mjs +190 -0
- package/dist/web-server/_libs/tanstack__react-router.mjs +1120 -0
- package/dist/web-server/_libs/tanstack__react-store.mjs +2 -0
- package/dist/web-server/_libs/tanstack__router-core.mjs +4288 -0
- package/dist/web-server/_libs/tanstack__store.mjs +1 -0
- package/dist/web-server/_libs/trim-lines.mjs +41 -0
- package/dist/web-server/_libs/trough.mjs +85 -0
- package/dist/web-server/_libs/ufo.mjs +54 -0
- package/dist/web-server/_libs/unctx.mjs +1 -0
- package/dist/web-server/_libs/ungap__structured-clone.mjs +224 -0
- package/dist/web-server/_libs/unified.mjs +661 -0
- package/dist/web-server/_libs/unist-util-is.mjs +100 -0
- package/dist/web-server/_libs/unist-util-position.mjs +27 -0
- package/dist/web-server/_libs/unist-util-stringify-position.mjs +27 -0
- package/dist/web-server/_libs/unist-util-visit-parents.mjs +83 -0
- package/dist/web-server/_libs/unist-util-visit.mjs +24 -0
- package/dist/web-server/_libs/unstorage.mjs +1 -0
- package/dist/web-server/_libs/use-sync-external-store.mjs +139 -0
- package/dist/web-server/_libs/vfile-message.mjs +138 -0
- package/dist/web-server/_libs/vfile.mjs +467 -0
- package/dist/web-server/_libs/zod.mjs +3915 -0
- package/dist/web-server/_libs/zustand.mjs +343 -0
- package/dist/web-server/_libs/zwitch.mjs +1 -0
- package/dist/web-server/_ssr/index-BLK6uN4p.mjs +612 -0
- package/dist/web-server/_ssr/index-BkkxTg0a.mjs +1855 -0
- package/dist/web-server/_ssr/index-Bp9a_nTf.mjs +66 -0
- package/dist/web-server/_ssr/index-C8t8AZQG.mjs +513 -0
- package/dist/web-server/_ssr/index-DSIu0x-q.mjs +449 -0
- package/dist/web-server/_ssr/index-DqFrn6kj.mjs +278 -0
- package/dist/web-server/_ssr/index-EKE8NFy_.mjs +189 -0
- package/dist/web-server/_ssr/index-JzLhPyir.mjs +213 -0
- package/dist/web-server/_ssr/index-wTy_4MhH.mjs +369 -0
- package/dist/web-server/_ssr/index.mjs +1558 -0
- package/dist/web-server/_ssr/input-BQFduUUo.mjs +20 -0
- package/dist/web-server/_ssr/router-59cN5lqo.mjs +1998 -0
- package/dist/web-server/_ssr/start-HYkvq4Ni.mjs +4 -0
- package/dist/web-server/_ssr/switch-Bim4kX8N.mjs +33 -0
- package/dist/web-server/_ssr/syntax-highlighter-5vezNTce.mjs +62 -0
- package/dist/web-server/_ssr/textarea-CK0ROhfF.mjs +18 -0
- package/dist/web-server/_tanstack-start-manifest_v-DLw6M7p4.mjs +4 -0
- package/dist/web-server/index.mjs +611 -0
- package/package.json +1 -1
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
|
|
2
|
+
import { a as cn, g as get } from "./router-59cN5lqo.mjs";
|
|
3
|
+
import { F as IconRefresh, s as IconChartBar } from "../_libs/tabler__icons-react.mjs";
|
|
4
|
+
import "../_libs/tanstack__react-router.mjs";
|
|
5
|
+
import "../_libs/tanstack__router-core.mjs";
|
|
6
|
+
import "../_libs/tanstack__history.mjs";
|
|
7
|
+
import "../_libs/cookie-es.mjs";
|
|
8
|
+
import "../_libs/seroval.mjs";
|
|
9
|
+
import "../_libs/seroval-plugins.mjs";
|
|
10
|
+
import "node:stream/web";
|
|
11
|
+
import "node:stream";
|
|
12
|
+
import "../_libs/react-dom.mjs";
|
|
13
|
+
import "util";
|
|
14
|
+
import "crypto";
|
|
15
|
+
import "async_hooks";
|
|
16
|
+
import "stream";
|
|
17
|
+
import "../_libs/isbot.mjs";
|
|
18
|
+
import "../_libs/tanstack__query-core.mjs";
|
|
19
|
+
import "../_libs/tanstack__react-query.mjs";
|
|
20
|
+
import "../_libs/clsx.mjs";
|
|
21
|
+
import "../_libs/class-variance-authority.mjs";
|
|
22
|
+
import "../_libs/zustand.mjs";
|
|
23
|
+
import "../_libs/base-ui__react.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
|
+
import "../_libs/zod.mjs";
|
|
31
|
+
function fetchUsage(days = 30) {
|
|
32
|
+
return get(`/api/hermes/insights?days=${days}`);
|
|
33
|
+
}
|
|
34
|
+
const PERIODS = [
|
|
35
|
+
{ label: "7d", days: 7 },
|
|
36
|
+
{ label: "30d", days: 30 },
|
|
37
|
+
{ label: "90d", days: 90 }
|
|
38
|
+
];
|
|
39
|
+
function fmt(n) {
|
|
40
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
41
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
42
|
+
return String(n);
|
|
43
|
+
}
|
|
44
|
+
function fmtCost(n) {
|
|
45
|
+
if (n >= 1) return `$${n.toFixed(2)}`;
|
|
46
|
+
if (n >= 0.01) return `$${n.toFixed(4)}`;
|
|
47
|
+
return n > 0 ? `$${n.toFixed(6)}` : "$0.00";
|
|
48
|
+
}
|
|
49
|
+
function fmtPct(n) {
|
|
50
|
+
return `${(n * 100).toFixed(1)}%`;
|
|
51
|
+
}
|
|
52
|
+
function fmtDate(day) {
|
|
53
|
+
try {
|
|
54
|
+
const d = /* @__PURE__ */ new Date(day + "T00:00:00");
|
|
55
|
+
return d.toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
56
|
+
} catch {
|
|
57
|
+
return day;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function StatCard({
|
|
61
|
+
label,
|
|
62
|
+
value,
|
|
63
|
+
sub
|
|
64
|
+
}) {
|
|
65
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-xl border border-border bg-card p-4 flex flex-col gap-1", children: [
|
|
66
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-muted-foreground/70", children: label }),
|
|
67
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xl font-semibold text-foreground tracking-tight", children: value }),
|
|
68
|
+
sub && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-muted-foreground/50", children: sub })
|
|
69
|
+
] });
|
|
70
|
+
}
|
|
71
|
+
function ModelBreakdown({ models }) {
|
|
72
|
+
if (models.length === 0) return null;
|
|
73
|
+
const total = models.reduce((s, m) => s + m.sessions, 0);
|
|
74
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-xl border border-border bg-card p-4", children: [
|
|
75
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-medium text-foreground mb-3", children: "Model Breakdown" }),
|
|
76
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2.5", children: models.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
77
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-1", children: [
|
|
78
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-foreground truncate", children: m.model }),
|
|
79
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-muted-foreground tabular-nums ml-3", children: m.sessions })
|
|
80
|
+
] }),
|
|
81
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-1.5 rounded-full bg-muted overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
82
|
+
"div",
|
|
83
|
+
{
|
|
84
|
+
className: "h-full rounded-full bg-primary/50 transition-all",
|
|
85
|
+
style: { width: `${total > 0 ? m.sessions / total * 100 : 0}%` }
|
|
86
|
+
}
|
|
87
|
+
) })
|
|
88
|
+
] }) }, m.model)) })
|
|
89
|
+
] });
|
|
90
|
+
}
|
|
91
|
+
function DailyTable({ daily }) {
|
|
92
|
+
if (daily.length === 0) return null;
|
|
93
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-xl border border-border bg-card", children: [
|
|
94
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-4 pt-4 pb-3", children: [
|
|
95
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconChartBar, { className: "size-4 text-muted-foreground" }),
|
|
96
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-medium text-foreground", children: "Daily Usage (Last 30 Days)" })
|
|
97
|
+
] }),
|
|
98
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full text-xs", children: [
|
|
99
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-t border-border text-muted-foreground/60", children: [
|
|
100
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left px-4 py-2 font-medium", children: "Date" }),
|
|
101
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right px-2 py-2 font-medium", children: "Input" }),
|
|
102
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right px-2 py-2 font-medium", children: "Output" }),
|
|
103
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right px-2 py-2 font-medium", children: "Cache Hit Rate" }),
|
|
104
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-right px-2 py-2 font-medium", children: "Sessions" })
|
|
105
|
+
] }) }),
|
|
106
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: daily.map((d) => /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-t border-border/50 hover:bg-muted/30 transition-colors", children: [
|
|
107
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-4 py-2.5 text-foreground font-medium whitespace-nowrap", children: fmtDate(d.date) }),
|
|
108
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-2 py-2.5 text-right text-muted-foreground tabular-nums", children: d.input_tokens > 0 ? fmt(d.input_tokens) : "—" }),
|
|
109
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-2 py-2.5 text-right text-muted-foreground tabular-nums", children: d.output_tokens > 0 ? fmt(d.output_tokens) : "—" }),
|
|
110
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
111
|
+
"td",
|
|
112
|
+
{
|
|
113
|
+
className: "px-2 py-2.5 text-right tabular-nums",
|
|
114
|
+
style: { color: d.cache_hit_rate > 0.8 ? "#22c55e" : d.cache_hit_rate > 0.5 ? "#eab308" : "inherit" },
|
|
115
|
+
children: d.cache_hit_rate > 0 ? fmtPct(d.cache_hit_rate) : "—"
|
|
116
|
+
}
|
|
117
|
+
),
|
|
118
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-2 py-2.5 text-right text-muted-foreground tabular-nums", children: d.sessions })
|
|
119
|
+
] }, d.date)) })
|
|
120
|
+
] }) })
|
|
121
|
+
] });
|
|
122
|
+
}
|
|
123
|
+
function UsagePage() {
|
|
124
|
+
const [days, setDays] = reactExports.useState(30);
|
|
125
|
+
const [data, setData] = reactExports.useState(null);
|
|
126
|
+
const [loading, setLoading] = reactExports.useState(true);
|
|
127
|
+
const [error, setError] = reactExports.useState(null);
|
|
128
|
+
const load = reactExports.useCallback(() => {
|
|
129
|
+
setLoading(true);
|
|
130
|
+
setError(null);
|
|
131
|
+
fetchUsage(days).then(setData).catch((err) => setError(err instanceof Error ? err.message : "Failed to load")).finally(() => setLoading(false));
|
|
132
|
+
}, [days]);
|
|
133
|
+
reactExports.useEffect(() => {
|
|
134
|
+
load();
|
|
135
|
+
}, [load]);
|
|
136
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0 overflow-y-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mx-auto max-w-3xl px-6 py-6 flex flex-col gap-5", children: [
|
|
137
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
138
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-lg font-semibold text-foreground", children: "Usage" }),
|
|
139
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
140
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-0.5 rounded-lg border border-border p-0.5", children: PERIODS.map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
141
|
+
"button",
|
|
142
|
+
{
|
|
143
|
+
onClick: () => setDays(p.days),
|
|
144
|
+
className: cn(
|
|
145
|
+
"rounded-md px-2.5 py-1 text-xs font-medium transition-colors",
|
|
146
|
+
days === p.days ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground"
|
|
147
|
+
),
|
|
148
|
+
children: p.label
|
|
149
|
+
},
|
|
150
|
+
p.label
|
|
151
|
+
)) }),
|
|
152
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
153
|
+
"button",
|
|
154
|
+
{
|
|
155
|
+
onClick: load,
|
|
156
|
+
disabled: loading,
|
|
157
|
+
className: "flex items-center justify-center rounded-md size-7 text-muted-foreground hover:text-foreground hover:bg-muted transition-colors disabled:opacity-50",
|
|
158
|
+
"aria-label": "Refresh",
|
|
159
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(IconRefresh, { className: cn("size-3.5", loading && "animate-spin") })
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
] })
|
|
163
|
+
] }),
|
|
164
|
+
loading && !data && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "size-5 rounded-full border-2 border-muted-foreground/30 border-t-foreground animate-spin" }) }),
|
|
165
|
+
error && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 px-4 py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-destructive", children: error }) }),
|
|
166
|
+
data && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
167
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-3", children: [
|
|
168
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
169
|
+
StatCard,
|
|
170
|
+
{
|
|
171
|
+
label: "Total Tokens",
|
|
172
|
+
value: data.total_tokens > 0 ? fmt(data.total_tokens) : "—",
|
|
173
|
+
sub: data.total_tokens > 0 ? `${fmt(data.total_input_tokens)} Input / ${fmt(data.total_output_tokens)} Output` : void 0
|
|
174
|
+
}
|
|
175
|
+
),
|
|
176
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
177
|
+
StatCard,
|
|
178
|
+
{
|
|
179
|
+
label: "Total Sessions",
|
|
180
|
+
value: String(data.total_sessions),
|
|
181
|
+
sub: data.total_sessions > 0 ? `~${(data.total_sessions / days).toFixed(1)}/day avg` : void 0
|
|
182
|
+
}
|
|
183
|
+
),
|
|
184
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
185
|
+
StatCard,
|
|
186
|
+
{
|
|
187
|
+
label: "Est. Cost",
|
|
188
|
+
value: fmtCost(data.total_cost)
|
|
189
|
+
}
|
|
190
|
+
),
|
|
191
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
192
|
+
StatCard,
|
|
193
|
+
{
|
|
194
|
+
label: "Cache Hit Rate",
|
|
195
|
+
value: data.cache_hit_rate > 0 ? fmtPct(data.cache_hit_rate) : "—",
|
|
196
|
+
sub: data.total_cache_read > 0 ? `${fmt(data.total_cache_read)} Tokens` : void 0
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
] }),
|
|
200
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ModelBreakdown, { models: data.models }),
|
|
201
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(DailyTable, { daily: data.daily_tokens }),
|
|
202
|
+
data.daily_tokens.length === 0 && data.models.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center py-20 text-muted-foreground", children: [
|
|
203
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconChartBar, { className: "size-8 mb-3 opacity-40" }),
|
|
204
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium", children: "No usage data available" }),
|
|
205
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs mt-1 text-muted-foreground/60", children: "Start a conversation to see usage stats." })
|
|
206
|
+
] })
|
|
207
|
+
] })
|
|
208
|
+
] }) });
|
|
209
|
+
}
|
|
210
|
+
const SplitComponent = UsagePage;
|
|
211
|
+
export {
|
|
212
|
+
SplitComponent as component
|
|
213
|
+
};
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
|
|
2
|
+
import { a as cn, g as get, p as post } from "./router-59cN5lqo.mjs";
|
|
3
|
+
import { o as IconBrain, e as IconUser, G as IconLoader2, H as IconAlertCircle, F as IconRefresh, a as IconX, N as IconCheck, v as IconPencil } from "../_libs/tabler__icons-react.mjs";
|
|
4
|
+
import { M as Markdown } from "../_libs/react-markdown.mjs";
|
|
5
|
+
import { r as remarkGfm } from "../_libs/remark-gfm.mjs";
|
|
6
|
+
import "../_libs/tanstack__react-router.mjs";
|
|
7
|
+
import "../_libs/tanstack__router-core.mjs";
|
|
8
|
+
import "../_libs/tanstack__history.mjs";
|
|
9
|
+
import "../_libs/cookie-es.mjs";
|
|
10
|
+
import "../_libs/seroval.mjs";
|
|
11
|
+
import "../_libs/seroval-plugins.mjs";
|
|
12
|
+
import "node:stream/web";
|
|
13
|
+
import "node:stream";
|
|
14
|
+
import "../_libs/react-dom.mjs";
|
|
15
|
+
import "util";
|
|
16
|
+
import "crypto";
|
|
17
|
+
import "async_hooks";
|
|
18
|
+
import "stream";
|
|
19
|
+
import "../_libs/isbot.mjs";
|
|
20
|
+
import "../_libs/tanstack__query-core.mjs";
|
|
21
|
+
import "../_libs/tanstack__react-query.mjs";
|
|
22
|
+
import "../_libs/clsx.mjs";
|
|
23
|
+
import "../_libs/class-variance-authority.mjs";
|
|
24
|
+
import "../_libs/zustand.mjs";
|
|
25
|
+
import "../_libs/base-ui__react.mjs";
|
|
26
|
+
import "../_libs/base-ui__utils.mjs";
|
|
27
|
+
import "../_libs/use-sync-external-store.mjs";
|
|
28
|
+
import "../_libs/floating-ui__utils.mjs";
|
|
29
|
+
import "../_libs/floating-ui__react-dom.mjs";
|
|
30
|
+
import "../_libs/floating-ui__dom.mjs";
|
|
31
|
+
import "../_libs/floating-ui__core.mjs";
|
|
32
|
+
import "../_libs/zod.mjs";
|
|
33
|
+
import "../_libs/devlop.mjs";
|
|
34
|
+
import "../_libs/unified.mjs";
|
|
35
|
+
import "../_libs/bail.mjs";
|
|
36
|
+
import "../_libs/extend.mjs";
|
|
37
|
+
import "../_libs/is-plain-obj.mjs";
|
|
38
|
+
import "../_libs/trough.mjs";
|
|
39
|
+
import "../_libs/vfile.mjs";
|
|
40
|
+
import "../_libs/vfile-message.mjs";
|
|
41
|
+
import "../_libs/unist-util-stringify-position.mjs";
|
|
42
|
+
import "node:process";
|
|
43
|
+
import "node:path";
|
|
44
|
+
import "node:url";
|
|
45
|
+
import "../_libs/remark-parse.mjs";
|
|
46
|
+
import "../_libs/mdast-util-from-markdown.mjs";
|
|
47
|
+
import "../_libs/micromark-util-decode-numeric-character-reference+[...].mjs";
|
|
48
|
+
import "../_libs/micromark-util-decode-string.mjs";
|
|
49
|
+
import "../_libs/decode-named-character-reference+[...].mjs";
|
|
50
|
+
import "../_libs/character-entities.mjs";
|
|
51
|
+
import "../_libs/micromark-util-normalize-identifier+[...].mjs";
|
|
52
|
+
import "../_libs/micromark.mjs";
|
|
53
|
+
import "../_libs/micromark-util-combine-extensions+[...].mjs";
|
|
54
|
+
import "../_libs/micromark-util-chunked.mjs";
|
|
55
|
+
import "../_libs/micromark-factory-space.mjs";
|
|
56
|
+
import "../_libs/micromark-util-character.mjs";
|
|
57
|
+
import "../_libs/micromark-core-commonmark.mjs";
|
|
58
|
+
import "../_libs/micromark-util-classify-character+[...].mjs";
|
|
59
|
+
import "../_libs/micromark-util-resolve-all.mjs";
|
|
60
|
+
import "../_libs/micromark-util-subtokenize.mjs";
|
|
61
|
+
import "../_libs/micromark-factory-destination.mjs";
|
|
62
|
+
import "../_libs/micromark-factory-label.mjs";
|
|
63
|
+
import "../_libs/micromark-factory-title.mjs";
|
|
64
|
+
import "../_libs/micromark-factory-whitespace.mjs";
|
|
65
|
+
import "../_libs/micromark-util-html-tag-name.mjs";
|
|
66
|
+
import "../_libs/mdast-util-to-string.mjs";
|
|
67
|
+
import "../_libs/remark-rehype.mjs";
|
|
68
|
+
import "../_libs/mdast-util-to-hast.mjs";
|
|
69
|
+
import "../_libs/ungap__structured-clone.mjs";
|
|
70
|
+
import "../_libs/micromark-util-sanitize-uri.mjs";
|
|
71
|
+
import "../_libs/unist-util-position.mjs";
|
|
72
|
+
import "../_libs/trim-lines.mjs";
|
|
73
|
+
import "../_libs/unist-util-visit.mjs";
|
|
74
|
+
import "../_libs/unist-util-visit-parents.mjs";
|
|
75
|
+
import "../_libs/unist-util-is.mjs";
|
|
76
|
+
import "../_libs/hast-util-to-jsx-runtime.mjs";
|
|
77
|
+
import "../_libs/comma-separated-tokens.mjs";
|
|
78
|
+
import "../_libs/property-information.mjs";
|
|
79
|
+
import "../_libs/space-separated-tokens.mjs";
|
|
80
|
+
import "../_libs/style-to-js.mjs";
|
|
81
|
+
import "../_libs/style-to-object.mjs";
|
|
82
|
+
import "../_libs/inline-style-parser.mjs";
|
|
83
|
+
import "../_libs/hast-util-whitespace.mjs";
|
|
84
|
+
import "../_libs/estree-util-is-identifier-name.mjs";
|
|
85
|
+
import "../_libs/html-url-attributes.mjs";
|
|
86
|
+
import "../_libs/micromark-extension-gfm.mjs";
|
|
87
|
+
import "../_libs/micromark-extension-gfm-autolink-literal+[...].mjs";
|
|
88
|
+
import "../_libs/micromark-extension-gfm-footnote+[...].mjs";
|
|
89
|
+
import "../_libs/micromark-extension-gfm-strikethrough+[...].mjs";
|
|
90
|
+
import "../_libs/micromark-extension-gfm-table.mjs";
|
|
91
|
+
import "../_libs/micromark-extension-gfm-task-list-item+[...].mjs";
|
|
92
|
+
import "../_libs/mdast-util-gfm.mjs";
|
|
93
|
+
import "../_libs/mdast-util-gfm-autolink-literal+[...].mjs";
|
|
94
|
+
import "../_libs/ccount.mjs";
|
|
95
|
+
import "../_libs/mdast-util-find-and-replace.mjs";
|
|
96
|
+
import "../_libs/escape-string-regexp.mjs";
|
|
97
|
+
import "../_libs/mdast-util-gfm-footnote.mjs";
|
|
98
|
+
import "../_libs/mdast-util-gfm-strikethrough.mjs";
|
|
99
|
+
import "../_libs/mdast-util-gfm-table.mjs";
|
|
100
|
+
import "../_libs/markdown-table.mjs";
|
|
101
|
+
import "../_libs/mdast-util-to-markdown.mjs";
|
|
102
|
+
import "../_libs/longest-streak.mjs";
|
|
103
|
+
import "../_libs/mdast-util-phrasing.mjs";
|
|
104
|
+
import "../_libs/mdast-util-gfm-task-list-item.mjs";
|
|
105
|
+
async function fetchMemory() {
|
|
106
|
+
return get("/api/hermes/memory");
|
|
107
|
+
}
|
|
108
|
+
async function saveMemory(section, content) {
|
|
109
|
+
return post("/api/hermes/memory/write", { section, content });
|
|
110
|
+
}
|
|
111
|
+
const SECTIONS = [
|
|
112
|
+
{ key: "memory", label: "My Notes", icon: IconBrain, desc: "Personal notes & knowledge", emptyLabel: "No notes yet — click Edit to start writing." },
|
|
113
|
+
{ key: "user", label: "User Profile", icon: IconUser, desc: "About you & your context", emptyLabel: "No profile yet — click Edit to add details about yourself." }
|
|
114
|
+
];
|
|
115
|
+
const markdownComponents = {
|
|
116
|
+
a({ href, children }) {
|
|
117
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 dark:text-blue-400 underline underline-offset-2 decoration-blue-400/30 hover:decoration-blue-600/60 transition-colors", children });
|
|
118
|
+
},
|
|
119
|
+
img({ src, alt }) {
|
|
120
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src, alt, className: "rounded-xl max-w-full my-4", loading: "lazy" });
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
function MemoryPage() {
|
|
124
|
+
const [data, setData] = reactExports.useState(null);
|
|
125
|
+
const [loading, setLoading] = reactExports.useState(true);
|
|
126
|
+
const [error, setError] = reactExports.useState(null);
|
|
127
|
+
const [activeSection, setActiveSection] = reactExports.useState("memory");
|
|
128
|
+
const [editing, setEditing] = reactExports.useState(false);
|
|
129
|
+
const [editContent, setEditContent] = reactExports.useState("");
|
|
130
|
+
const [saving, setSaving] = reactExports.useState(false);
|
|
131
|
+
const [saveError, setSaveError] = reactExports.useState(null);
|
|
132
|
+
const load = reactExports.useCallback(async () => {
|
|
133
|
+
setLoading(true);
|
|
134
|
+
setError(null);
|
|
135
|
+
try {
|
|
136
|
+
const result = await fetchMemory();
|
|
137
|
+
setData(result);
|
|
138
|
+
} catch (e) {
|
|
139
|
+
setError(e instanceof Error ? e.message : "Failed to load memory");
|
|
140
|
+
} finally {
|
|
141
|
+
setLoading(false);
|
|
142
|
+
}
|
|
143
|
+
}, []);
|
|
144
|
+
reactExports.useEffect(() => {
|
|
145
|
+
load();
|
|
146
|
+
}, [load]);
|
|
147
|
+
const activeContent = data ? activeSection === "memory" ? data.memory : data.user : "";
|
|
148
|
+
const activeMtime = data ? activeSection === "memory" ? data.memory_mtime : data.user_mtime : null;
|
|
149
|
+
const activeMeta = SECTIONS.find((s) => s.key === activeSection);
|
|
150
|
+
const handleEdit = () => {
|
|
151
|
+
setEditContent(activeContent);
|
|
152
|
+
setSaveError(null);
|
|
153
|
+
setEditing(true);
|
|
154
|
+
};
|
|
155
|
+
const handleCancel = () => {
|
|
156
|
+
setEditing(false);
|
|
157
|
+
setSaveError(null);
|
|
158
|
+
};
|
|
159
|
+
const handleSave = async () => {
|
|
160
|
+
setSaving(true);
|
|
161
|
+
setSaveError(null);
|
|
162
|
+
try {
|
|
163
|
+
await saveMemory(activeSection, editContent);
|
|
164
|
+
const updated = await fetchMemory();
|
|
165
|
+
setData(updated);
|
|
166
|
+
setEditing(false);
|
|
167
|
+
} catch (e) {
|
|
168
|
+
setSaveError(e instanceof Error ? e.message : "Failed to save");
|
|
169
|
+
} finally {
|
|
170
|
+
setSaving(false);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const switchSection = (section) => {
|
|
174
|
+
if (editing) {
|
|
175
|
+
if (!confirm("You have unsaved changes. Discard them?")) return;
|
|
176
|
+
setEditing(false);
|
|
177
|
+
}
|
|
178
|
+
setActiveSection(section);
|
|
179
|
+
setSaveError(null);
|
|
180
|
+
};
|
|
181
|
+
if (loading) {
|
|
182
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-3 text-muted-foreground", children: [
|
|
183
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconLoader2, { className: "size-6 animate-spin" }),
|
|
184
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: "Loading memory..." })
|
|
185
|
+
] }) });
|
|
186
|
+
}
|
|
187
|
+
if (error) {
|
|
188
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-3 text-muted-foreground", children: [
|
|
189
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconAlertCircle, { className: "size-8 text-red-500" }),
|
|
190
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: error }),
|
|
191
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
192
|
+
"button",
|
|
193
|
+
{
|
|
194
|
+
onClick: load,
|
|
195
|
+
className: "inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium bg-muted hover:bg-muted/80 transition-colors",
|
|
196
|
+
children: [
|
|
197
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconRefresh, { className: "size-3.5" }),
|
|
198
|
+
"Retry"
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
)
|
|
202
|
+
] }) });
|
|
203
|
+
}
|
|
204
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 overflow-hidden", children: [
|
|
205
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { className: "flex w-56 shrink-0 flex-col border-r border-border", children: [
|
|
206
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5 px-3 py-3.5", children: [
|
|
207
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconBrain, { className: "size-5 text-muted-foreground" }),
|
|
208
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-semibold text-foreground", children: "Memory" })
|
|
209
|
+
] }),
|
|
210
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("nav", { className: "flex-1 overflow-y-auto space-y-1 px-2 py-1", children: SECTIONS.map((s) => {
|
|
211
|
+
const Icon = s.icon;
|
|
212
|
+
const isActive = activeSection === s.key;
|
|
213
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
214
|
+
"button",
|
|
215
|
+
{
|
|
216
|
+
onClick: () => switchSection(s.key),
|
|
217
|
+
className: cn(
|
|
218
|
+
"flex w-full items-center gap-2.5 rounded-lg px-2.5 py-2.5 text-left transition-colors",
|
|
219
|
+
isActive ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
220
|
+
),
|
|
221
|
+
children: [
|
|
222
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { className: cn("size-4 shrink-0", isActive ? "text-foreground" : "text-muted-foreground/60") }),
|
|
223
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
|
|
224
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-sm font-medium", children: s.label }),
|
|
225
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[10px] text-muted-foreground/70", children: s.desc })
|
|
226
|
+
] })
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
s.key
|
|
230
|
+
);
|
|
231
|
+
}) })
|
|
232
|
+
] }),
|
|
233
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-1 flex-col min-w-0 overflow-y-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mx-auto w-full max-w-3xl px-8 py-8", children: [
|
|
234
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
235
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
236
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-lg font-semibold text-foreground", children: activeMeta.label }),
|
|
237
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground mt-0.5", children: activeMeta.desc }),
|
|
238
|
+
activeMtime && !editing && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-muted-foreground/60 mt-1", children: [
|
|
239
|
+
"Last modified ",
|
|
240
|
+
new Date(activeMtime * 1e3).toLocaleString()
|
|
241
|
+
] })
|
|
242
|
+
] }),
|
|
243
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2 shrink-0", children: editing ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
244
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
245
|
+
"button",
|
|
246
|
+
{
|
|
247
|
+
onClick: handleCancel,
|
|
248
|
+
disabled: saving,
|
|
249
|
+
className: "inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
|
|
250
|
+
children: [
|
|
251
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconX, { className: "size-4" }),
|
|
252
|
+
"Cancel"
|
|
253
|
+
]
|
|
254
|
+
}
|
|
255
|
+
),
|
|
256
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
257
|
+
"button",
|
|
258
|
+
{
|
|
259
|
+
onClick: handleSave,
|
|
260
|
+
disabled: saving,
|
|
261
|
+
className: cn(
|
|
262
|
+
"inline-flex items-center gap-1.5 rounded-lg px-4 py-1.5 text-sm font-medium transition-colors",
|
|
263
|
+
"bg-primary text-primary-foreground hover:bg-primary/90",
|
|
264
|
+
saving && "opacity-60 cursor-not-allowed"
|
|
265
|
+
),
|
|
266
|
+
children: [
|
|
267
|
+
saving ? /* @__PURE__ */ jsxRuntimeExports.jsx(IconLoader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(IconCheck, { className: "size-4" }),
|
|
268
|
+
saving ? "Saving..." : "Save"
|
|
269
|
+
]
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
273
|
+
"button",
|
|
274
|
+
{
|
|
275
|
+
onClick: handleEdit,
|
|
276
|
+
className: "inline-flex items-center gap-1.5 rounded-lg px-4 py-1.5 text-sm font-medium bg-muted text-muted-foreground hover:text-foreground hover:bg-muted/80 transition-colors",
|
|
277
|
+
children: [
|
|
278
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconPencil, { className: "size-4" }),
|
|
279
|
+
"Edit"
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
) })
|
|
283
|
+
] }) }),
|
|
284
|
+
saveError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-6 rounded-lg border border-red-200 dark:border-red-800/40 bg-red-50 dark:bg-red-950/20 px-4 py-2.5", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-red-700 dark:text-red-300 flex items-center gap-1.5", children: [
|
|
285
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconAlertCircle, { className: "size-3.5 shrink-0" }),
|
|
286
|
+
saveError
|
|
287
|
+
] }) }),
|
|
288
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-xl border border-border bg-card p-8", children: editing ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
289
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
290
|
+
"textarea",
|
|
291
|
+
{
|
|
292
|
+
value: editContent,
|
|
293
|
+
onChange: (e) => setEditContent(e.target.value),
|
|
294
|
+
className: cn(
|
|
295
|
+
"w-full min-h-[420px] rounded-lg border border-border bg-background p-4 font-mono text-sm leading-relaxed",
|
|
296
|
+
"focus:outline-none focus:ring-2 focus:ring-primary/15 focus:border-primary/40",
|
|
297
|
+
"resize-y placeholder:text-muted-foreground/30"
|
|
298
|
+
),
|
|
299
|
+
placeholder: `Write your ${activeMeta.label.toLowerCase()} using Markdown...`,
|
|
300
|
+
spellCheck: false,
|
|
301
|
+
autoFocus: true
|
|
302
|
+
}
|
|
303
|
+
),
|
|
304
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-muted-foreground/50", children: "Markdown formatting is supported — headers, lists, code blocks, links, and more." })
|
|
305
|
+
] }) : activeContent ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
306
|
+
"div",
|
|
307
|
+
{
|
|
308
|
+
className: cn(
|
|
309
|
+
"max-w-none",
|
|
310
|
+
// Headings — generous spacing for readability
|
|
311
|
+
"[&_h1]:mt-8 [&_h1]:mb-4 [&_h1]:text-2xl [&_h1]:font-bold [&_h1]:tracking-tight [&_h1]:text-foreground",
|
|
312
|
+
"[&_h2]:mt-7 [&_h2]:mb-3 [&_h2]:text-xl [&_h2]:font-semibold [&_h2]:tracking-tight [&_h2]:text-foreground",
|
|
313
|
+
"[&_h3]:mt-6 [&_h3]:mb-2.5 [&_h3]:text-lg [&_h3]:font-semibold [&_h3]:text-foreground",
|
|
314
|
+
"[&_h4]:mt-5 [&_h4]:mb-2 [&_h4]:text-base [&_h4]:font-medium [&_h4]:text-foreground",
|
|
315
|
+
"[&_h5]:mt-4 [&_h5]:mb-1.5 [&_h5]:text-sm [&_h5]:font-medium [&_h5]:text-foreground/90",
|
|
316
|
+
"[&_h6]:mt-4 [&_h6]:mb-1.5 [&_h6]:text-sm [&_h6]:font-medium [&_h6]:text-muted-foreground",
|
|
317
|
+
// Paragraphs
|
|
318
|
+
"[&_p]:my-4 [&_p]:leading-[1.75] [&_p]:text-foreground/85",
|
|
319
|
+
// Lists — proper indentation and spacing
|
|
320
|
+
"[&_ul]:my-4 [&_ul]:pl-6 [&_ul]:list-disc [&_ul]:space-y-1.5 [&_ul]:marker:text-muted-foreground/40",
|
|
321
|
+
"[&_ol]:my-4 [&_ol]:pl-6 [&_ol]:list-decimal [&_ol]:space-y-1.5 [&_ol]:marker:text-muted-foreground/40",
|
|
322
|
+
"[&_li]:leading-relaxed [&_li]:text-foreground/85",
|
|
323
|
+
// Inline code
|
|
324
|
+
"[&_:not(pre)>code]:rounded-md [&_:not(pre)>code]:bg-muted/70 [&_:not(pre)>code]:px-1.5 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:text-[13px] [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-foreground/90 [&_:not(pre)>code]:border [&_:not(pre)>code]:border-border/50",
|
|
325
|
+
// Code blocks
|
|
326
|
+
"[&_pre]:my-5 [&_pre]:rounded-xl [&_pre]:bg-muted/50 [&_pre]:border [&_pre]:border-border/60 [&_pre]:px-5 [&_pre]:py-4 [&_pre]:text-[13px] [&_pre]:leading-relaxed [&_pre]:overflow-x-auto [&_pre]:font-mono [&_pre]:whitespace-pre-wrap",
|
|
327
|
+
// Blockquotes
|
|
328
|
+
"[&_blockquote]:my-5 [&_blockquote]:border-l-[3px] [&_blockquote]:border-amber-400 dark:[&_blockquote]:border-amber-500 [&_blockquote]:pl-4 [&_blockquote]:text-muted-foreground [&_blockquote]:italic [&_blockquote]:leading-relaxed",
|
|
329
|
+
// Horizontal rules
|
|
330
|
+
"[&_hr]:my-8 [&_hr]:border-border/40",
|
|
331
|
+
// Tables
|
|
332
|
+
"[&_table]:w-full [&_table]:my-4 [&_table]:text-sm",
|
|
333
|
+
"[&_th]:border [&_th]:border-border [&_th]:bg-muted/60 [&_th]:px-4 [&_th]:py-2.5 [&_th]:text-left [&_th]:font-medium [&_th]:text-foreground/80 [&_th]:text-xs [&_th]:uppercase [&_th]:tracking-wider",
|
|
334
|
+
"[&_td]:border [&_td]:border-border [&_td]:px-4 [&_td]:py-2.5 [&_td]:text-foreground/80",
|
|
335
|
+
// Images
|
|
336
|
+
"[&_img]:rounded-xl [&_img]:my-5 [&_img]:max-w-full",
|
|
337
|
+
// First/last margin reset
|
|
338
|
+
"[&>*:first-child]:mt-0 [&>*:last-child]:mb-0"
|
|
339
|
+
),
|
|
340
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: [remarkGfm], components: markdownComponents, children: activeContent })
|
|
341
|
+
}
|
|
342
|
+
) : (
|
|
343
|
+
/* ── Empty state ── */
|
|
344
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center py-16 gap-4", children: [
|
|
345
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex size-14 items-center justify-center rounded-2xl bg-muted/50 border border-border/50", children: /* @__PURE__ */ jsxRuntimeExports.jsx(activeMeta.icon, { className: "size-6 text-muted-foreground/30" }) }),
|
|
346
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center max-w-xs", children: [
|
|
347
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium text-foreground/70", children: activeMeta.emptyLabel }),
|
|
348
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground/50 mt-1.5", children: "You can format your content with Markdown — headers, lists, code blocks, and more." })
|
|
349
|
+
] }),
|
|
350
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
351
|
+
"button",
|
|
352
|
+
{
|
|
353
|
+
onClick: handleEdit,
|
|
354
|
+
className: "inline-flex items-center gap-1.5 rounded-lg px-4 py-2 text-sm font-medium bg-muted hover:bg-muted/80 text-foreground/80 transition-colors",
|
|
355
|
+
children: [
|
|
356
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconPencil, { className: "size-3.5" }),
|
|
357
|
+
"Start Editing"
|
|
358
|
+
]
|
|
359
|
+
}
|
|
360
|
+
)
|
|
361
|
+
] })
|
|
362
|
+
) })
|
|
363
|
+
] }) })
|
|
364
|
+
] });
|
|
365
|
+
}
|
|
366
|
+
const SplitComponent = MemoryPage;
|
|
367
|
+
export {
|
|
368
|
+
SplitComponent as component
|
|
369
|
+
};
|