119 lines
3.3 KiB
TypeScript
119 lines
3.3 KiB
TypeScript
import React from 'react'
|
|
import type { ArticleDraft } from '@/lib/articlePublisher'
|
|
import type { MediaRef } from '@/types/nostr'
|
|
import { ArticleField } from './ArticleField'
|
|
import { MarkdownEditor } from './MarkdownEditor'
|
|
import { MarkdownEditorTwoColumns } from './MarkdownEditorTwoColumns'
|
|
import { t } from '@/lib/i18n'
|
|
|
|
interface ArticleFieldsRightProps {
|
|
draft: ArticleDraft
|
|
onDraftChange: (draft: ArticleDraft) => void
|
|
}
|
|
|
|
export function ArticleFieldsRight({ draft, onDraftChange }: ArticleFieldsRightProps): React.ReactElement {
|
|
return (
|
|
<div className="space-y-4">
|
|
<ContentEditorSection draft={draft} onDraftChange={onDraftChange} />
|
|
<ZapAmountField draft={draft} onDraftChange={onDraftChange} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function ContentEditorSection({
|
|
draft,
|
|
onDraftChange,
|
|
}: {
|
|
draft: ArticleDraft
|
|
onDraftChange: (draft: ArticleDraft) => void
|
|
}): React.ReactElement {
|
|
const useTwoColumns = draft.seriesId !== undefined
|
|
return (
|
|
<div className="space-y-2">
|
|
<div className="text-sm font-semibold text-gray-800">{t('article.editor.content.label')}</div>
|
|
<ContentEditor draft={draft} onDraftChange={onDraftChange} useTwoColumns={useTwoColumns} />
|
|
<p className="text-xs text-gray-500">{t('article.editor.content.help')}</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function ContentEditor({
|
|
draft,
|
|
onDraftChange,
|
|
useTwoColumns,
|
|
}: {
|
|
draft: ArticleDraft
|
|
onDraftChange: (draft: ArticleDraft) => void
|
|
useTwoColumns: boolean
|
|
}): React.ReactElement {
|
|
const onMediaAdd = buildMediaAddHandler({ draft, onDraftChange })
|
|
const onBannerChange = buildBannerChangeHandler({ draft, onDraftChange })
|
|
const onContentChange = (value: string): void => onDraftChange({ ...draft, content: value })
|
|
|
|
if (useTwoColumns) {
|
|
return (
|
|
<MarkdownEditorTwoColumns
|
|
value={draft.content}
|
|
onChange={onContentChange}
|
|
{...(draft.pages ? { pages: draft.pages } : {})}
|
|
onPagesChange={(pages) => onDraftChange({ ...draft, pages })}
|
|
onMediaAdd={onMediaAdd}
|
|
onBannerChange={onBannerChange}
|
|
/>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<MarkdownEditor
|
|
value={draft.content}
|
|
onChange={onContentChange}
|
|
onMediaAdd={onMediaAdd}
|
|
onBannerChange={onBannerChange}
|
|
/>
|
|
)
|
|
}
|
|
|
|
interface BuildMediaAddHandlerParams {
|
|
draft: ArticleDraft
|
|
onDraftChange: (draft: ArticleDraft) => void
|
|
}
|
|
|
|
function buildMediaAddHandler(params: BuildMediaAddHandlerParams): (media: MediaRef) => void {
|
|
return (media): void => {
|
|
const nextMedia = [...(params.draft.media ?? []), media]
|
|
params.onDraftChange({ ...params.draft, media: nextMedia })
|
|
}
|
|
}
|
|
|
|
interface BuildBannerChangeHandlerParams {
|
|
draft: ArticleDraft
|
|
onDraftChange: (draft: ArticleDraft) => void
|
|
}
|
|
|
|
function buildBannerChangeHandler(params: BuildBannerChangeHandlerParams): (url: string) => void {
|
|
return (url): void => {
|
|
params.onDraftChange({ ...params.draft, bannerUrl: url })
|
|
}
|
|
}
|
|
|
|
function ZapAmountField({
|
|
draft,
|
|
onDraftChange,
|
|
}: {
|
|
draft: ArticleDraft
|
|
onDraftChange: (draft: ArticleDraft) => void
|
|
}): React.ReactElement {
|
|
return (
|
|
<ArticleField
|
|
id="zapAmount"
|
|
label={t('article.editor.sponsoring.label')}
|
|
value={draft.zapAmount}
|
|
onChange={(value) => onDraftChange({ ...draft, zapAmount: value as number })}
|
|
required
|
|
type="number"
|
|
min={1}
|
|
helpText={t('article.editor.sponsoring.help')}
|
|
/>
|
|
)
|
|
}
|