Chat layout: history in the main sidebar, consistent header, cleaner icon
- Desktop: on /chat the main sidebar shows the chat list (search, New chat, items with rename/delete, active highlight) in place of the deck navigation; the separate second column is gone and the chat uses the full width. The expand/collapse chevron sits outside the swappable section and a collapsed rail stays clean (the highlighted Chat row already opens a new chat). Active conversation travels via a tiny store (lib/chat-active) so the sidebar needs no useSearchParams and pages stay static. - Header (phones): history, theme and New chat are now identical chips - same 44px hit area, rounded-2xl, border/surface tokens, size-5 icons, even spacing; the title block truncates cleanly. ThemeToggle gained a 'plain' variant so the header styles it without touching other pages. - ChatIcon redrawn (clean message-circle, no inner lines) and the empty state uses the app's icon-chip pattern (size-12 chip, accent-600/200) instead of the bare oversized glyph; the model chip icon follows. - Also fixed a pre-existing dev-only breakage found while verifying: the tab-bar bounce animated three keyframes with a spring, which framer motion's dev build throws on - breaking client updates in the dev instance (library tab switching, sheet Escape). It now uses a tween. - Dev metadata keeps the Apple icons in both branches. - SW -> freezmo-v35.
This commit is contained in:
parent
95643fa009
commit
8a3bef0add
9 changed files with 192 additions and 75 deletions
59
components/chat/SidebarChatSection.tsx
Normal file
59
components/chat/SidebarChatSection.tsx
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
"use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState, useSyncExternalStore } from "react";
|
||||
|
||||
import { ChatHistoryList } from "./HistoryPanel";
|
||||
import { chatActive } from "@/lib/chat-active";
|
||||
import { chatHistoryStore, deleteConversation, renameConversation, saveConversation } from "@/lib/chat-store";
|
||||
import { useI18n } from "@/lib/i18n";
|
||||
import { showToast } from "@/lib/toast";
|
||||
import type { ChatConversation } from "@/lib/schemas";
|
||||
|
||||
/**
|
||||
* Chat history inside the main sidebar: when the Chat section is active the
|
||||
* deck navigation is replaced by the chat list (search, new chat, items with
|
||||
* rename/delete). Collapsed, it keeps one New-chat icon row.
|
||||
*/
|
||||
export function SidebarChatSection({ collapsed }: { collapsed: boolean }) {
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const conversations = useSyncExternalStore(
|
||||
chatHistoryStore.subscribe,
|
||||
chatHistoryStore.getSnapshot,
|
||||
chatHistoryStore.getServerSnapshot,
|
||||
);
|
||||
const activeId = useSyncExternalStore(chatActive.subscribe, chatActive.getSnapshot, chatActive.getServerSnapshot);
|
||||
const [query, setQuery] = useState("");
|
||||
|
||||
const onDelete = (conversation: ChatConversation) => {
|
||||
deleteConversation(conversation.id);
|
||||
showToast({
|
||||
message: t("chat.deletedChat"),
|
||||
actionLabel: t("toast.undo"),
|
||||
onAction: () => saveConversation(conversation),
|
||||
});
|
||||
};
|
||||
|
||||
// Collapsed, the list needs width — the highlighted Chat row above (and the
|
||||
// expand chevron) already cover navigation, so the section renders nothing.
|
||||
if (collapsed) return null;
|
||||
|
||||
return (
|
||||
<div className="flex min-h-0 flex-1 flex-col">
|
||||
<h2 className="px-2 pb-1 pt-1 text-[11px] font-semibold uppercase tracking-wider text-[var(--text-subtle)]">
|
||||
{t("chat.history")}
|
||||
</h2>
|
||||
<ChatHistoryList
|
||||
conversations={conversations}
|
||||
currentId={activeId}
|
||||
query={query}
|
||||
onQueryChange={setQuery}
|
||||
onOpen={(id) => router.push(`/chat?c=${id}`)}
|
||||
onRename={renameConversation}
|
||||
onDelete={onDelete}
|
||||
onNew={() => router.push("/chat")}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue