feat(admin): rich text editor for blog content (TipTap)
CI/CD / CI · API (dotnet build + test) (push) Successful in 3m33s
CI/CD / CI · Admin API (dotnet build) (push) Failing after 3m18s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m6s
CI/CD / CI · Admin Web (tsc) (push) Failing after 3m43s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Has been skipped

Blog post bodies were plain <textarea>s labelled "Markdown". Replace with a
TipTap rich editor (bold/italic/strike, H1–H3, lists, blockquote, code, links,
undo/redo), RTL-aware, producing HTML.

- New RichTextEditor component (TipTap v2: react + starter-kit + pm + link +
  placeholder), immediatelyRender:false for Next SSR, self-contained content
  styling, external-value sync.
- Wired into the FA/EN content fields of the blog editor; labels no longer say
  "Markdown" (fa/en/ar).
- Website blog page now renders HTML when the body is HTML and falls back to
  MDXRemote for older Markdown posts (backward-compatible). Content is authored
  only by trusted SystemAdmins, so HTML is stored/rendered directly.

Admin build + website typecheck clean.
This commit is contained in:
soroush.asadi
2026-06-02 22:25:47 +03:30
parent 97a9481627
commit f1756b491e
8 changed files with 998 additions and 23 deletions
@@ -126,7 +126,12 @@ export default async function BlogPostPage({
{/* Content */}
<div className="mx-auto max-w-3xl px-4 py-12 sm:px-6 lg:px-8">
<div className="prose prose-sm sm:prose-base prose-gray max-w-none prose-headings:font-bold prose-headings:text-gray-900 prose-a:text-brand-700 prose-strong:text-gray-900">
<MDXRemote source={post.content} />
{/* New posts are authored as HTML (rich editor); older posts are MDX/Markdown. */}
{/^\s*</.test(post.content) ? (
<div dangerouslySetInnerHTML={{ __html: post.content }} />
) : (
<MDXRemote source={post.content} />
)}
</div>
{/* Back link */}