fix html (old) mods editing #192

Merged
enes merged 3 commits from 182-old-mods-edit into staging 2025-01-15 16:07:43 +00:00
4 changed files with 51 additions and 40 deletions

16
package-lock.json generated
View File

@ -39,7 +39,6 @@
"react-toastify": "10.0.5", "react-toastify": "10.0.5",
"react-window": "1.8.10", "react-window": "1.8.10",
"swiper": "11.1.11", "swiper": "11.1.11",
"turndown": "^7.2.0",
"uuid": "10.0.0", "uuid": "10.0.0",
"webln": "0.3.2" "webln": "0.3.2"
}, },
@ -2058,12 +2057,6 @@
"react-dom": ">= 18 || >= 19" "react-dom": ">= 18 || >= 19"
} }
}, },
"node_modules/@mixmark-io/domino": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz",
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==",
"license": "BSD-2-Clause"
},
"node_modules/@noble/ciphers": { "node_modules/@noble/ciphers": {
"version": "0.5.3", "version": "0.5.3",
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.5.3.tgz", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.5.3.tgz",
@ -8037,15 +8030,6 @@
"resolved": "https://registry.npmjs.org/tstl/-/tstl-2.5.16.tgz", "resolved": "https://registry.npmjs.org/tstl/-/tstl-2.5.16.tgz",
"integrity": "sha512-+O2ybLVLKcBwKm4HymCEwZIT0PpwS3gCYnxfSDEjJEKADvIFruaQjd3m7CAKNU1c7N3X3WjVz87re7TA2A5FUw==" "integrity": "sha512-+O2ybLVLKcBwKm4HymCEwZIT0PpwS3gCYnxfSDEjJEKADvIFruaQjd3m7CAKNU1c7N3X3WjVz87re7TA2A5FUw=="
}, },
"node_modules/turndown": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz",
"integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==",
"license": "MIT",
"dependencies": {
"@mixmark-io/domino": "^2.2.0"
}
},
"node_modules/type": { "node_modules/type": {
"version": "2.7.3", "version": "2.7.3",
"resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz",

View File

@ -41,7 +41,6 @@
"react-toastify": "10.0.5", "react-toastify": "10.0.5",
"react-window": "1.8.10", "react-window": "1.8.10",
"swiper": "11.1.11", "swiper": "11.1.11",
"turndown": "^7.2.0",
"uuid": "10.0.0", "uuid": "10.0.0",
"webln": "0.3.2" "webln": "0.3.2"
}, },

View File

@ -4,6 +4,8 @@ import {
codeBlockPlugin, codeBlockPlugin,
CodeToggle, CodeToggle,
CreateLink, CreateLink,
diffSourcePlugin,
DiffSourceToggleWrapper,
directivesPlugin, directivesPlugin,
headingsPlugin, headingsPlugin,
imagePlugin, imagePlugin,
@ -68,34 +70,42 @@ export const Editor = React.memo(
() => [ () => [
toolbarPlugin({ toolbarPlugin({
toolbarContents: () => ( toolbarContents: () => (
<> <DiffSourceToggleWrapper
<UndoRedo /> children={
<Separator /> <>
<BoldItalicUnderlineToggles /> <UndoRedo />
<CodeToggle /> <Separator />
<Separator /> <BoldItalicUnderlineToggles />
<StrikeThroughSupSubToggles /> <CodeToggle />
<Separator /> <Separator />
<ListsToggle /> <StrikeThroughSupSubToggles />
<Separator /> <Separator />
<BlockTypeSelect /> <ListsToggle />
<Separator /> <Separator />
<BlockTypeSelect />
<Separator />
<CreateLink /> <CreateLink />
<InsertImage /> <InsertImage />
<YouTubeButton /> <YouTubeButton />
<Separator /> <Separator />
<InsertTable /> <InsertTable />
<InsertThematicBreak /> <InsertThematicBreak />
<Separator /> <Separator />
<InsertCodeBlock /> <InsertCodeBlock />
</> </>
}
/>
) )
}), }),
headingsPlugin(), headingsPlugin(),
diffSourcePlugin({
viewMode: 'rich-text',
diffMarkdown: markdown
}),
quotePlugin(), quotePlugin(),
imagePlugin({ imagePlugin({
ImageDialog: ImageDialog ImageDialog: ImageDialog
@ -118,6 +128,7 @@ export const Editor = React.memo(
codeBlockEditorDescriptors: [PlainTextCodeEditorDescriptor] codeBlockEditorDescriptors: [PlainTextCodeEditorDescriptor]
}) })
], ],
// eslint-disable-next-line react-hooks/exhaustive-deps
[] []
) )

View File

@ -22,7 +22,12 @@ import {
ModPageLoaderResult, ModPageLoaderResult,
SubmitModActionResult SubmitModActionResult
} from '../types' } from '../types'
import { initializeFormState, MOD_DRAFT_CACHE_KEY } from '../utils' import {
initializeFormState,
log,
LogType,
MOD_DRAFT_CACHE_KEY
} from '../utils'
import { CheckboxField, InputField, InputFieldWithImageUpload } from './Inputs' import { CheckboxField, InputField, InputFieldWithImageUpload } from './Inputs'
import { OriginalAuthor } from './OriginalAuthor' import { OriginalAuthor } from './OriginalAuthor'
import { CategoryAutocomplete } from './CategoryAutocomplete' import { CategoryAutocomplete } from './CategoryAutocomplete'
@ -32,6 +37,7 @@ import { MEDIA_OPTIONS } from 'controllers'
import { InputError } from './Inputs/Error' import { InputError } from './Inputs/Error'
import { ImageUpload } from './Inputs/ImageUpload' import { ImageUpload } from './Inputs/ImageUpload'
import { useLocalCache } from 'hooks/useLocalCache' import { useLocalCache } from 'hooks/useLocalCache'
import { toast } from 'react-toastify'
interface GameOption { interface GameOption {
value: string value: string
@ -59,6 +65,13 @@ export const ModForm = () => {
isEditing ? initializeFormState(mod) : cache ? cache : initializeFormState() isEditing ? initializeFormState(mod) : cache ? cache : initializeFormState()
) )
// Enable backwards compatibility with the mods that used html
const body = useMemo(() => {
// Replace the most problematic HTML tags (<br>)
const fixed = formState.body.replaceAll(/<br>/g, '\r\n')
return fixed
}, [formState.body])
useEffect(() => { useEffect(() => {
if (!isEditing) { if (!isEditing) {
const newCache = _.cloneDeep(formState) const newCache = _.cloneDeep(formState)
@ -253,11 +266,15 @@ export const ModForm = () => {
<div className='inputMain'> <div className='inputMain'>
<Editor <Editor
ref={editorRef} ref={editorRef}
markdown={formState.body} markdown={body}
placeholder="Here's what this mod is all about" placeholder="Here's what this mod is all about"
onChange={(md) => { onChange={(md) => {
handleInputChange('body', md) handleInputChange('body', md)
}} }}
onError={(payload) => {
toast.error('Markdown error. Fix manually in the source mode.')
log(true, LogType.Error, payload.error)
}}
/> />
</div> </div>
{typeof formErrors?.body !== 'undefined' && ( {typeof formErrors?.body !== 'undefined' && (