feat: hierarchical notebook system - trash, selectors, breadcrumb, sidebar tree
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m9s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m9s
- Schema: soft delete with trashedAt on Notebook model - API: PATCH/GET notebooks support trashedAt filtering with cascade - Sidebar: recursive tree rendering with collapse/expand, visual guides, hover actions - HierarchicalNotebookSelector: portal-based dropdown with search, breadcrumbs, dropUp support - AI chat: context selector with Toutes mes notes + notebook selector - Agent detail: flat selects replaced with HierarchicalNotebookSelector - Breadcrumb: notebook path display on home page - Trash view: card grid with countdown, restore/permanent delete - CSS: design tokens (ink, paper, blueprint, concrete, etc.) - Types: parentId, trashedAt added to Notebook interface
This commit is contained in:
@@ -46,6 +46,7 @@ import {
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { getNotebookIcon } from '@/lib/notebook-icon'
|
||||
import { HierarchicalNotebookSelector } from '@/components/hierarchical-notebook-selector'
|
||||
import { scrapePageText } from '@/app/actions/scrape'
|
||||
|
||||
// ── Helpers ──────────────────────────────────────────────────────────────────
|
||||
@@ -111,7 +112,7 @@ interface ContextualAIChatProps {
|
||||
/** Whether the last action has been applied (so we can show undo) */
|
||||
lastActionApplied?: boolean
|
||||
/** Notebooks available for scope selection */
|
||||
notebooks?: Array<{ id: string; name: string }>
|
||||
notebooks?: Array<{ id: string; name: string; parentId?: string | null; trashedAt?: any }>
|
||||
/** Extra classes forwarded to the aside root element */
|
||||
className?: string
|
||||
/** How to embed generated diagram images (markdown vs rich text HTML) */
|
||||
@@ -679,21 +680,32 @@ export function ContextualAIChat({
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-3">
|
||||
<label className="text-[10px] uppercase tracking-[0.25em] font-bold text-foreground/40 px-1">CONTEXTE</label>
|
||||
<Select value={chatScope} onValueChange={setChatScope}>
|
||||
<SelectTrigger className="w-full h-10 px-3 bg-card/60 backdrop-blur-sm border border-border rounded-xl text-[11px] flex items-center justify-between cursor-pointer hover:border-foreground/20 transition-all outline-none ring-0 shadow-sm text-foreground">
|
||||
<div className="flex items-center gap-2">
|
||||
<BookOpen size={14} className="text-foreground/40" />
|
||||
<SelectValue />
|
||||
</div>
|
||||
</SelectTrigger>
|
||||
<SelectContent className="rounded-xl border-border shadow-xl bg-background">
|
||||
<SelectItem value="note" className="text-[11px] py-2.5 uppercase tracking-wider font-bold">Cette note</SelectItem>
|
||||
<SelectItem value="all" className="text-[11px] py-2.5 uppercase tracking-wider font-bold">Tout Momento</SelectItem>
|
||||
{notebooks.map(nb => (
|
||||
<SelectItem key={nb.id} value={nb.id} className="text-[11px] py-2.5 uppercase tracking-wider font-bold">{nb.name}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div className="flex flex-col gap-2">
|
||||
<button
|
||||
onClick={() => setChatScope('note')}
|
||||
className={cn(
|
||||
'w-full p-3 border rounded-lg text-xs flex items-center gap-2 transition-all',
|
||||
chatScope === 'note' ? 'bg-blueprint/10 border-blueprint/30 text-blueprint font-bold' : 'bg-card/60 border-border hover:border-foreground/20 text-foreground/60'
|
||||
)}
|
||||
>
|
||||
<BookOpen size={14} className="text-blueprint/60" />
|
||||
<span>{t('ai.activeNote') || 'Cette note'}</span>
|
||||
<span className="ml-auto text-[8px] bg-blueprint/10 text-blueprint px-1.5 py-0.5 rounded uppercase font-bold">Auto</span>
|
||||
</button>
|
||||
<div className="flex items-center gap-2 px-2">
|
||||
<div className="h-px flex-1 bg-border/40" />
|
||||
<span className="text-[9px] font-bold text-muted-foreground uppercase tracking-widest">+ Carnet</span>
|
||||
<div className="h-px flex-1 bg-border/40" />
|
||||
</div>
|
||||
<HierarchicalNotebookSelector
|
||||
notebooks={(notebooks || []).filter(nb => !nb.trashedAt)}
|
||||
selectedId={chatScope !== 'note' && chatScope !== 'all' ? chatScope : null}
|
||||
onSelect={(id) => setChatScope(id)}
|
||||
placeholder="Inclure un carnet..."
|
||||
className="w-full"
|
||||
dropUp
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<label className="text-[10px] uppercase tracking-[0.25em] font-bold text-foreground/40 px-1">TON D'ÉCRITURE</label>
|
||||
|
||||
Reference in New Issue
Block a user