فرانت‌اند: ویرایشگر WYSIWYG وبلاگ (TipTap) با آپلود تصویر در متن

- ArticleEditor: ویرایشگر TipTap v3 راست‌به‌چسب با نوار ابزار فارسی —
  بولد/ایتالیک/زیرخط/خط‌خورده، تیتر H2/H3، لیست نقطه‌ای/شماره‌ای،
  نقل‌قول، لینک (مسدودسازی javascript: با isAllowedUri)، واگرد/ازنو
- درج تصویر داخل متن: دکمه آپلود، چسباندن یا کشیدن فایل — ذخیره در
  MinIO از طریق /api/admin/upload و درج URL نسبی /media/...
- ذخیره خودکار: debounce ۸۰۰ms + flush هنگام بستن کشو
- کشوی مقاله عریض‌تر (max-w-3xl)؛ فیلد body مقالات به‌جای لیست متنی،
  ویرایشگر WYSIWYG رندر می‌کند
- رندر صفحه مقاله: تبدیل سند به HTML با @tiptap/static-renderer
  (فقط تگ‌های شناخته‌شده — بدون ریسک XSS) + استایل‌های .article-body
  (تیتر با خط مسی، لیست، نقل‌قول، تصویر) + پشتیبانی از ردیف‌های قدیمی
- وابستگی‌های جدید: @tiptap/react، @tiptap/pm، @tiptap/starter-kit،
  @tiptap/extension-image، @tiptap/extension-link، @tiptap/static-renderer
This commit is contained in:
MMD
2026-09-06 23:33:08 +03:30
parent 8f11df99ea
commit cfe5512ec7
8 changed files with 1188 additions and 16 deletions
+99
View File
@@ -40,3 +40,102 @@ body {
scroll-behavior: auto;
}
}
/* ---------- بدنه مقاله — رندر سند TipTap و ویرایشگر WYSIWYG ---------- */
.article-body {
line-height: 2.4;
word-wrap: break-word;
}
.article-body p {
margin-top: 1.75rem;
color: rgba(245, 243, 239, 0.7);
}
.article-body > :first-child {
margin-top: 0;
}
.article-body h2,
.article-body h3 {
color: #f5f3ef;
font-weight: 700;
margin-top: 3rem;
margin-bottom: 0.25rem;
line-height: 1.9;
}
.article-body h2 {
font-size: 1.6rem;
padding-right: 0.85rem;
border-right: 3px solid #d5874c;
}
.article-body h3 {
font-size: 1.25rem;
color: #e8c9a8;
}
.article-body ul,
.article-body ol {
margin-top: 1.5rem;
padding-right: 1.5rem;
}
.article-body ul {
list-style: disc;
}
.article-body ol {
list-style: decimal;
}
.article-body li {
margin-top: 0.6rem;
color: rgba(245, 243, 239, 0.7);
}
.article-body li p {
margin-top: 0;
display: inline;
}
.article-body blockquote {
margin-top: 2rem;
border-right: 3px solid #d5874c;
background: rgba(30, 26, 22, 0.5);
padding: 1rem 1.25rem;
font-style: normal;
color: rgba(245, 243, 239, 0.85);
}
.article-body blockquote p {
margin-top: 0;
color: inherit;
}
.article-body a {
color: #d5874c;
text-decoration: underline;
text-underline-offset: 4px;
}
.article-body img {
width: 100%;
margin-top: 2rem;
border: 1px solid rgba(245, 243, 239, 0.1);
object-fit: cover;
}
.article-body strong {
color: #f5f3ef;
font-weight: 700;
}
.article-body hr {
margin-top: 2.5rem;
border: 0;
height: 1px;
background: rgba(245, 243, 239, 0.12);
}
.article-body code {
background: rgba(30, 26, 22, 0.7);
padding: 0.15rem 0.45rem;
font-size: 0.85em;
}
.article-body pre {
background: rgba(30, 26, 22, 0.7);
padding: 1rem 1.25rem;
margin-top: 1.5rem;
overflow-x: auto;
direction: ltr;
text-align: left;
}
.article-body pre code {
background: transparent;
padding: 0;
}