thepopebot 1.2.25 → 1.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/chat/actions.js +33 -0
- package/lib/chat/components/app-sidebar.js +1 -33
- package/lib/chat/components/app-sidebar.jsx +1 -41
- package/lib/chat/components/chat.js +32 -15
- package/lib/chat/components/chat.jsx +36 -14
- package/lib/chat/components/chats-page.js +139 -27
- package/lib/chat/components/chats-page.jsx +133 -26
- package/lib/chat/components/crons-page.js +40 -16
- package/lib/chat/components/crons-page.jsx +49 -17
- package/lib/chat/components/greeting.js +1 -1
- package/lib/chat/components/greeting.jsx +1 -1
- package/lib/chat/components/icons.js +76 -0
- package/lib/chat/components/icons.jsx +74 -0
- package/lib/chat/components/notifications-page.js +3 -2
- package/lib/chat/components/notifications-page.jsx +6 -3
- package/lib/chat/components/settings-layout.js +3 -1
- package/lib/chat/components/settings-layout.jsx +3 -1
- package/lib/chat/components/sidebar-history-item.js +117 -22
- package/lib/chat/components/sidebar-history-item.jsx +117 -29
- package/lib/chat/components/sidebar-history.js +26 -3
- package/lib/chat/components/sidebar-history.jsx +27 -2
- package/lib/chat/components/triggers-page.js +42 -16
- package/lib/chat/components/triggers-page.jsx +51 -17
- package/lib/db/chats.js +16 -0
- package/lib/db/index.js +5 -0
- package/lib/db/schema.js +1 -0
- package/package.json +2 -2
- package/setup/setup.mjs +9 -0
- package/templates/.env.example +5 -2
- package/templates/app/crons/page.js +3 -5
- package/templates/app/globals.css +4 -0
- package/templates/app/settings/crons/page.js +5 -0
- package/templates/app/settings/page.js +1 -1
- package/templates/app/settings/triggers/page.js +5 -0
- package/templates/app/triggers/page.js +3 -5
package/lib/chat/actions.js
CHANGED
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
getMessagesByChatId,
|
|
8
8
|
deleteChat as dbDeleteChat,
|
|
9
9
|
deleteAllChatsByUser,
|
|
10
|
+
updateChatTitle,
|
|
11
|
+
toggleChatStarred,
|
|
10
12
|
} from '../db/chats.js';
|
|
11
13
|
import {
|
|
12
14
|
getNotifications as dbGetNotifications,
|
|
@@ -83,6 +85,37 @@ export async function deleteChat(chatId) {
|
|
|
83
85
|
return { success: true };
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Rename a chat (with ownership check).
|
|
90
|
+
* @param {string} chatId
|
|
91
|
+
* @param {string} title
|
|
92
|
+
* @returns {Promise<{success: boolean}>}
|
|
93
|
+
*/
|
|
94
|
+
export async function renameChat(chatId, title) {
|
|
95
|
+
const user = await requireAuth();
|
|
96
|
+
const chat = getChatById(chatId);
|
|
97
|
+
if (!chat || chat.userId !== user.id) {
|
|
98
|
+
return { success: false };
|
|
99
|
+
}
|
|
100
|
+
updateChatTitle(chatId, title);
|
|
101
|
+
return { success: true };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Toggle a chat's starred status (with ownership check).
|
|
106
|
+
* @param {string} chatId
|
|
107
|
+
* @returns {Promise<{success: boolean, starred?: number}>}
|
|
108
|
+
*/
|
|
109
|
+
export async function starChat(chatId) {
|
|
110
|
+
const user = await requireAuth();
|
|
111
|
+
const chat = getChatById(chatId);
|
|
112
|
+
if (!chat || chat.userId !== user.id) {
|
|
113
|
+
return { success: false };
|
|
114
|
+
}
|
|
115
|
+
const starred = toggleChatStarred(chatId);
|
|
116
|
+
return { success: true, starred };
|
|
117
|
+
}
|
|
118
|
+
|
|
86
119
|
/**
|
|
87
120
|
* Delete all chats for the authenticated user.
|
|
88
121
|
* @returns {Promise<{success: boolean}>}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useEffect } from "react";
|
|
4
|
-
import { SquarePenIcon, PanelLeftIcon, MessageIcon, BellIcon, SwarmIcon
|
|
4
|
+
import { SquarePenIcon, PanelLeftIcon, MessageIcon, BellIcon, SwarmIcon } from "./icons.js";
|
|
5
5
|
import { getUnreadNotificationCount } from "../actions.js";
|
|
6
6
|
import { SidebarHistory } from "./sidebar-history.js";
|
|
7
7
|
import { SidebarUserNav } from "./sidebar-user-nav.js";
|
|
@@ -113,38 +113,6 @@ function AppSidebar({ user }) {
|
|
|
113
113
|
}
|
|
114
114
|
) }),
|
|
115
115
|
collapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Swarm" })
|
|
116
|
-
] }) }),
|
|
117
|
-
/* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
118
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
119
|
-
SidebarMenuButton,
|
|
120
|
-
{
|
|
121
|
-
className: collapsed ? "justify-center" : "",
|
|
122
|
-
onClick: () => {
|
|
123
|
-
window.location.href = "/crons";
|
|
124
|
-
},
|
|
125
|
-
children: [
|
|
126
|
-
/* @__PURE__ */ jsx(ClockIcon, { size: 16 }),
|
|
127
|
-
!collapsed && /* @__PURE__ */ jsx("span", { children: "Cron Jobs" })
|
|
128
|
-
]
|
|
129
|
-
}
|
|
130
|
-
) }),
|
|
131
|
-
collapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Cron Jobs" })
|
|
132
|
-
] }) }),
|
|
133
|
-
/* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
134
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
135
|
-
SidebarMenuButton,
|
|
136
|
-
{
|
|
137
|
-
className: collapsed ? "justify-center" : "",
|
|
138
|
-
onClick: () => {
|
|
139
|
-
window.location.href = "/triggers";
|
|
140
|
-
},
|
|
141
|
-
children: [
|
|
142
|
-
/* @__PURE__ */ jsx(ZapIcon, { size: 16 }),
|
|
143
|
-
!collapsed && /* @__PURE__ */ jsx("span", { children: "Triggers" })
|
|
144
|
-
]
|
|
145
|
-
}
|
|
146
|
-
) }),
|
|
147
|
-
collapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Triggers" })
|
|
148
116
|
] }) })
|
|
149
117
|
] })
|
|
150
118
|
] }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
|
-
import { SquarePenIcon, PanelLeftIcon, MessageIcon, BellIcon, SwarmIcon
|
|
4
|
+
import { SquarePenIcon, PanelLeftIcon, MessageIcon, BellIcon, SwarmIcon } from './icons.js';
|
|
5
5
|
import { getUnreadNotificationCount } from '../actions.js';
|
|
6
6
|
import { SidebarHistory } from './sidebar-history.js';
|
|
7
7
|
import { SidebarUserNav } from './sidebar-user-nav.js';
|
|
@@ -151,46 +151,6 @@ export function AppSidebar({ user }) {
|
|
|
151
151
|
</Tooltip>
|
|
152
152
|
</SidebarMenuItem>
|
|
153
153
|
|
|
154
|
-
{/* Cron Jobs */}
|
|
155
|
-
<SidebarMenuItem>
|
|
156
|
-
<Tooltip>
|
|
157
|
-
<TooltipTrigger asChild>
|
|
158
|
-
<SidebarMenuButton
|
|
159
|
-
className={collapsed ? 'justify-center' : ''}
|
|
160
|
-
onClick={() => {
|
|
161
|
-
window.location.href = '/crons';
|
|
162
|
-
}}
|
|
163
|
-
>
|
|
164
|
-
<ClockIcon size={16} />
|
|
165
|
-
{!collapsed && <span>Cron Jobs</span>}
|
|
166
|
-
</SidebarMenuButton>
|
|
167
|
-
</TooltipTrigger>
|
|
168
|
-
{collapsed && (
|
|
169
|
-
<TooltipContent side="right">Cron Jobs</TooltipContent>
|
|
170
|
-
)}
|
|
171
|
-
</Tooltip>
|
|
172
|
-
</SidebarMenuItem>
|
|
173
|
-
|
|
174
|
-
{/* Triggers */}
|
|
175
|
-
<SidebarMenuItem>
|
|
176
|
-
<Tooltip>
|
|
177
|
-
<TooltipTrigger asChild>
|
|
178
|
-
<SidebarMenuButton
|
|
179
|
-
className={collapsed ? 'justify-center' : ''}
|
|
180
|
-
onClick={() => {
|
|
181
|
-
window.location.href = '/triggers';
|
|
182
|
-
}}
|
|
183
|
-
>
|
|
184
|
-
<ZapIcon size={16} />
|
|
185
|
-
{!collapsed && <span>Triggers</span>}
|
|
186
|
-
</SidebarMenuButton>
|
|
187
|
-
</TooltipTrigger>
|
|
188
|
-
{collapsed && (
|
|
189
|
-
<TooltipContent side="right">Triggers</TooltipContent>
|
|
190
|
-
)}
|
|
191
|
-
</Tooltip>
|
|
192
|
-
</SidebarMenuItem>
|
|
193
|
-
|
|
194
154
|
</SidebarMenu>
|
|
195
155
|
</SidebarHeader>
|
|
196
156
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useChat } from "@ai-sdk/react";
|
|
4
4
|
import { DefaultChatTransport } from "ai";
|
|
5
5
|
import { useState, useEffect, useRef, useMemo } from "react";
|
|
6
6
|
import { Messages } from "./messages.js";
|
|
7
7
|
import { ChatInput } from "./chat-input.js";
|
|
8
8
|
import { ChatHeader } from "./chat-header.js";
|
|
9
|
+
import { Greeting } from "./greeting.js";
|
|
9
10
|
function Chat({ chatId, initialMessages = [] }) {
|
|
10
11
|
const [input, setInput] = useState("");
|
|
11
12
|
const [files, setFiles] = useState([]);
|
|
@@ -57,20 +58,36 @@ function Chat({ chatId, initialMessages = [] }) {
|
|
|
57
58
|
};
|
|
58
59
|
return /* @__PURE__ */ jsxs("div", { className: "flex h-svh flex-col", children: [
|
|
59
60
|
/* @__PURE__ */ jsx(ChatHeader, { chatId }),
|
|
60
|
-
/* @__PURE__ */ jsx(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
61
|
+
messages.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col items-center justify-center px-2 md:px-4", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-4xl", children: [
|
|
62
|
+
/* @__PURE__ */ jsx(Greeting, {}),
|
|
63
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(
|
|
64
|
+
ChatInput,
|
|
65
|
+
{
|
|
66
|
+
input,
|
|
67
|
+
setInput,
|
|
68
|
+
onSubmit: handleSend,
|
|
69
|
+
status,
|
|
70
|
+
stop,
|
|
71
|
+
files,
|
|
72
|
+
setFiles
|
|
73
|
+
}
|
|
74
|
+
) })
|
|
75
|
+
] }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
76
|
+
/* @__PURE__ */ jsx(Messages, { messages, status }),
|
|
77
|
+
error && /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-4xl px-2 md:px-4", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-destructive/50 bg-destructive/10 px-4 py-2 text-sm text-destructive", children: error.message || "Something went wrong. Please try again." }) }),
|
|
78
|
+
/* @__PURE__ */ jsx(
|
|
79
|
+
ChatInput,
|
|
80
|
+
{
|
|
81
|
+
input,
|
|
82
|
+
setInput,
|
|
83
|
+
onSubmit: handleSend,
|
|
84
|
+
status,
|
|
85
|
+
stop,
|
|
86
|
+
files,
|
|
87
|
+
setFiles
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
] })
|
|
74
91
|
] });
|
|
75
92
|
}
|
|
76
93
|
export {
|
|
@@ -6,6 +6,7 @@ import { useState, useEffect, useRef, useMemo } from 'react';
|
|
|
6
6
|
import { Messages } from './messages.js';
|
|
7
7
|
import { ChatInput } from './chat-input.js';
|
|
8
8
|
import { ChatHeader } from './chat-header.js';
|
|
9
|
+
import { Greeting } from './greeting.js';
|
|
9
10
|
|
|
10
11
|
export function Chat({ chatId, initialMessages = [] }) {
|
|
11
12
|
const [input, setInput] = useState('');
|
|
@@ -69,23 +70,44 @@ export function Chat({ chatId, initialMessages = [] }) {
|
|
|
69
70
|
return (
|
|
70
71
|
<div className="flex h-svh flex-col">
|
|
71
72
|
<ChatHeader chatId={chatId} />
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
{messages.length === 0 ? (
|
|
74
|
+
<div className="flex flex-1 flex-col items-center justify-center px-2 md:px-4">
|
|
75
|
+
<div className="w-full max-w-4xl">
|
|
76
|
+
<Greeting />
|
|
77
|
+
<div className="mt-4">
|
|
78
|
+
<ChatInput
|
|
79
|
+
input={input}
|
|
80
|
+
setInput={setInput}
|
|
81
|
+
onSubmit={handleSend}
|
|
82
|
+
status={status}
|
|
83
|
+
stop={stop}
|
|
84
|
+
files={files}
|
|
85
|
+
setFiles={setFiles}
|
|
86
|
+
/>
|
|
87
|
+
</div>
|
|
77
88
|
</div>
|
|
78
89
|
</div>
|
|
90
|
+
) : (
|
|
91
|
+
<>
|
|
92
|
+
<Messages messages={messages} status={status} />
|
|
93
|
+
{error && (
|
|
94
|
+
<div className="mx-auto w-full max-w-4xl px-2 md:px-4">
|
|
95
|
+
<div className="rounded-lg border border-destructive/50 bg-destructive/10 px-4 py-2 text-sm text-destructive">
|
|
96
|
+
{error.message || 'Something went wrong. Please try again.'}
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
)}
|
|
100
|
+
<ChatInput
|
|
101
|
+
input={input}
|
|
102
|
+
setInput={setInput}
|
|
103
|
+
onSubmit={handleSend}
|
|
104
|
+
status={status}
|
|
105
|
+
stop={stop}
|
|
106
|
+
files={files}
|
|
107
|
+
setFiles={setFiles}
|
|
108
|
+
/>
|
|
109
|
+
</>
|
|
79
110
|
)}
|
|
80
|
-
<ChatInput
|
|
81
|
-
input={input}
|
|
82
|
-
setInput={setInput}
|
|
83
|
-
onSubmit={handleSend}
|
|
84
|
-
status={status}
|
|
85
|
-
stop={stop}
|
|
86
|
-
files={files}
|
|
87
|
-
setFiles={setFiles}
|
|
88
|
-
/>
|
|
89
111
|
</div>
|
|
90
112
|
);
|
|
91
113
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useEffect } from "react";
|
|
3
|
+
import { useState, useEffect, useRef } from "react";
|
|
4
4
|
import { PageLayout } from "./page-layout.js";
|
|
5
|
-
import { MessageIcon, TrashIcon, SearchIcon, PlusIcon } from "./icons.js";
|
|
6
|
-
import { getChats, deleteChat } from "../actions.js";
|
|
5
|
+
import { MessageIcon, TrashIcon, SearchIcon, PlusIcon, MoreHorizontalIcon, StarIcon, StarFilledIcon, PencilIcon } from "./icons.js";
|
|
6
|
+
import { getChats, deleteChat, renameChat, starChat } from "../actions.js";
|
|
7
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from "./ui/dropdown-menu.js";
|
|
7
8
|
import { cn } from "../utils.js";
|
|
8
9
|
function groupChatsByDate(chats) {
|
|
9
10
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -12,6 +13,7 @@ function groupChatsByDate(chats) {
|
|
|
12
13
|
const last7Days = new Date(today.getTime() - 7 * 864e5);
|
|
13
14
|
const last30Days = new Date(today.getTime() - 30 * 864e5);
|
|
14
15
|
const groups = {
|
|
16
|
+
Starred: [],
|
|
15
17
|
Today: [],
|
|
16
18
|
Yesterday: [],
|
|
17
19
|
"Last 7 Days": [],
|
|
@@ -19,6 +21,10 @@ function groupChatsByDate(chats) {
|
|
|
19
21
|
Older: []
|
|
20
22
|
};
|
|
21
23
|
for (const chat of chats) {
|
|
24
|
+
if (chat.starred) {
|
|
25
|
+
groups.Starred.push(chat);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
22
28
|
const date = new Date(chat.updatedAt);
|
|
23
29
|
if (date >= today) {
|
|
24
30
|
groups.Today.push(chat);
|
|
@@ -72,10 +78,23 @@ function ChatsPage({ session }) {
|
|
|
72
78
|
return () => window.removeEventListener("chatsupdated", handler);
|
|
73
79
|
}, []);
|
|
74
80
|
const handleDelete = async (chatId) => {
|
|
81
|
+
setChats((prev) => prev.filter((c) => c.id !== chatId));
|
|
75
82
|
const { success } = await deleteChat(chatId);
|
|
76
|
-
if (success)
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
if (!success) loadChats();
|
|
84
|
+
};
|
|
85
|
+
const handleStar = async (chatId) => {
|
|
86
|
+
setChats(
|
|
87
|
+
(prev) => prev.map((c) => c.id === chatId ? { ...c, starred: c.starred ? 0 : 1 } : c)
|
|
88
|
+
);
|
|
89
|
+
const { success } = await starChat(chatId);
|
|
90
|
+
if (!success) loadChats();
|
|
91
|
+
};
|
|
92
|
+
const handleRename = async (chatId, title) => {
|
|
93
|
+
setChats(
|
|
94
|
+
(prev) => prev.map((c) => c.id === chatId ? { ...c, title } : c)
|
|
95
|
+
);
|
|
96
|
+
const { success } = await renameChat(chatId, title);
|
|
97
|
+
if (!success) loadChats();
|
|
79
98
|
};
|
|
80
99
|
const filtered = query ? chats.filter((c) => c.title?.toLowerCase().includes(query.toLowerCase())) : chats;
|
|
81
100
|
const grouped = groupChatsByDate(filtered);
|
|
@@ -120,7 +139,9 @@ function ChatsPage({ session }) {
|
|
|
120
139
|
{
|
|
121
140
|
chat,
|
|
122
141
|
onNavigate: navigateToChat,
|
|
123
|
-
onDelete: handleDelete
|
|
142
|
+
onDelete: handleDelete,
|
|
143
|
+
onStar: handleStar,
|
|
144
|
+
onRename: handleRename
|
|
124
145
|
},
|
|
125
146
|
chat.id
|
|
126
147
|
)) })
|
|
@@ -128,39 +149,130 @@ function ChatsPage({ session }) {
|
|
|
128
149
|
) })
|
|
129
150
|
] });
|
|
130
151
|
}
|
|
131
|
-
function ChatRow({ chat, onNavigate, onDelete }) {
|
|
132
|
-
const [
|
|
152
|
+
function ChatRow({ chat, onNavigate, onDelete, onStar, onRename }) {
|
|
153
|
+
const [showMenu, setShowMenu] = useState(false);
|
|
154
|
+
const [editing, setEditing] = useState(false);
|
|
155
|
+
const [editTitle, setEditTitle] = useState(chat.title || "");
|
|
156
|
+
const inputRef = useRef(null);
|
|
157
|
+
useEffect(() => {
|
|
158
|
+
if (editing && inputRef.current) {
|
|
159
|
+
inputRef.current.focus();
|
|
160
|
+
inputRef.current.select();
|
|
161
|
+
}
|
|
162
|
+
}, [editing]);
|
|
163
|
+
const startRename = () => {
|
|
164
|
+
setEditTitle(chat.title || "");
|
|
165
|
+
setEditing(true);
|
|
166
|
+
};
|
|
167
|
+
const saveRename = () => {
|
|
168
|
+
const trimmed = editTitle.trim();
|
|
169
|
+
if (trimmed && trimmed !== chat.title) {
|
|
170
|
+
onRename(chat.id, trimmed);
|
|
171
|
+
}
|
|
172
|
+
setEditing(false);
|
|
173
|
+
};
|
|
174
|
+
const cancelRename = () => {
|
|
175
|
+
setEditing(false);
|
|
176
|
+
setEditTitle(chat.title || "");
|
|
177
|
+
};
|
|
133
178
|
return /* @__PURE__ */ jsxs(
|
|
134
179
|
"div",
|
|
135
180
|
{
|
|
136
181
|
className: "relative group flex items-center gap-3 px-3 py-3 cursor-pointer hover:bg-muted/50 rounded-md",
|
|
137
|
-
onMouseEnter: () =>
|
|
138
|
-
onMouseLeave: () =>
|
|
139
|
-
onClick: () => onNavigate(chat.id),
|
|
182
|
+
onMouseEnter: () => setShowMenu(true),
|
|
183
|
+
onMouseLeave: () => setShowMenu(false),
|
|
184
|
+
onClick: () => !editing && onNavigate(chat.id),
|
|
140
185
|
children: [
|
|
141
186
|
/* @__PURE__ */ jsx(MessageIcon, { size: 16 }),
|
|
142
187
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
143
|
-
/* @__PURE__ */ jsx(
|
|
188
|
+
editing ? /* @__PURE__ */ jsx(
|
|
189
|
+
"input",
|
|
190
|
+
{
|
|
191
|
+
ref: inputRef,
|
|
192
|
+
type: "text",
|
|
193
|
+
value: editTitle,
|
|
194
|
+
onChange: (e) => setEditTitle(e.target.value),
|
|
195
|
+
onKeyDown: (e) => {
|
|
196
|
+
if (e.key === "Enter") saveRename();
|
|
197
|
+
if (e.key === "Escape") cancelRename();
|
|
198
|
+
},
|
|
199
|
+
onBlur: saveRename,
|
|
200
|
+
onClick: (e) => e.stopPropagation(),
|
|
201
|
+
className: "w-full text-sm bg-background border border-input rounded px-1.5 py-0.5 focus:outline-none focus:ring-2 focus:ring-ring"
|
|
202
|
+
}
|
|
203
|
+
) : /* @__PURE__ */ jsx(
|
|
204
|
+
"span",
|
|
205
|
+
{
|
|
206
|
+
className: "text-sm truncate block",
|
|
207
|
+
onDoubleClick: (e) => {
|
|
208
|
+
e.stopPropagation();
|
|
209
|
+
startRename();
|
|
210
|
+
},
|
|
211
|
+
children: chat.title || "New Chat"
|
|
212
|
+
}
|
|
213
|
+
),
|
|
144
214
|
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
145
215
|
"Last message ",
|
|
146
216
|
timeAgo(chat.updatedAt)
|
|
147
217
|
] })
|
|
148
218
|
] }),
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
219
|
+
showMenu && !editing && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
220
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
221
|
+
"button",
|
|
222
|
+
{
|
|
223
|
+
className: cn(
|
|
224
|
+
"shrink-0 rounded-md p-1.5",
|
|
225
|
+
"text-muted-foreground hover:text-foreground hover:bg-muted"
|
|
226
|
+
),
|
|
227
|
+
onClick: (e) => e.stopPropagation(),
|
|
228
|
+
"aria-label": "Chat options",
|
|
229
|
+
children: /* @__PURE__ */ jsx(MoreHorizontalIcon, { size: 14 })
|
|
230
|
+
}
|
|
231
|
+
) }),
|
|
232
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", side: "bottom", children: [
|
|
233
|
+
/* @__PURE__ */ jsxs(
|
|
234
|
+
DropdownMenuItem,
|
|
235
|
+
{
|
|
236
|
+
onClick: (e) => {
|
|
237
|
+
e.stopPropagation();
|
|
238
|
+
onStar(chat.id);
|
|
239
|
+
},
|
|
240
|
+
children: [
|
|
241
|
+
chat.starred ? /* @__PURE__ */ jsx(StarFilledIcon, { size: 14 }) : /* @__PURE__ */ jsx(StarIcon, { size: 14 }),
|
|
242
|
+
chat.starred ? "Unstar" : "Star"
|
|
243
|
+
]
|
|
244
|
+
}
|
|
245
|
+
),
|
|
246
|
+
/* @__PURE__ */ jsxs(
|
|
247
|
+
DropdownMenuItem,
|
|
248
|
+
{
|
|
249
|
+
onClick: (e) => {
|
|
250
|
+
e.stopPropagation();
|
|
251
|
+
startRename();
|
|
252
|
+
},
|
|
253
|
+
children: [
|
|
254
|
+
/* @__PURE__ */ jsx(PencilIcon, { size: 14 }),
|
|
255
|
+
"Rename"
|
|
256
|
+
]
|
|
257
|
+
}
|
|
155
258
|
),
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
259
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
260
|
+
/* @__PURE__ */ jsxs(
|
|
261
|
+
DropdownMenuItem,
|
|
262
|
+
{
|
|
263
|
+
className: "text-destructive hover:text-destructive",
|
|
264
|
+
onClick: (e) => {
|
|
265
|
+
e.stopPropagation();
|
|
266
|
+
onDelete(chat.id);
|
|
267
|
+
},
|
|
268
|
+
children: [
|
|
269
|
+
/* @__PURE__ */ jsx(TrashIcon, { size: 14 }),
|
|
270
|
+
"Delete"
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
)
|
|
274
|
+
] })
|
|
275
|
+
] })
|
|
164
276
|
]
|
|
165
277
|
}
|
|
166
278
|
);
|