@peers-app/peers-ui 0.19.10 → 0.19.13
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/README.md +7 -2
- package/dist/components/group-switcher.js +3 -4
- package/dist/components/voice-playback.d.ts +15 -0
- package/dist/components/voice-playback.js +86 -0
- package/dist/components/voice-subscribe-events.d.ts +0 -4
- package/dist/index.d.ts +10 -2
- package/dist/index.js +23 -2
- package/dist/operator-console/operator-console-state.d.ts +49 -0
- package/dist/operator-console/operator-console-state.js +97 -0
- package/dist/operator-console/operator-console.d.ts +32 -0
- package/dist/operator-console/operator-console.js +88 -0
- package/dist/root-layout/global-overlays.d.ts +37 -0
- package/dist/root-layout/global-overlays.js +37 -0
- package/dist/root-layout/layout-picker.d.ts +9 -0
- package/dist/root-layout/layout-picker.js +22 -0
- package/dist/root-layout/layouts/full-screen-layout.d.ts +12 -0
- package/dist/root-layout/layouts/full-screen-layout.js +60 -0
- package/dist/root-layout/layouts/tabs-with-console-layout.d.ts +20 -0
- package/dist/root-layout/layouts/tabs-with-console-layout.js +158 -0
- package/dist/root-layout/root-layout-host.d.ts +19 -0
- package/dist/root-layout/root-layout-host.js +88 -0
- package/dist/root-layout/root-layout-registry.d.ts +15 -0
- package/dist/root-layout/root-layout-registry.js +50 -0
- package/dist/root-layout/root-layout-state.d.ts +23 -0
- package/dist/root-layout/root-layout-state.js +54 -0
- package/dist/root-layout/root-layout.d.ts +30 -0
- package/dist/root-layout/root-layout.js +12 -0
- package/dist/screens/network-viewer/connection-troubleshooter.js +7 -11
- package/dist/screens/settings/settings-page.js +2 -1
- package/dist/screens/setup-user.js +2 -7
- package/dist/tabs-layout/tabs-layout.d.ts +48 -4
- package/dist/tabs-layout/tabs-layout.js +27 -53
- package/dist/tabs-layout/tabs-state.d.ts +10 -0
- package/dist/tabs-layout/tabs-state.js +33 -1
- package/package.json +3 -3
- package/src/components/group-switcher.tsx +5 -7
- package/src/components/voice-playback.tsx +97 -0
- package/src/components/voice-subscribe-events.ts +0 -4
- package/src/index.tsx +24 -2
- package/src/operator-console/operator-console-state.ts +119 -0
- package/src/operator-console/operator-console.tsx +233 -0
- package/src/root-layout/global-overlays.ts +50 -0
- package/src/root-layout/layout-picker.tsx +47 -0
- package/src/root-layout/layouts/full-screen-layout.tsx +144 -0
- package/src/root-layout/layouts/tabs-with-console-layout.tsx +260 -0
- package/src/root-layout/root-layout-host.tsx +113 -0
- package/src/root-layout/root-layout-registry.ts +51 -0
- package/src/root-layout/root-layout-state.ts +55 -0
- package/src/root-layout/root-layout.ts +32 -0
- package/src/screens/network-viewer/connection-troubleshooter.tsx +10 -14
- package/src/screens/settings/settings-page.tsx +7 -1
- package/src/screens/setup-user.tsx +2 -9
- package/src/tabs-layout/tabs-layout.tsx +28 -74
- package/src/tabs-layout/tabs-state.ts +31 -0
- package/dist/components/chat-overlay.d.ts +0 -14
- package/dist/components/chat-overlay.js +0 -477
- package/src/components/chat-overlay.tsx +0 -854
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getUserContext,
|
|
3
|
-
hasShownWelcomeModal,
|
|
4
3
|
type IAppNav,
|
|
5
4
|
rpcServerCalls,
|
|
6
5
|
type Subscription,
|
|
7
|
-
setDefaultClientUserContext,
|
|
8
6
|
} from "@peers-app/peers-sdk";
|
|
9
7
|
import React, { Component, useEffect, useState } from "react";
|
|
10
8
|
import { openCommandPalette } from "../command-palette/command-palette";
|
|
11
|
-
import { CommandPaletteOverlay } from "../command-palette/command-palette-ui";
|
|
12
9
|
import { GroupSwitcher } from "../components/group-switcher";
|
|
13
10
|
import { Router } from "../components/router";
|
|
14
|
-
import { isDesktop
|
|
15
|
-
import { useObservable
|
|
11
|
+
import { isDesktop } from "../globals";
|
|
12
|
+
import { useObservable } from "../hooks";
|
|
16
13
|
import { colorMode } from "../screens/settings/color-mode-dropdown";
|
|
17
|
-
import { SetupUser } from "../screens/setup-user";
|
|
18
|
-
import { WelcomeModal } from "../screens/welcome-modal";
|
|
19
14
|
import { systemPackage } from "../system-apps";
|
|
20
|
-
import { allPackages
|
|
15
|
+
import { allPackages } from "../ui-router/routes-loader";
|
|
21
16
|
import { UIRouter } from "../ui-router/ui-loader";
|
|
22
17
|
import {
|
|
23
18
|
activeTabId,
|
|
@@ -41,7 +36,12 @@ interface TabErrorBoundaryState {
|
|
|
41
36
|
error: Error | null;
|
|
42
37
|
}
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Wraps a single tab's content so a crash in one tab doesn't take down the whole app.
|
|
41
|
+
* Exported so other root layouts (e.g. the full-screen layout) can render a tab body with
|
|
42
|
+
* the same crash isolation. Reset it across screens by giving it a `key`.
|
|
43
|
+
*/
|
|
44
|
+
export class TabErrorBoundary extends Component<TabErrorBoundaryProps, TabErrorBoundaryState> {
|
|
45
45
|
constructor(props: TabErrorBoundaryProps) {
|
|
46
46
|
super(props);
|
|
47
47
|
this.state = { hasError: false, error: null };
|
|
@@ -88,69 +88,18 @@ class TabErrorBoundary extends Component<TabErrorBoundaryProps, TabErrorBoundary
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return <SetupUser />;
|
|
104
|
-
} else {
|
|
105
|
-
return <TabsLayout userId={userId} />;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
let userContextInitialized = false;
|
|
110
|
-
export function TabsLayout(props: { userId: string }) {
|
|
111
|
-
if (!userContextInitialized) {
|
|
112
|
-
setDefaultClientUserContext(props.userId);
|
|
113
|
-
userContextInitialized = true;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const loaded = usePromise(async () => {
|
|
117
|
-
await loadGlobals();
|
|
118
|
-
await loadAllRoutes();
|
|
119
|
-
await Promise.all([
|
|
120
|
-
activeTabs.loadingPromise,
|
|
121
|
-
activeTabId.loadingPromise,
|
|
122
|
-
recentlyUsedApps.loadingPromise,
|
|
123
|
-
hasShownWelcomeModal.loadingPromise,
|
|
124
|
-
]);
|
|
125
|
-
return true;
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const [showWelcomeModal, setShowWelcomeModal] = useState(false);
|
|
129
|
-
const [_colorMode] = useObservable(colorMode);
|
|
130
|
-
|
|
131
|
-
// Check if we should show the welcome modal after loading
|
|
132
|
-
useEffect(() => {
|
|
133
|
-
if (loaded && !hasShownWelcomeModal()) {
|
|
134
|
-
setShowWelcomeModal(true);
|
|
135
|
-
}
|
|
136
|
-
}, [loaded]);
|
|
137
|
-
|
|
138
|
-
if (!loaded) return false;
|
|
139
|
-
|
|
140
|
-
document.getElementById("appLoadingDiv")?.remove();
|
|
141
|
-
|
|
142
|
-
return (
|
|
143
|
-
<>
|
|
144
|
-
<TabsLayoutInternal />
|
|
145
|
-
<CommandPaletteOverlay />
|
|
146
|
-
{showWelcomeModal && (
|
|
147
|
-
<WelcomeModal colorMode={_colorMode} onClose={() => setShowWelcomeModal(false)} />
|
|
148
|
-
)}
|
|
149
|
-
</>
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function TabsLayoutInternal() {
|
|
91
|
+
/**
|
|
92
|
+
* The tab UI body: the tab strip plus the active tab's content. Rendered as the body of
|
|
93
|
+
* the default `tabs` root layout inside `RootLayoutHost` (which owns bootstrapping, the
|
|
94
|
+
* command palette, and the welcome modal). Branches on `isDesktop` for mobile vs. desktop
|
|
95
|
+
* chrome.
|
|
96
|
+
*
|
|
97
|
+
* @param fillContainer When `true`, the body fills its parent (`height: 100%`) instead of
|
|
98
|
+
* sizing itself to the viewport. Set this when embedding the tabs UI inside another
|
|
99
|
+
* layout that owns the vertical space (e.g. the `tabs-with-console` split layout);
|
|
100
|
+
* leave it `false`/unset for the standalone `tabs` layout, which sizes to the viewport.
|
|
101
|
+
*/
|
|
102
|
+
export function TabsLayoutInternal({ fillContainer = false }: { fillContainer?: boolean } = {}) {
|
|
154
103
|
const [_colorMode] = useObservable(colorMode);
|
|
155
104
|
const [tabs] = useObservable(activeTabs);
|
|
156
105
|
const [activeTab] = useObservable(activeTabId);
|
|
@@ -209,7 +158,7 @@ function TabsLayoutInternal() {
|
|
|
209
158
|
<div
|
|
210
159
|
key={currentlyActiveGroupId}
|
|
211
160
|
className="d-flex flex-column"
|
|
212
|
-
style={{ height: "calc(100vh - 25px)", overflow: "hidden" }}
|
|
161
|
+
style={{ height: fillContainer ? "100%" : "calc(100vh - 25px)", overflow: "hidden" }}
|
|
213
162
|
>
|
|
214
163
|
{switchingGroup && (
|
|
215
164
|
<div
|
|
@@ -561,7 +510,12 @@ interface TabContentProps {
|
|
|
561
510
|
isActive: boolean;
|
|
562
511
|
}
|
|
563
512
|
|
|
564
|
-
|
|
513
|
+
/**
|
|
514
|
+
* Renders a single tab's body, lazily initializing it on first activation and keeping it
|
|
515
|
+
* mounted thereafter (`initializedTabs`). Exported so other root layouts (e.g. full-screen)
|
|
516
|
+
* can render the active screen through the same routing/launcher path.
|
|
517
|
+
*/
|
|
518
|
+
export function TabContent({ tab, isMobile, isActive }: TabContentProps) {
|
|
565
519
|
// Only render content if this tab is active OR has been previously initialized
|
|
566
520
|
const shouldRender = isActive || initializedTabs.has(tab.tabId);
|
|
567
521
|
|
|
@@ -244,6 +244,23 @@ export const updateActiveTabTitle = (newTitle: string) => {
|
|
|
244
244
|
}, 100);
|
|
245
245
|
};
|
|
246
246
|
|
|
247
|
+
// Single-tab mode: when enabled, opening an app replaces the current screen instead of
|
|
248
|
+
// appending a tab. Used by the full-screen root layout so it shows one screen at a time.
|
|
249
|
+
let singleTabModeEnabled = false;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Enable or disable single-tab mode.
|
|
253
|
+
*
|
|
254
|
+
* When enabled, {@link openNewTab} replaces the active (non-launcher) screen in place
|
|
255
|
+
* rather than appending a new tab, so single-screen layouts (e.g. full-screen) never
|
|
256
|
+
* accumulate tabs. This is non-destructive: any pre-existing tabs are left untouched and
|
|
257
|
+
* reappear when a multi-tab layout becomes active again. Layouts should enable it on mount
|
|
258
|
+
* and disable it on unmount.
|
|
259
|
+
*/
|
|
260
|
+
export const setSingleTabMode = (enabled: boolean) => {
|
|
261
|
+
singleTabModeEnabled = enabled;
|
|
262
|
+
};
|
|
263
|
+
|
|
247
264
|
// Global function to open content in new tab
|
|
248
265
|
export const openNewTab = (tab: Omit<TabState, "tabId">, forceNew = false) => {
|
|
249
266
|
const newTab: TabState = {
|
|
@@ -259,6 +276,20 @@ export const openNewTab = (tab: Omit<TabState, "tabId">, forceNew = false) => {
|
|
|
259
276
|
if (existingTabIndex >= 0 && !forceNew) {
|
|
260
277
|
// Switch to existing tab
|
|
261
278
|
activeTabId(currentTabs[existingTabIndex].tabId);
|
|
279
|
+
} else if (singleTabModeEnabled) {
|
|
280
|
+
// Single-tab mode: replace the active non-launcher screen in place. From the launcher
|
|
281
|
+
// (home), append once so the launcher stays put and the new app becomes the single
|
|
282
|
+
// app slot.
|
|
283
|
+
const activeIndex = currentTabs.findIndex((t) => t.tabId === activeTabId());
|
|
284
|
+
const canReplace = activeIndex >= 0 && currentTabs[activeIndex].tabId !== "launcher";
|
|
285
|
+
if (canReplace) {
|
|
286
|
+
const newTabs = [...currentTabs];
|
|
287
|
+
newTabs[activeIndex] = newTab;
|
|
288
|
+
activeTabs(newTabs);
|
|
289
|
+
} else {
|
|
290
|
+
activeTabs([...currentTabs, newTab]);
|
|
291
|
+
}
|
|
292
|
+
activeTabId(newTab.tabId);
|
|
262
293
|
} else {
|
|
263
294
|
// Always add new tab (for app launcher or when forceNew is true)
|
|
264
295
|
activeTabs([...currentTabs, newTab]);
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chat Overlay Component
|
|
3
|
-
*
|
|
4
|
-
* Floating UI element combining voice input with chat functionality.
|
|
5
|
-
* Shows minimized voice button that expands to full chat overlay.
|
|
6
|
-
* Supports both voice and text input in the same thread.
|
|
7
|
-
*/
|
|
8
|
-
import type React from "react";
|
|
9
|
-
interface ChatOverlayProps {
|
|
10
|
-
/** Position of the overlay */
|
|
11
|
-
position?: "bottom-right" | "bottom-left";
|
|
12
|
-
}
|
|
13
|
-
export declare const ChatOverlay: React.FC<ChatOverlayProps>;
|
|
14
|
-
export default ChatOverlay;
|