@hanzo/rooms 0.1.93 → 0.1.95
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/Chat.js +8 -12
- package/dist/Chrome.d.ts +20 -0
- package/dist/Chrome.js +31 -0
- package/dist/Orgs.js +14 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/lib/ai.d.ts +1 -1
- package/dist/lib/ai.js +2 -2
- package/package.json +1 -1
package/dist/Chat.js
CHANGED
|
@@ -18,9 +18,9 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
18
18
|
//
|
|
19
19
|
// The FREE lane is about PRICE, not identity: a free turn spends no balance and
|
|
20
20
|
// is data-shared in exchange. That choice is made once, at onboarding, where
|
|
21
|
-
// the terms are linked.
|
|
22
|
-
//
|
|
23
|
-
//
|
|
21
|
+
// the terms are linked. Nothing under the composer repeats it. Signing in buys
|
|
22
|
+
// the paid models and a history that follows you; it is never the price of
|
|
23
|
+
// asking a question.
|
|
24
24
|
//
|
|
25
25
|
// This file used to branch on `isAuthenticated` and hand a visitor a composer
|
|
26
26
|
// whose only action was a trip to hanzo.id, captioned "Sign in to send". The
|
|
@@ -31,7 +31,6 @@ import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "r
|
|
|
31
31
|
import { billed, detail, familyOf, planRequired, plainly, refused } from "./failure.js";
|
|
32
32
|
import { Prose } from "./Prose.js";
|
|
33
33
|
import { useAgent, useAi, useChat, } from "@hanzo/ai/react";
|
|
34
|
-
import { isFree } from "@hanzo/ai";
|
|
35
34
|
import { ASK, Chat as ChatSurface, Failure, Parts, words } from "@hanzo/ui/chat";
|
|
36
35
|
import { carriedIn, carrying, compose, partsOf, said as told, weigh } from "./lib/attach.js";
|
|
37
36
|
import { download, dropped, fileOf, pct, readable, refOf, retrieve } from "./lib/files.js";
|
|
@@ -70,7 +69,7 @@ import { Upgrade, useFree } from './Upgrade.js';
|
|
|
70
69
|
import { enter, LOGIN } from './lib/destination.js';
|
|
71
70
|
import { first } from './lib/first.js';
|
|
72
71
|
import { BAD } from "./lib/mix.js";
|
|
73
|
-
import { brand
|
|
72
|
+
import { brand } from './where.js';
|
|
74
73
|
// NO REASONING PANEL HERE. Every assistant turn opened a "Thinking" disclosure
|
|
75
74
|
// listing seven steps — "Planning CSS extraction for chat styles", "Designing
|
|
76
75
|
// responsive top bar grid layout" — typed into this file as a literal array.
|
|
@@ -466,8 +465,7 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
|
|
|
466
465
|
* `useState(anonymous ? FREE : ENSO)` read the flag ONCE, on the first render
|
|
467
466
|
* — which is the render before hydration settles, where `anonymous` is always
|
|
468
467
|
* false. So every visitor opened on ENSO while the composer beside them said
|
|
469
|
-
* "Enso Free"
|
|
470
|
-
* never appeared. A visitor was sending on the paid pool, because a state
|
|
468
|
+
* "Enso Free". A visitor was sending on the paid pool, because a state
|
|
471
469
|
* initialiser cannot see a value that arrives later.
|
|
472
470
|
*
|
|
473
471
|
* A CHOICE, or the identity. `null` is "nobody has chosen", which is a
|
|
@@ -684,8 +682,7 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
|
|
|
684
682
|
// EVERY MODEL IS CHOSEN, never asked for: one the plan does not cover still
|
|
685
683
|
// picks, and the gateway answers it with the policy's refusal or from Enso,
|
|
686
684
|
// which the room then shows. A turn the gateway refuses `plan_required`
|
|
687
|
-
// opens the upgrade, titled with the model.
|
|
688
|
-
// free-lane notice.
|
|
685
|
+
// opens the upgrade, titled with the model.
|
|
689
686
|
const free = useFree(!anonymous) && !held;
|
|
690
687
|
const [ask, setAsk] = useState(null);
|
|
691
688
|
// KEEPING THE CONVERSATION is the reader's account, not this pane's choice:
|
|
@@ -1115,8 +1112,7 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
|
|
|
1115
1112
|
* no longer allowed to draw. `:focus-within` would say this in CSS; the
|
|
1116
1113
|
* stylesheet that would hold it cannot reach past gui's own rule, so the
|
|
1117
1114
|
* state is read where the event is. */
|
|
1118
|
-
// A free send goes. The data-share choice was made at onboarding, once
|
|
1119
|
-
// and the line under the composer still says what a free model does.
|
|
1115
|
+
// A free send goes. The data-share choice was made at onboarding, once.
|
|
1120
1116
|
const guarded = speak;
|
|
1121
1117
|
/**
|
|
1122
1118
|
* The draft and the files, sent as one turn.
|
|
@@ -1523,5 +1519,5 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
|
|
|
1523
1519
|
empty: heading === null ? undefined : (_jsxs(YStack, { "data-slot": "opening", items: "center", width: "100%", pt: "$6", pb: "$2", ...(media.sm ? null : { flex: 1, justify: "flex-end" }), children: [room.length > 1 ? (_jsx(XStack, { items: "center", justify: "center", mb: "$4", children: room.map((name, i) => (_jsx(Box, { ml: i ? -16 : 0, rounded: 40, borderWidth: 2, borderColor: "$background", z: room.length - i, children: _jsx(Face, { src: faces[name]?.avatar, emoji: faces[name]?.emoji, name: name, size: 72 }) }, name))) })) : portrait ? (_jsx(Box, { width: 160, height: 160, rounded: 24, overflow: "hidden", borderWidth: 2, borderColor: "var(--white-15)", boxShadow: "0 10px 24px color-mix(in srgb, var(--pure-black) 70%, transparent)", mb: "$4", bg: "var(--neutral-900)", children: _jsx(View, { render: _jsx("img", { src: portrait, alt: withWhom }), width: "100%", height: "100%", objectFit: "cover" }) })) : null, room.length === 1 && !portrait ? (_jsx(Box, { mb: "$3", children: _jsx(Face, { emoji: mate?.emoji ?? persona?.emoji, name: withWhom, size: 72 }) })) : null, _jsx(Text, { render: "h1", fontSize: "$7", lineHeight: "$7", fontWeight: "700", color: "$ink", text: "center", mb: "$1", children: join(room) || heading || (firstName ? `What’s up, ${firstName}?` : "What’s up?") }), room.length === 1 && (mate?.description ?? persona?.description) ? (_jsx(Text, { fontSize: "$3", color: "$soft", text: "center", maxW: 500, mb: "$4", lineHeight: "$4", children: mate?.description ?? persona?.description })) : null] })),
|
|
1524
1520
|
// The transcript reads at the same measure. `Thread` defaults to 768
|
|
1525
1521
|
// itself; handing it the column here is what lets Width reach it.
|
|
1526
|
-
column: { maxW: MEASURE }, composer: prompt({ ...composing, field: mention.field }, mention.state) }), _jsx(AgentMaker, {}), carry.dialog, _jsx(
|
|
1522
|
+
column: { maxW: MEASURE }, composer: prompt({ ...composing, field: mention.field }, mention.state) }), _jsx(AgentMaker, {}), carry.dialog, _jsx(Upgrade, { ask: ask, onClose: () => setAsk(null) })] }));
|
|
1527
1523
|
}
|
package/dist/Chrome.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bar over a focused page: the organization chooser, the way in, the way to
|
|
3
|
+
* pay, a beta application. One bar for all of them, so none draws its own.
|
|
4
|
+
*
|
|
5
|
+
* The brand at the start (`HanzoLockup`: the mark and `brand()`), going to this
|
|
6
|
+
* host's root; then the host's `back`, where the page has a step to go back to.
|
|
7
|
+
* At the end, once someone is signed in, who it is: the face, the name and the
|
|
8
|
+
* address, with Use another account and Log out. Signed out, nothing but the
|
|
9
|
+
* brand. Under gui's `md` the account folds into its face, a menu of the address
|
|
10
|
+
* and the same two ways out.
|
|
11
|
+
*
|
|
12
|
+
* Use another account writes this page down first (destination.ts
|
|
13
|
+
* `rememberDestination`), so the sign-in that follows comes back to it, as
|
|
14
|
+
* hanzo.ai's /join does. Log out is the account menu's own (lib/signout). The
|
|
15
|
+
* session is IAM's: the host mounts `IamProvider`.
|
|
16
|
+
*/
|
|
17
|
+
import type { ReactNode } from 'react';
|
|
18
|
+
export declare function Chrome({ back }: {
|
|
19
|
+
back?: ReactNode;
|
|
20
|
+
}): import("react").JSX.Element;
|
package/dist/Chrome.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useIam } from '@hanzo/iam/react';
|
|
4
|
+
import { Text, View, XStack, YStack } from '@hanzo/gui';
|
|
5
|
+
import { Avatar, Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@hanzo/ui';
|
|
6
|
+
import { HanzoLockup } from '@hanzogui/shell';
|
|
7
|
+
import { rememberDestination } from './lib/destination.js';
|
|
8
|
+
import { named } from './lib/session.js';
|
|
9
|
+
import { useSignOut } from './lib/signout.js';
|
|
10
|
+
import { brand } from './where.js';
|
|
11
|
+
/** The bar's height under the notch: hanzo.ai's masthead's. */
|
|
12
|
+
const HEIGHT = 60;
|
|
13
|
+
/** The notch's inset. gui carries a CSS function to the page unchanged; its types only name custom properties. */
|
|
14
|
+
const NOTCH = 'env(safe-area-inset-top)';
|
|
15
|
+
export function Chrome({ back }) {
|
|
16
|
+
const { user, isAuthenticated } = useIam();
|
|
17
|
+
const signOut = useSignOut();
|
|
18
|
+
const claimed = named();
|
|
19
|
+
const u = user;
|
|
20
|
+
const name = u?.displayName || u?.name || claimed?.name || '';
|
|
21
|
+
const email = u?.email || claimed?.email || '';
|
|
22
|
+
const avatar = typeof u?.avatar === 'string' && u.avatar.startsWith('https://') ? u.avatar : '';
|
|
23
|
+
const who = name || email;
|
|
24
|
+
const other = () => {
|
|
25
|
+
rememberDestination();
|
|
26
|
+
void signOut();
|
|
27
|
+
};
|
|
28
|
+
const out = () => void signOut();
|
|
29
|
+
const signed = isAuthenticated && Boolean(who);
|
|
30
|
+
return (_jsxs(XStack, { render: "header", "data-slot": "masthead", position: "sticky", t: 0, z: "var(--z-header)", shrink: 0, boxSizing: "content-box", height: HEIGHT, pt: NOTCH, px: "var(--page-gutter, 20px)", gap: 12, items: "center", bg: "var(--background)", borderBottomWidth: 1, borderColor: "var(--border)", children: [_jsx(Text, { render: _jsx("a", { href: "/", "aria-label": `${brand()} home` }), display: "flex", items: "center", shrink: 0, color: "var(--foreground)", textDecorationLine: "none", children: _jsx(HanzoLockup, { label: brand(), size: 22 }) }), back, _jsx(View, { flex: 1 }), signed ? (_jsxs(_Fragment, { children: [_jsxs(XStack, { render: "section", "aria-label": "Account", items: "center", gap: 12, minW: 0, "$max-md": { display: 'none' }, children: [_jsx(Avatar, { src: avatar || null, name: who, alt: "" }), _jsxs(YStack, { minW: 0, gap: 2, children: [_jsx(Text, { fontSize: "$3", fontWeight: "500", color: "$ink", numberOfLines: 1, children: who }), name && email ? (_jsx(Text, { fontSize: "$2", color: "$soft", numberOfLines: 1, children: email })) : null] }), _jsx(Button, { variant: "ghost", size: "sm", onClick: other, children: "Use another account" }), _jsx(Button, { variant: "ghost", size: "sm", onClick: out, children: "Log out" })] }), _jsx(View, { display: "none", "$max-md": { display: 'flex' }, children: _jsxs(DropdownMenu, { placement: "bottom-end", offset: 8, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(XStack, { render: "button", "aria-label": `Account: ${who}`, width: 40, height: 40, rounded: 999, items: "center", justify: "center", borderWidth: 0, bg: "transparent", hoverStyle: { bg: '$hover' }, focusVisibleStyle: { outlineWidth: 2, outlineStyle: 'solid', outlineColor: '$outlineColor' }, cursor: "pointer", children: _jsx(Avatar, { src: avatar || null, name: who, alt: "" }) }) }), _jsxs(DropdownMenuContent, { minW: 240, maxW: "calc(100vw - 16px)", "aria-labelledby": undefined, "aria-label": "Account", children: [_jsx(DropdownMenuLabel, { children: _jsxs(YStack, { minW: 0, gap: 2, children: [_jsx(Text, { fontSize: "$3", fontWeight: "500", color: "$ink", numberOfLines: 1, children: who }), name && email ? (_jsx(Text, { fontSize: "$2", color: "$soft", numberOfLines: 1, children: email })) : null] }) }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuItem, { onSelect: other, children: _jsx(Text, { fontSize: "$3", color: "$ink", children: "Use another account" }) }), _jsx(DropdownMenuItem, { onSelect: out, children: _jsx(Text, { fontSize: "$3", color: "$ink", children: "Log out" }) })] })] }) })] })) : null] }));
|
|
31
|
+
}
|
package/dist/Orgs.js
CHANGED
|
@@ -52,7 +52,8 @@ import { createOrg, say } from './lib/org.js';
|
|
|
52
52
|
import { countSignup } from './lib/intent.js';
|
|
53
53
|
import { BAD, mix } from './lib/mix.js';
|
|
54
54
|
import { useRooms } from './host.js';
|
|
55
|
-
import {
|
|
55
|
+
import { Chrome } from './Chrome.js';
|
|
56
|
+
import { site, where } from './where.js';
|
|
56
57
|
/** A template to set up once the organization is live. */
|
|
57
58
|
const SETUP = 'hanzo:org:template';
|
|
58
59
|
/** Checkout for a plan, coming back to this room. */
|
|
@@ -292,9 +293,14 @@ const FIELD = {
|
|
|
292
293
|
bg: 'var(--background)',
|
|
293
294
|
color: 'var(--foreground)',
|
|
294
295
|
};
|
|
295
|
-
/**
|
|
296
|
+
/**
|
|
297
|
+
* The sheet every screen stands on: the whole viewport, scrolling, its column
|
|
298
|
+
* centred, under the focused pages' one bar (`Chrome`) once someone is signed
|
|
299
|
+
* in. "Signing you in" stands alone.
|
|
300
|
+
*/
|
|
296
301
|
function Page({ label, children }) {
|
|
297
|
-
|
|
302
|
+
const { isAuthenticated } = useIam();
|
|
303
|
+
return (_jsxs(YStack, { position: "fixed", inset: 0, z: SHEET, overflowY: "auto", bg: "var(--background)", role: "region", "aria-label": label, children: [isAuthenticated ? _jsx(Chrome, {}) : null, _jsx(YStack, { pt: TOP, px: 20, pb: 48, children: children })] }));
|
|
298
304
|
}
|
|
299
305
|
/** The column a screen's words sit in. */
|
|
300
306
|
function Column({ children }) {
|
|
@@ -331,9 +337,6 @@ function Forward({ to }) {
|
|
|
331
337
|
function Step({ at, of }) {
|
|
332
338
|
return (_jsxs(Text, { render: "p", mb: 10, fontSize: "$2", fontFamily: "$mono", color: "$soft", children: ["Step ", at, " of ", of] }));
|
|
333
339
|
}
|
|
334
|
-
function Brand() {
|
|
335
|
-
return (_jsx(Text, { fontSize: "$6", fontWeight: "500", mb: 28, color: "var(--foreground)", children: brand() }));
|
|
336
|
-
}
|
|
337
340
|
/** The free rung's name in the billing catalog. */
|
|
338
341
|
const FREE_TIER = 'free';
|
|
339
342
|
/**
|
|
@@ -362,7 +365,7 @@ function SignIn({ to }) {
|
|
|
362
365
|
function Create() {
|
|
363
366
|
const [open, setOpen] = useState(false);
|
|
364
367
|
const [details, setDetails] = useState(false);
|
|
365
|
-
return (_jsxs(Page, { label: "Organizations", children: [_jsxs(Column, { children: [
|
|
368
|
+
return (_jsxs(Page, { label: "Organizations", children: [_jsxs(Column, { children: [_jsxs(XStack, { items: "flex-start", justify: "space-between", gap: 16, flexWrap: "wrap", children: [_jsxs(YStack, { children: [_jsx(Text, { render: "h1", fontSize: "$10", fontWeight: "500", letterSpacing: -0.32, color: "var(--text-primary)", children: "Organizations" }), _jsx(Text, { render: "p", mt: 6, fontSize: "$4", color: muted, children: "You do not belong to one yet." })] }), _jsxs(Button, { variant: "primary", size: "lg", onClick: () => setOpen(true), children: [_jsx(Plus, { size: 16, "aria-hidden": true }), "New organization"] })] }), _jsx(Rule, {}), _jsxs(YStack, { items: "center", py: 28, children: [_jsx(Text, { render: "p", fontSize: "$6", fontWeight: "500", color: "var(--foreground)", text: "center", children: "No organizations yet" }), _jsx(Button, { variant: "linkMuted", size: "sm", mt: 8, onClick: () => setDetails((d) => !d), children: details ? '- Details' : '+ Details' }), details ? (_jsx(Text, { render: "p", mt: 12, maxW: 440, fontSize: "$4", color: muted, lineHeight: 23.25, text: "center", children: "An organization owns every agent, credit and member. Create one and you are its owner." })) : null] }), _jsx(Rule, {})] }), open ? _jsx(CreateDialog, { onClose: () => setOpen(false) }) : null] }));
|
|
366
369
|
}
|
|
367
370
|
/** Name it, pick what it runs and its plan: a paid plan goes to checkout, Free goes straight in. */
|
|
368
371
|
function CreateDialog({ onClose }) {
|
|
@@ -580,7 +583,7 @@ function Pick({ members, current, onPick, onClose, }) {
|
|
|
580
583
|
document.addEventListener('keydown', key);
|
|
581
584
|
return () => document.removeEventListener('keydown', key);
|
|
582
585
|
}, [onClose, founding]);
|
|
583
|
-
return (_jsxs(Page, { label: "Choose an organization", children: [_jsxs(Column, { children: [_jsxs(XStack, { items: "flex-start", justify: "space-between", gap: 12, children: [_jsx(
|
|
586
|
+
return (_jsxs(Page, { label: "Choose an organization", children: [_jsxs(Column, { children: [_jsxs(XStack, { items: "flex-start", justify: "space-between", gap: 12, children: [_jsx(YStack, { flex: 1, minW: 0, children: _jsx(Heading, { title: "Choose an organization", lede: _jsx(_Fragment, { children: "Everything you open \u2014 chats, agents, credit \u2014 is this one's." }) }) }), onClose ? (_jsx(Button, { variant: "ghost", size: "icon-sm", mr: -8, onClick: onClose, "aria-label": "Close", children: _jsx(X, { size: 16, "aria-hidden": true }) })) : null] }), _jsx(Rule, {}), _jsx(XStack, { render: "form", onSubmit: (e) => {
|
|
584
587
|
e.preventDefault();
|
|
585
588
|
if (shown[0])
|
|
586
589
|
onPick(shown[0].name);
|
|
@@ -712,7 +715,7 @@ function Found({ onClose }) {
|
|
|
712
715
|
function Subscribe({ org, members, onSwitch, }) {
|
|
713
716
|
const { plan, price } = usePlan('team');
|
|
714
717
|
const seat = plan?.pricePerUser ? ' / seat' : '';
|
|
715
|
-
return (_jsx(Page, { label: "Subscribe", children: _jsxs(Column, { children: [_jsx(
|
|
718
|
+
return (_jsx(Page, { label: "Subscribe", children: _jsxs(Column, { children: [_jsx(Heading, { title: org, lead: 22.5, lede: plan ? `This organization runs on the ${plan.name} plan at ${price}${seat} / month, and nothing in it works until that plan is live.` : 'Its plan is not live yet.' }), _jsx(Rule, {}), _jsxs(XStack, { gap: 10, flexWrap: "wrap", children: [plan ? (_jsx(Button, { asChild: true, variant: "primary", size: "lg", children: _jsx("a", { href: checkout(plan), children: `Subscribe — ${price}${seat} / month` }) })) : null, members.length > 1 ? (_jsx(Button, { size: "lg", onClick: onSwitch, children: "Switch organization" })) : null] })] }) }));
|
|
716
719
|
}
|
|
717
720
|
// ── the front door's setup ─────────────────────────────────────────────────────
|
|
718
721
|
/**
|
|
@@ -808,7 +811,7 @@ function Start({ founded = null, onFounded, first, members = [], onSwitch, }) {
|
|
|
808
811
|
};
|
|
809
812
|
if (step === 'plan' && founded)
|
|
810
813
|
return _jsx(Plan, { org: founded, members: [founded], seats: 1 + sent.filter((s) => s.link).length, setup: true });
|
|
811
|
-
return (_jsx(Page, { label: "Create your team", children:
|
|
814
|
+
return (_jsx(Page, { label: "Create your team", children: _jsx(Column, { children: step === 'name' ? (_jsxs(YStack, { render: "form", onSubmit: create, children: [_jsx(Step, { at: 1, of: 3 }), _jsx(Heading, { title: "Create your team", lede: "A team owns its agents, credit and members. You are its owner." }), _jsx(Rule, {}), _jsxs(View, { render: "label", display: "block", children: [_jsx(Text, { display: "block", fontSize: "$4", fontWeight: "500", mb: 8, color: "$ink", children: "Team name" }), _jsx(Text, { render: _jsx("input", { value: name, onChange: (e) => setName(e.target.value), placeholder: "Acme", autoFocus: true }), ...FIELD }), _jsx(Text, { display: "block", fontSize: "$3", color: "$soft", mt: 8, children: "What the rail and every invoice call it." })] }), refused ? (_jsx(Text, { render: "p", role: "alert", mt: 14, fontSize: "$3", color: BAD, children: refused })) : null, _jsxs(XStack, { gap: 10, flexWrap: "wrap", mt: 24, children: [_jsx(Button, { type: "submit", variant: "primary", size: "lg", disabled: busy, children: busy ? 'Creating…' : 'Continue' }), members.length > 1 && onSwitch ? (_jsx(Button, { type: "button", size: "lg", onClick: onSwitch, children: "Switch organization" })) : null] }), _jsx(Rule, {}), _jsxs(Text, { render: "p", fontSize: "$3", color: "$soft", children: ["Just you? Hanzo Chat is free for personal use at", ' ', _jsx(Text, { render: _jsx("a", { href: site('/chat') }), color: "$ink", textDecorationLine: "underline", children: "hanzo.ai/chat" }), "."] })] })) : (_jsxs(YStack, { render: "form", onSubmit: invite, children: [_jsx(Step, { at: 2, of: 3 }), _jsx(Heading, { title: "Invite your teammates", lede: "Each address gets its own single-use link to join. You can skip this and invite people later." }), _jsx(Rule, {}), _jsxs(View, { render: "label", display: "block", children: [_jsx(Text, { display: "block", fontSize: "$4", fontWeight: "500", mb: 8, color: "$ink", children: "Email addresses" }), _jsx(Text, { render: _jsx("textarea", { value: emails, onChange: (e) => setEmails(e.target.value), placeholder: "ada@acme.com, alan@acme.com", rows: 3 }), ...FIELD }), _jsx(Text, { display: "block", fontSize: "$3", color: "$soft", mt: 8, children: "Separate them with commas, spaces or new lines." })] }), sent.length ? (_jsx(YStack, { render: "ul", gap: 8, m: 0, p: 0, mt: 18, "aria-label": "Invitations", children: sent.map((s) => (_jsx(YStack, { render: "li", children: _jsxs(Text, { fontSize: "$3", color: "$soft", wordWrap: "break-word", children: [_jsx(Text, { fontWeight: "500", color: "$ink", children: s.email }), ' ', s.link ? (_jsxs(_Fragment, { children: ["invited. Their link:", ' ', _jsx(Text, { render: _jsx("a", { href: s.link }), color: "$ink", textDecorationLine: "underline", children: s.link })] })) : (_jsx(Text, { role: "alert", color: BAD, children: s.refused }))] }) }, s.email))) })) : null, _jsx(XStack, { gap: 10, flexWrap: "wrap", mt: 24, children: sent.length ? (_jsx(Button, { type: "button", variant: "primary", size: "lg", onClick: () => setStep('plan'), children: "Continue" })) : (_jsxs(_Fragment, { children: [_jsx(Button, { type: "submit", variant: "primary", size: "lg", disabled: busy, children: busy ? 'Inviting…' : emails.trim() ? 'Invite and continue' : 'Continue' }), _jsx(Button, { type: "button", size: "lg", onClick: () => setStep('plan'), children: "Skip for now" })] })) })] })) }) }));
|
|
812
815
|
}
|
|
813
816
|
/** Where a checkout from the setup returns: the rooms' Home, on this origin. */
|
|
814
817
|
const home = () => `${window.location.origin}${where().home}`;
|
|
@@ -835,7 +838,7 @@ function Plan({ org, members, onSwitch, outage, onRetry, seats: wanted = 1, setu
|
|
|
835
838
|
['month', 'Monthly', `${money(monthly)} / seat / month`],
|
|
836
839
|
...(yearly ? [['year', 'Annual', `${money(yearly)} / seat, billed once a year`]] : []),
|
|
837
840
|
];
|
|
838
|
-
return (_jsx(Page, { label: "Choose your plan", children: _jsxs(Column, { children: [
|
|
841
|
+
return (_jsx(Page, { label: "Choose your plan", children: _jsxs(Column, { children: [setup ? _jsx(Step, { at: 3, of: 3 }) : null, _jsx(Heading, { title: org, lead: 22.5, lede: outage
|
|
839
842
|
? 'Billing could not be read just now, so this team cannot open yet. That is ours to fix.'
|
|
840
843
|
: plan
|
|
841
844
|
? `A team runs on the ${plan.name} plan, and nothing in it works until that plan is live.`
|
package/dist/index.d.ts
CHANGED
|
@@ -12,3 +12,4 @@ export { configure, where, site, brand } from './where.js';
|
|
|
12
12
|
export type { Addresses } from './where.js';
|
|
13
13
|
export { Rooms, Look, useRooms, useLook, useOrg } from './host.js';
|
|
14
14
|
export type { Router, Link, RoomsProps } from './host.js';
|
|
15
|
+
export { Chrome } from './Chrome.js';
|
package/dist/index.js
CHANGED
|
@@ -10,3 +10,5 @@
|
|
|
10
10
|
*/
|
|
11
11
|
export { configure, where, site, brand } from './where.js';
|
|
12
12
|
export { Rooms, Look, useRooms, useLook, useOrg } from './host.js';
|
|
13
|
+
// The bar over a focused page (the chooser, the way in, the way to pay): one for every host.
|
|
14
|
+
export { Chrome } from './Chrome.js';
|
package/dist/lib/ai.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export declare const base: () => {
|
|
|
40
40
|
export interface Ai {
|
|
41
41
|
client: AiClient | null;
|
|
42
42
|
model: string;
|
|
43
|
-
/** Answering
|
|
43
|
+
/** Answering on the free pool. The data-share choice was made at onboarding. */
|
|
44
44
|
free: boolean;
|
|
45
45
|
/** Mounted client-side. The static export always prerenders the signed-out
|
|
46
46
|
* page, so nothing interactive may render until this is true. */
|
package/dist/lib/ai.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// their account like every other turn they run.
|
|
6
6
|
//
|
|
7
7
|
// Signed out — the FREE POOL, anonymously. There is no account to bill and none
|
|
8
|
-
// is needed: a free turn spends no balance
|
|
9
|
-
//
|
|
8
|
+
// is needed: a free turn spends no balance. The data-share choice is made
|
|
9
|
+
// once, at onboarding. A widget key, if
|
|
10
10
|
// one is configured, rides along so the turn attributes to the org that minted
|
|
11
11
|
// it; without one the turn is simply anonymous. Either way the client EXISTS,
|
|
12
12
|
// because a chat you cannot send is not a chat.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/rooms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.95",
|
|
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",
|