Co-authored-by: gobha <jasafpro@gmail.com> Co-committed-by: gobha <jasafpro@gmail.com>
110 lines
4.4 KiB
JavaScript
110 lines
4.4 KiB
JavaScript
// ==========================================
|
|
// Chat Surface — Sidebar Component
|
|
// ==========================================
|
|
// Search bar, new chat, channels section, chats section with folders.
|
|
// Footer has UserMenu (avatar) — all navigation lives in the menu flyout.
|
|
|
|
import { SidebarChannels } from './sidebar-channels.js';
|
|
import { SidebarChats } from './sidebar-chats.js';
|
|
import { UserMenu } from '../../shell/user-menu.js';
|
|
|
|
const html = window.html;
|
|
const { useCallback } = window.hooks;
|
|
|
|
const PLUS_SVG = html`
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="12" y1="5" x2="12" y2="19"/>
|
|
<line x1="5" y1="12" x2="19" y2="12"/>
|
|
</svg>`;
|
|
|
|
const SEARCH_SVG = html`
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="11" cy="11" r="8"/>
|
|
<line x1="21" y1="21" x2="16.65" y2="16.65"/>
|
|
</svg>`;
|
|
|
|
const COLLAPSE_SVG = html`
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<rect x="3" y="3" width="18" height="18" rx="2"/>
|
|
<line x1="9" y1="3" x2="9" y2="21"/>
|
|
</svg>`;
|
|
|
|
/**
|
|
* @param {{
|
|
* sidebar: ReturnType<import('./use-sidebar.js').useSidebar>,
|
|
* activeId: string|null,
|
|
* onSelectChat: (id: string) => void,
|
|
* onSelectChannel: (id: string) => void,
|
|
* onNewChat: () => void,
|
|
* onCollapse: () => void,
|
|
* }} props
|
|
*/
|
|
export function Sidebar({ sidebar, activeId, onSelectChat, onSelectChannel, onNewChat, onCollapse }) {
|
|
const _onSearch = useCallback((e) => {
|
|
sidebar.setSearch(e.target.value);
|
|
}, [sidebar.setSearch]);
|
|
|
|
return html`
|
|
<div class="sw-chat-surface__sidebar" role="navigation" aria-label="Chat sidebar">
|
|
${/* Header: new chat + collapse */''}
|
|
<div class="sw-chat-surface__sidebar-header">
|
|
<button class="sw-chat-surface__new-chat-btn"
|
|
onClick=${onNewChat}
|
|
title="New chat"
|
|
aria-label="Start new chat">
|
|
${PLUS_SVG}
|
|
<span>New Chat</span>
|
|
</button>
|
|
<button class="sw-chat-surface__collapse-btn"
|
|
onClick=${onCollapse}
|
|
title="Collapse sidebar"
|
|
aria-label="Collapse sidebar">
|
|
${COLLAPSE_SVG}
|
|
</button>
|
|
</div>
|
|
|
|
${/* Search */''}
|
|
<div class="sw-chat-surface__search-wrap">
|
|
<span class="sw-chat-surface__search-icon">${SEARCH_SVG}</span>
|
|
<input class="sw-chat-surface__search"
|
|
type="text"
|
|
placeholder="Search\u2026"
|
|
value=${sidebar.search}
|
|
onInput=${_onSearch}
|
|
aria-label="Search chats and channels" />
|
|
</div>
|
|
|
|
${/* Scrollable content */''}
|
|
<div class="sw-chat-surface__sidebar-body">
|
|
<${SidebarChannels}
|
|
channels=${sidebar.channels}
|
|
activeId=${activeId}
|
|
collapsed=${sidebar.collapsed.channels}
|
|
onToggle=${() => sidebar.toggleCollapsed('channels')}
|
|
onSelect=${onSelectChannel} />
|
|
|
|
<${SidebarChats}
|
|
chatsByFolder=${sidebar.chatsByFolder}
|
|
folders=${sidebar.folders}
|
|
activeId=${activeId}
|
|
collapsed=${sidebar.collapsed.chats}
|
|
onToggle=${() => sidebar.toggleCollapsed('chats')}
|
|
onSelect=${onSelectChat}
|
|
onRename=${sidebar.renameChat}
|
|
onDelete=${sidebar.deleteChat}
|
|
onMoveToFolder=${sidebar.moveToFolder}
|
|
onCreateFolder=${sidebar.createFolder}
|
|
onRenameFolder=${sidebar.renameFolder}
|
|
onDeleteFolder=${sidebar.deleteFolder} />
|
|
</div>
|
|
|
|
${/* Footer: UserMenu only */''}
|
|
<div class="sw-chat-surface__sidebar-footer">
|
|
<${UserMenu} placement="up-right" />
|
|
</div>
|
|
</div>`;
|
|
}
|