@fungi.computer/tourtois 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +127 -2
- package/dist/AgentMcpServers.d.ts +34 -0
- package/dist/AgentMcpServers.js +124 -0
- package/dist/AppAccessConsent.d.ts +23 -0
- package/dist/AppAccessConsent.js +122 -0
- package/dist/AppCallPermissions.d.ts +9 -0
- package/dist/AppCallPermissions.js +21 -0
- package/dist/AppDesktopSettings.d.ts +11 -0
- package/dist/AppDesktopSettings.js +102 -0
- package/dist/AppPane.d.ts +37 -0
- package/dist/AppPane.js +184 -0
- package/dist/AppWorkbench.d.ts +44 -0
- package/dist/AppWorkbench.js +575 -0
- package/dist/AvatarPicker.d.ts +7 -0
- package/dist/AvatarPicker.js +78 -0
- package/dist/AvatarPreview.d.ts +10 -0
- package/dist/AvatarPreview.js +6 -0
- package/dist/DesktopMenuBar.d.ts +18 -0
- package/dist/DesktopMenuBar.js +23 -0
- package/dist/FocusedAppMenus.d.ts +2 -0
- package/dist/FocusedAppMenus.js +10 -0
- package/dist/Keys.d.ts +131 -0
- package/dist/Keys.js +201 -0
- package/dist/MushroomMark.d.ts +2 -0
- package/dist/MushroomMark.js +5 -0
- package/dist/SettingsHome.d.ts +18 -0
- package/dist/SettingsHome.js +48 -0
- package/dist/SettingsNavigation.d.ts +17 -0
- package/dist/SettingsNavigation.js +153 -0
- package/dist/SystemSettings.d.ts +24 -0
- package/dist/SystemSettings.js +177 -0
- package/dist/TeamDesktop.d.ts +36 -0
- package/dist/TeamDesktop.js +39 -0
- package/dist/WorkbenchAppBar.d.ts +5 -0
- package/dist/WorkbenchAppBar.js +12 -0
- package/dist/app-authority.d.ts +150 -0
- package/dist/app-authority.js +41 -0
- package/dist/app-directory-reconciliation.d.ts +14 -0
- package/dist/app-directory-reconciliation.js +72 -0
- package/dist/app-directory.d.ts +206 -0
- package/dist/app-directory.js +21 -0
- package/dist/app-icon.d.ts +9 -0
- package/dist/app-icon.js +27 -0
- package/dist/app-launch.d.ts +53 -0
- package/dist/app-launch.js +204 -0
- package/dist/app-menus.d.ts +6 -0
- package/dist/app-menus.js +81 -0
- package/dist/app-open-url.d.ts +8 -0
- package/dist/app-open-url.js +63 -0
- package/dist/app-surface.d.ts +62 -0
- package/dist/app-surface.js +10 -0
- package/dist/app-windows.d.ts +107 -0
- package/dist/app-windows.js +21 -0
- package/dist/chrome.css +153 -0
- package/dist/command-dialogs.d.ts +42 -0
- package/dist/command-dialogs.js +194 -0
- package/dist/desktop/Desktop.d.ts +34 -0
- package/dist/desktop/Desktop.js +275 -0
- package/dist/desktop/consent.d.ts +4 -0
- package/dist/desktop/consent.js +64 -0
- package/dist/desktop/gill-frame.d.ts +14 -0
- package/dist/desktop/gill-frame.js +41 -0
- package/dist/desktop/gill-param-picker.d.ts +15 -0
- package/dist/desktop/gill-param-picker.js +145 -0
- package/dist/desktop/launcher-gill.d.ts +20 -0
- package/dist/desktop/launcher-gill.js +49 -0
- package/dist/desktop/own-launchers.d.ts +9 -0
- package/dist/desktop/own-launchers.js +9 -0
- package/dist/desktop/row-gill.d.ts +24 -0
- package/dist/desktop/row-gill.js +136 -0
- package/dist/desktop-api.d.ts +63 -0
- package/dist/desktop-api.js +31 -0
- package/dist/desktop-client.d.ts +19 -0
- package/dist/desktop-client.js +127 -0
- package/dist/desktop-layout.d.ts +117 -0
- package/dist/desktop-layout.js +305 -0
- package/dist/desktop-visibility.d.ts +8 -0
- package/dist/desktop-visibility.js +5 -0
- package/dist/layers.d.ts +5 -0
- package/dist/layers.js +31 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +17 -0
- package/dist/member-avatar-cache.d.ts +15 -0
- package/dist/member-avatar-cache.js +69 -0
- package/dist/member-avatar.d.ts +39 -0
- package/dist/member-avatar.js +88 -0
- package/dist/menu-bar.d.ts +5 -0
- package/dist/menu-bar.js +5 -0
- package/dist/model.d.ts +6 -0
- package/dist/model.js +13 -0
- package/dist/oyster-platform-controls.d.ts +4 -0
- package/dist/oyster-platform-controls.js +107 -0
- package/dist/platform-controls.d.ts +84 -0
- package/dist/platform-controls.js +266 -0
- package/dist/queries.d.ts +7 -0
- package/dist/queries.js +7 -0
- package/dist/session-registry.d.ts +16 -0
- package/dist/session-registry.js +69 -0
- package/dist/session-selection.d.ts +6 -0
- package/dist/session-selection.js +22 -0
- package/dist/settings-leave-guard.d.ts +5 -0
- package/dist/settings-leave-guard.js +9 -0
- package/dist/settings-navigation.css +129 -0
- package/dist/settings-routes.d.ts +118 -0
- package/dist/settings-routes.js +216 -0
- package/dist/settings-sections.d.ts +74 -0
- package/dist/settings-sections.js +17 -0
- package/dist/shell-commands.d.ts +15 -0
- package/dist/shell-commands.js +95 -0
- package/dist/shell-host.d.ts +52 -0
- package/dist/shell-host.js +224 -0
- package/dist/shell-module.d.ts +12 -0
- package/dist/shell-module.js +17 -0
- package/dist/shell-release.d.ts +3 -0
- package/dist/shell-release.js +4 -0
- package/dist/shell.css +858 -0
- package/dist/shell.d.ts +6 -0
- package/dist/shell.js +83 -0
- package/dist/spa.css +11 -0
- package/dist/status-bar.d.ts +9 -0
- package/dist/status-bar.js +51 -0
- package/dist/team-directory.d.ts +3 -0
- package/dist/team-directory.js +6 -0
- package/dist/use-window-motion.d.ts +3 -0
- package/dist/use-window-motion.js +37 -0
- package/dist/useAppOpenUrlHandoff.d.ts +11 -0
- package/dist/useAppOpenUrlHandoff.js +62 -0
- package/dist/useAppWindowManager.d.ts +323 -0
- package/dist/useAppWindowManager.js +47 -0
- package/dist/useDirectoryCommands.d.ts +12 -0
- package/dist/useDirectoryCommands.js +80 -0
- package/dist/workbench.d.ts +3 -0
- package/dist/workbench.js +2 -0
- package/package.json +222 -3
package/dist/AppPane.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { IconButton } from "@fungi.computer/caps/components/icon-button";
|
|
3
|
+
import { AppStatusBar, StatusBarPicker, } from "@fungi.computer/caps/blocks/app-status-bar";
|
|
4
|
+
import { Sigil } from "@fungi.computer/sigils";
|
|
5
|
+
import { WindowActions, WindowBody, WindowFrame, WindowHeader, } from "@fungi.computer/caps/components/window";
|
|
6
|
+
import { Settings, ShieldCheck } from "lucide-react";
|
|
7
|
+
import { WindowStatusItem } from "./status-bar.js";
|
|
8
|
+
import { useLayer, useMaosaicoItem, useMaosaicoLayout, } from "@fungi.computer/maosaico";
|
|
9
|
+
import { AppError, } from "@fungi.computer/agar";
|
|
10
|
+
import { useEffect, useRef, useState } from "react";
|
|
11
|
+
import { AppIcon } from "./app-icon.js";
|
|
12
|
+
import { useWindowMotion } from "./use-window-motion.js";
|
|
13
|
+
import { backHint } from "./shell-commands.js";
|
|
14
|
+
import { createAppWindowManager, } from "./app-windows.js";
|
|
15
|
+
import { launchComputerId } from "./app-launch.js";
|
|
16
|
+
const windowStatusLabel = (projection) => {
|
|
17
|
+
if (projection.status === "error")
|
|
18
|
+
return `${projection.launch.title} unavailable`;
|
|
19
|
+
if (projection.status === "loading")
|
|
20
|
+
return `${projection.launch.title} opening…`;
|
|
21
|
+
return projection.launch.title;
|
|
22
|
+
};
|
|
23
|
+
/** The focused window's App-level settings; its Computer lives in its status bar. */
|
|
24
|
+
export function FocusedWindowControls({ app, onOpenSettings, onOpenPermissions, projection, }) {
|
|
25
|
+
if (!app)
|
|
26
|
+
return null;
|
|
27
|
+
return (_jsxs("div", { className: "tourtois-focused-controls", role: "group", "aria-label": `${projection.launch.title} settings`, children: [_jsx(IconButton, { size: "responsive", "aria-label": `Permissions for ${projection.launch.title}`, title: "App permissions", icon: _jsx(ShieldCheck, {}), onClick: onOpenPermissions }), _jsx(IconButton, { size: "responsive", "aria-label": `Settings for ${projection.launch.title}`, title: "App settings", icon: _jsx(Settings, {}), onClick: onOpenSettings })] }));
|
|
28
|
+
}
|
|
29
|
+
export function AppPane({ projection, icon, manager, onError, index, focusWindow, afterHide, onBack, onSelectComputer, }) {
|
|
30
|
+
const containerRef = useRef(null);
|
|
31
|
+
const [computerPickerOpen, setComputerPickerOpen] = useState(false);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (projection.launch.computers === undefined)
|
|
34
|
+
return;
|
|
35
|
+
return manager.registerComputerChoice(projection.windowId, () => {
|
|
36
|
+
setComputerPickerOpen(true);
|
|
37
|
+
});
|
|
38
|
+
}, [
|
|
39
|
+
manager,
|
|
40
|
+
projection.windowId,
|
|
41
|
+
projection.generation,
|
|
42
|
+
projection.launch.computers,
|
|
43
|
+
]);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (containerRef.current)
|
|
46
|
+
containerRef.current.inert = projection.status !== "ready";
|
|
47
|
+
}, [projection.status]);
|
|
48
|
+
const binding = useMaosaicoItem({
|
|
49
|
+
id: projection.windowId,
|
|
50
|
+
frame: {
|
|
51
|
+
x: 24 + index * 40,
|
|
52
|
+
y: 24 + index * 32,
|
|
53
|
+
width: 600,
|
|
54
|
+
height: 480,
|
|
55
|
+
},
|
|
56
|
+
minima: { width: 320, height: 360 },
|
|
57
|
+
}, { participating: projection.status !== "minimized" });
|
|
58
|
+
const layout = useMaosaicoLayout();
|
|
59
|
+
const element = useWindowMotion(binding, layout.interacting);
|
|
60
|
+
const zoomed = layout.zoomedId === projection.windowId;
|
|
61
|
+
const zoom = () => {
|
|
62
|
+
layout.zoom(zoomed ? null : projection.windowId);
|
|
63
|
+
focusWindow(projection.windowId);
|
|
64
|
+
};
|
|
65
|
+
const close = () => {
|
|
66
|
+
void manager
|
|
67
|
+
.close(projection.windowId)
|
|
68
|
+
.then(() => {
|
|
69
|
+
// The App may veto a close to protect unsaved work.
|
|
70
|
+
if (!manager
|
|
71
|
+
.read()
|
|
72
|
+
.windows.some((item) => item.windowId === projection.windowId))
|
|
73
|
+
afterHide(projection.windowId);
|
|
74
|
+
})
|
|
75
|
+
.catch((cause) => {
|
|
76
|
+
console.error("App workbench operation failed", cause);
|
|
77
|
+
onError("App could not be closed.");
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
const parent = containerRef.current;
|
|
82
|
+
if (!parent)
|
|
83
|
+
return;
|
|
84
|
+
parent.appendChild(projection.container);
|
|
85
|
+
manager.attach(projection.windowId);
|
|
86
|
+
return () => {
|
|
87
|
+
projection.container.remove();
|
|
88
|
+
};
|
|
89
|
+
}, [manager, projection.container, projection.windowId]);
|
|
90
|
+
return (_jsxs(WindowFrame, { ref: element, className: "tourtois-pane tourtois-app-pane", "aria-label": projection.launch.title, active: binding.active, floating: layout.mode === "floating" && !zoomed, "data-window-id": projection.windowId, "data-app-id": projection.launch.appId, "data-installation-id": projection.launch.installationId ?? undefined, "data-surface-id": projection.launch.surfaceId, "data-release-id": projection.launch.releaseId, hidden: projection.status === "minimized" || !binding.visible, onFocusCapture: () => {
|
|
91
|
+
binding.focus();
|
|
92
|
+
}, onPointerDownCapture: () => {
|
|
93
|
+
binding.focus();
|
|
94
|
+
},
|
|
95
|
+
// The mouse back button over this window's chrome is its App's Back;
|
|
96
|
+
// inside the App, Agar maps it the same way.
|
|
97
|
+
onMouseUp: (event) => {
|
|
98
|
+
if (event.button !== 3 || projection.navigation?.canGoBack !== true)
|
|
99
|
+
return;
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
onBack(projection.windowId);
|
|
102
|
+
}, style: binding.stackingStyle, children: [_jsx(WindowHeader, { title: projection.launch.title, ...(projection.navigation?.title === undefined
|
|
103
|
+
? {}
|
|
104
|
+
: { subtitle: projection.navigation.title }), density: layout.mode === "tiled" ? "compact" : "regular", icon: _jsx(AppIcon, { roles: projection.launch.roles, icon: icon }), ...(projection.navigation?.canGoBack === true
|
|
105
|
+
? {
|
|
106
|
+
back: {
|
|
107
|
+
label: `Back in ${projection.launch.title}`,
|
|
108
|
+
hint: backHint(),
|
|
109
|
+
onBack: () => {
|
|
110
|
+
onBack(projection.windowId);
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
: {}), handleProps: {
|
|
115
|
+
...binding.props,
|
|
116
|
+
onClick: binding.focus,
|
|
117
|
+
onDoubleClick: zoom,
|
|
118
|
+
}, actions: _jsx(_Fragment, { children: _jsx(WindowActions, { title: projection.launch.title, maximized: zoomed, ...(layout.mode === "tiled" &&
|
|
119
|
+
layout.order[0] !== projection.windowId
|
|
120
|
+
? {
|
|
121
|
+
onPromote: () => {
|
|
122
|
+
const main = layout.order[0];
|
|
123
|
+
if (main)
|
|
124
|
+
layout.swap(projection.windowId, main);
|
|
125
|
+
focusWindow(projection.windowId);
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
: {}), onToggleMaximize: zoom, onMinimize: () => {
|
|
129
|
+
void manager
|
|
130
|
+
.minimize(projection.windowId)
|
|
131
|
+
.then(() => {
|
|
132
|
+
afterHide(projection.windowId);
|
|
133
|
+
})
|
|
134
|
+
.catch((cause) => {
|
|
135
|
+
console.error("App workbench operation failed", cause);
|
|
136
|
+
onError("App could not be minimized.");
|
|
137
|
+
});
|
|
138
|
+
}, onClose: close }) }) }), projection.status === "loading" ? (_jsxs("div", { className: "tourtois-app-loading", role: "status", children: [_jsx(AppIcon, { roles: projection.launch.roles, icon: icon }), _jsxs("div", { children: [_jsxs("strong", { children: ["Opening ", projection.launch.title, "\u2026"] }), _jsx("span", { children: "Preparing this App for your workspace." })] })] })) : null, projection.status === "error" &&
|
|
139
|
+
!(projection.error instanceof AppError &&
|
|
140
|
+
projection.error.code === "DISCONNECTED") ? (_jsx("p", { className: "tourtois-window-status", role: "status", children: windowStatusLabel(projection) })) : null, _jsx(WindowBody, { ref: containerRef, className: "tourtois-pane-body", hidden: projection.status === "error" }), _jsx(WindowStatusBar, { projection: projection, computerPickerOpen: computerPickerOpen, onComputerPickerOpenChange: setComputerPickerOpen, onSelectComputer: (computerId) => {
|
|
141
|
+
onSelectComputer(projection.windowId, computerId);
|
|
142
|
+
}, surface: () => containerRef.current, onAction: (action) => {
|
|
143
|
+
void manager
|
|
144
|
+
.activateStatus(projection.windowId, action)
|
|
145
|
+
.catch((cause) => {
|
|
146
|
+
console.error("App workbench operation failed", cause);
|
|
147
|
+
onError("App could not handle that action.");
|
|
148
|
+
});
|
|
149
|
+
} })] }));
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* One window's status bar, owned by the shell like its title bar: the
|
|
153
|
+
* window's Computer first (only the person changes it, here), then the items
|
|
154
|
+
* the App declared as data. The shell renders every item with Caps pieces and
|
|
155
|
+
* hands the person's use back to the App. A window with neither has no bar.
|
|
156
|
+
*/
|
|
157
|
+
export function WindowStatusBar({ projection, onSelectComputer, onAction, surface, computerPickerOpen, onComputerPickerOpenChange, }) {
|
|
158
|
+
const popover = useLayer("popover");
|
|
159
|
+
const { computers, title } = projection.launch;
|
|
160
|
+
const items = projection.statusItems;
|
|
161
|
+
if (computers === undefined && items.length === 0)
|
|
162
|
+
return null;
|
|
163
|
+
const anchorFor = (key) => {
|
|
164
|
+
const origin = surface?.()?.getBoundingClientRect();
|
|
165
|
+
if (!origin)
|
|
166
|
+
return undefined;
|
|
167
|
+
const rect = key.getBoundingClientRect();
|
|
168
|
+
return {
|
|
169
|
+
start: Math.max(0, rect.left - origin.left),
|
|
170
|
+
width: Math.max(0, rect.width),
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
const render = (item) => (_jsx(WindowStatusItem, { item: item, container: popover, onAction: onAction, anchorFor: anchorFor }, item.id));
|
|
174
|
+
const end = items.filter((item) => item.end === true);
|
|
175
|
+
const start = items.filter((item) => item.end !== true);
|
|
176
|
+
return (_jsx(AppStatusBar, { className: "tourtois-window-status-bar", "aria-label": `${title} status`, attachment: computers === undefined ? undefined : (_jsx(StatusBarPicker, { ...(computerPickerOpen === undefined
|
|
177
|
+
? {}
|
|
178
|
+
: { open: computerPickerOpen }), ...(onComputerPickerOpenChange === undefined
|
|
179
|
+
? {}
|
|
180
|
+
: { onOpenChange: onComputerPickerOpenChange }), noun: "Computer", pluralNoun: "Computers", accessibleLabel: `Choose Computer for ${title}`, icon: _jsx(Sigil, { name: "computer", size: 16 }), options: computers.map((computer) => ({
|
|
181
|
+
id: computer.computerId,
|
|
182
|
+
label: computer.name,
|
|
183
|
+
})), value: launchComputerId(projection.launch.href), emptyMessage: "No Computers are granted to this App", disabled: projection.status === "loading", onSelect: onSelectComputer })), end: end.length === 0 ? undefined : end.map(render), children: start.length === 0 ? undefined : start.map(render) }));
|
|
184
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { DesktopMethods } from "./desktop-api.js";
|
|
2
|
+
import type { AppOpenInput } from "@fungi.computer/agar/apps";
|
|
3
|
+
import { type AppBarItem } from "@fungi.computer/caps/blocks/app-bar";
|
|
4
|
+
import { type ReactNode, type RefObject } from "react";
|
|
5
|
+
import type { WorkbenchDirectory } from "@fungi.computer/oyster/shell/workbench-directory";
|
|
6
|
+
import { type ComputerOption } from "./app-launch.js";
|
|
7
|
+
import type { PlatformControls } from "./platform-controls.js";
|
|
8
|
+
import type { AppStorage } from "@fungi.computer/agar/storage";
|
|
9
|
+
import type { DesktopGillTransport } from "./desktop/row-gill.js";
|
|
10
|
+
import type { SettingsLocation } from "./settings-routes.js";
|
|
11
|
+
export type AppWorkbenchProps = Readonly<{
|
|
12
|
+
teamId: string;
|
|
13
|
+
teamName: string;
|
|
14
|
+
initialComputerId: string | null;
|
|
15
|
+
computers: readonly ComputerOption[];
|
|
16
|
+
computersUnavailable: boolean;
|
|
17
|
+
paneLayerRef: RefObject<HTMLDivElement>;
|
|
18
|
+
phone: boolean;
|
|
19
|
+
extraPanes?: (context: {
|
|
20
|
+
activeId: string | null;
|
|
21
|
+
order: readonly string[];
|
|
22
|
+
focus: (id: string) => void;
|
|
23
|
+
}) => ReactNode;
|
|
24
|
+
initialFocusId?: string;
|
|
25
|
+
onLayoutChange?: ((tiled: boolean) => void) | undefined;
|
|
26
|
+
extraLaunchers?: readonly AppBarItem[];
|
|
27
|
+
settingsLaunchers?: readonly Readonly<{
|
|
28
|
+
id: string;
|
|
29
|
+
label: string;
|
|
30
|
+
icon?: ReactNode;
|
|
31
|
+
location: SettingsLocation;
|
|
32
|
+
}>[];
|
|
33
|
+
systemMenuItems?: ReactNode;
|
|
34
|
+
/** Read the Team's App directory through the host's `directory()` port. */
|
|
35
|
+
directoryReader: () => Promise<WorkbenchDirectory>;
|
|
36
|
+
/** Take the host address's App-open handoff once, instead of this URL's. */
|
|
37
|
+
takeAppOpenRequest?: () => Promise<AppOpenInput | null>;
|
|
38
|
+
/** Team administration, rendered by the host with the owner's authority. */
|
|
39
|
+
platform: PlatformControls;
|
|
40
|
+
desktopStorage: AppStorage;
|
|
41
|
+
desktopMethods: DesktopMethods;
|
|
42
|
+
gills: DesktopGillTransport;
|
|
43
|
+
}>;
|
|
44
|
+
export declare function AppWorkbench({ paneLayerRef, phone, teamId, teamName, initialComputerId, computers, computersUnavailable, extraPanes, initialFocusId, onLayoutChange, extraLaunchers, settingsLaunchers, systemMenuItems, directoryReader, takeAppOpenRequest, platform, desktopStorage, desktopMethods, gills, }: AppWorkbenchProps): import("react/jsx-runtime").JSX.Element;
|