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
This commit is contained in:
@@ -118,7 +118,7 @@ export function HomeClient({
|
||||
const searchDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
const notesRef = useRef(notes)
|
||||
notesRef.current = notes
|
||||
const { labels, notebooks, refreshNotebooks } = useNotebooks()
|
||||
const { labels, notebooks, refreshNotebooks, moveNoteToNotebookOptimistic } = useNotebooks()
|
||||
const labelsRef = useRef(labels)
|
||||
labelsRef.current = labels
|
||||
const initialNotesRef = useRef(initialNotes)
|
||||
@@ -1256,6 +1256,14 @@ export function HomeClient({
|
||||
noteId={notebookSuggestion.noteId}
|
||||
noteContent={notebookSuggestion.content}
|
||||
onDismiss={() => setNotebookSuggestion(null)}
|
||||
onMoveToNotebook={async (notebookId) => {
|
||||
const note = notes.find((n) => n.id === notebookSuggestion.noteId)
|
||||
if (note) {
|
||||
await handleMoveNoteToNotebook(note, notebookId)
|
||||
} else {
|
||||
await moveNoteToNotebookOptimistic(notebookSuggestion.noteId, notebookId)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog'
|
||||
import { ExternalLink, Link2, Columns2, GitMerge, Loader2, X } from 'lucide-react'
|
||||
import { useLanguage } from '@/lib/i18n/LanguageProvider'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { sanitizeRichHtml } from '@/lib/sanitize-content'
|
||||
|
||||
interface LinkedNotePreviewDialogProps {
|
||||
isOpen: boolean
|
||||
@@ -117,7 +118,7 @@ export function LinkedNotePreviewDialog({
|
||||
'prose-headings:text-sm prose-headings:font-semibold prose-headings:mt-3 prose-headings:mb-1',
|
||||
'prose-li:text-sm prose-table:text-xs'
|
||||
)}
|
||||
dangerouslySetInnerHTML={{ __html: content }}
|
||||
dangerouslySetInnerHTML={{ __html: sanitizeRichHtml(content) }}
|
||||
/>
|
||||
)}
|
||||
{!isHtml && plainBody && (
|
||||
|
||||
@@ -93,9 +93,11 @@ export function NotebookSuggestionToast({
|
||||
if (!suggestion) return
|
||||
|
||||
try {
|
||||
// Move note to suggested notebook
|
||||
await moveNoteToNotebookOptimistic(noteId, suggestion.id)
|
||||
// No need for router.refresh() - triggerRefresh() is already called in moveNoteToNotebookOptimistic
|
||||
if (onMoveToNotebook) {
|
||||
await onMoveToNotebook(suggestion.id)
|
||||
} else {
|
||||
await moveNoteToNotebookOptimistic(noteId, suggestion.id)
|
||||
}
|
||||
handleDismiss()
|
||||
} catch (error) {
|
||||
console.error('Failed to move note to notebook:', error)
|
||||
|
||||
@@ -26,6 +26,7 @@ import { toast } from 'sonner'
|
||||
import { fr } from 'date-fns/locale/fr'
|
||||
import { enUS } from 'date-fns/locale/en-US'
|
||||
import { formatAbsoluteDateLocalized } from '@/lib/utils/format-localized-date'
|
||||
import { sanitizeIllustrationSvg } from '@/lib/sanitize-content'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useHydrated } from '@/lib/use-hydrated'
|
||||
|
||||
@@ -282,7 +283,7 @@ function EditorialThumbnail({
|
||||
<div
|
||||
className="w-full h-full flex items-center justify-center bg-muted/30 p-2 [&_svg]:max-w-full [&_svg]:max-h-full [&_svg]:w-auto [&_svg]:h-auto"
|
||||
// SVG déjà sanitisé côté serveur (note-illustration.ts)
|
||||
dangerouslySetInnerHTML={{ __html: note.illustrationSvg }}
|
||||
dangerouslySetInnerHTML={{ __html: sanitizeIllustrationSvg(note.illustrationSvg) }}
|
||||
aria-hidden
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -25,6 +25,7 @@ import type { Note } from '@/lib/types'
|
||||
import { NotesEditorialView } from '@/components/notes-editorial-view'
|
||||
import type { NoteCollectionActions } from '@/lib/note-change-sync'
|
||||
import { getNoteDisplayTitle, getNoteFeedImage, getNotePlainExcerpt, prepareNoteIllustrationForGrid } from '@/lib/note-preview'
|
||||
import { sanitizeIllustrationSvg } from '@/lib/sanitize-content'
|
||||
import { useLanguage } from '@/lib/i18n'
|
||||
import { useNotebooks } from '@/context/notebooks-context'
|
||||
import { useLabelsQuery } from '@/lib/query-hooks'
|
||||
@@ -209,7 +210,7 @@ function NoteGridThumbnail({
|
||||
<>
|
||||
<div
|
||||
className="absolute inset-0 w-full h-full overflow-hidden bg-[#F5F0E8] dark:bg-muted/30"
|
||||
dangerouslySetInnerHTML={{ __html: prepareNoteIllustrationForGrid(note.illustrationSvg) }}
|
||||
dangerouslySetInnerHTML={{ __html: sanitizeIllustrationSvg(prepareNoteIllustrationForGrid(note.illustrationSvg)) }}
|
||||
aria-hidden
|
||||
/>
|
||||
{aiIllustrationEnabled && (
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { NotebookSchemaPayload, NotePropertyValues } from '@/lib/structured
|
||||
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[]
|
||||
@@ -84,7 +85,7 @@ function GalleryCard({
|
||||
) : note.illustrationSvg ? (
|
||||
<div
|
||||
className="w-full h-full p-4 [&_svg]:w-full [&_svg]:h-full opacity-80"
|
||||
dangerouslySetInnerHTML={{ __html: note.illustrationSvg }}
|
||||
dangerouslySetInnerHTML={{ __html: sanitizeIllustrationSvg(note.illustrationSvg) }}
|
||||
/>
|
||||
) : (
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
|
||||
Reference in New Issue
Block a user