feat: add URL-driven workspace state and streamed Codex research
This commit is contained in:
@@ -1,15 +1,7 @@
|
||||
import { Link, useLocation, useRouteContext } from '@tanstack/react-router'
|
||||
import {
|
||||
Activity,
|
||||
House,
|
||||
Inbox,
|
||||
Layers3,
|
||||
MessagesSquare,
|
||||
NotebookPen,
|
||||
Search,
|
||||
} from 'lucide-react'
|
||||
import { type ReactNode, useState } from 'react'
|
||||
import { Avatar, AvatarFallback } from '#/components/ui/avatar'
|
||||
import { Link, useLocation, useRouteContext } from "@tanstack/react-router";
|
||||
import { Activity, House, Inbox, Layers3, MessagesSquare, NotebookPen, Search } from "lucide-react";
|
||||
import type { ReactNode } from "react";
|
||||
import { Avatar, AvatarFallback } from "#/components/ui/avatar";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
@@ -21,62 +13,62 @@ import {
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarSeparator,
|
||||
} from '#/components/ui/sidebar'
|
||||
import { ConnectionManagerDialog } from '#/features/connections/connection-manager-dialog'
|
||||
} from "#/components/ui/sidebar";
|
||||
import { ConnectionManagerDialog } from "#/features/connections/connection-manager-dialog";
|
||||
import { useUrlState } from "#/features/navigation/use-url-state";
|
||||
|
||||
type WorkspaceNavigationProps = {
|
||||
children?: ReactNode
|
||||
footer?: ReactNode
|
||||
hasTemporaryDecks?: boolean
|
||||
}
|
||||
children?: ReactNode;
|
||||
footer?: ReactNode;
|
||||
hasTemporaryDecks?: boolean;
|
||||
};
|
||||
|
||||
export function WorkspaceNavigation({
|
||||
children,
|
||||
footer,
|
||||
hasTemporaryDecks,
|
||||
}: WorkspaceNavigationProps) {
|
||||
const { auth } = useRouteContext({ from: '__root__' })
|
||||
const [managingAccounts, setManagingAccounts] = useState(false)
|
||||
const pathname = useLocation({ select: (location) => location.pathname })
|
||||
const { auth } = useRouteContext({ from: "__root__" });
|
||||
const [search, updateSearch] = useUrlState();
|
||||
const managingAccounts = search.accounts;
|
||||
const setManagingAccounts = (open: boolean) => updateSearch({ accounts: open || undefined });
|
||||
const pathname = useLocation({ select: (location) => location.pathname });
|
||||
const navigation = [
|
||||
{ title: 'Home', to: '/', icon: House, active: pathname === '/' },
|
||||
{ title: "Home", to: "/", icon: House, active: pathname === "/" },
|
||||
{
|
||||
title: 'Vitals',
|
||||
to: '/vitals',
|
||||
title: "Vitals",
|
||||
to: "/vitals",
|
||||
icon: Activity,
|
||||
active: pathname === '/vitals',
|
||||
active: pathname === "/vitals",
|
||||
},
|
||||
{
|
||||
title: 'Messages',
|
||||
to: '/support',
|
||||
title: "Messages",
|
||||
to: "/support",
|
||||
icon: MessagesSquare,
|
||||
active: pathname === '/support',
|
||||
active: pathname === "/support",
|
||||
},
|
||||
{
|
||||
title: 'Journal',
|
||||
to: '/journal',
|
||||
title: "Journal",
|
||||
to: "/journal",
|
||||
icon: NotebookPen,
|
||||
active: pathname === '/journal',
|
||||
active: pathname === "/journal",
|
||||
},
|
||||
{
|
||||
title: 'Reader',
|
||||
to: '/inbox',
|
||||
title: "Reader",
|
||||
to: "/inbox",
|
||||
icon: Inbox,
|
||||
active: pathname === '/inbox',
|
||||
active: pathname === "/inbox",
|
||||
},
|
||||
{
|
||||
title: 'Research',
|
||||
to: '/deck',
|
||||
title: "Research",
|
||||
to: "/deck",
|
||||
icon: Search,
|
||||
active: pathname === '/deck',
|
||||
active: pathname === "/deck",
|
||||
},
|
||||
] as const
|
||||
] as const;
|
||||
|
||||
return (
|
||||
<Sidebar
|
||||
collapsible="none"
|
||||
className="workspace-navigation w-16! shrink-0 border-r"
|
||||
>
|
||||
<Sidebar collapsible="none" className="w-16! shrink-0 border-r">
|
||||
<SidebarHeader className="items-center py-4">
|
||||
<div
|
||||
className="flex size-9 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"
|
||||
@@ -94,7 +86,7 @@ export function WorkspaceNavigation({
|
||||
<SidebarMenuItem key={item.to}>
|
||||
<SidebarMenuButton
|
||||
aria-label={item.title}
|
||||
aria-current={item.active ? 'page' : undefined}
|
||||
aria-current={item.active ? "page" : undefined}
|
||||
tooltip={{ children: item.title, hidden: false }}
|
||||
isActive={item.active}
|
||||
render={<Link to={item.to} />}
|
||||
@@ -125,14 +117,12 @@ export function WorkspaceNavigation({
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton
|
||||
aria-label="Manage connected accounts"
|
||||
tooltip={{ children: 'Manage connected accounts', hidden: false }}
|
||||
tooltip={{ children: "Manage connected accounts", hidden: false }}
|
||||
className="size-10 justify-center p-0"
|
||||
onClick={() => setManagingAccounts(true)}
|
||||
>
|
||||
<Avatar className="size-8">
|
||||
<AvatarFallback>
|
||||
{auth.owner?.name.slice(0, 1).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
<AvatarFallback>{auth.owner?.name.slice(0, 1).toUpperCase()}</AvatarFallback>
|
||||
</Avatar>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
@@ -145,5 +135,5 @@ export function WorkspaceNavigation({
|
||||
/>
|
||||
)}
|
||||
</Sidebar>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user