Skip to content

Commit 72f7b73

Browse files
authored
New bundle: left sidebar 3 tabs (#1542)
1 parent d69217b commit 72f7b73

File tree

10 files changed

+278
-134
lines changed

10 files changed

+278
-134
lines changed

apps/desktop/src/components/toolbar/bars/main-toolbar.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ import { useMatch } from "@tanstack/react-router";
33
import { DeleteNoteButton } from "@/components/toolbar/buttons/delete-note-button";
44
import { NewNoteButton } from "@/components/toolbar/buttons/new-note-button";
55
import { NewWindowButton } from "@/components/toolbar/buttons/new-window-button";
6-
// import { ShareButton } from "@/components/toolbar/buttons/share-button";
76
import { getCurrentWebviewWindowLabel } from "@hypr/plugin-windows";
7+
import { ChatPanelButton } from "@hypr/ui/components/block/chat-panel-button";
88
import { cn } from "@hypr/ui/lib/utils";
9-
import { useLeftSidebar } from "@hypr/utils/contexts";
9+
import { useLeftSidebar, useRightPanel } from "@hypr/utils/contexts";
1010
import { SearchBar } from "../../search-bar";
11-
import { ChatPanelButton } from "../buttons/chat-panel-button";
1211
import { LeftSidebarButton } from "../buttons/left-sidebar-button";
1312
import { ShareButton } from "../buttons/share-button";
1413

@@ -24,6 +23,8 @@ export function MainToolbar() {
2423
const isNote = !!noteMatch;
2524
const isMain = getCurrentWebviewWindowLabel() === "main";
2625

26+
const { isExpanded: isChatPanelExpanded, togglePanel: toggleChatPanel } = useRightPanel();
27+
2728
return (
2829
<header
2930
data-tauri-drag-region
@@ -58,7 +59,7 @@ export function MainToolbar() {
5859
<>
5960
{(organizationMatch || humanMatch) && <NewWindowButton />}
6061
{isNote && <ShareButton />}
61-
<ChatPanelButton />
62+
<ChatPanelButton isExpanded={isChatPanelExpanded} togglePanel={toggleChatPanel} />
6263
</>
6364
)}
6465
</div>

apps/desktop/src/components/toolbar/buttons/chat-panel-button.tsx

Lines changed: 0 additions & 53 deletions
This file was deleted.

apps/desktop2/src/components/chat.tsx

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -53,40 +53,64 @@ export function Chat() {
5353

5454
if (!currentChatGroupId || !messageIds?.length) {
5555
return (
56-
<div className="border border-gray-300 rounded p-2">
57-
<div className="text-gray-500">Select or create a chat group</div>
58-
59-
<div className="flex flex-col gap-2">
60-
{chatGroupIds?.map((chatGroupId) => (
61-
<ChatGroup
62-
key={chatGroupId}
63-
id={chatGroupId}
64-
handleClick={() => setCurrentChatGroupId(chatGroupId)}
56+
<div className="h-full flex flex-col bg-gray-100">
57+
<div className="flex-1 overflow-y-auto p-4">
58+
<div className="flex flex-col gap-2">
59+
{chatGroupIds?.map((chatGroupId) => (
60+
<ChatGroup
61+
key={chatGroupId}
62+
id={chatGroupId}
63+
handleClick={() => setCurrentChatGroupId(chatGroupId)}
64+
/>
65+
))}
66+
</div>
67+
</div>
68+
69+
<div className="border-t border-gray-300 p-4">
70+
<form onSubmit={handleSubmitMessage}>
71+
<textarea
72+
name="message"
73+
placeholder="Type a message..."
74+
className="w-full border border-gray-300 rounded p-2 resize-none focus:outline-none focus:ring-2 focus:ring-blue-500"
75+
rows={3}
6576
/>
66-
))}
77+
<button className="mt-2 border border-gray-300 rounded px-4 py-2 hover:bg-gray-100">
78+
Send
79+
</button>
80+
</form>
6781
</div>
6882
</div>
6983
);
7084
}
7185

7286
return (
73-
<div className="border border-gray-300 rounded p-2">
74-
<button onClick={() => setCurrentChatGroupId("")}>
75-
reset
76-
</button>
87+
<div className="h-full flex flex-col border border-gray-300 rounded">
88+
<div className="border-b border-gray-300 p-2">
89+
<button
90+
onClick={() => setCurrentChatGroupId("")}
91+
className="border border-gray-300 rounded px-3 py-1 hover:bg-gray-100"
92+
>
93+
reset
94+
</button>
95+
</div>
7796

78-
<div className="space-y-2">
97+
<div className="flex-1 overflow-y-auto p-4 space-y-2">
7998
{messageIds?.map((messageId) => <ChatMessage key={messageId} messageId={messageId} />)}
8099
</div>
81100

82-
<form onSubmit={handleSubmitMessage}>
83-
<input
84-
name="message"
85-
type="text"
86-
className="border border-gray-300 rounded p-2"
87-
/>
88-
<button className="border border-gray-300 rounded p-2">Send</button>
89-
</form>
101+
<div className="border-t border-gray-300 p-4">
102+
<form onSubmit={handleSubmitMessage} className="flex flex-col gap-2">
103+
<textarea
104+
name="message"
105+
placeholder="Type a message..."
106+
className="w-full border border-gray-300 rounded p-2 resize-none focus:outline-none focus:ring-2 focus:ring-blue-500"
107+
rows={3}
108+
/>
109+
<button className="self-end border border-gray-300 rounded px-4 py-2 hover:bg-gray-100">
110+
Send
111+
</button>
112+
</form>
113+
</div>
90114
</div>
91115
);
92116
}

apps/desktop2/src/components/main/left-sidebar.tsx

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
import { Link } from "@tanstack/react-router";
22
import { clsx } from "clsx";
3-
import { ChartNoAxesGantt, FolderOpenIcon } from "lucide-react";
3+
import { ChartNoAxesGantt, FolderOpenIcon, PanelLeftCloseIcon, SearchIcon } from "lucide-react";
44
import { useState } from "react";
55
import { useCell, useRowIds, useSliceRowIds } from "tinybase/ui-react";
66

77
import * as persisted from "../../tinybase/store/persisted";
88

99
import { ContextMenuItem } from "@hypr/ui/components/ui/context-menu";
1010
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@hypr/ui/components/ui/tabs";
11+
import { useLeftSidebar } from "@hypr/utils/contexts";
1112
import { useTabs } from "../../hooks/useTabs";
1213
import { Tab } from "../../types";
1314
import { InteractiveButton } from "../interactive-button";
1415

1516
export function LeftSidebar() {
17+
const { togglePanel: toggleLeftPanel } = useLeftSidebar();
18+
1619
return (
17-
<div className="h-screen border-r w-[300px]">
18-
<Tabs defaultValue="timeline">
20+
<div className="h-full border-r w-full flex flex-col overflow-hidden">
21+
<Tabs defaultValue="timeline" className="flex flex-col flex-1 overflow-hidden">
1922
<TabsList
2023
data-tauri-drag-region
2124
className={clsx([
22-
"h-full flex flex-row",
25+
"flex flex-row shrink-0",
2326
"flex w-full items-center justify-between min-h-11 py-1 px-2 border-b",
2427
"border-border bg-neutral-50",
2528
"pl-[72px]",
@@ -31,14 +34,32 @@ export function LeftSidebar() {
3134
<TabsTrigger value="timeline" className="flex-1">
3235
<ChartNoAxesGantt />
3336
</TabsTrigger>
37+
<TabsTrigger value="search" className="flex-1">
38+
<SearchIcon />
39+
</TabsTrigger>
40+
41+
<PanelLeftCloseIcon
42+
onClick={toggleLeftPanel}
43+
className="cursor-pointer h-5 w-5"
44+
/>
3445
</TabsList>
3546

36-
<TabsContent value="timeline" className="flex-1 overflow-auto p-2 mt-0">
37-
<TimelineView />
47+
<TabsContent value="timeline" className="flex-1 mt-0 h-0">
48+
<div className="h-full overflow-y-auto p-2">
49+
<TimelineView />
50+
</div>
51+
</TabsContent>
52+
53+
<TabsContent value="folder" className="flex-1 mt-0 h-0">
54+
<div className="h-full overflow-y-auto p-2">
55+
<FolderView />
56+
</div>
3857
</TabsContent>
3958

40-
<TabsContent value="folder" className="flex-1 overflow-auto p-2 mt-0">
41-
<FolderView />
59+
<TabsContent value="search" className="flex-1 mt-0 h-0">
60+
<div className="h-full flex flex-col overflow-hidden">
61+
<SearchView />
62+
</div>
4263
</TabsContent>
4364
</Tabs>
4465
</div>
@@ -47,29 +68,53 @@ export function LeftSidebar() {
4768

4869
function TimelineView() {
4970
const allSessionIds = useRowIds("sessions", persisted.STORE_ID);
71+
const { currentTab } = useTabs();
5072

5173
return (
5274
<div className="flex flex-col">
53-
{allSessionIds?.map((sessionId) => <SessionItem key={sessionId} sessionId={sessionId} />)}
75+
{allSessionIds?.map((sessionId) => (
76+
<SessionItem key={sessionId} sessionId={sessionId} active={currentTab?.id === sessionId} />
77+
))}
5478
</div>
5579
);
5680
}
5781

82+
function SearchView() {
83+
return (
84+
<>
85+
<div className="sticky top-0 bg-white z-10 p-2 border-b">
86+
<input
87+
type="text"
88+
placeholder="Search..."
89+
className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
90+
/>
91+
</div>
92+
<div className="flex-1 overflow-y-auto p-2">
93+
{/* Search results will go here */}
94+
</div>
95+
</>
96+
);
97+
}
98+
5899
function FolderView() {
59100
const rootFolderIds = useSliceRowIds(persisted.INDEXES.foldersByParent, "", persisted.STORE_ID);
60101
const rootSessionIds = useSliceRowIds(persisted.INDEXES.sessionsByFolder, "", persisted.STORE_ID);
102+
const { currentTab } = useTabs();
61103

62104
return (
63105
<div className="flex flex-col">
64106
{rootFolderIds?.map((folderId) => <FolderTreeItem key={folderId} folderId={folderId} />)}
65-
66-
{rootSessionIds?.map((sessionId) => <SessionItemNested key={sessionId} sessionId={sessionId} depth={0} />)}
107+
{rootSessionIds?.map((sessionId) => (
108+
<SessionItemNested key={sessionId} sessionId={sessionId} depth={0} active={currentTab?.id === sessionId} />
109+
))}
67110
</div>
68111
);
69112
}
70113

71114
function FolderTreeItem({ folderId, depth = 0 }: { folderId: string; depth?: number }) {
72115
const [isOpen, setIsOpen] = useState(true);
116+
const { currentTab } = useTabs();
117+
73118
const name = useCell("folders", folderId, "name", persisted.STORE_ID);
74119
const sessionIds = useSliceRowIds(persisted.INDEXES.sessionsByFolder, folderId, persisted.STORE_ID);
75120
const subFolderIds = useSliceRowIds(persisted.INDEXES.foldersByParent, folderId, persisted.STORE_ID);
@@ -92,7 +137,12 @@ function FolderTreeItem({ folderId, depth = 0 }: { folderId: string; depth?: num
92137
{isOpen && (
93138
<>
94139
{sessionIds?.map((sessionId) => (
95-
<SessionItemNested key={sessionId} sessionId={sessionId} depth={depth + 1} />
140+
<SessionItemNested
141+
key={sessionId}
142+
sessionId={sessionId}
143+
depth={depth + 1}
144+
active={currentTab?.id === sessionId}
145+
/>
96146
))}
97147

98148
{subFolderIds?.map((subId) => <FolderTreeItem key={subId} folderId={subId} depth={depth + 1} />)}

0 commit comments

Comments
 (0)