@hanzo/rooms 0.1.44 → 0.1.46

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.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function App(): import("react").JSX.Element;
package/dist/App.js ADDED
@@ -0,0 +1,87 @@
1
+ 'use client';
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ // The web app as the whole window, in two modes: Chat, a conversation with the
4
+ // product's AI, and Dev, @hanzo/build's `<Builder>` without a rail of its own.
5
+ // One column serves both (Column.tsx): the wordmark and the switch, New, Dev's
6
+ // places, the reader's Recents in both modes, and the account. The address says
7
+ // the mode, as a path (lib/host `talk`, `app`, `place`): `/` and `/chat` are
8
+ // Chat on a new conversation, `/chat/<id>` one of the reader's, and a path under
9
+ // `/dev` is Dev: `/dev/run/<id>` a run, `/dev/projects/<org>/<repo>` a project.
10
+ // Moving between the modes is a history entry (`go`), never a load, so a host
11
+ // serves this one component for every path under each.
12
+ //
13
+ // Every host draws this: hanzo.ai at `/`, the desktop app as its main window.
14
+ // The host mounts IamProvider and `<Rooms>` with its router and the path, and
15
+ // draws this only for a signed-in reader; what a stranger sees is the host's.
16
+ //
17
+ // DEV'S PANE HAS NO COLUMN BESIDE IT. The column beside a pane is Chat's (its
18
+ // pinned summary, `useOpen().aside`), and that choice outlives a move to Dev,
19
+ // where nothing fills it: drawn there it was an empty pane to the right of the
20
+ // builder. So Dev's pane is cut on its own and the summary is Chat's alone.
21
+ //
22
+ // THE WINDOW IS A FRAME (`data-slot="frame"`): the column, the pane and the
23
+ // column beside it are three panes floating on a lit floor (ground.ts), one
24
+ // gutter round them and between them, `--pane-gap`, each sized by the edge
25
+ // beside it.
26
+ import { useEffect, useState } from 'react';
27
+ import { Menu } from 'lucide-react';
28
+ import { AiProvider } from '@hanzo/ai/react';
29
+ import { Text, XStack, YStack } from '@hanzo/gui';
30
+ import { Builder, HostProvider, route } from '@hanzo/build';
31
+ import { SidebarIconButton } from '@hanzo/ui/chat';
32
+ import { scrim } from '@hanzo/ui/glass';
33
+ import { useAi } from './lib/ai.js';
34
+ import { Chat } from './Chat.js';
35
+ import { Column } from './Column.js';
36
+ import { useDevHost } from './dev.js';
37
+ import { useRooms } from './host.js';
38
+ import { wordmark } from './ModeMark.js';
39
+ import { empty, openThread, useOpen } from './open.js';
40
+ import { Paned } from './Shell.js';
41
+ import { floor, pane } from './ground.js';
42
+ import { app, go, place, talk } from './lib/host.js';
43
+ /** `/` is Chat on a new conversation. */
44
+ const HOME = { mode: 'chat', thread: null };
45
+ /** Where each mode was last, so the switch goes back to it. */
46
+ const last = { chat: '', dev: '' };
47
+ export function App() {
48
+ const host = useDevHost();
49
+ const { client } = useAi();
50
+ const here = useRooms().path ?? '/';
51
+ const at = place(here) ?? HOME;
52
+ const mode = at.mode;
53
+ // A run floats two panes of its own, so the pane it stands in is not cut.
54
+ const run = at.mode === 'dev' && route(at.at).kind === 'run';
55
+ const asked = at.mode === 'chat' ? at.thread : null;
56
+ const { thread } = useOpen();
57
+ const [drawer, setDrawer] = useState(false);
58
+ // An address names Chat's conversation, and one just begun writes its id back.
59
+ useEffect(() => {
60
+ if (mode !== 'chat')
61
+ return;
62
+ if (asked && asked !== thread)
63
+ openThread(asked);
64
+ else if (!asked && thread)
65
+ empty();
66
+ // The address decides; the selection follows it.
67
+ // eslint-disable-next-line react-hooks/exhaustive-deps
68
+ }, [mode, asked]);
69
+ useEffect(() => {
70
+ if (mode === 'chat' && thread && thread !== asked)
71
+ go(talk(thread), true);
72
+ // The selection writes the address only when it moves.
73
+ // eslint-disable-next-line react-hooks/exhaustive-deps
74
+ }, [mode, thread]);
75
+ useEffect(() => {
76
+ last[mode] = `${window.location.pathname}${window.location.search}`;
77
+ setDrawer(false);
78
+ }, [mode, here]);
79
+ const toChat = () => go(last.chat || talk());
80
+ const toDev = () => go(last.dev || app(''));
81
+ return (_jsx(AiProvider, { client: client ?? undefined, children: _jsx(HostProvider, { host: host, children: _jsxs(XStack, { "data-room": "", "data-app": mode, "data-slot": "frame", ...floor, flex: 1, minW: 0, p: "var(--pane-gap)", gap: "var(--pane-gap)", height: "100dvh", overflow: "hidden", "$max-md": {
82
+ p: 0,
83
+ gap: 0,
84
+ bg: 'var(--black)',
85
+ backgroundImage: 'radial-gradient(ellipse 80% 50% at 50% -20%, rgba(255, 255, 255, 0.04), transparent 70%), linear-gradient(180deg, #000000 0%, #030303 50%, #080808 100%)',
86
+ }, children: [_jsx(Column, { host: host, mode: mode, thread: thread, onChat: toChat, onDev: toDev, go: go }), _jsxs(YStack, { "data-slot": "stage", flex: 1, minW: 0, minH: 0, gap: "var(--pane-gap)", "$max-md": { gap: 0 }, children: [_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: _jsx(Builder, { host: host, rail: false }) })) })] }), drawer ? (_jsxs(_Fragment, { children: [_jsx(YStack, { render: "button", "aria-label": "Close sidebar", onPress: () => setDrawer(false), ...scrim, 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: "var(--pane-gap)", b: "var(--pane-gap)", l: "var(--pane-gap)", 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, onChat: toChat, onDev: toDev, go: go, drawer: true }) })] })) : null] }) }) }));
87
+ }
package/dist/Me.js CHANGED
@@ -35,12 +35,12 @@ import { createOrg, say } from './lib/org.js';
35
35
  import { list } from './lib/list.js';
36
36
  import { org as current, orgs, pick, renew, scope, superAdmin } from './lib/session.js';
37
37
  import { ENTRY } from './lib/host.js';
38
- import { where } from './where.js';
38
+ import { site, where } from './where.js';
39
39
  import { SupportPicker } from './Support.js';
40
40
  import { BAD } from './lib/mix.js';
41
41
  /** The documentation Get help opens. */
42
42
  const DOCS = 'https://docs.hanzo.ai/docs/dev';
43
- /** Where an organization's own settings live. */
43
+ /** Where an organization's own settings live: a page of the site (`site()`), not of the app. */
44
44
  const ORG_SETTINGS = '/settings/organization';
45
45
  /** The organization's API keys: one home, the platform's keys page, never a second copy in an app. */
46
46
  const KEYS = 'https://platform.hanzo.ai/api-keys';
@@ -172,7 +172,7 @@ export function Me({ host, narrow = false, onOrg, }) {
172
172
  menu.onOpenChange(false);
173
173
  if (o.name !== current)
174
174
  onOrg(o.name);
175
- } }, o.name))) }), _jsx(Item, { icon: _jsx(Plus, { size: 15, "aria-hidden": true }), label: "Create organization", onPress: () => (menu.onOpenChange(false), setCreating(true)) }), _jsx(Item, { icon: _jsx(Settings, { size: 15, "aria-hidden": true }), label: "Organization settings", onPress: () => (menu.onOpenChange(false), window.location.assign(ORG_SETTINGS)) }), where().team ? null : here && !here.personal ? (_jsx(Item, { icon: _jsx(Users, { size: 15, "aria-hidden": true }), label: "Open in Hanzo Team", trail: _jsx(ExternalLink, { size: 13, "aria-hidden": true, opacity: 0.6 }), onPress: () => (menu.onOpenChange(false), window.location.assign(`${ENTRY}&org=${encodeURIComponent(here.name)}`)) })) : (_jsx(Item, { icon: _jsx(Users, { size: 15, "aria-hidden": true }), label: "Create a team", onPress: () => (menu.onOpenChange(false), setCreating(true)) })), superAdmin() ? (_jsx(Item, { icon: _jsx(Building2, { size: 15, "aria-hidden": true }), label: "All organizations", onPress: () => (menu.onOpenChange(false), setSupporting(true)) })) : null, _jsx(Rule, {}), _jsx(Item, { icon: _jsx(Settings, { size: 15, "aria-hidden": true }), label: "Settings", onPress: () => go(path({ kind: 'settings', section: 'general' })) }), _jsx(Item, { icon: _jsx(Gauge, { size: 15, "aria-hidden": true }), label: "Usage", onPress: () => go(path({ kind: 'settings', section: 'usage' })) }), _jsx(Item, { icon: _jsx(CreditCard, { size: 15, "aria-hidden": true }), label: "Billing", onPress: () => go(path({ kind: 'settings', section: 'billing' })) }), _jsx(Item, { icon: _jsx(KeyRound, { size: 15, "aria-hidden": true }), label: "API keys", onPress: () => (menu.onOpenChange(false), window.location.assign(KEYS)) }), _jsx(Item, { icon: _jsx(Sparkles, { size: 15, "aria-hidden": true }), label: "View all plans", onPress: () => go(path({ kind: 'screen', screen: 'plans' })) }), _jsx(Item, { icon: _jsx(LifeBuoy, { size: 15, "aria-hidden": true }), label: "Get help", onPress: () => (menu.onOpenChange(false), window.open(DOCS, '_blank', 'noopener,noreferrer')) }), host.signOut ? (_jsxs(_Fragment, { children: [_jsx(Rule, {}), _jsx(Item, { icon: _jsx(LogOut, { size: 15, "aria-hidden": true }), label: "Log out", onPress: () => (menu.onOpenChange(false), host.signOut?.()) })] })) : null] }) }) })] }), _jsx(Create, { open: creating, onOpenChange: setCreating }), supporting ? _jsx(SupportPicker, { onClose: () => setSupporting(false) }) : null] }));
175
+ } }, o.name))) }), _jsx(Item, { icon: _jsx(Plus, { size: 15, "aria-hidden": true }), label: "Create organization", onPress: () => (menu.onOpenChange(false), setCreating(true)) }), _jsx(Item, { icon: _jsx(Settings, { size: 15, "aria-hidden": true }), label: "Organization settings", onPress: () => (menu.onOpenChange(false), window.location.assign(site(ORG_SETTINGS))) }), where().team ? null : here && !here.personal ? (_jsx(Item, { icon: _jsx(Users, { size: 15, "aria-hidden": true }), label: "Open in Hanzo Team", trail: _jsx(ExternalLink, { size: 13, "aria-hidden": true, opacity: 0.6 }), onPress: () => (menu.onOpenChange(false), window.location.assign(`${ENTRY}&org=${encodeURIComponent(here.name)}`)) })) : (_jsx(Item, { icon: _jsx(Users, { size: 15, "aria-hidden": true }), label: "Create a team", onPress: () => (menu.onOpenChange(false), setCreating(true)) })), superAdmin() ? (_jsx(Item, { icon: _jsx(Building2, { size: 15, "aria-hidden": true }), label: "All organizations", onPress: () => (menu.onOpenChange(false), setSupporting(true)) })) : null, _jsx(Rule, {}), _jsx(Item, { icon: _jsx(Settings, { size: 15, "aria-hidden": true }), label: "Settings", onPress: () => go(path({ kind: 'settings', section: 'general' })) }), _jsx(Item, { icon: _jsx(Gauge, { size: 15, "aria-hidden": true }), label: "Usage", onPress: () => go(path({ kind: 'settings', section: 'usage' })) }), _jsx(Item, { icon: _jsx(CreditCard, { size: 15, "aria-hidden": true }), label: "Billing", onPress: () => go(path({ kind: 'settings', section: 'billing' })) }), _jsx(Item, { icon: _jsx(KeyRound, { size: 15, "aria-hidden": true }), label: "API keys", onPress: () => (menu.onOpenChange(false), window.location.assign(KEYS)) }), _jsx(Item, { icon: _jsx(Sparkles, { size: 15, "aria-hidden": true }), label: "View all plans", onPress: () => go(path({ kind: 'screen', screen: 'plans' })) }), _jsx(Item, { icon: _jsx(LifeBuoy, { size: 15, "aria-hidden": true }), label: "Get help", onPress: () => (menu.onOpenChange(false), window.open(DOCS, '_blank', 'noopener,noreferrer')) }), host.signOut ? (_jsxs(_Fragment, { children: [_jsx(Rule, {}), _jsx(Item, { icon: _jsx(LogOut, { size: 15, "aria-hidden": true }), label: "Log out", onPress: () => (menu.onOpenChange(false), host.signOut?.()) })] })) : null] }) }) })] }), _jsx(Create, { open: creating, onOpenChange: setCreating }), supporting ? _jsx(SupportPicker, { onClose: () => setSupporting(false) }) : null] }));
176
176
  }
177
177
  /**
178
178
  * The sheet that creates an organization: a name, then `POST /v1/account/orgs`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/rooms",
3
- "version": "0.1.44",
3
+ "version": "0.1.46",
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",