Files
Momento/memento-note/components/note-editor/note-content-area.tsx

141 lines
4.7 KiB
TypeScript

'use client'
import { useNoteEditorContext } from './note-editor-context'
import { RichTextEditor } from '@/components/rich-text-editor'
import { MarkdownContent } from '@/components/markdown-content'
import { MarkdownSlashCommands } from '@/components/markdown-slash-commands'
import { GhostTags } from '@/components/ghost-tags'
import { Textarea } from '@/components/ui/textarea'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Checkbox } from '@/components/ui/checkbox'
import { X, Plus } from 'lucide-react'
import { useLanguage } from '@/lib/i18n'
import { cn } from '@/lib/utils'
export function NoteContentArea() {
const { state, actions, readOnly, fullPage, textareaRef, note, richTextEditorRef } = useNoteEditorContext()
const { t } = useLanguage()
const uploadImageFile = async (file: File) => {
const formData = new FormData()
formData.append('file', file)
const response = await fetch('/api/upload', { method: 'POST', body: formData })
if (!response.ok) throw new Error('Upload failed')
const data = await response.json()
return data.url
}
// Markdown preview mode
if (state.isMarkdown && state.showMarkdownPreview) {
return (
<div
className={cn(
'min-h-[280px] cursor-text prose prose-lg dark:prose-invert max-w-none leading-relaxed',
fullPage ? '' : 'p-3 rounded-md border border-border/40 bg-muted/20'
)}
onClick={() => !readOnly && actions.setShowMarkdownPreview(false)}
>
<MarkdownContent content={state.content} />
{!readOnly && (
<p className="text-[11px] text-foreground/30 mt-8 select-none not-prose italic">
Cliquez pour éditer
</p>
)}
</div>
)
}
// Markdown edit mode
if (state.isMarkdown) {
if (fullPage) {
return (
<div className="relative">
<textarea
ref={textareaRef}
dir="auto"
placeholder={t('notes.takeNote') || "Commencez à écrire… tapez '/' pour les commandes"}
value={state.content}
onFocus={() => actions.setShowMarkdownPreview(false)}
onChange={(e) => actions.setContent(e.target.value)}
disabled={readOnly}
className="w-full min-h-[280px] border-0 outline-none px-0 bg-transparent editor-body leading-relaxed resize-none overflow-hidden placeholder:text-foreground/30 text-foreground"
/>
{!readOnly && (
<MarkdownSlashCommands
textareaRef={textareaRef as React.RefObject<HTMLTextAreaElement>}
value={state.content}
onChange={(v: string) => actions.setContent(v)}
/>
)}
</div>
)
}
return (
<div className="space-y-2">
<Textarea
dir="auto"
placeholder={t('notes.takeNoteMarkdown') || t('notes.takeNote')}
value={state.content}
onChange={(e) => actions.setContent(e.target.value)}
disabled={readOnly}
className={cn(
"min-h-[200px] border-0 focus-visible:ring-0 px-0 bg-transparent resize-none text-sm leading-relaxed",
readOnly && "cursor-default"
)}
/>
<GhostTags
suggestions={state.filteredSuggestions}
addedTags={state.labels}
isAnalyzing={state.isAnalyzingSuggestions}
onSelectTag={actions.handleSelectGhostTag}
onDismissTag={actions.handleDismissGhostTag}
/>
</div>
)
}
// Richtext mode (default)
if (fullPage) {
return (
<div className="fullpage-editor">
<RichTextEditor
ref={richTextEditorRef}
content={state.content}
onChange={(v: string) => actions.setContent(v)}
className="min-h-[280px]"
onImageUpload={uploadImageFile}
noteId={note.id}
notebookId={note.notebookId}
noteTitle={state.title || note.title || undefined}
sourceUrl={note.sourceUrl}
/>
</div>
)
}
return (
<div className="space-y-2">
<RichTextEditor
ref={richTextEditorRef}
content={state.content}
onChange={actions.setContent}
className="min-h-[200px]"
onImageUpload={uploadImageFile}
noteId={note.id}
notebookId={note.notebookId}
noteTitle={state.title || note.title || undefined}
sourceUrl={note.sourceUrl}
/>
<GhostTags
suggestions={state.filteredSuggestions}
addedTags={state.labels}
isAnalyzing={state.isAnalyzingSuggestions}
onSelectTag={actions.handleSelectGhostTag}
onDismissTag={actions.handleDismissGhostTag}
/>
</div>
)
}