feat: add script to generate default blog cover image
- Introduced a new script `make-blog-cover.mjs` to create a default cover image for blog posts. - The image is generated in PNG format with dimensions 1200x630, suitable for Open Graph. - Utilizes the site's branding colors and logo from `public/nobat724.svg`. - Includes custom font styling using the Vazirmatn font. - The generated image is saved to `public/assets/images/blog-default-cover.png`.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* تولید تصویر پیشفرض مقالهها — `public/assets/images/blog-default-cover.png`.
|
||||
*
|
||||
* یکبار اجرا میشود و خروجی PNG کامیت میگردد؛ اسکریپت میماند تا اگر برند یا
|
||||
* ابعاد عوض شد، تصویر قابل بازتولید باشد:
|
||||
*
|
||||
* node scripts/make-blog-cover.mjs
|
||||
*
|
||||
* ابعاد ۱۲۰۰×۶۳۰ استاندارد Open Graph است و با `aspect-video` کارتها هم میخواند.
|
||||
* رنگها و نشان از `public/nobat724.svg` میآیند تا با لوگوی سایت یکی بماند.
|
||||
*/
|
||||
import sharp from 'sharp';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
|
||||
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const W = 1200;
|
||||
const H = 630;
|
||||
const BRAND = '#5559CE'; // stroke نشان در public/nobat724.svg
|
||||
const ACCENT = '#FF8848'; // پلاس نارنجی همان نشان
|
||||
const OUT = join(ROOT, 'public/assets/images/blog-default-cover.png');
|
||||
|
||||
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');
|
||||
|
||||
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>
|
||||
</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>
|
||||
</svg>`;
|
||||
|
||||
// density بالا برای متن تیز، سپس resize به ابعاد دقیق OG.
|
||||
const png = await sharp(Buffer.from(svg), { density: 144 }).resize(W, H).png().toBuffer();
|
||||
writeFileSync(OUT, png);
|
||||
|
||||
const meta = await sharp(png).metadata();
|
||||
console.log(`✓ ${OUT} — ${meta.width}×${meta.height}, ${(png.length / 1024).toFixed(0)}KB`);
|
||||
Reference in New Issue
Block a user