* Make thread screen as default screen * Blank state when user have not any model * Cleanup topbar thread screen * Improve style right panel * Add instructions right panel * Styling thread list history * Resolve conflict * Default title new thread * Fix trigger panel sidebar * Make default right panel false when no activethread * Fix CI test * chore: assistant instruction with system prompt * Fix title and blank state explore the hub * Claenup style thread screen and add buble message for assitant * Remove unused import * Styling more menus on thread list and right panel, and make max height textarea 400 pixel * Finished revamp ui thread * Finished system monitor UI * Style box running models * Make animate right panel more smooth * Add status arround textarea for starting model info * Temporary disable hide left panel * chore: system resource monitoring update * copy nits * chore: typo * Reverse icon chevron accordion * Move my models into setting page --------- Co-authored-by: Louis <louis@jan.ai> Co-authored-by: 0xSage <n@pragmatic.vc>
100 lines
3.0 KiB
TypeScript
100 lines
3.0 KiB
TypeScript
import { ReactNode, useState, useRef } from 'react'
|
|
|
|
import {
|
|
ChevronDownIcon,
|
|
MoreVerticalIcon,
|
|
FolderOpenIcon,
|
|
Code2Icon,
|
|
} from 'lucide-react'
|
|
import { twMerge } from 'tailwind-merge'
|
|
|
|
import { useClickOutside } from '@/hooks/useClickOutside'
|
|
|
|
interface Props {
|
|
children: ReactNode
|
|
title: string
|
|
onRevealInFinderClick: (type: string) => void
|
|
onViewJsonClick: (type: string) => void
|
|
}
|
|
export default function CardSidebar({
|
|
children,
|
|
title,
|
|
onRevealInFinderClick,
|
|
onViewJsonClick,
|
|
}: Props) {
|
|
const [show, setShow] = useState(true)
|
|
const [more, setMore] = useState(false)
|
|
const [menu, setMenu] = useState<HTMLDivElement | null>(null)
|
|
const [toggle, setToggle] = useState<HTMLDivElement | null>(null)
|
|
|
|
useClickOutside(() => setMore(false), null, [menu, toggle])
|
|
|
|
return (
|
|
<div
|
|
className={twMerge(
|
|
'flex w-full flex-col rounded-lg border border-border',
|
|
show && 'border border-border'
|
|
)}
|
|
>
|
|
<div
|
|
className={twMerge(
|
|
'relative flex items-center rounded-t-md bg-zinc-200 dark:bg-zinc-600/10',
|
|
show && 'border-b border-border'
|
|
)}
|
|
>
|
|
<button
|
|
onClick={() => setShow(!show)}
|
|
className="flex w-full flex-1 items-center space-x-2 px-3 py-2"
|
|
>
|
|
<ChevronDownIcon
|
|
className={twMerge(
|
|
'h-5 w-5 flex-none rotate-180 text-gray-400',
|
|
show && 'rotate-0'
|
|
)}
|
|
/>
|
|
<span className="font-bold">{title}</span>
|
|
</button>
|
|
<div
|
|
ref={setToggle}
|
|
className="cursor-pointer bg-zinc-200 p-2 dark:bg-zinc-600/10"
|
|
onClick={() => setMore(!more)}
|
|
>
|
|
<MoreVerticalIcon className="h-5 w-5" />
|
|
</div>
|
|
{more && (
|
|
<div
|
|
className="absolute right-0 top-8 z-20 w-52 overflow-hidden rounded-lg border border-border bg-background shadow-lg"
|
|
ref={setMenu}
|
|
>
|
|
<div
|
|
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-secondary"
|
|
onClick={() => {
|
|
onRevealInFinderClick(title)
|
|
setMore(false)
|
|
}}
|
|
>
|
|
<FolderOpenIcon size={16} className="text-muted-foreground" />
|
|
<span className="text-bold text-black dark:text-muted-foreground">
|
|
Reveal in Finder
|
|
</span>
|
|
</div>
|
|
<div
|
|
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-secondary"
|
|
onClick={() => {
|
|
onViewJsonClick(title)
|
|
setMore(false)
|
|
}}
|
|
>
|
|
<Code2Icon size={16} className="text-muted-foreground" />
|
|
<span className="text-bold text-black dark:text-muted-foreground">
|
|
View as JSON
|
|
</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
{show && <div className="flex flex-col gap-2 p-2">{children}</div>}
|
|
</div>
|
|
)
|
|
}
|