some ui tweaks
This commit is contained in:
116
web/src/App.tsx
116
web/src/App.tsx
@@ -821,6 +821,7 @@ export default function App() {
|
||||
const [isRenamingChat, setIsRenamingChat] = useState(false);
|
||||
const [isChatSettingsOpen, setIsChatSettingsOpen] = useState(false);
|
||||
const [isSavingChatSettings, setIsSavingChatSettings] = useState(false);
|
||||
const [isTogglingChatSettingsStar, setIsTogglingChatSettingsStar] = useState(false);
|
||||
const [chatSettingsError, setChatSettingsError] = useState<string | null>(null);
|
||||
const [draftChatTitle, setDraftChatTitle] = useState("");
|
||||
const [chatSettingsTitleDraft, setChatSettingsTitleDraft] = useState("");
|
||||
@@ -957,6 +958,7 @@ export default function App() {
|
||||
setPendingAttachments([]);
|
||||
setIsChatSettingsOpen(false);
|
||||
setIsSavingChatSettings(false);
|
||||
setIsTogglingChatSettingsStar(false);
|
||||
setChatSettingsError(null);
|
||||
setDraftChatTitle("");
|
||||
setChatSettingsTitleDraft("");
|
||||
@@ -1353,11 +1355,6 @@ export default function App() {
|
||||
return chats.find((chat) => chat.id === selectedItem.id) ?? null;
|
||||
}, [chats, selectedItem]);
|
||||
|
||||
const selectedSidebarItem = useMemo(() => {
|
||||
if (!selectedItem) return null;
|
||||
return sidebarItems.find((item) => item.kind === selectedItem.kind && item.id === selectedItem.id) ?? null;
|
||||
}, [selectedItem, sidebarItems]);
|
||||
|
||||
const selectedSearchSummary = useMemo(() => {
|
||||
if (!selectedItem || selectedItem.kind !== "search") return null;
|
||||
return searches.find((search) => search.id === selectedItem.id) ?? null;
|
||||
@@ -1737,6 +1734,29 @@ export default function App() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggleChatSettingsStar = async () => {
|
||||
if (draftKind !== null || selectedItem?.kind !== "chat" || isTogglingChatSettingsStar) return;
|
||||
const current = sidebarItems.find((item) => item.kind === "chat" && item.id === selectedItem.id);
|
||||
const nextStarred = !current?.starred;
|
||||
setIsTogglingChatSettingsStar(true);
|
||||
setChatSettingsError(null);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const updatedChat = await updateChatStar(selectedItem.id, nextStarred);
|
||||
applyChatSummary(updatedChat, false);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
if (message.includes("bearer token")) {
|
||||
handleAuthFailure(message);
|
||||
} else {
|
||||
setChatSettingsError(message);
|
||||
}
|
||||
} finally {
|
||||
setIsTogglingChatSettingsStar(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteFromContextMenu = async () => {
|
||||
if (!contextMenu || isItemRunning(contextMenu.item)) return;
|
||||
const target = contextMenu.item;
|
||||
@@ -2817,6 +2837,10 @@ export default function App() {
|
||||
}
|
||||
};
|
||||
|
||||
const chatSettingsChatId = draftKind === null && selectedItem?.kind === "chat" ? selectedItem.id : null;
|
||||
const chatSettingsStarred = chatSettingsChatId
|
||||
? sidebarItems.find((item) => item.kind === "chat" && item.id === chatSettingsChatId)?.starred ?? false
|
||||
: false;
|
||||
|
||||
if (isCheckingSession) {
|
||||
return (
|
||||
@@ -2995,8 +3019,8 @@ export default function App() {
|
||||
</aside>
|
||||
|
||||
<main className="glass-panel relative flex min-w-0 flex-1 flex-col overflow-hidden border-violet-300/18 md:rounded-2xl md:border">
|
||||
<header className="flex flex-wrap items-center justify-between gap-3 border-b border-violet-300/12 bg-[linear-gradient(180deg,hsl(243_48%_10%_/_0.86),hsl(236_48%_6%_/_0.66))] px-4 py-3 md:px-7">
|
||||
<div className="flex items-start gap-2">
|
||||
<header className="flex items-center justify-between gap-2 border-b border-violet-300/12 bg-[linear-gradient(180deg,hsl(243_48%_10%_/_0.86),hsl(236_48%_6%_/_0.66))] px-4 py-3 md:gap-3 md:px-7">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
@@ -3010,46 +3034,20 @@ export default function App() {
|
||||
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<h1 className="truncate text-sm font-semibold text-violet-50 md:text-base">{selectedTitle}</h1>
|
||||
{draftKind === null && selectedItem ? (
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="h-7 w-7 shrink-0 text-violet-100/72 hover:text-violet-50"
|
||||
onClick={() => void handleToggleStar(selectedItem)}
|
||||
title={selectedSidebarItem?.starred ? "Unstar" : "Star"}
|
||||
aria-label={selectedSidebarItem?.starred ? "Unstar" : "Star"}
|
||||
>
|
||||
<Star className={cn("h-3.5 w-3.5", selectedSidebarItem?.starred ? "fill-amber-300 text-amber-300" : "")} />
|
||||
</Button>
|
||||
) : null}
|
||||
{draftKind === null && selectedItem?.kind === "chat" ? (
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="h-7 w-7 shrink-0 text-violet-100/72 hover:text-violet-50"
|
||||
onClick={() => openRenameChatDialog(selectedItem.id)}
|
||||
title="Rename chat"
|
||||
aria-label="Rename chat"
|
||||
>
|
||||
<Pencil className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full max-w-xl items-center justify-end gap-2 md:w-auto">
|
||||
<div className="flex shrink-0 items-center justify-end gap-2">
|
||||
{!isSearchMode ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
className="h-10 max-w-full gap-2 rounded-lg px-3"
|
||||
className="h-10 max-w-[44vw] gap-2 rounded-lg px-3 md:max-w-full"
|
||||
onClick={openChatSettings}
|
||||
disabled={isActiveSelectionSending}
|
||||
aria-label="Open chat settings"
|
||||
>
|
||||
<Settings2 className="h-4 w-4 shrink-0" />
|
||||
<span className="shrink-0">Settings</span>
|
||||
<span className="hidden shrink-0 sm:inline">Settings</span>
|
||||
<span className="hidden min-w-0 max-w-[18rem] truncate text-xs font-medium text-violet-100/58 sm:inline">
|
||||
{getProviderLabel(provider)} · {model || "No model"}
|
||||
</span>
|
||||
@@ -3260,20 +3258,40 @@ export default function App() {
|
||||
</div>
|
||||
|
||||
<div className="min-h-0 flex-1 space-y-4 overflow-y-auto pr-1">
|
||||
<label className="block">
|
||||
<div>
|
||||
<span className="mb-1.5 block text-xs font-semibold text-violet-100/72">Chat title</span>
|
||||
<input
|
||||
value={chatSettingsTitleDraft}
|
||||
onInput={(event) => {
|
||||
setChatSettingsTitleDraft(event.currentTarget.value);
|
||||
if (chatSettingsError) setChatSettingsError(null);
|
||||
}}
|
||||
maxLength={120}
|
||||
placeholder={draftKind === null && selectedItem?.kind === "chat" ? "Chat title" : "Optional title"}
|
||||
className="h-11 w-full rounded-lg border border-violet-300/22 bg-background/72 px-3 text-sm text-violet-50 outline-none shadow-[inset_0_1px_0_hsl(255_100%_92%_/_0.06)] placeholder:text-muted-foreground focus:border-violet-300/45 focus:ring-1 focus:ring-ring/70"
|
||||
disabled={isSavingChatSettings}
|
||||
/>
|
||||
</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
value={chatSettingsTitleDraft}
|
||||
onInput={(event) => {
|
||||
setChatSettingsTitleDraft(event.currentTarget.value);
|
||||
if (chatSettingsError) setChatSettingsError(null);
|
||||
}}
|
||||
maxLength={120}
|
||||
placeholder={draftKind === null && selectedItem?.kind === "chat" ? "Chat title" : "Optional title"}
|
||||
className="h-11 min-w-0 flex-1 rounded-lg border border-violet-300/22 bg-background/72 px-3 text-sm text-violet-50 outline-none shadow-[inset_0_1px_0_hsl(255_100%_92%_/_0.06)] placeholder:text-muted-foreground focus:border-violet-300/45 focus:ring-1 focus:ring-ring/70"
|
||||
disabled={isSavingChatSettings}
|
||||
/>
|
||||
{chatSettingsChatId ? (
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
variant="secondary"
|
||||
className="h-11 w-11 shrink-0 rounded-lg"
|
||||
onClick={() => void handleToggleChatSettingsStar()}
|
||||
disabled={isSavingChatSettings || isTogglingChatSettingsStar}
|
||||
aria-label={chatSettingsStarred ? "Unstar chat" : "Star chat"}
|
||||
title={chatSettingsStarred ? "Unstar chat" : "Star chat"}
|
||||
>
|
||||
{isTogglingChatSettingsStar ? (
|
||||
<LoaderCircle className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Star className={cn("h-4 w-4", chatSettingsStarred ? "fill-amber-300 text-amber-300" : "")} />
|
||||
)}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 md:grid-cols-[minmax(9rem,0.7fr)_minmax(14rem,1fr)]">
|
||||
<label className="block">
|
||||
|
||||
Reference in New Issue
Block a user