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

@@ -0,0 +1,135 @@
import React from 'react'
import { Head, Link, usePage } from '@inertiajs/react'
import EnhanceStatusBadge from '../../components/enhance/EnhanceStatusBadge'
import EnhanceStubWarning from '../../components/enhance/EnhanceStubWarning'
import { formatEnhanceDate, formatEnhanceInteger } from '../../utils/enhanceFormatting'
function formatDate(value) {
return formatEnhanceDate(value)
}
function JobCard({ job }) {
return (
<article className="overflow-hidden rounded-[28px] border border-white/10 bg-[#08111d] shadow-[0_18px_48px_rgba(2,6,23,0.2)]">
<div className="grid gap-4 md:grid-cols-[220px_1fr]">
<div className="aspect-square bg-black/30">
{job.preview_url || job.source_url ? <img src={job.preview_url || job.source_url} alt="Enhance preview" className="h-full w-full object-cover" /> : <div className="flex h-full items-center justify-center text-white/20"><i className="fa-solid fa-image text-4xl" /></div>}
</div>
<div className="p-5">
<div className="flex flex-wrap items-center gap-2">
<EnhanceStatusBadge status={job.status} />
<span className="rounded-full border border-white/10 bg-white/[0.05] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-200">{job.scale}x</span>
<span className="rounded-full border border-white/10 bg-white/[0.05] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-200">{job.mode}</span>
<span className="rounded-full border border-white/10 bg-white/[0.05] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-200">{job.engine}</span>
</div>
<h2 className="mt-4 text-2xl font-semibold tracking-[-0.03em] text-white">
{job.artwork?.title ? `Artwork enhance: ${job.artwork.title}` : `Enhance job #${job.id}`}
</h2>
<p className="mt-2 text-sm leading-6 text-slate-300">Created {formatDate(job.created_at)} {job.processing_seconds ? `${job.processing_seconds}s processing` : ''}</p>
<div className="mt-2 text-sm text-slate-400">{job.input_width} × {job.input_height}{job.output_width && job.output_height ? `${job.output_width} × ${job.output_height}` : ''}</div>
{job.error_message ? <div className="mt-4 rounded-2xl border border-rose-300/20 bg-rose-400/10 px-4 py-3 text-sm text-rose-100">{job.error_message}</div> : null}
<div className="mt-5 flex flex-wrap gap-2">
<Link href={job.show_url} className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.05] px-4 py-2 text-xs font-semibold uppercase tracking-[0.14em] text-white transition hover:bg-white/[0.09]">Open job</Link>
{job.artwork?.url ? <a href={job.artwork.url} className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.05] px-4 py-2 text-xs font-semibold uppercase tracking-[0.14em] text-white transition hover:bg-white/[0.09]">Open artwork</a> : null}
</div>
</div>
</div>
</article>
)
}
export default function EnhanceIndex() {
const { props } = usePage()
const jobs = props.jobs?.data || []
const latestCompleted = props.latestCompleted || []
const flash = props.flash || {}
const enhanceConfig = props.enhanceConfig || {}
return (
<div className="w-full pb-16 pt-8">
<Head title="Skinbase Enhance" />
<section className="rounded-[32px] border border-white/10 bg-[radial-gradient(circle_at_top_left,rgba(56,189,248,0.16),transparent_36%),linear-gradient(180deg,rgba(15,23,42,0.96),rgba(2,6,23,0.92))] p-6 shadow-[0_24px_70px_rgba(2,6,23,0.32)]">
<div className="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
<div>
<p className="text-[11px] font-semibold uppercase tracking-[0.28em] text-sky-200/80">Skinbase Enhance</p>
<h1 className="mt-3 text-3xl font-semibold tracking-[-0.04em] text-white">Image Upscaler</h1>
<p className="mt-2 max-w-3xl text-sm leading-relaxed text-slate-300">Improve older wallpapers, digital art, and photos with a clean upscaled version. Your original file is never replaced automatically.</p>
</div>
<div className="flex flex-wrap gap-3">
<Link href={props.createUrl} className="inline-flex items-center gap-2 rounded-full border border-sky-300/20 bg-sky-400/12 px-5 py-3 text-xs font-semibold uppercase tracking-[0.14em] text-sky-50 transition hover:bg-sky-400/20">
<i className="fa-solid fa-sparkles text-[10px]" />
Start enhance
</Link>
</div>
</div>
<div className="mt-6 grid gap-4 md:grid-cols-3">
<div className="rounded-[24px] border border-white/10 bg-white/[0.04] p-5">
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400">Daily limit</div>
<div className="mt-4 text-3xl font-semibold tracking-[-0.04em] text-white">{formatEnhanceInteger(props.dailyLimit || 0)}</div>
</div>
<div className="rounded-[24px] border border-white/10 bg-white/[0.04] p-5">
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400">Total jobs</div>
<div className="mt-4 text-3xl font-semibold tracking-[-0.04em] text-white">{formatEnhanceInteger(props.jobs?.total || jobs.length)}</div>
</div>
<div className="rounded-[24px] border border-white/10 bg-white/[0.04] p-5">
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400">Completed outputs</div>
<div className="mt-4 text-3xl font-semibold tracking-[-0.04em] text-white">{formatEnhanceInteger(latestCompleted.length)}</div>
</div>
</div>
</section>
<EnhanceStubWarning config={enhanceConfig} className="mt-6" />
{flash.success ? <div className="mt-6 rounded-2xl border border-emerald-300/20 bg-emerald-400/10 px-4 py-3 text-sm text-emerald-50">{flash.success}</div> : null}
{flash.error ? <div className="mt-6 rounded-2xl border border-rose-300/20 bg-rose-400/10 px-4 py-3 text-sm text-rose-100">{flash.error}</div> : null}
{latestCompleted.length > 0 ? (
<section className="mt-8">
<div className="mb-4 flex items-center justify-between gap-3">
<div>
<p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">Latest completed</p>
<h2 className="mt-2 text-2xl font-semibold tracking-[-0.03em] text-white">Recent enhanced outputs</h2>
</div>
</div>
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
{latestCompleted.map((job) => (
<Link key={job.id} href={job.show_url} className="overflow-hidden rounded-[28px] border border-white/10 bg-[#08111d] transition hover:border-sky-300/30 hover:bg-[#0b1524]">
<div className="aspect-square bg-black/20">
{job.output_url ? <img src={job.output_url} alt={`Enhance job ${job.id}`} className="h-full w-full object-cover" /> : null}
</div>
<div className="p-4">
<EnhanceStatusBadge status={job.status} />
<div className="mt-3 text-sm font-semibold text-white">Job #{job.id}</div>
<div className="mt-1 text-xs uppercase tracking-[0.16em] text-slate-400">{job.scale}x {job.mode}</div>
</div>
</Link>
))}
</div>
</section>
) : null}
<section className="mt-8">
<div className="mb-4">
<p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">History</p>
<h2 className="mt-2 text-2xl font-semibold tracking-[-0.03em] text-white">Your enhance jobs</h2>
</div>
{jobs.length === 0 ? (
<div className="rounded-[28px] border border-white/10 bg-white/[0.04] px-6 py-12 text-center text-slate-300">No enhance jobs yet. Upload an image to start your first upscale.</div>
) : (
<div className="space-y-4">
{jobs.map((job) => <JobCard key={job.id} job={job} />)}
</div>
)}
</section>
</div>
)
}