Skip to content

Commit 4b2dcf9

Browse files
authored
Open Settings in a dialog on the web build (#581)
1 parent 569f552 commit 4b2dcf9

3 files changed

Lines changed: 32 additions & 27 deletions

File tree

apps/yaak-client/commands/openSettings.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,42 @@
11
import { platform } from "@yaakapp-internal/platform";
2-
import type { SettingsTab } from "../components/Settings/Settings";
2+
import type { SettingsTab, SettingsTabWithSubtab } from "../components/Settings/Settings";
33
import { activeWorkspaceIdAtom } from "../hooks/useActiveWorkspace";
44
import { createFastMutation } from "../hooks/useFastMutation";
5+
import { showDialog } from "../lib/dialog";
56
import { jotaiStore } from "../lib/jotai";
67
import { router } from "../lib/router";
78
import { rpc } from "../lib/rpc";
89

9-
// Allow tab with optional subtab (e.g., "plugins:installed")
10-
type SettingsTabWithSubtab = SettingsTab | `${SettingsTab}:${string}` | null;
11-
12-
export const openSettings = createFastMutation<void, string, SettingsTabWithSubtab>({
10+
export const openSettings = createFastMutation<void, string, SettingsTabWithSubtab | null>({
1311
mutationKey: ["open_settings"],
1412
mutationFn: async (tab) => {
1513
const workspaceId = jotaiStore.get(activeWorkspaceIdAtom);
1614
if (workspaceId == null) return;
1715

18-
const to = "/workspaces/$workspaceId/settings" as const;
19-
const params = { workspaceId };
20-
const search = { tab: (tab ?? undefined) as SettingsTab | undefined };
21-
2216
// Settings is its own window where the host has windows to give. Where it
23-
// doesn't — a browser tab — the same route opens in place, which is the
24-
// whole difference: it is already a route, not a separate app.
17+
// doesn't — a browser tab — it's a dialog like any other, so opening it
18+
// doesn't take you away from the request you were working on.
2519
if (!platform.capabilities.multiWindow) {
26-
await router.navigate({ to, params, search });
20+
// Imported here so Settings stays out of the startup bundle, the way the
21+
// route that renders it on desktop already keeps it
22+
const { default: Settings } = await import("../components/Settings/Settings");
23+
showDialog({
24+
id: "settings",
25+
size: "md",
26+
className: "h-[calc(100vh-5rem)] max-h-150! overflow-hidden",
27+
noPadding: true,
28+
noScroll: true,
29+
// Keyed so opening a specific tab while the dialog is already up moves to it
30+
render: ({ hide }) => <Settings key={tab ?? "general"} tab={tab} hide={hide} />,
31+
});
2732
return;
2833
}
2934

30-
const location = router.buildLocation({ to, params, search });
35+
const location = router.buildLocation({
36+
to: "/workspaces/$workspaceId/settings",
37+
params: { workspaceId },
38+
search: { tab: (tab ?? undefined) as SettingsTab | undefined },
39+
});
3140

3241
await rpc("cmd_new_child_window", {
3342
url: location.href,

apps/yaak-client/components/Settings/Settings.tsx

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { useSearch } from "@tanstack/react-router";
21
import { platform } from "@yaakapp-internal/platform";
32
import { useLicense } from "@yaakapp-internal/license";
43
import { pluginsAtom, settingsAtom } from "@yaakapp-internal/models";
@@ -20,6 +19,8 @@ import { SettingsProxy } from "./SettingsProxy";
2019
import { SettingsTheme } from "./SettingsTheme";
2120

2221
interface Props {
22+
tab?: SettingsTabWithSubtab | null;
23+
/** Set when Settings is in a dialog rather than owning a window. */
2324
hide?: () => void;
2425
}
2526

@@ -42,25 +43,19 @@ const tabs = [
4243
TAB_LICENSE,
4344
] as const;
4445
export type SettingsTab = (typeof tabs)[number];
46+
export type SettingsTabWithSubtab = SettingsTab | `${SettingsTab}:${string}`;
4547

46-
export default function Settings({ hide }: Props) {
47-
const { tab: tabFromQuery } = useSearch({ from: "/workspaces/$workspaceId/settings" });
48+
export default function Settings({ tab, hide }: Props) {
4849
// Parse tab and subtab (e.g., "plugins:installed")
49-
const [mainTab, subtab] = tabFromQuery?.split(":") ?? [];
50+
const [mainTab, subtab] = tab?.split(":") ?? [];
5051
const settings = useAtomValue(settingsAtom);
5152
const plugins = useAtomValue(pluginsAtom);
5253
const licenseCheck = useLicense();
5354

54-
// Close settings window on escape
55+
// Close settings window on escape. In a dialog, the dialog handles Escape itself.
5556
// TODO: Could this be put in a better place? Eg. in Rust key listener when creating the window
5657
useKeyPressEvent("Escape", async () => {
57-
if (hide != null) {
58-
// It's being shown in a dialog, so close the dialog
59-
hide();
60-
} else {
61-
// It's being shown in a window, so close the window
62-
await platform.window.close();
63-
}
58+
if (hide == null) await platform.window.close();
6459
});
6560

6661
return (
@@ -90,7 +85,7 @@ export default function Settings({ hide }: Props) {
9085
)}
9186
<Tabs
9287
layout="horizontal"
93-
defaultValue={mainTab || tabFromQuery}
88+
defaultValue={mainTab}
9489
addBorders
9590
tabListClassName="min-w-40 bg-surface x-theme-sidebar border-r border-border pl-3"
9691
label="Settings"

apps/yaak-client/routes/workspaces/$workspaceId/settings.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ export const Route = createFileRoute("/workspaces/$workspaceId/settings")({
1414
});
1515

1616
function RouteComponent() {
17-
return <Settings />;
17+
const { tab } = Route.useSearch();
18+
return <Settings tab={tab} />;
1819
}

0 commit comments

Comments
 (0)