83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
import './Sidebar.css';
|
|
import { route } from 'preact-router';
|
|
import type { RecommendationSummary } from '../types/index.js';
|
|
|
|
interface SidebarProps {
|
|
list: RecommendationSummary[];
|
|
selectedId: string | null;
|
|
onSelect: (id: string) => void;
|
|
onNewClick: () => void;
|
|
}
|
|
|
|
function statusIcon(status: RecommendationSummary['status']): string {
|
|
switch (status) {
|
|
case 'done': return '✓';
|
|
case 'error': return '✗';
|
|
case 'running': return '⟳';
|
|
default: return '…';
|
|
}
|
|
}
|
|
|
|
function statusClass(status: RecommendationSummary['status']): string {
|
|
switch (status) {
|
|
case 'done': return 'status-done';
|
|
case 'error': return 'status-error';
|
|
case 'running': return 'status-running';
|
|
default: return 'status-pending';
|
|
}
|
|
}
|
|
|
|
export function Sidebar({ list, selectedId, onSelect, onNewClick }: SidebarProps) {
|
|
return (
|
|
<aside class="sidebar">
|
|
<div class="sidebar-header">
|
|
<a
|
|
href="/"
|
|
class="sidebar-title"
|
|
onClick={(event) => {
|
|
event.preventDefault();
|
|
route('/');
|
|
}}
|
|
>
|
|
Recommender
|
|
</a>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
class="btn-new"
|
|
onClick={(event) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
onNewClick();
|
|
}}
|
|
>
|
|
+ New Recommendation
|
|
</button>
|
|
|
|
<div class="sidebar-section-label">History</div>
|
|
|
|
<ul class="sidebar-list">
|
|
{list.length === 0 && (
|
|
<li class="sidebar-empty">No recommendations yet</li>
|
|
)}
|
|
{list.map((item) => (
|
|
<li
|
|
key={item.id}
|
|
class={`sidebar-item${selectedId === item.id ? ' selected' : ''}`}
|
|
onClick={() => onSelect(item.id)}
|
|
>
|
|
<span class={`sidebar-icon ${statusClass(item.status)}`}>
|
|
{statusIcon(item.status)}
|
|
</span>
|
|
<span class="sidebar-item-title">{item.title}</span>
|
|
<span class={`sidebar-type-badge sidebar-type-${item.media_type}`}>
|
|
{item.media_type === 'movie' ? 'Film' : 'TV'}
|
|
</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</aside>
|
|
);
|
|
}
|