Allow heading tags (h1-h6) in ContentSanitizer so news editor headings render

This commit is contained in:
2026-06-04 07:52:57 +02:00
parent 0b33a1b074
commit 15870ddb1f
191 changed files with 15453 additions and 1786 deletions

View File

@@ -3,8 +3,10 @@ import { usePage } from '@inertiajs/react'
import SeoHead from '../../components/seo/SeoHead'
import TagInput from '../../components/tags/TagInput'
import UploadWizard from '../../components/upload/UploadWizard'
import UploadDescriptionEditor from '../../components/upload/UploadDescriptionEditor'
import Checkbox from '../../Components/ui/Checkbox'
import { mapUploadErrorNotice, mapUploadResultNotice } from '../../lib/uploadNotices'
import { validateMarkdownLiteContent } from '../../utils/contentValidation'
const phases = {
idle: 'idle',
@@ -177,7 +179,7 @@ function getTypeKey(ct) {
return String(ct.name || '').toLowerCase().replace(/\s+/g, '_').replace(/[^a-z0-9_]/g, '')
}
function useUploadMachine({ draftId, filesCdnUrl, chunkSize, chunkRequestTimeoutMs, userId }) {
function useUploadMachine({ draftId = null, filesCdnUrl = '', chunkSize, chunkRequestTimeoutMs, userId = null } = {}) {
const [state, dispatch] = useReducer(reducer, { ...initialState, draftId })
const pollRef = useRef(null)
const adaptiveChunkSizeRef = useRef(Math.max(1, Number(chunkSize || 0)))
@@ -548,6 +550,14 @@ function useUploadMachine({ draftId, filesCdnUrl, chunkSize, chunkRequestTimeout
return
}
const descriptionErrors = validateMarkdownLiteContent(state.metadata.description)
if (descriptionErrors.length > 0) {
const message = descriptionErrors[0]
dispatch({ type: 'UPLOAD_ERROR', error: message })
pushNotice('error', message)
return
}
if (!state.metadata.licenseAccepted) {
const message = 'You must confirm ownership of the artwork.'
dispatch({ type: 'UPLOAD_ERROR', error: message })
@@ -619,7 +629,7 @@ function useUploadMachine({ draftId, filesCdnUrl, chunkSize, chunkRequestTimeout
}
}
export default function UploadPage({ draftId, filesCdnUrl, chunkSize, chunkRequestTimeoutMs }) {
export default function UploadPage({ draftId = null, filesCdnUrl = '', chunkSize, chunkRequestTimeoutMs } = {}) {
const { props } = usePage()
const pageTitle = 'Upload Artwork — Creator Studio'
const pageDescription = 'Submit a new artwork, complete the required metadata, and publish it from Skinbase Creator Studio.'
@@ -745,6 +755,7 @@ export default function UploadPage({ draftId, filesCdnUrl, chunkSize, chunkReque
)
const categoryOptions = useMemo(() => selectedType?.categories || [], [selectedType])
const hasAtLeastOneTag = useMemo(() => parseUiTags(state.metadata.tags).length > 0, [state.metadata.tags])
const descriptionErrors = useMemo(() => validateMarkdownLiteContent(state.metadata.description), [state.metadata.description])
useEffect(() => {
// Prefer server-provided props, else try fetching from API endpoints
@@ -1047,13 +1058,17 @@ export default function UploadPage({ draftId, filesCdnUrl, chunkSize, chunkReque
<label className="mt-4 block text-sm">
<span className="text-white/80">Description</span>
<textarea
value={state.metadata.description}
onChange={(e) => dispatch({ type: 'SET_METADATA', payload: { description: e.target.value } })}
className="mt-2 w-full rounded-xl border border-white/10 bg-white/10 px-3 py-2 text-white focus:border-sky-400 focus:outline-none"
rows={4}
placeholder="Tell the story behind this artwork."
/>
<div className="mt-2">
<UploadDescriptionEditor
id="legacy-upload-description"
value={state.metadata.description}
onChange={(value) => dispatch({ type: 'SET_METADATA', payload: { description: value } })}
placeholder="Tell the story behind this artwork."
error={descriptionErrors[0] || ''}
rows={8}
/>
</div>
{descriptionErrors.length > 0 && <p className="mt-2 text-xs text-red-200">{descriptionErrors[0]}</p>}
</label>
<div className="mt-4">
@@ -1099,9 +1114,10 @@ export default function UploadPage({ draftId, filesCdnUrl, chunkSize, chunkReque
!state.metadata.category ||
!hasAtLeastOneTag ||
!state.metadata.description.trim() ||
descriptionErrors.length > 0 ||
!state.metadata.licenseAccepted
}
className={`inline-flex items-center gap-2 rounded-full px-5 py-2 text-sm font-semibold text-white ${(!state.file || !state.metadata.title.trim() || !state.metadata.type || !state.metadata.category || !hasAtLeastOneTag || !state.metadata.description.trim() || !state.metadata.licenseAccepted) ? 'bg-white/10 cursor-not-allowed' : 'bg-emerald-500 shadow-lg shadow-emerald-500/30'}`}
className={`inline-flex items-center gap-2 rounded-full px-5 py-2 text-sm font-semibold text-white ${(!state.file || !state.metadata.title.trim() || !state.metadata.type || !state.metadata.category || !hasAtLeastOneTag || !state.metadata.description.trim() || descriptionErrors.length > 0 || !state.metadata.licenseAccepted) ? 'bg-white/10 cursor-not-allowed' : 'bg-emerald-500 shadow-lg shadow-emerald-500/30'}`}
>
<i className="fa-solid fa-rocket" aria-hidden="true"></i>
Start upload