Fix sidebar session list responsiveness
This commit is contained in:
@@ -14,7 +14,11 @@ import {
|
|||||||
} from "@/components/assistant-ui/activity-panel";
|
} from "@/components/assistant-ui/activity-panel";
|
||||||
import { Thread } from "@/components/assistant-ui/thread";
|
import { Thread } from "@/components/assistant-ui/thread";
|
||||||
import { ThreadListSidebar } from "@/components/assistant-ui/threadlist-sidebar";
|
import { ThreadListSidebar } from "@/components/assistant-ui/threadlist-sidebar";
|
||||||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
|
import {
|
||||||
|
SidebarInset,
|
||||||
|
SidebarProvider,
|
||||||
|
SidebarTrigger,
|
||||||
|
} from "@/components/ui/sidebar";
|
||||||
import { ClawSessionReplayProvider } from "@/lib/claw-session-replay";
|
import { ClawSessionReplayProvider } from "@/lib/claw-session-replay";
|
||||||
import { ClawAccountGate, useClawAccount } from "./claw-account-gate";
|
import { ClawAccountGate, useClawAccount } from "./claw-account-gate";
|
||||||
|
|
||||||
@@ -85,6 +89,7 @@ export const Assistant = () => {
|
|||||||
<ActivityProvider>
|
<ActivityProvider>
|
||||||
<SidebarProvider>
|
<SidebarProvider>
|
||||||
<div className="flex h-dvh w-full">
|
<div className="flex h-dvh w-full">
|
||||||
|
<SidebarTrigger className="fixed top-3 left-3 z-40 size-9 rounded-lg bg-background/90 shadow-sm ring-1 ring-border backdrop-blur sm:hidden" />
|
||||||
<ThreadListSidebar
|
<ThreadListSidebar
|
||||||
account={account}
|
account={account}
|
||||||
onLogout={() => setAccount(null)}
|
onLogout={() => setAccount(null)}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ type ClawStoredToolCall = {
|
|||||||
|
|
||||||
export const ThreadList: FC = () => {
|
export const ThreadList: FC = () => {
|
||||||
return (
|
return (
|
||||||
<ThreadListPrimitive.Root className="aui-root aui-thread-list-root flex flex-col gap-1">
|
<ThreadListPrimitive.Root className="aui-root aui-thread-list-root flex min-h-0 flex-1 flex-col gap-1">
|
||||||
<ThreadListNew />
|
<ThreadListNew />
|
||||||
<ClawSessionList />
|
<ClawSessionList />
|
||||||
</ThreadListPrimitive.Root>
|
</ThreadListPrimitive.Root>
|
||||||
@@ -146,8 +146,7 @@ const ClawSessionList: FC = () => {
|
|||||||
fetch("/api/claw/sessions")
|
fetch("/api/claw/sessions")
|
||||||
.then((res) => (res.ok ? res.json() : []))
|
.then((res) => (res.ok ? res.json() : []))
|
||||||
.then((payload) => {
|
.then((payload) => {
|
||||||
if (Array.isArray(payload))
|
if (Array.isArray(payload)) setSessions(dedupeSessions(payload));
|
||||||
setSessions(dedupeSessions(payload).slice(0, 8));
|
|
||||||
})
|
})
|
||||||
.catch(() => setSessions([]));
|
.catch(() => setSessions([]));
|
||||||
};
|
};
|
||||||
@@ -204,6 +203,7 @@ const ClawSessionList: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className="min-h-0 flex-1 overflow-y-auto pr-1">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
{sessions.map((session) => {
|
{sessions.map((session) => {
|
||||||
const active = activeSessionId === session.session_id;
|
const active = activeSessionId === session.session_id;
|
||||||
@@ -333,7 +333,9 @@ const ClawSessionList: FC = () => {
|
|||||||
);
|
);
|
||||||
setOpenMenuSessionId(null);
|
setOpenMenuSessionId(null);
|
||||||
if (activeSessionId === session.session_id) {
|
if (activeSessionId === session.session_id) {
|
||||||
window.localStorage.removeItem("claw.activeSessionId");
|
window.localStorage.removeItem(
|
||||||
|
"claw.activeSessionId",
|
||||||
|
);
|
||||||
setActiveSessionId(null);
|
setActiveSessionId(null);
|
||||||
window.dispatchEvent(
|
window.dispatchEvent(
|
||||||
new Event("claw-active-session-cleared"),
|
new Event("claw-active-session-cleared"),
|
||||||
@@ -353,6 +355,7 @@ const ClawSessionList: FC = () => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export function ThreadListSidebar({
|
|||||||
<SidebarTrigger className="size-8 shrink-0" />
|
<SidebarTrigger className="size-8 shrink-0" />
|
||||||
</div>
|
</div>
|
||||||
</SidebarHeader>
|
</SidebarHeader>
|
||||||
<SidebarContent className="aui-sidebar-content px-2">
|
<SidebarContent className="aui-sidebar-content overflow-hidden px-2">
|
||||||
<ThreadList />
|
<ThreadList />
|
||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
<SidebarRail />
|
<SidebarRail />
|
||||||
@@ -341,7 +341,7 @@ function useSidebarSessions(open: boolean) {
|
|||||||
.then((res) => (res.ok ? res.json() : []))
|
.then((res) => (res.ok ? res.json() : []))
|
||||||
.then((payload) => {
|
.then((payload) => {
|
||||||
if (cancelled || !Array.isArray(payload)) return;
|
if (cancelled || !Array.isArray(payload)) return;
|
||||||
setSessions(dedupeSidebarSessions(payload).slice(0, 12));
|
setSessions(dedupeSidebarSessions(payload));
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
if (!cancelled) setSessions([]);
|
if (!cancelled) setSessions([]);
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ function Sidebar({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="group peer hidden text-sidebar-foreground md:block"
|
className="group peer hidden text-sidebar-foreground sm:block"
|
||||||
data-state={state}
|
data-state={state}
|
||||||
data-collapsible={state === "collapsed" ? collapsible : ""}
|
data-collapsible={state === "collapsed" ? collapsible : ""}
|
||||||
data-variant={variant}
|
data-variant={variant}
|
||||||
@@ -227,7 +227,7 @@ function Sidebar({
|
|||||||
<div
|
<div
|
||||||
data-slot="sidebar-container"
|
data-slot="sidebar-container"
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
|
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear sm:flex",
|
||||||
side === "left"
|
side === "left"
|
||||||
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
|
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
|
||||||
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
||||||
@@ -308,7 +308,7 @@ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
|
|||||||
data-slot="sidebar-inset"
|
data-slot="sidebar-inset"
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex w-full flex-1 flex-col bg-background",
|
"relative flex w-full flex-1 flex-col bg-background",
|
||||||
"md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2 md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm",
|
"sm:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2 sm:peer-data-[variant=inset]:m-2 sm:peer-data-[variant=inset]:ml-0 sm:peer-data-[variant=inset]:rounded-xl sm:peer-data-[variant=inset]:shadow-sm",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -426,7 +426,7 @@ function SidebarGroupAction({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-hidden ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
"absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-hidden ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||||
// Increases the hit area of the button on mobile.
|
// Increases the hit area of the button on mobile.
|
||||||
"after:absolute after:-inset-2 md:after:hidden",
|
"after:absolute after:-inset-2 sm:after:hidden",
|
||||||
"group-data-[collapsible=icon]:hidden",
|
"group-data-[collapsible=icon]:hidden",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
@@ -561,13 +561,13 @@ function SidebarMenuAction({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-hidden ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0",
|
"absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-hidden ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0",
|
||||||
// Increases the hit area of the button on mobile.
|
// Increases the hit area of the button on mobile.
|
||||||
"after:absolute after:-inset-2 md:after:hidden",
|
"after:absolute after:-inset-2 sm:after:hidden",
|
||||||
"peer-data-[size=sm]/menu-button:top-1",
|
"peer-data-[size=sm]/menu-button:top-1",
|
||||||
"peer-data-[size=default]/menu-button:top-1.5",
|
"peer-data-[size=default]/menu-button:top-1.5",
|
||||||
"peer-data-[size=lg]/menu-button:top-2.5",
|
"peer-data-[size=lg]/menu-button:top-2.5",
|
||||||
"group-data-[collapsible=icon]:hidden",
|
"group-data-[collapsible=icon]:hidden",
|
||||||
showOnHover &&
|
showOnHover &&
|
||||||
"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0",
|
"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground sm:opacity-0",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
const MOBILE_BREAKPOINT = 768;
|
const MOBILE_BREAKPOINT = 640;
|
||||||
|
|
||||||
export function useIsMobile() {
|
export function useIsMobile() {
|
||||||
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
|
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
|
||||||
|
|||||||
Reference in New Issue
Block a user