141 lines
4.7 KiB
TypeScript
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>
|
|
)
|
|
}
|