Files
Momento/memento-note/components/structured-views/notes-gallery-view.tsx
Antigravity e9e829e579
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 5m15s
CI / Deploy production (on server) (push) Successful in 37s
fix: TOUTES les clés i18n manquantes ajoutées — 0 erreur
- general.continue/send
- structuredViews.tagApplied/filterDone/filterTodo/propertyStatus
- wizard.taskA/taskB
- richTextEditor.preview*Tip (7 clés SlashPreview)
- wizard.* au niveau racine (48 clés FR + 48 EN)
- Total: 0 clé manquante pour FR et EN
- 0 erreur TypeScript
2026-06-20 17:01:04 +00:00

131 lines
4.2 KiB
TypeScript

'use client'
import { useState } from 'react'
import type { Note } from '@/lib/types'
import type { NotebookSchemaPayload, NotePropertyValues } from '@/lib/structured-views/types'
import { formatPropertyDisplay } from '@/lib/structured-views/property-utils'
import { getNoteDisplayTitle, getNoteFeedImage } from '@/lib/note-preview'
import { useLanguage } from '@/lib/i18n'
import { sanitizeIllustrationSvg } from '@/lib/sanitize-content'
type NotesGalleryViewProps = {
notes: Note[]
schema: NotebookSchemaPayload
noteValues: Record<string, NotePropertyValues>
notebookColor?: string | null
onOpen: (note: Note) => void
}
export function NotesGalleryView({
notes,
schema,
noteValues,
notebookColor,
onOpen,
}: NotesGalleryViewProps) {
const { t } = useLanguage()
const untitled = t('notes.untitled')
const previewProps = schema.properties.slice(0, 2)
return (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 max-w-7xl mx-auto">
{notes.map((note) => (
<GalleryCard
key={note.id}
note={note}
title={getNoteDisplayTitle(note, untitled)}
image={getNoteFeedImage(note)}
notebookColor={notebookColor}
previewProps={previewProps}
allProps={schema.properties}
values={noteValues[note.id] ?? {}}
onOpen={() => onOpen(note)}
/>
))}
</div>
)
}
function GalleryCard({
note,
title,
image,
notebookColor,
previewProps,
allProps,
values,
onOpen,
}: {
note: Note
title: string
image: string | null
notebookColor?: string | null
previewProps: NotebookSchemaPayload['properties']
allProps: NotebookSchemaPayload['properties']
values: NotePropertyValues
onOpen: () => void
}) {
const [hover, setHover] = useState(false)
const accent = notebookColor || '#A47148'
return (
<button
type="button"
onClick={onOpen}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
className="text-left rounded-2xl border border-border/40 bg-card/40 overflow-hidden shadow-sm hover:shadow-md hover:border-border transition-all group"
>
<div
className="aspect-[4/3] relative overflow-hidden"
style={{ backgroundColor: `${accent}18` }}
>
{image ? (
<img src={image} alt="" className="w-full h-full object-cover grayscale group-hover:grayscale-0 transition-all duration-500" />
) : note.illustrationSvg ? (
<div
className="w-full h-full p-4 [&_svg]:w-full [&_svg]:h-full opacity-80"
dangerouslySetInnerHTML={{ __html: sanitizeIllustrationSvg(note.illustrationSvg) }}
/>
) : (
<div className="absolute inset-0 flex items-center justify-center">
<span
className="font-memento-serif text-4xl opacity-20"
style={{ color: accent }}
>
{title.charAt(0).toUpperCase()}
</span>
</div>
)}
</div>
<div className="p-4 space-y-2">
<h3 className="font-memento-serif text-[15px] font-medium line-clamp-2 group-hover:text-brand-accent transition-colors">
{title}
</h3>
{!hover && previewProps.length > 0 && (
<div className="space-y-1">
{previewProps.map((p) => (
<div key={p.id} className="flex gap-2 text-[11px]">
<span className="text-muted-foreground shrink-0">{p.name}:</span>
<span className="truncate">{formatPropertyDisplay(p.type, values[p.id])}</span>
</div>
))}
</div>
)}
{hover && allProps.length > 0 ? (
<div className="space-y-1.5 pt-1 border-t border-border/30">
{allProps.map((p) => (
<div key={p.id} className="flex justify-between gap-2 text-[11px]">
<span className="text-muted-foreground">{p.name}</span>
<span className="font-medium text-right truncate max-w-[55%]">
{formatPropertyDisplay(p.type, values[p.id])}
</span>
</div>
))}
</div>
) : null}
</div>
</button>
)
}