feat(dashboard): tableau de bord Second Brain configurable avec chargement progressif
Briefing granulaire, pistes rapides puis enrichissement async, layout persisté v5, suggestions agents, intégration Gmail et navigation sidebar alignée sur /home. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useLanguage } from '@/lib/i18n'
|
||||
import { motion } from 'motion/react'
|
||||
import { Zap, Lightbulb, Trophy } from 'lucide-react'
|
||||
|
||||
@@ -32,6 +33,7 @@ interface BridgeNotesDashboardProps {
|
||||
}
|
||||
|
||||
export function BridgeNotesDashboard({ onNoteClick, clusters }: BridgeNotesDashboardProps) {
|
||||
const { t } = useLanguage()
|
||||
const [bridgeNotes, setBridgeNotes] = useState<BridgeNote[]>([])
|
||||
const [suggestions, setSuggestions] = useState<BridgeSuggestion[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
@@ -109,14 +111,14 @@ export function BridgeNotesDashboard({ onNoteClick, clusters }: BridgeNotesDashb
|
||||
<div className="p-5 rounded-2xl bg-white dark:bg-white/5 border border-border shadow-sm">
|
||||
<div className="flex items-center gap-2 text-indigo-500 mb-2">
|
||||
<Trophy size={14} />
|
||||
<span className="text-[10px] font-bold uppercase tracking-widest">Bridges</span>
|
||||
<span className="text-[10px] font-bold uppercase tracking-widest">{t('bridgeNotes.bridges')}</span>
|
||||
</div>
|
||||
<div className="text-3xl font-memento-serif font-medium text-ink dark:text-dark-ink">{bridgeNotes.length}</div>
|
||||
</div>
|
||||
<div className="p-5 rounded-2xl bg-white dark:bg-white/5 border border-border shadow-sm">
|
||||
<div className="flex items-center gap-2 text-ochre mb-2">
|
||||
<Lightbulb size={14} />
|
||||
<span className="text-[10px] font-bold uppercase tracking-widest">Suggestions</span>
|
||||
<span className="text-[10px] font-bold uppercase tracking-widest">{t('bridgeNotes.suggestions')}</span>
|
||||
</div>
|
||||
<div className="text-3xl font-memento-serif font-medium text-ink dark:text-dark-ink">{suggestions.length}</div>
|
||||
</div>
|
||||
@@ -126,7 +128,7 @@ export function BridgeNotesDashboard({ onNoteClick, clusters }: BridgeNotesDashb
|
||||
<section>
|
||||
<div className="flex items-center gap-2 mb-6 px-1">
|
||||
<Zap size={16} className="text-ochre" />
|
||||
<h3 className="text-sm font-bold uppercase tracking-widest text-ink dark:text-dark-ink">Powerful Bridge Notes</h3>
|
||||
<h3 className="text-sm font-bold uppercase tracking-widest text-ink dark:text-dark-ink">{t('bridgeNotes.powerfulTitle')}</h3>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{bridgeNotes.map((bridge) => (
|
||||
@@ -138,10 +140,10 @@ export function BridgeNotesDashboard({ onNoteClick, clusters }: BridgeNotesDashb
|
||||
>
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h4 className="text-sm font-medium text-ink dark:text-dark-ink truncate flex-1">
|
||||
{bridge.note?.title || 'Untitled'}
|
||||
{bridge.note?.title || t('common.untitled')}
|
||||
</h4>
|
||||
<span className="text-[10px] font-bold text-ochre bg-ochre/10 px-2 py-0.5 rounded-full">
|
||||
Score: {(bridge.bridgeScore * 100).toFixed(0)}%
|
||||
{t('bridgeNotes.score')}: {(bridge.bridgeScore * 100).toFixed(0)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -158,7 +160,7 @@ export function BridgeNotesDashboard({ onNoteClick, clusters }: BridgeNotesDashb
|
||||
</motion.div>
|
||||
))}
|
||||
{bridgeNotes.length === 0 && (
|
||||
<div className="text-xs text-concrete italic p-4">No significant bridge notes found yet. Deepen your research to find new connections.</div>
|
||||
<div className="text-xs text-concrete italic p-4">{t('bridgeNotes.empty')}</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
@@ -167,7 +169,7 @@ export function BridgeNotesDashboard({ onNoteClick, clusters }: BridgeNotesDashb
|
||||
<section>
|
||||
<div className="flex items-center gap-2 mb-6 px-1">
|
||||
<Lightbulb size={16} className="text-indigo-500" />
|
||||
<h3 className="text-sm font-bold uppercase tracking-widest text-ink dark:text-dark-ink">Missing Links (AI Generated)</h3>
|
||||
<h3 className="text-sm font-bold uppercase tracking-widest text-ink dark:text-dark-ink">{t('bridgeNotes.missingLinks')}</h3>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
{suggestions.map((s, idx) => (
|
||||
@@ -180,7 +182,7 @@ export function BridgeNotesDashboard({ onNoteClick, clusters }: BridgeNotesDashb
|
||||
<div className="w-6 h-6 rounded-full border-2 border-paper bg-ochre flex items-center justify-center text-[10px] text-white">B</div>
|
||||
</div>
|
||||
<span className="text-[9px] font-bold uppercase tracking-widest text-indigo-500/60">
|
||||
Bridging {s.clusterAName} & {s.clusterBName}
|
||||
{t('bridgeNotes.bridging')} {s.clusterAName} & {s.clusterBName}
|
||||
</span>
|
||||
</div>
|
||||
<h4 className="text-base font-memento-serif font-medium text-ink dark:text-dark-ink mb-2">{s.suggestedTitle}</h4>
|
||||
@@ -193,7 +195,7 @@ export function BridgeNotesDashboard({ onNoteClick, clusters }: BridgeNotesDashb
|
||||
<button
|
||||
onClick={() => dismissSuggestion(s.clusterAId, s.clusterBId)}
|
||||
className="ml-4 p-2 text-concrete hover:text-ink dark:hover:text-dark-ink hover:bg-concrete/10 rounded-lg transition-colors"
|
||||
title="Dismiss suggestion"
|
||||
title={t('bridgeNotes.dismiss')}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
@@ -203,13 +205,13 @@ export function BridgeNotesDashboard({ onNoteClick, clusters }: BridgeNotesDashb
|
||||
{suggestions.length === 0 && !loading && (
|
||||
<div className="text-center py-8 text-concrete">
|
||||
<Lightbulb size={24} className="mx-auto mb-3 opacity-50" />
|
||||
<p className="text-sm">No connection suggestions yet</p>
|
||||
<p className="text-xs mt-1">All your clusters may already be connected!</p>
|
||||
<p className="text-sm">{t('bridgeNotes.noSuggestions')}</p>
|
||||
<p className="text-xs mt-1">{t('bridgeNotes.allConnected')}</p>
|
||||
<button
|
||||
onClick={generateNewSuggestions}
|
||||
className="mt-4 px-4 py-2 bg-indigo-500 text-white text-xs rounded-lg hover:bg-indigo-600 transition-colors"
|
||||
>
|
||||
Generate Suggestions
|
||||
{t('bridgeNotes.generate')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user