@schlessera/brain-ui-react 0.6.3 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/graph/graph-canvas.d.ts +20 -0
- package/dist/components/graph/graph-canvas.d.ts.map +1 -0
- package/dist/components/graph/graph-canvas.js +387 -0
- package/dist/components/graph/graph-canvas.js.map +1 -0
- package/dist/components/graph/graph-controls.d.ts +8 -0
- package/dist/components/graph/graph-controls.d.ts.map +1 -0
- package/dist/components/graph/graph-controls.js +132 -0
- package/dist/components/graph/graph-controls.js.map +1 -0
- package/dist/components/graph/graph-empty-state.d.ts +15 -0
- package/dist/components/graph/graph-empty-state.d.ts.map +1 -0
- package/dist/components/graph/graph-empty-state.js +21 -0
- package/dist/components/graph/graph-empty-state.js.map +1 -0
- package/dist/components/graph/graph-page.d.ts +7 -0
- package/dist/components/graph/graph-page.d.ts.map +1 -0
- package/dist/components/graph/graph-page.js +400 -0
- package/dist/components/graph/graph-page.js.map +1 -0
- package/dist/components/graph/lib/graph-helpers.d.ts +98 -0
- package/dist/components/graph/lib/graph-helpers.d.ts.map +1 -0
- package/dist/components/graph/lib/graph-helpers.js +240 -0
- package/dist/components/graph/lib/graph-helpers.js.map +1 -0
- package/dist/components/graph/node-popover.d.ts +11 -0
- package/dist/components/graph/node-popover.d.ts.map +1 -0
- package/dist/components/graph/node-popover.js +39 -0
- package/dist/components/graph/node-popover.js.map +1 -0
- package/dist/components/graph/use-graph-theme.d.ts +19 -0
- package/dist/components/graph/use-graph-theme.d.ts.map +1 -0
- package/dist/components/graph/use-graph-theme.js +38 -0
- package/dist/components/graph/use-graph-theme.js.map +1 -0
- package/dist/components/layout/mobile-tab-bar.d.ts.map +1 -1
- package/dist/components/layout/mobile-tab-bar.js +16 -5
- package/dist/components/layout/mobile-tab-bar.js.map +1 -1
- package/dist/components/layout/side-rail.d.ts.map +1 -1
- package/dist/components/layout/side-rail.js +14 -4
- package/dist/components/layout/side-rail.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/stores/graph-store.d.ts +85 -0
- package/dist/stores/graph-store.d.ts.map +1 -0
- package/dist/stores/graph-store.js +236 -0
- package/dist/stores/graph-store.js.map +1 -0
- package/dist/stores/ui-store.d.ts +5 -0
- package/dist/stores/ui-store.d.ts.map +1 -1
- package/dist/stores/ui-store.js +2 -0
- package/dist/stores/ui-store.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +5 -2
- package/src/components/graph/graph-canvas.tsx +450 -0
- package/src/components/graph/graph-controls.tsx +436 -0
- package/src/components/graph/graph-empty-state.tsx +45 -0
- package/src/components/graph/graph-page.tsx +1045 -0
- package/src/components/graph/lib/graph-helpers.ts +311 -0
- package/src/components/graph/node-popover.tsx +135 -0
- package/src/components/graph/use-graph-theme.ts +51 -0
- package/src/components/layout/mobile-tab-bar.tsx +26 -3
- package/src/components/layout/side-rail.tsx +28 -4
- package/src/index.ts +3 -1
- package/src/stores/graph-store.ts +345 -0
- package/src/stores/ui-store.ts +8 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// --- Query strings -----------------------------------------------------------
|
|
2
|
+
/**
|
|
3
|
+
* Build a query string from a param bag. null/undefined/empty-string values
|
|
4
|
+
* are dropped; everything else is encoded. Returns "" when nothing survives.
|
|
5
|
+
*/
|
|
6
|
+
export function buildQuery(params) {
|
|
7
|
+
const parts = [];
|
|
8
|
+
for (const [key, value] of Object.entries(params)) {
|
|
9
|
+
if (value === null || value === undefined || value === "")
|
|
10
|
+
continue;
|
|
11
|
+
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
|
12
|
+
}
|
|
13
|
+
return parts.join("&");
|
|
14
|
+
}
|
|
15
|
+
// --- Subgraph merging --------------------------------------------------------
|
|
16
|
+
/**
|
|
17
|
+
* Merge an expansion fetch into the current scene. Nodes dedupe by id — the
|
|
18
|
+
* richer record wins (more analytical fields), which in practice means an
|
|
19
|
+
* existing node keeps its coordinates/metrics when the expansion returns a
|
|
20
|
+
* barer copy. Edges dedupe by (source, target).
|
|
21
|
+
*/
|
|
22
|
+
export function mergeSubgraphs(base, addition) {
|
|
23
|
+
const nodesById = new Map();
|
|
24
|
+
for (const node of base.nodes)
|
|
25
|
+
nodesById.set(node.id, node);
|
|
26
|
+
for (const node of addition.nodes) {
|
|
27
|
+
const existing = nodesById.get(node.id);
|
|
28
|
+
nodesById.set(node.id, existing ? { ...node, ...existing } : node);
|
|
29
|
+
}
|
|
30
|
+
const edgeKeys = new Set();
|
|
31
|
+
const edges = [];
|
|
32
|
+
for (const edge of [...base.edges, ...addition.edges]) {
|
|
33
|
+
const key = `${edge.source}->${edge.target}`;
|
|
34
|
+
if (edgeKeys.has(key))
|
|
35
|
+
continue;
|
|
36
|
+
edgeKeys.add(key);
|
|
37
|
+
edges.push(edge);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
nodes: [...nodesById.values()],
|
|
41
|
+
edges,
|
|
42
|
+
truncated: base.truncated || addition.truncated,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Deterministic radial layout for discovery mode: radius = BFS distance,
|
|
47
|
+
* nodes ordered within their ring by id (stable across refetches), the root
|
|
48
|
+
* (distance 0) at the origin. Rings get a slight angular offset per ring so
|
|
49
|
+
* spokes don't visually align into artificial lines.
|
|
50
|
+
*/
|
|
51
|
+
export function radialLayout(nodes, ringSpacing = 1) {
|
|
52
|
+
const rings = new Map();
|
|
53
|
+
for (const node of nodes) {
|
|
54
|
+
const d = node.distance ?? 0;
|
|
55
|
+
const ring = rings.get(d) ?? [];
|
|
56
|
+
ring.push(node.id);
|
|
57
|
+
rings.set(d, ring);
|
|
58
|
+
}
|
|
59
|
+
const positions = new Map();
|
|
60
|
+
for (const [distance, ids] of rings) {
|
|
61
|
+
ids.sort((a, b) => a - b);
|
|
62
|
+
const radius = distance * ringSpacing;
|
|
63
|
+
const offset = distance * 0.5; // radians; de-aligns consecutive rings
|
|
64
|
+
ids.forEach((id, i) => {
|
|
65
|
+
if (distance === 0) {
|
|
66
|
+
positions.set(id, { x: 0, y: 0 });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const angle = offset + (2 * Math.PI * i) / ids.length;
|
|
70
|
+
positions.set(id, {
|
|
71
|
+
x: radius * Math.cos(angle),
|
|
72
|
+
y: radius * Math.sin(angle),
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return positions;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Node size in rendered pixels. Sqrt scale keeps hubs prominent without
|
|
80
|
+
* letting a 45-in-degree hub dwarf the scene.
|
|
81
|
+
*/
|
|
82
|
+
export function nodeSize(node, sizeBy = "degree", min = 3, max = 14) {
|
|
83
|
+
if (node.virtual)
|
|
84
|
+
return max;
|
|
85
|
+
let value;
|
|
86
|
+
if (sizeBy === "pagerank" && node.pagerank !== undefined) {
|
|
87
|
+
// Typical pagerank values are ~1/n; normalize into a usable range.
|
|
88
|
+
value = node.pagerank * 1000;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
value = node.inDegree + node.outDegree;
|
|
92
|
+
}
|
|
93
|
+
return Math.max(min, Math.min(max, min + Math.sqrt(value) * 1.8));
|
|
94
|
+
}
|
|
95
|
+
// --- Palettes ----------------------------------------------------------------
|
|
96
|
+
//
|
|
97
|
+
// Both palettes ran through the dataviz validator against the app surface
|
|
98
|
+
// (#0c0e12, dark): the categorical set passes lightness band, chroma floor,
|
|
99
|
+
// CVD separation (worst adjacent ΔE 8.4), normal-vision floor and 3:1
|
|
100
|
+
// contrast; the distance ramp passes monotone-lightness, step-gap, light-end
|
|
101
|
+
// contrast and single-hue checks. Slot ORDER is the CVD-safety mechanism —
|
|
102
|
+
// do not reorder without re-validating.
|
|
103
|
+
/** Fixed categorical slots (validated, dark). Community/folder identity. */
|
|
104
|
+
export const CATEGORICAL_SLOTS = [
|
|
105
|
+
"#3987e5", // blue
|
|
106
|
+
"#d95926", // orange
|
|
107
|
+
"#199e70", // aqua
|
|
108
|
+
"#c98500", // yellow
|
|
109
|
+
"#d55181", // magenta
|
|
110
|
+
"#008300", // green
|
|
111
|
+
"#9085e9", // violet
|
|
112
|
+
"#e66767", // red
|
|
113
|
+
];
|
|
114
|
+
/** Recessive slot for everything past the eight distinguishable ones. */
|
|
115
|
+
export const OTHER_COLOR = "#565b66";
|
|
116
|
+
/** The root's own color in discovery mode (the app's amber primary). */
|
|
117
|
+
export const ROOT_COLOR = "#e09f3e";
|
|
118
|
+
/** Ordinal distance ramp, near → far (validated, 5 visible steps). */
|
|
119
|
+
export const DISTANCE_RAMP = [
|
|
120
|
+
"#b7d3f6",
|
|
121
|
+
"#86b6ef",
|
|
122
|
+
"#5598e7",
|
|
123
|
+
"#2a78d6",
|
|
124
|
+
"#184f95",
|
|
125
|
+
];
|
|
126
|
+
/**
|
|
127
|
+
* Linear blend of two hex colors: t=0 → a, t=1 → b. Used for the gentle
|
|
128
|
+
* non-match fade during search highlight (half the strength of the hover
|
|
129
|
+
* fade, which jumps straight to the edge color). Falls back to `b` when a
|
|
130
|
+
* color is not parseable hex, so a bad token degrades to the strong fade
|
|
131
|
+
* rather than an invalid color string.
|
|
132
|
+
*/
|
|
133
|
+
export function mixColors(a, b, t) {
|
|
134
|
+
const pa = parseHex(a);
|
|
135
|
+
const pb = parseHex(b);
|
|
136
|
+
if (!pa || !pb)
|
|
137
|
+
return b;
|
|
138
|
+
const clamp = Math.max(0, Math.min(1, t));
|
|
139
|
+
const channel = (i) => Math.round(pa[i] + (pb[i] - pa[i]) * clamp);
|
|
140
|
+
return `#${[0, 1, 2].map((i) => channel(i).toString(16).padStart(2, "0")).join("")}`;
|
|
141
|
+
}
|
|
142
|
+
function parseHex(color) {
|
|
143
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(color.trim());
|
|
144
|
+
if (!m)
|
|
145
|
+
return null;
|
|
146
|
+
const n = parseInt(m[1], 16);
|
|
147
|
+
return [(n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff];
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Color for a community. Communities are numbered by size (0 = largest) at
|
|
151
|
+
* index time, so the first eight — the ones a legend can carry — get the
|
|
152
|
+
* distinguishable slots and the long tail shares one recessive color.
|
|
153
|
+
*/
|
|
154
|
+
export function communityColor(community) {
|
|
155
|
+
return community < CATEGORICAL_SLOTS.length
|
|
156
|
+
? CATEGORICAL_SLOTS[community]
|
|
157
|
+
: OTHER_COLOR;
|
|
158
|
+
}
|
|
159
|
+
/** Color for a BFS distance: amber root, then the blue ramp fading out. */
|
|
160
|
+
export function distanceColor(distance) {
|
|
161
|
+
if (distance <= 0)
|
|
162
|
+
return ROOT_COLOR;
|
|
163
|
+
return DISTANCE_RAMP[Math.min(distance - 1, DISTANCE_RAMP.length - 1)];
|
|
164
|
+
}
|
|
165
|
+
/** First path segment — "career/opportunities/x.md" → "career". */
|
|
166
|
+
export function topLevelDir(path) {
|
|
167
|
+
const slash = path.indexOf("/");
|
|
168
|
+
return slash === -1 ? "" : path.slice(0, slash);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Assign categorical slots to top-level directories, biggest first — the
|
|
172
|
+
* same eight-then-other policy as communities. Returns dir → color.
|
|
173
|
+
*/
|
|
174
|
+
export function assignFolderColors(paths) {
|
|
175
|
+
const counts = new Map();
|
|
176
|
+
for (const path of paths) {
|
|
177
|
+
const dir = topLevelDir(path);
|
|
178
|
+
counts.set(dir, (counts.get(dir) ?? 0) + 1);
|
|
179
|
+
}
|
|
180
|
+
const ranked = [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
|
|
181
|
+
const colors = new Map();
|
|
182
|
+
ranked.forEach(([dir], i) => {
|
|
183
|
+
colors.set(dir, i < CATEGORICAL_SLOTS.length ? CATEGORICAL_SLOTS[i] : OTHER_COLOR);
|
|
184
|
+
});
|
|
185
|
+
return colors;
|
|
186
|
+
}
|
|
187
|
+
/** Split a community list into legend-worthy entries and the singleton tail. */
|
|
188
|
+
export function groupCommunities(communities) {
|
|
189
|
+
const major = communities
|
|
190
|
+
.filter((c) => c.size > 1)
|
|
191
|
+
.sort((a, b) => b.size - a.size || a.community - b.community);
|
|
192
|
+
return { major, singletonCount: communities.length - major.length };
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Which nodes must always carry a label: selection, hover, search matches,
|
|
196
|
+
* the virtual root, plus the top-K nodes by rank where K grows as the user
|
|
197
|
+
* zooms in. Never "all labels" — the renderer's own density threshold handles
|
|
198
|
+
* the rest.
|
|
199
|
+
*/
|
|
200
|
+
export function labelSet(input) {
|
|
201
|
+
const forced = new Set();
|
|
202
|
+
if (input.selectedId !== null)
|
|
203
|
+
forced.add(input.selectedId);
|
|
204
|
+
if (input.hoveredId !== null)
|
|
205
|
+
forced.add(input.hoveredId);
|
|
206
|
+
for (const id of input.matchIds)
|
|
207
|
+
forced.add(id);
|
|
208
|
+
for (const node of input.nodes)
|
|
209
|
+
if (node.virtual)
|
|
210
|
+
forced.add(node.id);
|
|
211
|
+
// Zoomed out (ratio >= 1): a handful of anchors. Each halving of the ratio
|
|
212
|
+
// doubles the quota. Capped so a deep zoom cannot force thousands.
|
|
213
|
+
const zoomFactor = Math.max(0.05, Math.min(4, input.cameraRatio));
|
|
214
|
+
const quota = Math.min(60, Math.max(4, Math.round(8 / zoomFactor)));
|
|
215
|
+
const ranked = [...input.nodes].sort((a, b) => rank(b) - rank(a));
|
|
216
|
+
for (let i = 0; i < Math.min(quota, ranked.length); i++) {
|
|
217
|
+
forced.add(ranked[i].id);
|
|
218
|
+
}
|
|
219
|
+
return forced;
|
|
220
|
+
}
|
|
221
|
+
function rank(node) {
|
|
222
|
+
return node.pagerank !== undefined
|
|
223
|
+
? node.pagerank
|
|
224
|
+
: (node.inDegree + node.outDegree) / 1e6;
|
|
225
|
+
}
|
|
226
|
+
// --- Scene search ------------------------------------------------------------
|
|
227
|
+
/** Ids of nodes whose title or path matches the in-scene query. */
|
|
228
|
+
export function matchScene(nodes, query) {
|
|
229
|
+
const q = query.trim().toLowerCase();
|
|
230
|
+
const matches = new Set();
|
|
231
|
+
if (q.length < 2)
|
|
232
|
+
return matches;
|
|
233
|
+
for (const node of nodes) {
|
|
234
|
+
if (node.title.toLowerCase().includes(q) || node.path.toLowerCase().includes(q)) {
|
|
235
|
+
matches.add(node.id);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return matches;
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=graph-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-helpers.js","sourceRoot":"","sources":["../../../../src/components/graph/lib/graph-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GraphNodePayload } from "@schlessera/brain-ui-sdk/protocol";
|
|
2
|
+
/**
|
|
3
|
+
* Detail card for the selected node, docked to the bottom-left of the canvas
|
|
4
|
+
* (bottom sheet width on phones). "Open note" hands over to the file viewer
|
|
5
|
+
* panel — the same hand-off the search modal uses.
|
|
6
|
+
*/
|
|
7
|
+
export declare function NodePopover({ node, communityLabel, }: {
|
|
8
|
+
node: GraphNodePayload;
|
|
9
|
+
communityLabel?: string | null;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=node-popover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-popover.d.ts","sourceRoot":"","sources":["../../../src/components/graph/node-popover.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAM1E;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,cAAc,GACf,EAAE;IACD,IAAI,EAAE,gBAAgB,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,+BA0FA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { X, FileText, Crosshair, Expand } from "lucide-react";
|
|
3
|
+
import { useFileStore } from "../../stores/file-store.js";
|
|
4
|
+
import { useUIStore } from "../../stores/ui-store.js";
|
|
5
|
+
import { useGraphStore } from "../../stores/graph-store.js";
|
|
6
|
+
import { communityColor } from "./lib/graph-helpers.js";
|
|
7
|
+
/**
|
|
8
|
+
* Detail card for the selected node, docked to the bottom-left of the canvas
|
|
9
|
+
* (bottom sheet width on phones). "Open note" hands over to the file viewer
|
|
10
|
+
* panel — the same hand-off the search modal uses.
|
|
11
|
+
*/
|
|
12
|
+
export function NodePopover({ node, communityLabel, }) {
|
|
13
|
+
const openFile = useFileStore((s) => s.openFile);
|
|
14
|
+
const setFilePanelOpen = useUIStore((s) => s.setFilePanelOpen);
|
|
15
|
+
const mode = useGraphStore((s) => s.mode);
|
|
16
|
+
const select = useGraphStore((s) => s.select);
|
|
17
|
+
const setMode = useGraphStore((s) => s.setMode);
|
|
18
|
+
const setLocalParams = useGraphStore((s) => s.setLocalParams);
|
|
19
|
+
const expandNode = useGraphStore((s) => s.expandNode);
|
|
20
|
+
const isVirtual = node.virtual === true;
|
|
21
|
+
function handleOpen() {
|
|
22
|
+
setFilePanelOpen(true);
|
|
23
|
+
void openFile(node.path);
|
|
24
|
+
}
|
|
25
|
+
function handleFocus() {
|
|
26
|
+
// Re-center the local view on this node (switching mode when needed).
|
|
27
|
+
if (mode !== "local")
|
|
28
|
+
setMode("local");
|
|
29
|
+
setLocalParams({ center: node.path });
|
|
30
|
+
select(null);
|
|
31
|
+
}
|
|
32
|
+
return (_jsxs("div", { className: "pointer-events-auto absolute inset-x-2 bottom-2 z-10 rounded-xl border border-border bg-surface-overlay/95 p-4 shadow-2xl backdrop-blur md:inset-x-auto md:left-4 md:bottom-4 md:w-80", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "shrink-0 rounded bg-surface-raised px-1.5 py-0.5 text-[10px] uppercase tracking-wide text-muted-foreground", children: isVirtual ? "root" : node.type }), communityLabel && (_jsxs("span", { title: "Topic cluster inferred from this note's links", className: "flex min-w-0 items-center gap-1 rounded bg-surface-raised px-1.5 py-0.5 text-[10px] text-muted-foreground", children: [node.community !== undefined && (_jsx("span", { "aria-hidden": "true", className: "h-1.5 w-1.5 shrink-0 rounded-full", style: { backgroundColor: communityColor(node.community) } })), _jsxs("span", { className: "truncate", children: ["Topic: ", communityLabel] })] }))] }), _jsx("h3", { className: "mt-1 truncate text-sm font-medium text-foreground", children: node.title || node.path }), _jsx("p", { className: "truncate font-mono text-[10px] text-muted-foreground/60", children: node.path })] }), _jsx("button", { onClick: () => select(null), className: "shrink-0 rounded p-1 text-muted-foreground transition-colors hover:text-foreground", title: "Close", children: _jsx(X, { className: "h-3.5 w-3.5" }) })] }), _jsxs("div", { className: "mt-2 flex gap-4 text-[11px] text-muted-foreground", children: [_jsxs("span", { children: [node.inDegree, " in"] }), _jsxs("span", { children: [node.outDegree, " out"] }), node.distance !== undefined && node.distance > 0 && (_jsxs("span", { children: [node.distance, " hop", node.distance === 1 ? "" : "s"] }))] }), _jsxs("div", { className: "mt-3 flex flex-wrap gap-2", children: [!isVirtual && (_jsx(ActionButton, { icon: FileText, label: "Open note", onClick: handleOpen, primary: true })), !isVirtual && (mode !== "local" || node.distance !== 0) && (_jsx(ActionButton, { icon: Crosshair, label: "Focus here", onClick: handleFocus })), mode === "local" && !isVirtual && node.distance !== 0 && (_jsx(ActionButton, { icon: Expand, label: "Expand", onClick: () => void expandNode(node.path) }))] })] }));
|
|
33
|
+
}
|
|
34
|
+
function ActionButton({ icon: Icon, label, onClick, primary, }) {
|
|
35
|
+
return (_jsxs("button", { onClick: onClick, className: primary
|
|
36
|
+
? "flex min-h-9 items-center gap-1.5 rounded-lg bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90"
|
|
37
|
+
: "flex min-h-9 items-center gap-1.5 rounded-lg bg-surface-raised px-3 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-surface-overlay", children: [_jsx(Icon, { className: "h-3.5 w-3.5" }), label] }));
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=node-popover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-popover.js","sourceRoot":"","sources":["../../../src/components/graph/node-popover.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface GraphTheme {
|
|
2
|
+
background: string;
|
|
3
|
+
/** Raised surface used for the hover-label plate (sigma's default is #FFF,
|
|
4
|
+
* unreadable under our near-white label text). */
|
|
5
|
+
surfaceOverlay: string;
|
|
6
|
+
node: string;
|
|
7
|
+
nodeSelected: string;
|
|
8
|
+
edge: string;
|
|
9
|
+
edgeHighlight: string;
|
|
10
|
+
label: string;
|
|
11
|
+
labelMuted: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the Tailwind theme tokens into concrete colors for the canvas —
|
|
15
|
+
* WebGL cannot read CSS custom properties itself. Read once per mount; the
|
|
16
|
+
* app is dark-only, so tokens do not change at runtime.
|
|
17
|
+
*/
|
|
18
|
+
export declare function useGraphTheme(): GraphTheme;
|
|
19
|
+
//# sourceMappingURL=use-graph-theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-graph-theme.d.ts","sourceRoot":"","sources":["../../../src/components/graph/use-graph-theme.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB;sDACkD;IAClD,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAaD;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,UAAU,CAmB1C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
const FALLBACK = {
|
|
3
|
+
background: "#0c0e12",
|
|
4
|
+
surfaceOverlay: "#1e2128",
|
|
5
|
+
node: "#8a8691",
|
|
6
|
+
nodeSelected: "#e09f3e",
|
|
7
|
+
edge: "#2a2d35",
|
|
8
|
+
edgeHighlight: "#5bb5a2",
|
|
9
|
+
label: "#e8e4df",
|
|
10
|
+
labelMuted: "#8a8691",
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the Tailwind theme tokens into concrete colors for the canvas —
|
|
14
|
+
* WebGL cannot read CSS custom properties itself. Read once per mount; the
|
|
15
|
+
* app is dark-only, so tokens do not change at runtime.
|
|
16
|
+
*/
|
|
17
|
+
export function useGraphTheme() {
|
|
18
|
+
return useMemo(() => {
|
|
19
|
+
if (typeof window === "undefined")
|
|
20
|
+
return FALLBACK;
|
|
21
|
+
const style = getComputedStyle(document.documentElement);
|
|
22
|
+
const token = (name, fallback) => {
|
|
23
|
+
const value = style.getPropertyValue(name).trim();
|
|
24
|
+
return value || fallback;
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
background: token("--color-background", FALLBACK.background),
|
|
28
|
+
surfaceOverlay: token("--color-surface-overlay", FALLBACK.surfaceOverlay),
|
|
29
|
+
node: token("--color-muted-foreground", FALLBACK.node),
|
|
30
|
+
nodeSelected: token("--color-primary", FALLBACK.nodeSelected),
|
|
31
|
+
edge: token("--color-border", FALLBACK.edge),
|
|
32
|
+
edgeHighlight: token("--color-accent", FALLBACK.edgeHighlight),
|
|
33
|
+
label: token("--color-foreground", FALLBACK.label),
|
|
34
|
+
labelMuted: token("--color-muted-foreground", FALLBACK.labelMuted),
|
|
35
|
+
};
|
|
36
|
+
}, []);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=use-graph-theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-graph-theme.js","sourceRoot":"","sources":["../../../src/components/graph/use-graph-theme.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAehC,MAAM,QAAQ,GAAe;IAC3B,UAAU,EAAE,SAAS;IACrB,cAAc,EAAE,SAAS;IACzB,IAAI,EAAE,SAAS;IACf,YAAY,EAAE,SAAS;IACvB,IAAI,EAAE,SAAS;IACf,aAAa,EAAE,SAAS;IACxB,KAAK,EAAE,SAAS;IAChB,UAAU,EAAE,SAAS;CACtB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO,QAAQ,CAAC;QACnD,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,QAAgB,EAAE,EAAE;YAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YAClD,OAAO,KAAK,IAAI,QAAQ,CAAC;QAC3B,CAAC,CAAC;QACF,OAAO;YACL,UAAU,EAAE,KAAK,CAAC,oBAAoB,EAAE,QAAQ,CAAC,UAAU,CAAC;YAC5D,cAAc,EAAE,KAAK,CAAC,yBAAyB,EAAE,QAAQ,CAAC,cAAc,CAAC;YACzE,IAAI,EAAE,KAAK,CAAC,0BAA0B,EAAE,QAAQ,CAAC,IAAI,CAAC;YACtD,YAAY,EAAE,KAAK,CAAC,iBAAiB,EAAE,QAAQ,CAAC,YAAY,CAAC;YAC7D,IAAI,EAAE,KAAK,CAAC,gBAAgB,EAAE,QAAQ,CAAC,IAAI,CAAC;YAC5C,aAAa,EAAE,KAAK,CAAC,gBAAgB,EAAE,QAAQ,CAAC,aAAa,CAAC;YAC9D,KAAK,EAAE,KAAK,CAAC,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC;YAClD,UAAU,EAAE,KAAK,CAAC,0BAA0B,EAAE,QAAQ,CAAC,UAAU,CAAC;SACnE,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-tab-bar.d.ts","sourceRoot":"","sources":["../../../src/components/layout/mobile-tab-bar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mobile-tab-bar.d.ts","sourceRoot":"","sources":["../../../src/components/layout/mobile-tab-bar.tsx"],"names":[],"mappings":"AAeA,wBAAgB,YAAY,gCAqG3B"}
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
|
-
import { Brain, RefreshCw, History, SlidersHorizontal, FolderTree, SquarePen, MoreHorizontal, } from "lucide-react";
|
|
3
|
+
import { Brain, RefreshCw, History, SlidersHorizontal, FolderTree, SquarePen, MoreHorizontal, Waypoints, } from "lucide-react";
|
|
4
4
|
import { useUIStore } from "../../stores/ui-store.js";
|
|
5
5
|
import { useChatStore } from "../../stores/chat-store.js";
|
|
6
6
|
import { cn } from "../../lib/utils.js";
|
|
7
7
|
export function MobileTabBar() {
|
|
8
|
+
const activeView = useUIStore((s) => s.activeView);
|
|
9
|
+
const setActiveView = useUIStore((s) => s.setActiveView);
|
|
8
10
|
const toggleSessionPanel = useUIStore((s) => s.toggleSessionPanel);
|
|
9
11
|
const toggleSyncPanel = useUIStore((s) => s.toggleSyncPanel);
|
|
10
12
|
const toggleFilePanel = useUIStore((s) => s.toggleFilePanel);
|
|
11
13
|
const toggleSettingsPanel = useUIStore((s) => s.toggleSettingsPanel);
|
|
12
14
|
const clearMessages = useChatStore((s) => s.clearMessages);
|
|
15
|
+
/** Chat-scoped panels live in the chat page — surface it before opening them. */
|
|
16
|
+
function inChat(toggle) {
|
|
17
|
+
return () => {
|
|
18
|
+
if (activeView !== "chat")
|
|
19
|
+
setActiveView("chat");
|
|
20
|
+
toggle();
|
|
21
|
+
};
|
|
22
|
+
}
|
|
13
23
|
const [moreOpen, setMoreOpen] = useState(false);
|
|
14
24
|
const moreRef = useRef(null);
|
|
15
25
|
useEffect(() => {
|
|
@@ -30,15 +40,16 @@ export function MobileTabBar() {
|
|
|
30
40
|
document.removeEventListener("keydown", onKey);
|
|
31
41
|
};
|
|
32
42
|
}, [moreOpen]);
|
|
33
|
-
return (_jsxs("nav", { className: "md:hidden fixed bottom-0 inset-x-0 z-30 flex h-14 items-center justify-around border-t border-border bg-surface px-1 pb-[env(safe-area-inset-bottom)]", children: [_jsx(TabIcon, { icon: Brain, label: "Chat", active:
|
|
43
|
+
return (_jsxs("nav", { className: "md:hidden fixed bottom-0 inset-x-0 z-30 flex h-14 items-center justify-around border-t border-border bg-surface px-1 pb-[env(safe-area-inset-bottom)]", children: [_jsx(TabIcon, { icon: Brain, label: "Chat", active: activeView === "chat", onClick: () => setActiveView("chat") }), _jsx(TabIcon, { icon: SquarePen, label: "New chat", onClick: () => {
|
|
34
44
|
setMoreOpen(false);
|
|
45
|
+
setActiveView("chat");
|
|
35
46
|
clearMessages();
|
|
36
|
-
} }), _jsx(TabIcon, { icon: FolderTree, label: "Files", onClick: toggleFilePanel }), _jsxs("div", { ref: moreRef, className: "relative", children: [_jsx(TabIcon, { icon: MoreHorizontal, label: "More", active: moreOpen, onClick: () => setMoreOpen((v) => !v) }), moreOpen && (_jsxs("div", { role: "menu", className: "absolute bottom-full right-0 z-50 mb-2 min-w-[10rem] overflow-hidden rounded-xl border border-border bg-surface-overlay py-1 shadow-2xl", children: [_jsx(MoreItem, { icon: RefreshCw, label: "Sync", onClick: () => {
|
|
47
|
+
} }), _jsx(TabIcon, { icon: Waypoints, label: "Graph", active: activeView === "graph", onClick: () => setActiveView("graph") }), _jsx(TabIcon, { icon: FolderTree, label: "Files", onClick: toggleFilePanel }), _jsxs("div", { ref: moreRef, className: "relative", children: [_jsx(TabIcon, { icon: MoreHorizontal, label: "More", active: moreOpen, onClick: () => setMoreOpen((v) => !v) }), moreOpen && (_jsxs("div", { role: "menu", className: "absolute bottom-full right-0 z-50 mb-2 min-w-[10rem] overflow-hidden rounded-xl border border-border bg-surface-overlay py-1 shadow-2xl", children: [_jsx(MoreItem, { icon: RefreshCw, label: "Sync", onClick: () => {
|
|
37
48
|
setMoreOpen(false);
|
|
38
|
-
toggleSyncPanel();
|
|
49
|
+
inChat(toggleSyncPanel)();
|
|
39
50
|
} }), _jsx(MoreItem, { icon: History, label: "History", onClick: () => {
|
|
40
51
|
setMoreOpen(false);
|
|
41
|
-
toggleSessionPanel();
|
|
52
|
+
inChat(toggleSessionPanel)();
|
|
42
53
|
} }), _jsx(MoreItem, { icon: SlidersHorizontal, label: "Settings", onClick: () => {
|
|
43
54
|
setMoreOpen(false);
|
|
44
55
|
toggleSettingsPanel();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-tab-bar.js","sourceRoot":"","sources":["../../../src/components/layout/mobile-tab-bar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EACL,KAAK,EACL,SAAS,EACT,OAAO,EACP,iBAAiB,EACjB,UAAU,EACV,SAAS,EACT,cAAc,
|
|
1
|
+
{"version":3,"file":"mobile-tab-bar.js","sourceRoot":"","sources":["../../../src/components/layout/mobile-tab-bar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"side-rail.d.ts","sourceRoot":"","sources":["../../../src/components/layout/side-rail.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"side-rail.d.ts","sourceRoot":"","sources":["../../../src/components/layout/side-rail.tsx"],"names":[],"mappings":"AAeA,wBAAgB,QAAQ,gCAwGvB"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Brain, RefreshCw, Newspaper, History, SlidersHorizontal, SquarePen, FolderTree, } from "lucide-react";
|
|
2
|
+
import { Brain, RefreshCw, Newspaper, History, SlidersHorizontal, SquarePen, FolderTree, Waypoints, } from "lucide-react";
|
|
3
3
|
import { useConnectionStore } from "../../stores/connection-store.js";
|
|
4
4
|
import { useUIStore } from "../../stores/ui-store.js";
|
|
5
5
|
import { useChatStore, activeChat } from "../../stores/chat-store.js";
|
|
6
6
|
import { cn } from "../../lib/utils.js";
|
|
7
7
|
export function SideRail() {
|
|
8
8
|
const wsStatus = useConnectionStore((s) => s.wsStatus);
|
|
9
|
+
const activeView = useUIStore((s) => s.activeView);
|
|
10
|
+
const setActiveView = useUIStore((s) => s.setActiveView);
|
|
9
11
|
const toggleSessionPanel = useUIStore((s) => s.toggleSessionPanel);
|
|
10
12
|
const toggleSyncPanel = useUIStore((s) => s.toggleSyncPanel);
|
|
11
13
|
const toggleWhatsupPanel = useUIStore((s) => s.toggleWhatsupPanel);
|
|
@@ -14,13 +16,21 @@ export function SideRail() {
|
|
|
14
16
|
const clearMessages = useChatStore((s) => s.clearMessages);
|
|
15
17
|
const hasMessages = useChatStore((s) => activeChat(s).messages.length > 0);
|
|
16
18
|
const isStreaming = useChatStore((s) => activeChat(s).isStreaming);
|
|
17
|
-
|
|
19
|
+
/** Chat-scoped panels live in the chat page — surface it before opening them. */
|
|
20
|
+
function inChat(toggle) {
|
|
21
|
+
return () => {
|
|
22
|
+
if (activeView !== "chat")
|
|
23
|
+
setActiveView("chat");
|
|
24
|
+
toggle();
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return (_jsxs("nav", { className: "hidden md:flex w-16 shrink-0 flex-col items-center border-r border-border bg-surface py-4 gap-1", children: [_jsx("div", { className: "mb-4", children: _jsx(Brain, { className: "h-7 w-7 text-primary" }) }), hasMessages && (_jsx(RailButton, { icon: SquarePen, label: "New chat", onClick: clearMessages })), _jsx("div", { className: "my-2 h-px w-8 bg-border" }), _jsx(RailButton, { icon: RefreshCw, label: "Sync", onClick: inChat(toggleSyncPanel), disabled: isStreaming }), _jsx(RailButton, { icon: Newspaper, label: "Whatsup", onClick: inChat(toggleWhatsupPanel), disabled: isStreaming }), _jsx(RailButton, { icon: FolderTree, label: "Files", onClick: toggleFilePanel }), _jsx(RailButton, { icon: Waypoints, label: "Graph", active: activeView === "graph", onClick: () => setActiveView(activeView === "graph" ? "chat" : "graph") }), _jsx("div", { className: "flex-1" }), _jsx(RailButton, { icon: History, label: "Sessions", onClick: inChat(toggleSessionPanel) }), _jsx(RailButton, { icon: SlidersHorizontal, label: "Settings", onClick: toggleSettingsPanel }), _jsxs("div", { className: "mt-2 flex flex-col items-center gap-1", children: [_jsx("span", { className: cn("inline-block h-2 w-2 rounded-full", wsStatus === "connected" && "bg-green-500", wsStatus === "connecting" && "bg-primary animate-pulse", wsStatus === "disconnected" && "bg-destructive") }), _jsx("span", { className: "text-[10px] text-muted-foreground", children: wsStatus === "connected"
|
|
18
28
|
? "Live"
|
|
19
29
|
: wsStatus === "connecting"
|
|
20
30
|
? "..."
|
|
21
31
|
: "Off" })] })] }));
|
|
22
32
|
}
|
|
23
|
-
function RailButton({ icon: Icon, label, onClick, disabled, }) {
|
|
24
|
-
return (_jsxs("button", { onClick: onClick, disabled: disabled, title: label, className: "group relative flex h-10 w-10 items-center justify-center rounded-lg
|
|
33
|
+
function RailButton({ icon: Icon, label, onClick, disabled, active, }) {
|
|
34
|
+
return (_jsxs("button", { onClick: onClick, disabled: disabled, title: label, className: cn("group relative flex h-10 w-10 items-center justify-center rounded-lg transition-all duration-150 hover:bg-surface-raised hover:text-foreground hover:scale-110 disabled:opacity-40 disabled:hover:scale-100", active ? "bg-surface-raised text-primary" : "text-muted-foreground"), children: [_jsx(Icon, { className: "h-4.5 w-4.5" }), _jsx("span", { className: "pointer-events-none absolute left-full ml-2 whitespace-nowrap rounded-md bg-surface-overlay px-2.5 py-1 text-xs font-medium text-foreground opacity-0 shadow-lg transition-opacity group-hover:opacity-100 border border-border", children: label })] }));
|
|
25
35
|
}
|
|
26
36
|
//# sourceMappingURL=side-rail.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"side-rail.js","sourceRoot":"","sources":["../../../src/components/layout/side-rail.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,KAAK,EACL,SAAS,EACT,SAAS,EACT,OAAO,EACP,iBAAiB,EACjB,SAAS,EACT,UAAU,
|
|
1
|
+
{"version":3,"file":"side-rail.js","sourceRoot":"","sources":["../../../src/components/layout/side-rail.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,10 +11,12 @@ export { configureBrainUi, uiConfig, type BrainUiConfig } from "./config.js";
|
|
|
11
11
|
export { ConnectionGate } from "./components/connectivity/connection-gate.js";
|
|
12
12
|
export { AppShell } from "./components/layout/app-shell.js";
|
|
13
13
|
export { ChatPage } from "./components/chat/chat-page.js";
|
|
14
|
+
export { GraphPage } from "./components/graph/graph-page.js";
|
|
14
15
|
export { BrainMarkdown } from "./components/chat/brain-markdown.js";
|
|
15
16
|
export { useChatStore, activeChat, anyStreaming, type ChatKey, type ChatMessage, type SessionChat, type ToolCall, type AskUserExchange, type MessageAttachment, } from "./stores/chat-store.js";
|
|
16
17
|
export { useFileStore } from "./stores/file-store.js";
|
|
17
|
-
export { useUIStore } from "./stores/ui-store.js";
|
|
18
|
+
export { useUIStore, type ActiveView } from "./stores/ui-store.js";
|
|
19
|
+
export { useGraphStore, type GraphMode } from "./stores/graph-store.js";
|
|
18
20
|
export { useConnectionStore } from "./stores/connection-store.js";
|
|
19
21
|
export { useProviderStore } from "./stores/provider-store.js";
|
|
20
22
|
export { useVoiceStore } from "./voice/voice-store.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAG7E,OAAO,EAAE,cAAc,EAAE,MAAM,8CAA8C,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAG7E,OAAO,EAAE,cAAc,EAAE,MAAM,8CAA8C,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAGpE,OAAO,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG/F,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -13,12 +13,14 @@ export { configureBrainUi, uiConfig } from "./config.js";
|
|
|
13
13
|
export { ConnectionGate } from "./components/connectivity/connection-gate.js";
|
|
14
14
|
export { AppShell } from "./components/layout/app-shell.js";
|
|
15
15
|
export { ChatPage } from "./components/chat/chat-page.js";
|
|
16
|
+
export { GraphPage } from "./components/graph/graph-page.js";
|
|
16
17
|
// Markdown renderer (also useful standalone, e.g. for a dev kitchen sink).
|
|
17
18
|
export { BrainMarkdown } from "./components/chat/brain-markdown.js";
|
|
18
19
|
// Stores + selectors the shell reads (service-worker busy check, deep links).
|
|
19
20
|
export { useChatStore, activeChat, anyStreaming, } from "./stores/chat-store.js";
|
|
20
21
|
export { useFileStore } from "./stores/file-store.js";
|
|
21
22
|
export { useUIStore } from "./stores/ui-store.js";
|
|
23
|
+
export { useGraphStore } from "./stores/graph-store.js";
|
|
22
24
|
export { useConnectionStore } from "./stores/connection-store.js";
|
|
23
25
|
export { useProviderStore } from "./stores/provider-store.js";
|
|
24
26
|
export { useVoiceStore } from "./voice/voice-store.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,sEAAsE;AACtE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAsB,MAAM,aAAa,CAAC;AAE7E,yCAAyC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,8CAA8C,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,sEAAsE;AACtE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAsB,MAAM,aAAa,CAAC;AAE7E,yCAAyC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,8CAA8C,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAE7D,2EAA2E;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEpE,8EAA8E;AAC9E,OAAO,EACL,YAAY,EACZ,UAAU,EACV,YAAY,GAOb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAmB,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAkB,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,uBAAuB;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE/F,yDAAyD;AACzD,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|