Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions apps/web/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Button, EmptyState } from "@corbits/react-ui";
import { WorkbenchLoadingState } from "@/chat";
import { QueryClientProvider } from "@tanstack/react-query";
import { BoldIconProvider, WarningCircle } from "@/lib/icons";
import { useMemo } from "react";
import { useMemo, useState } from "react";

import { AuthScreen } from "./auth-screen";
import { BenchProvider } from "./bench-context";
Expand All @@ -18,7 +18,8 @@ import { OnboardingPage } from "./pages/onboarding-page";
import { ProvisioningErrorPage } from "./pages/provisioning-error-page";
import { createAppQueryClient } from "./query-client";
import { Redirect } from "./redirect";
import { APP_ROUTES, LOGIN_PATH, matchesRoute, ONBOARDING_PATH } from "./routes";
import { SettingsDialog } from "./pages/settings-dialog";
import { APP_ROUTES, LOGIN_PATH, matchesRoute, ONBOARDING_PATH, SETTINGS_PATH } from "./routes";
import type { SessionState, SessionUser } from "./session";
import { AppShell } from "./shell/app-shell";
import { ComposerInsertionProvider } from "./shell/composer-insertion";
Expand Down Expand Up @@ -62,17 +63,30 @@ function Shell({
// cache; wired to `onSignOut` so a session going invalid anywhere routes
// the whole shell back to login, not just one stuck panel.
const queryClient = useMemo(() => createAppQueryClient(onSignOut), [onSignOut]);
const route = APP_ROUTES.find((candidate) => matchesRoute(candidate.path, path));
// Settings is a dialog over the last page, so that page stays mounted
// behind it; a cold load of /settings falls back to /new.
const settingsOpen = matchesRoute(SETTINGS_PATH, path);
const [backdropPath, setBackdropPath] = useState(settingsOpen ? "/new" : path);
if (!settingsOpen && backdropPath !== path) setBackdropPath(path);
const pagePath = settingsOpen ? backdropPath : path;
const route = APP_ROUTES.find((candidate) => matchesRoute(candidate.path, pagePath));
return (
<QueryClientProvider client={queryClient}>
<NavigationProvider navigate={navigate} onSignOut={onSignOut} user={user}>
<BenchProvider>
<ComposerInsertionProvider>
<ShellChromeProvider path={path} navigate={navigate}>
<CommandPaletteProvider path={path} navigate={navigate}>
<AppShell path={path} user={user} onSignOut={onSignOut}>
{route === undefined ? <NotFoundPage /> : route.render(path, navigate)}
<AppShell path={pagePath} user={user} onSignOut={onSignOut}>
{route === undefined ? <NotFoundPage /> : route.render(pagePath, navigate)}
</AppShell>
{settingsOpen ? (
<SettingsDialog
path={path}
navigate={navigate}
onClose={() => navigate(backdropPath)}
/>
) : null}
</CommandPaletteProvider>
</ShellChromeProvider>
</ComposerInsertionProvider>
Expand Down
80 changes: 80 additions & 0 deletions apps/web/src/pages/settings-dialog.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/* Settings as a dialog: raised card, left section nav + one section body. */
[data-slot="dialog-content"].settings-dialog {
display: flex;
flex-direction: column;
gap: 0;
width: min(calc(100vw - 2rem), 960px);
max-width: none;
height: 80vh;
max-height: none;
padding: 0;
border: 0;
border-radius: 12px;
background: var(--card, var(--popover));
box-shadow: var(--raised);
}

.settings-dialog-head {
padding: 14px 56px 12px 20px;
border-bottom: 1px solid var(--border);
}

.settings-dialog-title {
font-size: 16px;
font-weight: 800;
letter-spacing: -0.01em;
}

.settings-dialog-layout {
flex: 1;
min-height: 0;
}

.settings-dialog-body {
flex: 1;
min-width: 0;
padding: 20px;
}

@media (max-width: 640px) {
[data-slot="dialog-content"].settings-dialog {
width: 100vw;
height: 100dvh;
border-radius: 0;
top: 0;
left: 0;
translate: none;
max-width: none;
}

.settings-dialog-layout {
flex-direction: column;
}

.settings-dialog-layout .settings-nav {
width: 100%;
flex-direction: row;
flex-shrink: 0;
gap: 0.5rem;
padding: 0.5rem;
border-right: 0;
border-bottom: 1px solid var(--border);
overflow: auto hidden;
}

.settings-dialog-layout .settings-nav-group {
flex-direction: row;
flex-shrink: 0;
gap: 0.25rem;
}

.settings-dialog-layout .settings-nav [data-slot="sidebar-item-row"] {
flex-shrink: 0;
white-space: nowrap;
}

.settings-dialog-layout .settings-nav-heading,
.settings-dialog-layout .settings-nav-advanced {
display: none;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
// Thin mount: this file only adapts the app's bench-selection state and
// the URL into the shape `@/settings`'s shell expects.
// Thin mount: adapts the bench-selection state and the URL into the shape
// `@/settings`'s shell expects, and presents it over whatever page is behind.

import { flattenSettingsSections, resolveActiveSection, SettingsShell } from "@/settings";
import { PageShell } from "@corbits/react-ui";
import {
Dialog,
DialogBody,
DialogContent,
DialogHeader,
DialogTitle,
} from "@corbits/react-ui/ui/dialog";

import { useBench } from "../bench-context";
import { useSignOut } from "../navigation";
Expand All @@ -14,15 +20,17 @@ import {
} from "../path-ids";
import { resolveAppSettingsSectionGroups } from "../settings-groups";
import { SettingsNav } from "./settings-nav";
import { StageTopBar } from "../shell/stage-top-bar";
import "./settings-dialog.css";
import { useSettingsAccess } from "../settings-access";

export function SettingsRoute({
export function SettingsDialog({
path,
navigate,
onClose,
}: {
readonly path: string;
readonly navigate: (to: string) => void;
readonly onClose: () => void;
}) {
const { selectedTenantId, selectedPrincipalId } = useBench();
const onSignOut = useSignOut();
Expand Down Expand Up @@ -58,16 +66,19 @@ export function SettingsRoute({
}

return (
<div className="flex h-full min-h-0 flex-col">
<StageTopBar crumbs={[{ label: "Settings" }]} />
<div className="settings-page-head">
<h1>Settings</h1>
<p>Personal and shared, side by side.</p>
</div>
<div className="settings-layout min-h-0 flex-1">
<SettingsNav path={path} onNavigate={navigate} />
<div className="min-h-0 flex-1 overflow-y-auto">
<PageShell width="full" className="page-fill">
<Dialog
open
onOpenChange={(next) => {
if (!next) onClose();
}}
>
<DialogContent className="settings-dialog" aria-describedby={undefined}>
<DialogHeader className="settings-dialog-head">
<DialogTitle className="settings-dialog-title">Settings</DialogTitle>
</DialogHeader>
<div className="settings-layout settings-dialog-layout">
<SettingsNav path={path} onNavigate={navigate} />
<DialogBody className="settings-dialog-body">
<SettingsShell
sections={sections}
activeId={activeSection?.id ?? null}
Expand All @@ -79,9 +90,9 @@ export function SettingsRoute({
...(onSignOut !== undefined ? { onSignOut } : {}),
}}
/>
</PageShell>
</DialogBody>
</div>
</div>
</div>
</DialogContent>
</Dialog>
);
}
9 changes: 3 additions & 6 deletions apps/web/src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ const ToolsRoute = lazy(async () => ({
const InsightsRoute = lazy(async () => ({
default: (await import("./pages/insights-page")).InsightsRoute,
}));
const SettingsRoute = lazy(async () => ({
default: (await import("./pages/settings-page")).SettingsRoute,
}));
const SkillDetailRoute = lazy(async () => ({
default: (await import("./pages/skill-detail-page")).SkillDetailRoute,
}));
Expand Down Expand Up @@ -259,12 +256,12 @@ export const APP_ROUTES: readonly AppRoute[] = [
render: (path: string) => <InsightsRoute path={path} />,
},
{
// Presented as a dialog over the page behind it by `Shell` (app.tsx); the
// route exists so the palette and path matching still know Settings.
path: SETTINGS_PATH,
label: "Settings",
icon: <SlidersHorizontal />,
render: (path: string, navigate: (to: string) => void) => (
<SettingsRoute path={path} navigate={navigate} />
),
render: () => <></>,
},
];

Expand Down
19 changes: 0 additions & 19 deletions apps/web/src/settings/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -748,28 +748,9 @@
color: var(--ink-2);
}

.settings-page-head {
flex-shrink: 0;
padding: 24px 28px 16px;
}

/* react-ui's SettingsPanel card: ring-as-border like the mockup's raised cards. */
.settings-stage-body > section.border {
border-color: transparent;
border-radius: 12px;
box-shadow: var(--raised);
}

.settings-page-head h1 {
margin: 0;
font-size: 26px;
font-weight: 800;
letter-spacing: -0.02em;
line-height: 1.2;
}

.settings-page-head p {
margin: 6px 0 0;
color: var(--ink-2);
font-size: 15px;
}
Loading