Skip to content

Commit 3eceb1f

Browse files
authored
Revert "Keep app chrome visible in settings"
Reverts 5a876ec. Generated-By: PostHog Code Task-Id: 5579dbc2-d5dd-440f-8fb5-3cbd00ed0957
1 parent 5a876ec commit 3eceb1f

3 files changed

Lines changed: 147 additions & 94 deletions

File tree

packages/ui/src/features/settings/components/SettingsPanel.tsx

Lines changed: 79 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,28 @@ import {
1515
Palette,
1616
Plugs,
1717
Robot,
18+
SignOut,
1819
SlackLogo,
1920
Terminal,
2021
TrafficSignal,
2122
TreeStructure,
2223
Wrench,
2324
} from "@phosphor-icons/react";
2425
import { BILLING_FLAG } from "@posthog/shared";
26+
import { useOptionalAuthenticatedClient } from "@posthog/ui/features/auth/authClient";
27+
import { useAuthStateValue } from "@posthog/ui/features/auth/store";
28+
import { useLogoutMutation } from "@posthog/ui/features/auth/useAuthMutations";
29+
import { useCurrentUser } from "@posthog/ui/features/auth/useCurrentUser";
30+
import { getUserInitials } from "@posthog/ui/features/auth/userInitials";
2531
import { useFeatureFlag } from "@posthog/ui/features/feature-flags/useFeatureFlag";
2632
import { SettingsPageContent } from "@posthog/ui/features/settings/components/SettingsPageContent";
2733
import { closeSettings } from "@posthog/ui/features/settings/hooks/useOpenSettings";
2834
import { useSettingsPageStore } from "@posthog/ui/features/settings/stores/settingsPageStore";
2935
import type { SettingsCategory } from "@posthog/ui/features/settings/types";
30-
import { ProjectSwitcher } from "@posthog/ui/features/sidebar/components/ProjectSwitcher";
3136
import { useSpendAnalysisEnabled } from "@posthog/ui/features/usage/useSpendAnalysisEnabled";
3237
import * as nav from "@posthog/ui/router/navigationBridge";
3338
import { useHostCapabilities } from "@posthog/ui/shell/useHostCapabilities";
34-
import { Box, ScrollArea, Text } from "@radix-ui/themes";
39+
import { Avatar, Flex, ScrollArea, Text } from "@radix-ui/themes";
3540
import type { ReactNode } from "react";
3641
import { useHotkeys } from "react-hotkeys-hook";
3742

@@ -165,24 +170,27 @@ export interface SettingsPanelProps {
165170
onClose?: () => void;
166171
/** Override the category-change handler. Defaults to router navigation. */
167172
onCategoryChange?: (category: SettingsCategory) => void;
168-
/** Whether to show the settings navigation sidebar. */
169-
sidebarOpen?: boolean;
170173
}
171174

172175
export function SettingsPanel({
173176
activeCategory: activeCategoryProp,
174177
onClose,
175178
onCategoryChange,
176-
sidebarOpen = true,
177179
}: SettingsPanelProps = {}) {
178180
const formMode = useSettingsPageStore((s) => s.formMode);
179181
const activeCategory = activeCategoryProp ?? "general";
180182
const close = onClose ?? closeSettings;
181183
const setCategory =
182184
onCategoryChange ??
183185
((cat: SettingsCategory) => nav.navigateToSettings(cat, { replace: true }));
186+
const isAuthenticated = useAuthStateValue(
187+
(state) => state.status === "authenticated",
188+
);
189+
const client = useOptionalAuthenticatedClient();
190+
const { data: user } = useCurrentUser({ client });
184191
const billingEnabled = useFeatureFlag(BILLING_FLAG);
185192
const { localWorkspaces } = useHostCapabilities();
193+
const logoutMutation = useLogoutMutation();
186194

187195
const spendAnalysisEnabled = useSpendAnalysisEnabled();
188196
const hiddenCategories = getHiddenSettingsCategories({
@@ -218,52 +226,83 @@ export function SettingsPanel({
218226
(item) => item.id === activeSidebarCategory,
219227
)?.icon;
220228

229+
const initials = getUserInitials(user);
230+
221231
return (
222232
<div
223233
className="flex h-full w-full bg-(--color-background)"
224234
data-page="settings"
225235
>
226-
{sidebarOpen && (
227-
<div className="flex h-full w-[256px] shrink-0 flex-col border-gray-6 border-r">
236+
<div className="flex h-full w-[256px] shrink-0 flex-col border-gray-6 border-r">
237+
<div className="drag h-[36px] shrink-0 border-b border-b-(--gray-6)" />
238+
239+
{isAuthenticated && user && (
240+
<Flex
241+
align="center"
242+
gap="3"
243+
px="3"
244+
py="3"
245+
className="border-b border-b-(--gray-5)"
246+
>
247+
<Avatar size="2" fallback={initials} radius="full" color="amber" />
248+
<Flex direction="column" className="min-w-0">
249+
<Text truncate className="font-medium text-sm">
250+
{user.email}
251+
</Text>
252+
</Flex>
253+
</Flex>
254+
)}
255+
256+
<button
257+
type="button"
258+
className="mt-2 flex cursor-pointer items-center gap-2 border-0 bg-transparent px-3 py-2 text-left text-[13px] text-gray-11 transition-colors hover:bg-gray-3"
259+
onClick={close}
260+
>
261+
<ArrowLeft size={14} />
262+
<span>Back to app</span>
263+
</button>
264+
265+
<ScrollArea className="flex-1">
266+
<div className="flex flex-col gap-3 py-2">
267+
{sidebarGroups.map((group) => (
268+
<div key={group.label}>
269+
<Text className="px-3 pb-1 font-medium text-[10px] text-gray-9 uppercase tracking-wider">
270+
{group.label}
271+
</Text>
272+
{group.items.map((item) => {
273+
const isActive = activeSidebarCategory === item.id;
274+
return (
275+
<SidebarNavItem
276+
key={item.id}
277+
item={item}
278+
isActive={isActive}
279+
onClick={() => setCategory(item.id)}
280+
/>
281+
);
282+
})}
283+
</div>
284+
))}
285+
</div>
286+
</ScrollArea>
287+
288+
{isAuthenticated && (
228289
<button
229290
type="button"
230-
className="mt-2 flex cursor-pointer items-center gap-2 border-0 bg-transparent px-3 py-2 text-left text-[13px] text-gray-11 transition-colors hover:bg-gray-3"
231-
onClick={close}
291+
disabled={logoutMutation.isPending}
292+
className="flex cursor-pointer items-center gap-2 border-0 border-gray-5 border-t bg-transparent px-3 py-2.5 text-left font-mono text-[12px] text-gray-9 transition-colors hover:bg-gray-3 hover:text-gray-11 disabled:pointer-events-none disabled:opacity-50"
293+
onClick={() => {
294+
close();
295+
logoutMutation.mutate();
296+
}}
232297
>
233-
<ArrowLeft size={14} />
234-
<span>Back to app</span>
298+
<SignOut size={14} />
299+
<span>Sign out</span>
235300
</button>
236-
237-
<ScrollArea className="flex-1">
238-
<div className="flex flex-col gap-3 py-2">
239-
{sidebarGroups.map((group) => (
240-
<div key={group.label}>
241-
<Text className="px-3 pb-1 font-medium text-[10px] text-gray-9 uppercase tracking-wider">
242-
{group.label}
243-
</Text>
244-
{group.items.map((item) => {
245-
const isActive = activeSidebarCategory === item.id;
246-
return (
247-
<SidebarNavItem
248-
key={item.id}
249-
item={item}
250-
isActive={isActive}
251-
onClick={() => setCategory(item.id)}
252-
/>
253-
);
254-
})}
255-
</div>
256-
))}
257-
</div>
258-
</ScrollArea>
259-
260-
<Box className="shrink-0 px-2 pb-2">
261-
<ProjectSwitcher />
262-
</Box>
263-
</div>
264-
)}
301+
)}
302+
</div>
265303

266304
<div className="relative flex flex-1 flex-col overflow-hidden">
305+
<div className="drag h-[36px] shrink-0 border-b border-b-(--gray-6)" />
267306
<div className="relative flex flex-1 justify-center overflow-hidden">
268307
<svg
269308
aria-hidden="true"

packages/ui/src/router/routes/__root.tsx

Lines changed: 67 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ function RootLayout() {
275275
}
276276
}, [flagsLoaded, homeTabEnabled, view.type]);
277277

278+
// Settings is a full-page route — drop the app chrome (header/sidebar/
279+
// space-switcher) so the panel occupies the full window.
278280
const isSettingsRoute = useRouterState({
279281
select: (s) => s.matches.some((m) => m.routeId.startsWith("/settings")),
280282
});
@@ -309,6 +311,31 @@ function RootLayout() {
309311
const activeTabBlank = useActiveTabIsBlank();
310312
const showBlankTab = onChannelsIndex && activeTabBlank;
311313

314+
if (isSettingsRoute) {
315+
return (
316+
<Flex direction="column" height="100%">
317+
<ConnectivityBanner />
318+
<Outlet />
319+
<CommandMenu open={commandMenuOpen} onOpenChange={setCommandMenuOpen} />
320+
<GlobalFilePicker />
321+
<KeyboardShortcutsSheet
322+
open={shortcutsSheetOpen}
323+
onOpenChange={(open) => (open ? null : closeShortcutsSheet())}
324+
/>
325+
<GlobalEventHandlers
326+
onToggleCommandMenu={toggleCommandMenu}
327+
onToggleShortcutsSheet={toggleShortcutsSheet}
328+
/>
329+
{billingEnabled && <UsageLimitModal />}
330+
<UsageBillingAnnouncementModal />
331+
<UpdateAvailableModal />
332+
<WhatsNewModal />
333+
<RemoteBranchCheckoutDialog />
334+
<ExistingWorktreeDialog />
335+
</Flex>
336+
);
337+
}
338+
312339
return (
313340
// DnD scope for the tab strip's drag-to-reorder (pill sortables live in
314341
// the title bar; the provider must sit above them).
@@ -338,17 +365,12 @@ function RootLayout() {
338365
// over- or under-shoots; the env var fallback covers hosts
339366
// without Window Controls Overlay.
340367
paddingLeft: isMac ? "env(titlebar-area-x, 78px)" : "78px",
341-
width: sidebarOpen
342-
? isSettingsRoute
343-
? "256px"
344-
: channelsSidebarWidth
345-
: undefined,
368+
width: sidebarOpen ? channelsSidebarWidth : undefined,
346369
// Same curve/duration as ResizableSidebar's SLIDE_EASING so the
347370
// title bar tracks the sidebar edge.
348-
transition:
349-
isSettingsRoute || sidebarIsResizing
350-
? "none"
351-
: "width 0.2s cubic-bezier(0, 0, 0.2, 1)",
371+
transition: sidebarIsResizing
372+
? "none"
373+
: "width 0.2s cubic-bezier(0, 0, 0.2, 1)",
352374
}}
353375
>
354376
<Flex align="center" gap="2" className="no-drag">
@@ -361,7 +383,7 @@ function RootLayout() {
361383
aria-label="Toggle sidebar"
362384
onClick={handleToggleSidebar}
363385
onMouseEnter={() => {
364-
if (!isSettingsRoute && !sidebarOpen) beginSidebarPeek();
386+
if (!sidebarOpen) beginSidebarPeek();
365387
}}
366388
>
367389
{sidebarOpen ? (
@@ -422,48 +444,42 @@ function RootLayout() {
422444
)}
423445
</Flex>
424446
<ConnectivityBanner />
425-
{isSettingsRoute ? (
426-
<Box flexGrow="1" className="overflow-hidden bg-background">
427-
<Outlet />
428-
</Box>
429-
) : (
430-
<Flex flexGrow="1" overflow="hidden" className="relative">
431-
{/* Scrim under the peeked nav: dims the content while the overlay is
432-
out. Purely visual (pointer-transparent) and paired with the
433-
panel's slide — same 200ms ease-out — so they read as one unit. */}
434-
{!sidebarOpen && (
435-
<Box
436-
aria-hidden
437-
// The radix preset replaces Tailwind's palette, so plain
438-
// `bg-black/*` doesn't exist — use the radix black-alpha scale
439-
// (--black-a2 = 10%, --black-a5 = 30%).
440-
className={`pointer-events-none absolute inset-0 z-40 bg-blackA-2 transition-opacity duration-200 ease-out motion-reduce:transition-none dark:bg-blackA-5 ${
441-
sidebarPeek ? "opacity-100" : "opacity-0"
442-
}`}
443-
/>
444-
)}
445-
<ChannelsSidebar />
446-
{/* Content sits in a bordered, rounded card inset from the window
447-
edges — the framed pane from the design. */}
448-
<Box flexGrow="1" className="overflow-hidden">
449-
<Box
450-
className={`h-full overflow-hidden border-border border-t border-l bg-background ${
451-
sidebarOpen ? "rounded-tl-sm" : ""
452-
}`}
453-
>
454-
<Flex direction="column" height="100%">
455-
{/* The /website space renders its own header (WebsiteLayout);
456-
everywhere else the shared header carries the view title
457-
and, on a task, its action row. */}
458-
{!onWebsitePath && <ContentHeader />}
459-
<Box flexGrow="1" overflow="hidden">
460-
{showBlankTab ? <BlankTabView /> : <Outlet />}
461-
</Box>
462-
</Flex>
463-
</Box>
447+
<Flex flexGrow="1" overflow="hidden" className="relative">
448+
{/* Scrim under the peeked nav: dims the content while the overlay is
449+
out. Purely visual (pointer-transparent) and paired with the
450+
panel's slide — same 200ms ease-out — so they read as one unit. */}
451+
{!sidebarOpen && (
452+
<Box
453+
aria-hidden
454+
// The radix preset replaces Tailwind's palette, so plain
455+
// `bg-black/*` doesn't exist — use the radix black-alpha scale
456+
// (--black-a2 = 10%, --black-a5 = 30%).
457+
className={`pointer-events-none absolute inset-0 z-40 bg-blackA-2 transition-opacity duration-200 ease-out motion-reduce:transition-none dark:bg-blackA-5 ${
458+
sidebarPeek ? "opacity-100" : "opacity-0"
459+
}`}
460+
/>
461+
)}
462+
<ChannelsSidebar />
463+
{/* Content sits in a bordered, rounded card inset from the window
464+
edges — the framed pane from the design. */}
465+
<Box flexGrow="1" className="overflow-hidden">
466+
<Box
467+
className={`h-full overflow-hidden border-border border-t border-l bg-background ${
468+
sidebarOpen ? "rounded-tl-sm" : ""
469+
}`}
470+
>
471+
<Flex direction="column" height="100%">
472+
{/* The /website space renders its own header (WebsiteLayout);
473+
everywhere else the shared header carries the view title
474+
and, on a task, its action row. */}
475+
{!onWebsitePath && <ContentHeader />}
476+
<Box flexGrow="1" overflow="hidden">
477+
{showBlankTab ? <BlankTabView /> : <Outlet />}
478+
</Box>
479+
</Flex>
464480
</Box>
465-
</Flex>
466-
)}
481+
</Box>
482+
</Flex>
467483
<CommandMenu open={commandMenuOpen} onOpenChange={setCommandMenuOpen} />
468484
<GlobalFilePicker />
469485
<KeyboardShortcutsSheet

packages/ui/src/router/routes/settings/$category.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { SettingsPanel } from "@posthog/ui/features/settings/components/SettingsPanel";
22
import { useSettingsPageStore } from "@posthog/ui/features/settings/stores/settingsPageStore";
33
import { isSettingsCategory } from "@posthog/ui/features/settings/types";
4-
import { useSidebarStore } from "@posthog/ui/features/sidebar/sidebarStore";
54
import { createFileRoute } from "@tanstack/react-router";
65
import { useEffect } from "react";
76

@@ -12,7 +11,6 @@ export const Route = createFileRoute("/settings/$category")({
1211
function SettingsRoute() {
1312
const { category } = Route.useParams();
1413
const cat = isSettingsCategory(category) ? category : "general";
15-
const sidebarOpen = useSidebarStore((state) => state.open);
1614

1715
// Reset transient state when leaving the route entirely. Switching between
1816
// categories (e.g. general → environments) does not unmount this component,
@@ -21,5 +19,5 @@ function SettingsRoute() {
2119
return () => useSettingsPageStore.getState().reset();
2220
}, []);
2321

24-
return <SettingsPanel activeCategory={cat} sidebarOpen={sidebarOpen} />;
22+
return <SettingsPanel activeCategory={cat} />;
2523
}

0 commit comments

Comments
 (0)