some ui tweaks

This commit is contained in:
2026-05-30 18:33:58 -07:00
parent dda20955bb
commit f71b69ca8b

View File

@@ -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">