@hanzo/rooms 0.1.68 → 0.1.69
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/App.js +38 -9
- package/dist/Column.d.ts +10 -3
- package/dist/Column.js +4 -4
- package/dist/Rail.d.ts +5 -4
- package/dist/Rail.js +5 -6
- package/dist/lib/host.d.ts +5 -0
- package/dist/lib/host.js +6 -1
- package/dist/where.d.ts +1 -1
- package/dist/where.js +1 -1
- package/package.json +3 -1
package/dist/App.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
// The web app as the whole window, in
|
|
4
|
-
// product's AI
|
|
3
|
+
// The web app as the whole window, in three modes: Chat, a conversation with
|
|
4
|
+
// the product's AI; Dev, @hanzo/build's `<Builder>` without a rail of its own;
|
|
5
|
+
// and Studio, @hanzo/studio's `<Studio>` the same way, its places (`nav`) in the
|
|
6
|
+
// sidebar where Dev's stand for Dev.
|
|
5
7
|
//
|
|
6
8
|
// OUTER the rail (Rail.tsx) and the sidebar beside it (Column.tsx), on the
|
|
7
9
|
// window's floor, with the window's bar above them where the host has
|
|
@@ -14,11 +16,12 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
14
16
|
// search, New, Dev's places and the reader's Recents. The address says the
|
|
15
17
|
// mode, as a path (lib/host `talk`, `app`, `place`): `/` and `/chat` are Chat on
|
|
16
18
|
// a new conversation, `/chat/<id>` one of the reader's, and a path under `/dev`
|
|
17
|
-
// is Dev: `/dev/run/<id>` a run, `/dev/projects/<org>/<repo>` a project
|
|
19
|
+
// is Dev: `/dev/run/<id>` a run, `/dev/projects/<org>/<repo>` a project; a path
|
|
20
|
+
// under `/studio` is Studio, its own address after it (`c/<id>`, `library`). Moving
|
|
18
21
|
// between the modes is a history entry (`go`), never a load, so a host serves
|
|
19
22
|
// this one component for every path under each.
|
|
20
23
|
//
|
|
21
|
-
// Every host draws this: hanzo.ai at `/`, `/chat` and `/
|
|
24
|
+
// Every host draws this: hanzo.ai at `/`, `/chat`, `/dev` and `/studio`, and the desktop
|
|
22
25
|
// app as its main window. The host mounts IamProvider and `<Rooms>` with its
|
|
23
26
|
// router and the path, and draws this only for a signed-in reader; what a
|
|
24
27
|
// stranger sees is the host's.
|
|
@@ -46,13 +49,19 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
46
49
|
// EVERY MOVE PUTS THE DRAWER AWAY, the one to where the reader already is
|
|
47
50
|
// included.
|
|
48
51
|
//
|
|
52
|
+
// STUDIO LOADS WITH ITS MODE. Its module (and three.js behind a 3D tab) is
|
|
53
|
+
// fetched the first time the reader stands in Studio; its places are a few
|
|
54
|
+
// lines and come with the app. Another organization opens it at its New, so
|
|
55
|
+
// nothing it read under the last one stays.
|
|
56
|
+
//
|
|
49
57
|
// THE PLANS' OWN ADDRESS LEAVES for the pay site in its place (dev.tsx `leave`),
|
|
50
58
|
// so the builder's own plans are never drawn.
|
|
51
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
59
|
+
import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
52
60
|
import { ArrowLeft, ArrowRight, Menu } from 'lucide-react';
|
|
53
61
|
import { AiProvider } from '@hanzo/ai/react';
|
|
54
62
|
import { Text, XStack, YStack } from '@hanzo/gui';
|
|
55
63
|
import { Builder, HostProvider, path as written, route } from '@hanzo/build';
|
|
64
|
+
import { nav as places } from '@hanzo/studio';
|
|
56
65
|
import { SidebarIconButton } from '@hanzo/ui/chat';
|
|
57
66
|
import { useAi } from './lib/ai.js';
|
|
58
67
|
import { Chat } from './Chat.js';
|
|
@@ -66,8 +75,10 @@ import { empty, openThread, useOpen } from './open.js';
|
|
|
66
75
|
import { Paned } from './Shell.js';
|
|
67
76
|
import { floor, pane } from './ground.js';
|
|
68
77
|
import { pick } from './lib/session.js';
|
|
69
|
-
import { app, go, place, talk } from './lib/host.js';
|
|
78
|
+
import { app, go, place, studio, talk } from './lib/host.js';
|
|
70
79
|
import { wordmark } from './where.js';
|
|
80
|
+
/** Studio, fetched the first time the reader stands in it. */
|
|
81
|
+
const Studio = lazy(() => import('@hanzo/studio').then((m) => ({ default: m.Studio })));
|
|
71
82
|
/** `/` is Chat on a new conversation. */
|
|
72
83
|
const HOME = { mode: 'chat', thread: null };
|
|
73
84
|
/** The bar's height, px: the reference window's title bar. */
|
|
@@ -85,7 +96,7 @@ const INSET = {
|
|
|
85
96
|
left: 'max(var(--pane-gap), var(--safe-left))',
|
|
86
97
|
};
|
|
87
98
|
/** Where each mode was last, so the rail goes back to it. */
|
|
88
|
-
const last = { chat: '', dev: '' };
|
|
99
|
+
const last = { chat: '', dev: '', studio: '' };
|
|
89
100
|
/** Whether a key press is the reader typing, where the app's keys are the field's. */
|
|
90
101
|
const typing = (e) => {
|
|
91
102
|
const el = e.target;
|
|
@@ -119,6 +130,22 @@ function Window({ bar }) {
|
|
|
119
130
|
const at = place(here) ?? HOME;
|
|
120
131
|
const mode = at.mode;
|
|
121
132
|
const where = at.mode === 'dev' ? at.at : null;
|
|
133
|
+
// Studio's host: Dev's, at Studio's address, its moves under /studio, and
|
|
134
|
+
// another organization opening Studio's New in it.
|
|
135
|
+
const made = at.mode === 'studio' ? at.at : '';
|
|
136
|
+
const maker = useMemo(() => ({
|
|
137
|
+
...host,
|
|
138
|
+
name: 'Hanzo Studio',
|
|
139
|
+
path: made,
|
|
140
|
+
go: (to, how) => {
|
|
141
|
+
shut();
|
|
142
|
+
go(studio(to), how?.replace);
|
|
143
|
+
},
|
|
144
|
+
chooseOrg: (next) => {
|
|
145
|
+
pick(next);
|
|
146
|
+
window.location.assign(studio(''));
|
|
147
|
+
},
|
|
148
|
+
}), [host, made, shut]);
|
|
122
149
|
// A run floats two panes of its own, so the pane it stands in is not cut.
|
|
123
150
|
const run = where !== null && route(where).kind === 'run';
|
|
124
151
|
const asked = at.mode === 'chat' ? at.thread : null;
|
|
@@ -202,11 +229,13 @@ function Window({ bar }) {
|
|
|
202
229
|
}, [bar, router, move]);
|
|
203
230
|
const toChat = () => move(last.chat || talk());
|
|
204
231
|
const toDev = () => move(last.dev || app(''));
|
|
232
|
+
const toStudio = () => move(last.studio || studio(''));
|
|
205
233
|
// Another organization: picked, and the app opened in it at the mode's New.
|
|
206
234
|
const org = (o) => {
|
|
207
235
|
pick(o);
|
|
208
|
-
window.location.assign(mode === 'dev' ? app('') : talk());
|
|
236
|
+
window.location.assign(mode === 'dev' ? app('') : mode === 'studio' ? studio('') : talk());
|
|
209
237
|
};
|
|
238
|
+
const sidebar = mode === 'studio' ? places(maker, (p) => maker.go(p)) : undefined;
|
|
210
239
|
const flip = () => setClosed(!closed);
|
|
211
|
-
return (_jsx(AiProvider, { client: client ?? undefined, children: _jsx(HostProvider, { host: host, children: _jsxs(YStack, { "data-slot": "window", ...(bar ? floor : null), flex: 1, minW: 0, height: "100dvh", overflow: "hidden", children: [bar ? (_jsxs(XStack, { "data-slot": "title-bar", height: BAR, shrink: 0, items: "center", gap: 2, pl: (bar.inset ?? 0) + 6, pr: "$2", ...bar.drag, children: [_jsx(XStack, { "$max-md": { display: 'none' }, children: _jsx(Toggle, { open: !closed, onPress: flip }) }), _jsx(XStack, { $md: { display: 'none' }, children: _jsx(Toggle, { open: drawer, onPress: () => setDrawer(true), label: "Open sidebar" }) }), _jsx(Mark, { label: "Back", "data-slot": "back", onPress: () => router.back(), children: _jsx(ArrowLeft, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Forward", "data-slot": "forward", onPress: () => router.forward(), children: _jsx(ArrowRight, { size: 18, "aria-hidden": true }) }), _jsx(XStack, { flex: 1, self: "stretch", ...bar.drag })] })) : null, _jsxs(XStack, { "data-room": "", "data-app": mode, "data-slot": "frame", ...(bar ? null : floor), flex: 1, minW: 0, minH: 0, pr: "var(--pane-gap)", pb: "var(--pane-gap)", pt: bar ? 0 : 'var(--pane-gap)', "$max-md": { p: 0 }, children: [_jsx(YStack, { height: "100%", "$max-md": { display: 'none' }, children: _jsx(Rail, { host: host, mode: mode, at: where, open: !closed, toggle: bar ? undefined : flip, onChat: toChat, onDev: toDev, go: move, onOrg: org }) }), closed ? null : (_jsx(YStack, { "$max-md": { display: 'none' }, children: _jsx(Column, { host: host, mode: mode, thread: thread, go: move, onShut: () => setClosed(true), seek: seek }) })), _jsxs(YStack, { "data-slot": "stage", flex: 1, minW: 0, minH: 0, ml: "var(--pane-gap)", "$max-md": { ml: 0 }, children: [bar ? null : (_jsxs(XStack, { "data-slot": "app-bar", height: 44, px: "$1", gap: "$1", items: "center", shrink: 0, $md: { display: 'none' }, children: [_jsx(SidebarIconButton, { label: "Open sidebar", onPress: () => setDrawer(true), width: 44, height: 44, rounded: 999, children: _jsx(Menu, { size: 18 }) }), _jsx(Text, { fontSize: "$4", fontWeight: "600", color: "$ink", numberOfLines: 1, children: wordmark(mode) })] })), _jsx(XStack, { "data-slot": "panes", flex: 1, minW: 0, minH: 0, children: mode === 'chat' ? (_jsx(Paned, { framed: true, children: _jsx(Chat, {}) })) : (_jsx(YStack, { render: "main", "data-slot": "pane", ...(run ? null : { ...pane(), overflow: 'hidden' }), flex: 1, minW: 0, minH: 0, children: plans ? null : _jsx(Builder, { host: host, rail: false }) })) })] })] }), drawer ? (_jsxs(_Fragment, { children: [_jsx(YStack, { render: "button", "aria-label": "Close sidebar", onPress: () => setDrawer(false), bg: DIM, position: "absolute", t: 0, r: 0, b: 0, l: 0, z: "var(--z-overlay)", $md: { display: 'none' } }), _jsx(YStack, { "data-slot": "drawer", position: "absolute", t: INSET.top, b: INSET.bottom, l: INSET.left, width: "min(320px, calc(100% - 2 * var(--pane-gap) - 48px))", z: "var(--z-modal)", $md: { display: 'none' }, children: _jsx(Column, { host: host, mode: mode, thread: thread, go: move, onShut: shut, seek: seek, drawer: true, foot: _jsx(Rail, { host: host, mode: mode, at: where, open: true, flat: true, onChat: toChat, onDev: toDev, go: move, onOrg: org }) }) })] })) : null] }) }) }));
|
|
240
|
+
return (_jsx(AiProvider, { client: client ?? undefined, children: _jsx(HostProvider, { host: host, children: _jsxs(YStack, { "data-slot": "window", ...(bar ? floor : null), flex: 1, minW: 0, height: "100dvh", overflow: "hidden", children: [bar ? (_jsxs(XStack, { "data-slot": "title-bar", height: BAR, shrink: 0, items: "center", gap: 2, pl: (bar.inset ?? 0) + 6, pr: "$2", ...bar.drag, children: [_jsx(XStack, { "$max-md": { display: 'none' }, children: _jsx(Toggle, { open: !closed, onPress: flip }) }), _jsx(XStack, { $md: { display: 'none' }, children: _jsx(Toggle, { open: drawer, onPress: () => setDrawer(true), label: "Open sidebar" }) }), _jsx(Mark, { label: "Back", "data-slot": "back", onPress: () => router.back(), children: _jsx(ArrowLeft, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Forward", "data-slot": "forward", onPress: () => router.forward(), children: _jsx(ArrowRight, { size: 18, "aria-hidden": true }) }), _jsx(XStack, { flex: 1, self: "stretch", ...bar.drag })] })) : null, _jsxs(XStack, { "data-room": "", "data-app": mode, "data-slot": "frame", ...(bar ? null : floor), flex: 1, minW: 0, minH: 0, pr: "var(--pane-gap)", pb: "var(--pane-gap)", pt: bar ? 0 : 'var(--pane-gap)', "$max-md": { p: 0 }, children: [_jsx(YStack, { height: "100%", "$max-md": { display: 'none' }, children: _jsx(Rail, { host: host, mode: mode, at: where, open: !closed, toggle: bar ? undefined : flip, onChat: toChat, onDev: toDev, onStudio: toStudio, go: move, onOrg: org }) }), closed ? null : (_jsx(YStack, { "$max-md": { display: 'none' }, children: _jsx(Column, { host: host, mode: mode, thread: thread, go: move, onShut: () => setClosed(true), seek: seek, places: sidebar }) })), _jsxs(YStack, { "data-slot": "stage", flex: 1, minW: 0, minH: 0, ml: "var(--pane-gap)", "$max-md": { ml: 0 }, children: [bar ? null : (_jsxs(XStack, { "data-slot": "app-bar", height: 44, px: "$1", gap: "$1", items: "center", shrink: 0, $md: { display: 'none' }, children: [_jsx(SidebarIconButton, { label: "Open sidebar", onPress: () => setDrawer(true), width: 44, height: 44, rounded: 999, children: _jsx(Menu, { size: 18 }) }), _jsx(Text, { fontSize: "$4", fontWeight: "600", color: "$ink", numberOfLines: 1, children: wordmark(mode) })] })), _jsx(XStack, { "data-slot": "panes", flex: 1, minW: 0, minH: 0, children: mode === 'chat' ? (_jsx(Paned, { framed: true, children: _jsx(Chat, {}) })) : mode === 'studio' ? (_jsx(YStack, { render: "main", "data-slot": "pane", ...pane(), overflow: "hidden", flex: 1, minW: 0, minH: 0, children: _jsx(YStack, { flex: 1, minH: 0, height: "100%", children: _jsx(Suspense, { fallback: null, children: _jsx(Studio, { host: maker, rail: false }) }) }) })) : (_jsx(YStack, { render: "main", "data-slot": "pane", ...(run ? null : { ...pane(), overflow: 'hidden' }), flex: 1, minW: 0, minH: 0, children: plans ? null : _jsx(Builder, { host: host, rail: false }) })) })] })] }), drawer ? (_jsxs(_Fragment, { children: [_jsx(YStack, { render: "button", "aria-label": "Close sidebar", onPress: () => setDrawer(false), bg: DIM, position: "absolute", t: 0, r: 0, b: 0, l: 0, z: "var(--z-overlay)", $md: { display: 'none' } }), _jsx(YStack, { "data-slot": "drawer", position: "absolute", t: INSET.top, b: INSET.bottom, l: INSET.left, width: "min(320px, calc(100% - 2 * var(--pane-gap) - 48px))", z: "var(--z-modal)", $md: { display: 'none' }, children: _jsx(Column, { host: host, mode: mode, thread: thread, go: move, onShut: shut, seek: seek, drawer: true, places: sidebar, foot: _jsx(Rail, { host: host, mode: mode, at: where, open: true, flat: true, onChat: toChat, onDev: toDev, onStudio: toStudio, go: move, onOrg: org }) }) })] })) : null] }) }) }));
|
|
212
241
|
}
|
package/dist/Column.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type Host } from '@hanzo/build';
|
|
2
|
+
import { type RailLink } from '@hanzo/ui/chat';
|
|
2
3
|
import { type ReactNode } from 'react';
|
|
3
|
-
import { type
|
|
4
|
-
export declare function Column({ host, mode, thread, go, onShut, seek, drawer, foot, }: {
|
|
4
|
+
import { type Place } from './lib/host.js';
|
|
5
|
+
export declare function Column({ host, mode, thread, go, onShut, seek, drawer, foot, places, }: {
|
|
5
6
|
host: Host;
|
|
6
|
-
mode:
|
|
7
|
+
mode: Place['mode'];
|
|
7
8
|
/** The Chat conversation the pane holds, or null. */
|
|
8
9
|
thread: string | null;
|
|
9
10
|
/** Moves the app to an address of this page. */
|
|
@@ -16,4 +17,10 @@ export declare function Column({ host, mode, thread, go, onShut, seek, drawer, f
|
|
|
16
17
|
drawer?: boolean;
|
|
17
18
|
/** What stands at its foot: the drawer's rail, laid flat. */
|
|
18
19
|
foot?: ReactNode;
|
|
20
|
+
/** The mode's places, where they are not Dev's (Studio's `nav`). */
|
|
21
|
+
places?: {
|
|
22
|
+
id: string;
|
|
23
|
+
label: string;
|
|
24
|
+
links: RailLink[];
|
|
25
|
+
}[];
|
|
19
26
|
}): import("react").JSX.Element;
|
package/dist/Column.js
CHANGED
|
@@ -89,7 +89,7 @@ function Activity({ host }) {
|
|
|
89
89
|
];
|
|
90
90
|
return (_jsx(DropdownMenu, { minWidth: 280, trigger: _jsx(XStack, { render: "button", "aria-label": "Activity", ...{ title: 'Activity' }, ...HEAD, items: "center", justify: "center", cursor: "pointer", opacity: 0.7, hoverStyle: { bg: '$hover', opacity: 1 }, focusVisibleStyle: { outlineWidth: 2, outlineStyle: 'solid', outlineColor: '$outlineColor' }, children: _jsx(Bell, { size: 16, "aria-hidden": true }) }), items: items }));
|
|
91
91
|
}
|
|
92
|
-
export function Column({ host, mode, thread, go, onShut, seek = 0, drawer = false, foot, }) {
|
|
92
|
+
export function Column({ host, mode, thread, go, onShut, seek = 0, drawer = false, foot, places, }) {
|
|
93
93
|
const [words, setWords] = useState('');
|
|
94
94
|
// The search field shows once asked for, and while it holds words.
|
|
95
95
|
const [seeking, setSeeking] = useState(false);
|
|
@@ -98,7 +98,7 @@ export function Column({ host, mode, thread, go, onShut, seek = 0, drawer = fals
|
|
|
98
98
|
const uid = useId();
|
|
99
99
|
const span = useSpan(SPAN, WIDTH, FLOOR, CEIL);
|
|
100
100
|
const dev = (p) => host.go(p);
|
|
101
|
-
const groups = nav(host, dev);
|
|
101
|
+
const groups = places ?? nav(host, dev);
|
|
102
102
|
const open = (row) => (row.kind === 'chat' ? go(talk(row.id)) : dev(row.id));
|
|
103
103
|
// Chat's New; Dev's is the first of its places.
|
|
104
104
|
const create = () => {
|
|
@@ -119,13 +119,13 @@ export function Column({ host, mode, thread, go, onShut, seek = 0, drawer = fals
|
|
|
119
119
|
}, [seek]);
|
|
120
120
|
return (_jsxs(YStack, { "data-slot": "app-column", ref: drawer ? undefined : span.ref,
|
|
121
121
|
// inline-style: `--span`, the width a drag rewrites on the element itself (span.ts); no prop sets a variable.
|
|
122
|
-
style: drawer ? undefined : span.style, position: "relative", flex: drawer ? 1 : undefined, shrink: drawer ? 1 : 0, minW: 0, height: "100%", width: drawer ? undefined : 'var(--span)', children: [_jsxs(Sidebar, { "data-slot": "app-rail", role: "navigation", "aria-label": brand(), ...(drawer ? { ...pane(), ...FLOAT } : { bg: 'transparent', borderWidth: 0 }), ...FILL, px: "$2", pt: drawer ? '$2' : 0, pb: "$2", gap: "$0", children: [_jsxs(XStack, { "data-slot": "app-head", items: "center", gap: "$1", pl: "$2", pr: 2, height: 52, shrink: 0, minW: 0, children: [_jsx(Text, { flex: 1, minW: 0, fontSize: 18, lineHeight: 24, fontWeight: "600", color: "$ink", numberOfLines: 1, children: wordmark(mode) }), _jsx(Activity, { host: host }), _jsx(SidebarIconButton, { label: mode === 'chat' ? 'Search chats' : 'Search runs', onPress: seeking ? done : ask, "aria-expanded": seeking || !!words, ...HEAD, children: _jsx(Search, { size: 16, "aria-hidden": true }) })] }), seeking || words ? (_jsxs(XStack, { "data-slot": "app-filter", items: "center", gap: "$2", pl: "$3", pr: "$1", height: 36, rounded: 999, borderWidth: 1, borderColor: "$borderColor", bg: "$edge", shrink: 0, mb: "$1.5", children: [_jsx(Search, { size: 15, "aria-hidden": true, color: "var(--soft, var(--muted-foreground))" }), _jsx(Text, { render: _jsx("input", { ref: field, value: words, onChange: (e) => setWords(e.target.value), onKeyDown: (e) => {
|
|
122
|
+
style: drawer ? undefined : span.style, position: "relative", flex: drawer ? 1 : undefined, shrink: drawer ? 1 : 0, minW: 0, height: "100%", width: drawer ? undefined : 'var(--span)', children: [_jsxs(Sidebar, { "data-slot": "app-rail", role: "navigation", "aria-label": brand(), ...(drawer ? { ...pane(), ...FLOAT } : { bg: 'transparent', borderWidth: 0 }), ...FILL, px: "$2", pt: drawer ? '$2' : 0, pb: "$2", gap: "$0", children: [_jsxs(XStack, { "data-slot": "app-head", items: "center", gap: "$1", pl: "$2", pr: 2, height: 52, shrink: 0, minW: 0, children: [_jsx(Text, { flex: 1, minW: 0, fontSize: 18, lineHeight: 24, fontWeight: "600", color: "$ink", numberOfLines: 1, children: wordmark(mode) }), _jsx(Activity, { host: host }), mode === 'studio' ? null : (_jsx(SidebarIconButton, { label: mode === 'chat' ? 'Search chats' : 'Search runs', onPress: seeking ? done : ask, "aria-expanded": seeking || !!words, ...HEAD, children: _jsx(Search, { size: 16, "aria-hidden": true }) }))] }), seeking || words ? (_jsxs(XStack, { "data-slot": "app-filter", items: "center", gap: "$2", pl: "$3", pr: "$1", height: 36, rounded: 999, borderWidth: 1, borderColor: "$borderColor", bg: "$edge", shrink: 0, mb: "$1.5", children: [_jsx(Search, { size: 15, "aria-hidden": true, color: "var(--soft, var(--muted-foreground))" }), _jsx(Text, { render: _jsx("input", { ref: field, value: words, onChange: (e) => setWords(e.target.value), onKeyDown: (e) => {
|
|
123
123
|
if (e.key === 'Escape')
|
|
124
124
|
done();
|
|
125
125
|
}, onBlur: () => {
|
|
126
126
|
if (!words)
|
|
127
127
|
setSeeking(false);
|
|
128
|
-
}, placeholder: mode === 'chat' ? 'Search chats' : 'Search runs', "aria-label": "Filter recents" }), flex: 1, minW: 0, bg: "transparent", borderWidth: 0, outlineStyle: "none", color: "inherit", fontSize: "$3" }), words ? (_jsx(SidebarIconButton, { label: "Clear search", onPress: done, width: 28, height: 28, rounded: 999, children: _jsx(X, { size: 14, "aria-hidden": true }) })) : null] })) : null, mode === 'chat' ? (_jsx(YStack, { role: "list", gap: 2, shrink: 0, children: _jsx(YStack, { role: "listitem", children: _jsx(SidebarItem, { "data-slot": "app-new", ...ROW, active: !thread, bg: "transparent", hoverStyle: { bg: '$hover' }, icon: _jsx(SquarePen, { size: 16, "aria-hidden": true }), onPress: create, ...keys(create), children: _jsx(Text, { fontSize: "$3", color: "$ink", children: "New chat" }) }) }) })) : (_jsx(YStack, { "data-slot": "app-places", shrink: 0, children: groups.map((g, i) => (_jsxs(YStack, { pt: i ? '$2' : 0, children: [i ? (_jsx(Text, { id: `${uid}-${g.id}`, pl: "$2", pb: 2, fontSize: "$3", color: "$soft", children: g.label })) : null, _jsx(YStack, { role: "list", "aria-labelledby": i ? `${uid}-${g.id}` : undefined, "aria-label": i ? undefined : g.label, gap: 1, children: g.links.map((link) => (_jsx(YStack, { role: "listitem", children: _jsx(SidebarItem, { ...ROW, ...(link.id === NEW ? { 'data-slot': 'app-new' } : {}), active: link.active, icon: link.id === NEW ? _jsx(SquarePen, { size: 16, "aria-hidden": true }) : link.icon, onPress: link.onPress, ...keys(() => link.onPress?.()), children: _jsx(Text, { fontSize: "$3", color: link.active ? '$ink' : '$quiet', children: link.label }) }) }, link.id))) })] }, g.id))) })), _jsx(Recents, { host: host, mode: mode, thread: thread, words: words, onOpen: open, onNew: create }), _jsxs(YStack, { gap: "$2", pt: "$2", shrink: 0, children: [_jsx(Made, {}), _jsx(Setup, {})] }), foot] }), drawer ? null : (_jsx(Grip, { side: "left", span: span.span, floor: FLOOR, ceil: CEIL, reset: WIDTH, onSpan: span.move, onKeep: span.keep, onShut: onShut, label: "Resize sidebar",
|
|
128
|
+
}, placeholder: mode === 'chat' ? 'Search chats' : 'Search runs', "aria-label": "Filter recents" }), flex: 1, minW: 0, bg: "transparent", borderWidth: 0, outlineStyle: "none", color: "inherit", fontSize: "$3" }), words ? (_jsx(SidebarIconButton, { label: "Clear search", onPress: done, width: 28, height: 28, rounded: 999, children: _jsx(X, { size: 14, "aria-hidden": true }) })) : null] })) : null, mode === 'chat' ? (_jsx(YStack, { role: "list", gap: 2, shrink: 0, children: _jsx(YStack, { role: "listitem", children: _jsx(SidebarItem, { "data-slot": "app-new", ...ROW, active: !thread, bg: "transparent", hoverStyle: { bg: '$hover' }, icon: _jsx(SquarePen, { size: 16, "aria-hidden": true }), onPress: create, ...keys(create), children: _jsx(Text, { fontSize: "$3", color: "$ink", children: "New chat" }) }) }) })) : (_jsx(YStack, { "data-slot": "app-places", shrink: 0, children: groups.map((g, i) => (_jsxs(YStack, { pt: i ? '$2' : 0, children: [i ? (_jsx(Text, { id: `${uid}-${g.id}`, pl: "$2", pb: 2, fontSize: "$3", color: "$soft", children: g.label })) : null, _jsx(YStack, { role: "list", "aria-labelledby": i ? `${uid}-${g.id}` : undefined, "aria-label": i ? undefined : g.label, gap: 1, children: g.links.map((link) => (_jsx(YStack, { role: "listitem", children: _jsx(SidebarItem, { ...ROW, ...(link.id === NEW ? { 'data-slot': 'app-new' } : {}), active: link.active, icon: link.id === NEW ? _jsx(SquarePen, { size: 16, "aria-hidden": true }) : link.icon, onPress: link.onPress, ...keys(() => link.onPress?.()), children: _jsx(Text, { fontSize: "$3", color: link.active ? '$ink' : '$quiet', children: link.label }) }) }, link.id))) })] }, g.id))) })), mode === 'studio' ? null : _jsx(Recents, { host: host, mode: mode, thread: thread, words: words, onOpen: open, onNew: create }), _jsxs(YStack, { gap: "$2", pt: "$2", shrink: 0, children: [_jsx(Made, {}), _jsx(Setup, {})] }), foot] }), drawer ? null : (_jsx(Grip, { side: "left", span: span.span, floor: FLOOR, ceil: CEIL, reset: WIDTH, onSpan: span.move, onKeep: span.keep, onShut: onShut, label: "Resize sidebar",
|
|
129
129
|
// In the gutter between the sidebar and the panel, not over the sidebar's own rows.
|
|
130
130
|
r: GUTTER_END, width: "var(--pane-gap)" }))] }));
|
|
131
131
|
}
|
package/dist/Rail.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import { type Host } from '@hanzo/build';
|
|
3
|
-
import type
|
|
3
|
+
import { type Place } from './lib/host.js';
|
|
4
4
|
/** The rail's width, px. */
|
|
5
5
|
export declare const RAIL = 48;
|
|
6
6
|
/** One mark: an icon button named for where it goes, its name its tooltip, lit where the reader is. */
|
|
@@ -18,9 +18,9 @@ export declare function Toggle({ open, onPress, label }: {
|
|
|
18
18
|
onPress: () => void;
|
|
19
19
|
label?: string;
|
|
20
20
|
}): import("react").JSX.Element;
|
|
21
|
-
export declare function Rail({ host, mode, at, open, toggle, flat, onChat, onDev, go, onOrg, }: {
|
|
21
|
+
export declare function Rail({ host, mode, at, open, toggle, flat, onChat, onDev, onStudio, go, onOrg, }: {
|
|
22
22
|
host: Host;
|
|
23
|
-
mode:
|
|
23
|
+
mode: Place['mode'];
|
|
24
24
|
/** Dev's builder address, or null in Chat. */
|
|
25
25
|
at: string | null;
|
|
26
26
|
/** The sidebar beside the rail is open. */
|
|
@@ -29,9 +29,10 @@ export declare function Rail({ host, mode, at, open, toggle, flat, onChat, onDev
|
|
|
29
29
|
toggle?: () => void;
|
|
30
30
|
/** Laid along the foot of the phone's drawer rather than down the window's edge. */
|
|
31
31
|
flat?: boolean;
|
|
32
|
-
/** To Chat and
|
|
32
|
+
/** To Chat, Dev and Studio, each where the reader left it. */
|
|
33
33
|
onChat: () => void;
|
|
34
34
|
onDev: () => void;
|
|
35
|
+
onStudio: () => void;
|
|
35
36
|
/** Moves the app to an address of this page. */
|
|
36
37
|
go: (address: string) => void;
|
|
37
38
|
/** Work in another organization. */
|
package/dist/Rail.js
CHANGED
|
@@ -5,8 +5,8 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
5
5
|
// menu of the rest, and the account at the foot. It is how the app moves
|
|
6
6
|
// between its products; there is no switch anywhere else.
|
|
7
7
|
//
|
|
8
|
-
// Studio is
|
|
9
|
-
//
|
|
8
|
+
// Studio is the app's third mode (@hanzo/studio at /studio), each of the three
|
|
9
|
+
// opened where the reader left it.
|
|
10
10
|
//
|
|
11
11
|
// Library, Scheduled tasks and Customize are Dev's own places (@hanzo/build's
|
|
12
12
|
// Artifacts, Automations and Customize), raised to the rail; each is lit while
|
|
@@ -27,8 +27,7 @@ import { XStack, YStack } from '@hanzo/gui';
|
|
|
27
27
|
import { route } from '@hanzo/build';
|
|
28
28
|
import { DropdownMenu } from '@hanzo/ui';
|
|
29
29
|
import { Me } from './Me.js';
|
|
30
|
-
import { app,
|
|
31
|
-
import { site } from './where.js';
|
|
30
|
+
import { app, TABS, WORKSPACE } from './lib/host.js';
|
|
32
31
|
/** The rail's width, px. */
|
|
33
32
|
export const RAIL = 48;
|
|
34
33
|
/** A mark, px: a 36px square on a 44px pitch. */
|
|
@@ -72,7 +71,7 @@ export function Mark({ label, on = false, onPress, children, ...rest }) {
|
|
|
72
71
|
export function Toggle({ open, onPress, label }) {
|
|
73
72
|
return (_jsx(Mark, { label: label ?? (open ? 'Close sidebar' : 'Open sidebar'), "data-slot": "sidebar-toggle", "aria-expanded": open, onPress: onPress, children: _jsx(PanelLeft, { size: 18, "aria-hidden": true }) }));
|
|
74
73
|
}
|
|
75
|
-
export function Rail({ host, mode, at, open, toggle, flat = false, onChat, onDev, go, onOrg, }) {
|
|
74
|
+
export function Rail({ host, mode, at, open, toggle, flat = false, onChat, onDev, onStudio, go, onOrg, }) {
|
|
76
75
|
const here = mode === 'dev' ? raised(at) : null;
|
|
77
76
|
const to = (p) => () => go(app(p));
|
|
78
77
|
// Everything else the app reaches, behind More: on a phone the raised places first, then Dev's other places, then the products on hosts of their own.
|
|
@@ -95,5 +94,5 @@ export function Rail({ host, mode, at, open, toggle, flat = false, onChat, onDev
|
|
|
95
94
|
{ key: 'team', label: 'Team', icon: _jsx(Users, { size: 16, "aria-hidden": true }), onSelect: () => out(WORKSPACE) },
|
|
96
95
|
];
|
|
97
96
|
const Stack = flat ? XStack : YStack;
|
|
98
|
-
return (_jsxs(Stack, { "data-slot": "rail", render: "nav", "aria-label": "Products", ...(flat ? { pt: '$2', mt: '$2', borderTopWidth: 1, borderColor: '$borderColor', gap: '$1' } : { width: RAIL, flex: 1, pt: '$2', pb: '$2', gap: 8 }), shrink: 0, items: "center", children: [toggle ? (_jsx(YStack, { pb: 8, children: _jsx(Toggle, { open: open, onPress: toggle }) })) : null, _jsx(Mark, { label: "Chat", on: mode === 'chat', onPress: onChat, "data-slot": "rail-chat", children: _jsx(MessageSquare, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Dev", on: mode === 'dev' && !here, onPress: onDev, "data-slot": "rail-dev", children: _jsx(Code2, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Studio",
|
|
97
|
+
return (_jsxs(Stack, { "data-slot": "rail", render: "nav", "aria-label": "Products", ...(flat ? { pt: '$2', mt: '$2', borderTopWidth: 1, borderColor: '$borderColor', gap: '$1' } : { width: RAIL, flex: 1, pt: '$2', pb: '$2', gap: 8 }), shrink: 0, items: "center", children: [toggle ? (_jsx(YStack, { pb: 8, children: _jsx(Toggle, { open: open, onPress: toggle }) })) : null, _jsx(Mark, { label: "Chat", on: mode === 'chat', onPress: onChat, "data-slot": "rail-chat", children: _jsx(MessageSquare, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Dev", on: mode === 'dev' && !here, onPress: onDev, "data-slot": "rail-dev", children: _jsx(Code2, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Studio", on: mode === 'studio', onPress: onStudio, "data-slot": "rail-studio", children: _jsx(WandSparkles, { size: 18, "aria-hidden": true }) }), flat ? null : (_jsxs(_Fragment, { children: [_jsx(Mark, { label: "Library", on: here === 'library', onPress: to(RAISED.library), "data-slot": "rail-library", children: _jsx(Library, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Scheduled tasks", on: here === 'scheduled', onPress: to(RAISED.scheduled), "data-slot": "rail-scheduled", children: _jsx(Clock, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Customize", on: here === 'customize', onPress: to(RAISED.customize), "data-slot": "rail-customize", children: _jsx(Puzzle, { size: 18, "aria-hidden": true }) })] })), _jsx(DropdownMenu, { placement: flat ? 'top-start' : 'right-start', minWidth: 220, trigger: _jsx(XStack, { render: "button", "aria-label": "More", ...{ title: 'More' }, "data-slot": "rail-more", width: MARK, height: MARK, rounded: "$4", items: "center", justify: "center", cursor: "pointer", opacity: 0.62, hoverStyle: { bg: '$hover', opacity: 1 }, pressStyle: { bg: '$raised' }, focusVisibleStyle: { outlineWidth: 2, outlineStyle: 'solid', outlineColor: '$outlineColor' }, $touchable: { width: 44, height: 44 }, children: _jsx(Ellipsis, { size: 18, "aria-hidden": true }) }), items: rest }), _jsx(YStack, { flex: 1 }), _jsx(Me, { host: host, narrow: true, above: flat, onOrg: onOrg })] }));
|
|
99
98
|
}
|
package/dist/lib/host.d.ts
CHANGED
|
@@ -51,6 +51,8 @@ export declare const DEV = "/dev";
|
|
|
51
51
|
* hanzo.ai/studio, whose page draws the app for a signed-in reader.
|
|
52
52
|
*/
|
|
53
53
|
export declare const STUDIO = "/studio";
|
|
54
|
+
/** Studio at an address of its own (@hanzo/studio `route`): '' is New, /studio. */
|
|
55
|
+
export declare const studio: (at: string) => string;
|
|
54
56
|
/** Chat on a conversation, or /chat itself for a new one. */
|
|
55
57
|
export declare const talk: (id?: string | null) => string;
|
|
56
58
|
/** Dev at a builder address (`route` in @hanzo/build); '' is New, /dev. What is not an address is New. */
|
|
@@ -62,6 +64,9 @@ export type Place = {
|
|
|
62
64
|
} | {
|
|
63
65
|
mode: 'dev';
|
|
64
66
|
at: string;
|
|
67
|
+
} | {
|
|
68
|
+
mode: 'studio';
|
|
69
|
+
at: string;
|
|
65
70
|
};
|
|
66
71
|
/** The place a path names, or null when it names none of the app's. */
|
|
67
72
|
export declare function place(pathname: string): Place | null;
|
package/dist/lib/host.js
CHANGED
|
@@ -54,6 +54,8 @@ export const DEV = '/dev';
|
|
|
54
54
|
* hanzo.ai/studio, whose page draws the app for a signed-in reader.
|
|
55
55
|
*/
|
|
56
56
|
export const STUDIO = '/studio';
|
|
57
|
+
/** Studio at an address of its own (@hanzo/studio `route`): '' is New, /studio. */
|
|
58
|
+
export const studio = (at) => (at ? `${STUDIO}/${at.replace(/^\/+/, '')}` : STUDIO);
|
|
57
59
|
/** Chat on a conversation, or /chat itself for a new one. */
|
|
58
60
|
export const talk = (id) => (id ? `${CHAT}/${encodeURIComponent(id)}` : CHAT);
|
|
59
61
|
/** Dev at a builder address (`route` in @hanzo/build); '' is New, /dev. What is not an address is New. */
|
|
@@ -67,6 +69,8 @@ export function place(pathname) {
|
|
|
67
69
|
return { mode: 'chat', thread: null };
|
|
68
70
|
if (p === DEV || p.startsWith(`${DEV}/`))
|
|
69
71
|
return { mode: 'dev', at: path(parse(p.slice(DEV.length))) };
|
|
72
|
+
if (p === STUDIO || p.startsWith(`${STUDIO}/`))
|
|
73
|
+
return { mode: 'studio', at: p.slice(STUDIO.length + 1) };
|
|
70
74
|
if (!p.startsWith(`${CHAT}/`))
|
|
71
75
|
return null;
|
|
72
76
|
const id = p.slice(CHAT.length + 1);
|
|
@@ -136,7 +140,8 @@ export function remember(mode) {
|
|
|
136
140
|
/** Where `/` takes a member: the mode they were last in, Chat when none is kept. */
|
|
137
141
|
export function resume() {
|
|
138
142
|
try {
|
|
139
|
-
|
|
143
|
+
const kept = window.localStorage.getItem(MODE);
|
|
144
|
+
return kept === 'dev' ? DEV : kept === 'studio' ? STUDIO : CHAT;
|
|
140
145
|
}
|
|
141
146
|
catch {
|
|
142
147
|
return CHAT;
|
package/dist/where.d.ts
CHANGED
|
@@ -68,6 +68,6 @@ export declare const where: () => Addresses;
|
|
|
68
68
|
/** The product's name, as the host states it. Read at call time, like every address. */
|
|
69
69
|
export declare const brand: () => string;
|
|
70
70
|
/** The product's name in each mode of the app: the host's brand in Chat (Hanzo AI, Hanzo Team), Hanzo Dev in Dev. */
|
|
71
|
-
export declare const wordmark: (mode: 'chat' | 'dev') => string;
|
|
71
|
+
export declare const wordmark: (mode: 'chat' | 'dev' | 'studio') => string;
|
|
72
72
|
/** A page of the app's own, from wherever the rooms are mounted. */
|
|
73
73
|
export declare const site: (path: string) => string;
|
package/dist/where.js
CHANGED
|
@@ -12,6 +12,6 @@ export const where = () => addresses;
|
|
|
12
12
|
/** The product's name, as the host states it. Read at call time, like every address. */
|
|
13
13
|
export const brand = () => addresses.brand ?? 'Hanzo AI';
|
|
14
14
|
/** The product's name in each mode of the app: the host's brand in Chat (Hanzo AI, Hanzo Team), Hanzo Dev in Dev. */
|
|
15
|
-
export const wordmark = (mode) => (mode === 'dev' ? 'Hanzo Dev' : brand());
|
|
15
|
+
export const wordmark = (mode) => (mode === 'dev' ? 'Hanzo Dev' : mode === 'studio' ? 'Hanzo Studio' : brand());
|
|
16
16
|
/** A page of the app's own, from wherever the rooms are mounted. */
|
|
17
17
|
export const site = (path) => `${addresses.site}${path}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/rooms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.69",
|
|
4
4
|
"description": "The workspace rooms — Home, Chat, Inbox, Contacts, Meet, Cal, Drive, Board, Work, Bots — and the frame that holds them, once, for every Hanzo surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"@hanzo/gui": "^8.3.5",
|
|
56
56
|
"@hanzo/iam": ">=0.21.28",
|
|
57
57
|
"@hanzo/logo": ">=1.0.26",
|
|
58
|
+
"@hanzo/studio": ">=0.1.0",
|
|
58
59
|
"@hanzo/ui": ">=8.27.67",
|
|
59
60
|
"@hanzo/usage": ">=0.1.18",
|
|
60
61
|
"@hanzo/voice": ">=0.1.16",
|
|
@@ -73,6 +74,7 @@
|
|
|
73
74
|
"@hanzo/gui": "8.3.5",
|
|
74
75
|
"@hanzo/iam": "0.21.28",
|
|
75
76
|
"@hanzo/logo": "1.0.26",
|
|
77
|
+
"@hanzo/studio": "0.1.0",
|
|
76
78
|
"@hanzo/ui": "8.27.67",
|
|
77
79
|
"@hanzo/usage": "0.1.18",
|
|
78
80
|
"@hanzo/voice": "0.1.16",
|