feat(blogCover): enhance default blog cover layout with RTL support and improved design elements

This commit is contained in:
hamed
2026-07-27 19:20:34 +03:30
parent cea8982e6d
commit 19ae08c04a
2 changed files with 61 additions and 15 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 38 KiB

+61 -15
View File
@@ -25,31 +25,77 @@ const mark = readFileSync(join(ROOT, 'public/nobat724.svg'), 'utf8')
.replace(/<\?xml[^>]*\?>/, '')
.replace(/width="\d+"\s+height="\d+"/, 'width="200" height="200"');
const fontPath = join(ROOT, 'public/fonts/vazir/Vazirmatn-RD-FD-Bold.ttf');
const fontData = readFileSync(fontPath).toString('base64');
/**
* چیدمان RTL: لوگو سمت راست، «اسکلتون» یک مقاله سمت چپ — کارت سفید با جای
* تصویر شاخص، یک نوار عنوان و چند خط پاراگراف. همان زبان بصریِ حالت بارگذاری،
* پس «مقالهٔ بدون کاور» به‌جای عکس بی‌ربط، قالبِ خالی مقاله را نشان می‌دهد.
*
* خط‌ها راست‌چین‌اند (RTL) و عرضشان نامنظم است تا شبیه متن واقعی باشد؛ خط آخر
* کوتاه است، همان‌طور که آخرین سطر یک پاراگراف کوتاه می‌افتد.
*/
const CARD = { x: 132, y: 88, w: 628, h: 410, pad: 40 };
const INNER_RIGHT = CARD.x + CARD.w - CARD.pad;
const INNER_W = CARD.w - CARD.pad * 2;
// عرض هر سطر پاراگراف نسبت به عرض داخلی کارت
const PARAGRAPH = [1, 0.94, 0.99, 0.88, 0.52];
const lines = PARAGRAPH.map((ratio, i) => {
const w = Math.round(INNER_W * ratio);
return { x: INNER_RIGHT - w, y: 344 + i * 26, w, h: 14 };
});
const svg = `
<svg xmlns="http://www.w3.org/2000/svg" width="${W}" height="${H}" viewBox="0 0 ${W} ${H}">
<defs>
<style>
@font-face {
font-family: 'VazirmatnCover';
src: url('data:font/ttf;base64,${fontData}') format('truetype');
}
.brand { font-family: 'VazirmatnCover'; font-size: 68px; fill: #1F2247; }
.sub { font-family: 'VazirmatnCover'; font-size: 32px; fill: #6B6E8F; }
</style>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#F7F8FE"/>
<stop offset="100%" stop-color="#ECEDFB"/>
</linearGradient>
<linearGradient id="bar" x1="1" y1="0" x2="0" y2="0">
<stop offset="0%" stop-color="#DEDFF4"/>
<stop offset="100%" stop-color="#EFF0FB"/>
</linearGradient>
<linearGradient id="cover" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#D9DAF2"/>
<stop offset="100%" stop-color="#E9EAF8"/>
</linearGradient>
<filter id="cardShadow" x="-10%" y="-10%" width="130%" height="130%">
<feDropShadow dx="0" dy="10" stdDeviation="16" flood-color="#5559CE" flood-opacity="0.10"/>
</filter>
</defs>
<rect width="${W}" height="${H}" fill="url(#bg)"/>
<rect x="0" y="0" width="${W}" height="10" fill="${BRAND}"/>
<rect x="0" y="${H - 10}" width="${W}" height="10" fill="${ACCENT}"/>
<g transform="translate(${W / 2 - 100}, 130)">${mark}</g>
<text class="brand" x="${W / 2}" y="420" text-anchor="middle" direction="rtl">نوبت ۷۲۴</text>
<text class="sub" x="${W / 2}" y="480" text-anchor="middle" direction="rtl">مقالات و اخبار پزشکی</text>
<rect x="0" y="0" width="${W}" height="8" fill="${BRAND}"/>
<rect x="0" y="${H - 8}" width="${W}" height="8" fill="${ACCENT}"/>
<!-- کارت اسکلتون مقاله (سمت چپ) -->
<rect x="${CARD.x}" y="${CARD.y}" width="${CARD.w}" height="${CARD.h}" rx="20"
fill="#FFFFFF" stroke="#E6E7F5" stroke-width="2" filter="url(#cardShadow)"/>
<!-- جای تصویر شاخص + گلیف عکس -->
<rect x="${CARD.x + CARD.pad}" y="128" width="${INNER_W}" height="118" rx="12" fill="url(#cover)"/>
<g fill="#C6C8E8">
<circle cx="${CARD.x + CARD.pad + 62}" cy="168" r="13"/>
<path d="M${CARD.x + CARD.pad + 34} 232 L${CARD.x + CARD.pad + 96} 178
L${CARD.x + CARD.pad + 150} 232 Z"/>
<path d="M${CARD.x + CARD.pad + 128} 232 L${CARD.x + CARD.pad + 178} 190
L${CARD.x + CARD.pad + 226} 232 Z" opacity="0.75"/>
</g>
<!-- نوار عنوان (راست‌چین، پررنگ‌تر از خطوط متن) -->
<rect x="${INNER_RIGHT - 322}" y="278" width="322" height="26" rx="9" fill="#CBCDEC"/>
<!-- خطوط پاراگراف -->
${lines
.map(
(b) =>
`<rect x="${b.x}" y="${b.y}" width="${b.w}" height="${b.h}" rx="7" fill="url(#bar)"/>`
)
.join('\n ')}
<!-- لوگو (سمت راست) — مرکزش با مرکز کارت اسکلتون هم‌تراز است -->
<g transform="translate(815, 193)">${mark}</g>
</svg>`;
// density بالا برای متن تیز، سپس resize به ابعاد دقیق OG.