fix(ui): thème, textes et lisibilité restants de la revue
Les boutons suivent la couleur d’apparence, les libellés trop petits ou trop techniques sont clarifiés, et le catalogue des fournisseurs se met à jour tout seul. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import { useLanguage } from '@/lib/i18n'
|
||||
import { RevisionHeatmap } from '@/components/flashcards/revision-heatmap'
|
||||
import { UsageMeter } from '@/components/usage-meter'
|
||||
import { DashboardWidgetTitleRow } from '@/components/dashboard-widget-title-row'
|
||||
import { pathNoteTitle } from '@/lib/dashboard/path-title'
|
||||
import type { DashboardWidgetId } from '@/lib/dashboard/layout'
|
||||
|
||||
interface DashboardWidgetShellProps {
|
||||
@@ -41,21 +42,40 @@ export function DashboardWidgetShell({
|
||||
)
|
||||
}
|
||||
|
||||
function inboxDisplayTitle(
|
||||
note: { title: string | null; excerpt?: string },
|
||||
fallback: string,
|
||||
): string {
|
||||
const titled = note.title?.trim()
|
||||
if (titled) return titled
|
||||
const excerpt = note.excerpt?.trim()
|
||||
if (!excerpt) return fallback
|
||||
return excerpt.length > 80 ? `${excerpt.slice(0, 80).trim()}…` : excerpt
|
||||
}
|
||||
|
||||
export function DashboardInboxWidget({
|
||||
count,
|
||||
notes,
|
||||
loading,
|
||||
onOpen,
|
||||
onSelect,
|
||||
formatRelativeTime,
|
||||
}: {
|
||||
count: number
|
||||
notes: Array<{ id: string; title: string | null; notebookId: string | null }>
|
||||
notes: Array<{
|
||||
id: string
|
||||
title: string | null
|
||||
excerpt?: string
|
||||
notebookId: string | null
|
||||
updatedAt?: string
|
||||
}>
|
||||
loading: boolean
|
||||
onOpen: () => void
|
||||
onSelect: (id: string, notebookId: string | null) => void
|
||||
formatRelativeTime?: (date: string) => string
|
||||
}) {
|
||||
const { t } = useLanguage()
|
||||
const reduced = !!useReducedMotion()
|
||||
const untitled = t('homeDashboard.untitled')
|
||||
return (
|
||||
<DashboardWidgetShell
|
||||
widgetId="inbox"
|
||||
@@ -83,21 +103,22 @@ export function DashboardInboxWidget({
|
||||
className="w-full text-start p-2.5 rounded-xl border border-border/20 hover:border-brand-accent/30 hover:bg-brand-accent/[0.03] transition-all"
|
||||
>
|
||||
<p className="text-[11px] text-ink dark:text-dark-ink truncate">
|
||||
{note.title || t('homeDashboard.untitled')}
|
||||
{inboxDisplayTitle(note, untitled)}
|
||||
</p>
|
||||
<p className="text-[9px] text-concrete truncate mt-0.5">
|
||||
{t('homeDashboard.inbox')}
|
||||
{note.updatedAt && formatRelativeTime
|
||||
? ` · ${formatRelativeTime(note.updatedAt)}`
|
||||
: ''}
|
||||
</p>
|
||||
</motion.button>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
onClick={onOpen}
|
||||
className="w-full flex items-center justify-between gap-2 px-1 pt-1 text-start"
|
||||
className="w-full text-start px-1 pt-1 text-[9px] font-mono uppercase font-bold text-brand-accent hover:underline"
|
||||
>
|
||||
<span className="text-[9px] font-mono uppercase font-bold text-concrete">
|
||||
{t('homeDashboard.inboxSeeAll', { count })}
|
||||
</span>
|
||||
<span className="text-[9px] font-mono uppercase font-bold text-brand-accent">
|
||||
{t('homeDashboard.widgetOpen')} →
|
||||
</span>
|
||||
{t('homeDashboard.inboxOpenList')} →
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
@@ -278,12 +299,22 @@ export function DashboardPinnedWidget({
|
||||
notes,
|
||||
loading,
|
||||
onSelect,
|
||||
formatRelativeTime,
|
||||
}: {
|
||||
notes: { id: string; title: string | null; notebookId: string | null }[]
|
||||
notes: {
|
||||
id: string
|
||||
title: string | null
|
||||
excerpt?: string
|
||||
notebookId: string | null
|
||||
updatedAt?: string
|
||||
notebook?: { name: string; color: string | null } | null
|
||||
}[]
|
||||
loading: boolean
|
||||
onSelect: (id: string, notebookId: string | null) => void
|
||||
formatRelativeTime?: (date: string) => string
|
||||
}) {
|
||||
const { t } = useLanguage()
|
||||
const untitled = t('homeDashboard.untitled')
|
||||
return (
|
||||
<DashboardWidgetShell
|
||||
widgetId="pinned"
|
||||
@@ -298,17 +329,37 @@ export function DashboardPinnedWidget({
|
||||
) : notes.length === 0 ? (
|
||||
<p className="text-[10px] text-concrete italic py-2">{t('homeDashboard.widgetPinnedEmpty')}</p>
|
||||
) : (
|
||||
<div className="space-y-1">
|
||||
{notes.map(n => (
|
||||
<button
|
||||
key={n.id}
|
||||
type="button"
|
||||
onClick={() => onSelect(n.id, n.notebookId)}
|
||||
className="w-full text-[10px] text-ink dark:text-dark-ink truncate text-start p-2 rounded-lg hover:bg-brand-accent/[0.04] transition-colors"
|
||||
>
|
||||
{n.title || t('homeDashboard.untitled')}
|
||||
</button>
|
||||
))}
|
||||
<div className="space-y-1.5">
|
||||
{notes.map(n => {
|
||||
const displayTitle = pathNoteTitle(n.title, n.excerpt) || untitled
|
||||
const notebookName = n.notebook?.name || t('homeDashboard.pinnedNoNotebook')
|
||||
const notebookColor = n.notebook?.color || '#C4A574'
|
||||
return (
|
||||
<button
|
||||
key={n.id}
|
||||
type="button"
|
||||
onClick={() => onSelect(n.id, n.notebookId)}
|
||||
className="w-full flex items-center gap-2.5 p-2 rounded-xl border border-border/20 hover:border-brand-accent/30 hover:bg-brand-accent/[0.03] transition-all text-start group"
|
||||
>
|
||||
<span
|
||||
className="w-1 h-7 rounded-full shrink-0"
|
||||
style={{ backgroundColor: notebookColor }}
|
||||
aria-hidden
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-[11px] text-ink dark:text-dark-ink truncate group-hover:text-brand-accent transition-colors">
|
||||
{displayTitle}
|
||||
</p>
|
||||
<p className="text-[9px] text-concrete truncate mt-0.5">
|
||||
{notebookName}
|
||||
{n.updatedAt && formatRelativeTime
|
||||
? ` · ${formatRelativeTime(n.updatedAt)}`
|
||||
: ''}
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</DashboardWidgetShell>
|
||||
@@ -338,8 +389,7 @@ export function DashboardActivityWidget({
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<RevisionHeatmap data={data} />
|
||||
<p className="text-[9px] text-concrete mt-2">{t('homeDashboard.widgetActivityHint')}</p>
|
||||
<RevisionHeatmap data={data} kind="edits" />
|
||||
</>
|
||||
)}
|
||||
</DashboardWidgetShell>
|
||||
@@ -426,15 +476,12 @@ export function DashboardFlashcardsProgressWidget({
|
||||
style={{ width: `${retention}%` }}
|
||||
/>
|
||||
</div>
|
||||
{dueCount > 0 ? (
|
||||
<p className="text-[10px] font-medium text-brand-accent group-hover:underline">
|
||||
{t('homeDashboard.flashDueCta', { count: dueCount })} →
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-[9px] text-concrete group-hover:text-brand-accent transition-colors">
|
||||
{t('homeDashboard.flashOpenCta')} →
|
||||
</p>
|
||||
)}
|
||||
<p className="text-[9px] text-concrete leading-relaxed mb-2">
|
||||
{t('homeDashboard.flashRetentionHint')}
|
||||
</p>
|
||||
<p className="text-[10px] font-medium text-brand-accent group-hover:underline">
|
||||
{dueCount > 0 ? t('homeDashboard.flashDueCta') : t('homeDashboard.flashOpenCta')} →
|
||||
</p>
|
||||
</button>
|
||||
)}
|
||||
</DashboardWidgetShell>
|
||||
|
||||
Reference in New Issue
Block a user