import satori from 'satori' import { Resvg } from '@resvg/resvg-js' import fs from 'node:fs/promises' import path from 'node:path' import { fileURLToPath } from 'node:url' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const FONTS = path.join(__dirname, 'fonts') const OUT = path.resolve(__dirname, '..', 'public', 'og') const interReg = await fs.readFile(path.join(FONTS, 'Inter-Regular.ttf')) const interBold = await fs.readFile(path.join(FONTS, 'Inter-Bold.ttf')) // Логотип ALL MARKET (готовый файл бренда, color на прозрачном). viewBox 3:1. const logoPng = await fs.readFile(path.join(__dirname, 'allmarket-logo-color.png')) const logoUri = `data:image/png;base64,${logoPng.toString('base64')}` const pages = [ { file: 'home.png', title: 'Программа учёта и касса для розничных магазинов в Казахстане', sub: 'Касса с торговыми весами, импорт каталога, ОФД РК. Бесплатно 90 дней.' }, { file: 'pos.png', title: 'Касса для Windows с поддержкой торговых весов', sub: 'Установка за 5 минут. Офлайн-режим. Стандартное оборудование.' }, { file: 'pricing.png', title: 'Прозрачные тарифы ALL MARKET', sub: 'От 5 000 ₸/мес. Все возможности на любом тарифе. 90 дней триал.' }, { file: 'import.png', title: 'Перенесите каталог за один клик', sub: 'Excel, CSV, REST API. До 100 000 товаров. Бесплатно.' }, { file: 'about.png', title: 'О ALL MARKET', sub: 'Программа учёта розничной торговли, созданная в Казахстане.' }, { file: 'for-grocery.png', title: 'ALL MARKET для продуктового магазина', sub: 'Весовой товар, скоропорт, штрихкоды, ABC-анализ.' }, { file: 'for-pharmacy.png', title: 'ALL MARKET для аптеки', sub: 'Серии, сроки годности, рецептурный отпуск, контроль ЛП.' }, { file: 'for-cafe.png', title: 'ALL MARKET для кафе и общепита', sub: 'Модификаторы блюд, столики, печать на кухню.' }, { file: 'for-alcohol.png', title: 'ALL MARKET для алкомаркета', sub: 'Акцизные марки, контроль времени продаж, маркировка.' }, { file: 'for-clothing.png', title: 'ALL MARKET для магазина одежды', sub: 'Размерные сетки, цветовые матрицы, остатки по размерам.' }, { file: 'for-household.png', title: 'ALL MARKET для дома и быта', sub: 'Гарантийные сроки, серийные номера, характеристики.' }, ] const tmpl = ({ title, sub }) => ({ type: 'div', props: { style: { width: '1200px', height: '630px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', padding: '64px', background: 'linear-gradient(135deg, #FFFFFF 0%, #ECFDF5 100%)', fontFamily: 'Inter', }, children: [ // Logo (готовый файл бренда на светлом фоне) { type: 'img', props: { src: logoUri, width: 300, height: 99 }, }, // Title + subtitle { type: 'div', props: { style: { display: 'flex', flexDirection: 'column', gap: '20px', maxWidth: '1000px' }, children: [ { type: 'div', props: { style: { color: '#0F172A', fontSize: title.length > 60 ? '54px' : '64px', fontWeight: 700, lineHeight: 1.15 }, children: title } }, { type: 'div', props: { style: { color: '#475569', fontSize: '28px', fontWeight: 400, lineHeight: 1.3 }, children: sub } }, ], }, }, // Footer { type: 'div', props: { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [ { type: 'div', props: { style: { color: '#0F172A', fontSize: '20px', fontWeight: 700 }, children: 'food-market.kz' } }, { type: 'div', props: { style: { background: '#00B207', color: '#FFFFFF', padding: '14px 28px', borderRadius: '10px', fontSize: '20px', fontWeight: 700, }, children: 'Начать бесплатно →', }, }, ], }, }, ], }, }) await fs.mkdir(OUT, { recursive: true }) for (const p of pages) { const svg = await satori(tmpl(p), { width: 1200, height: 630, fonts: [ { name: 'Inter', data: interReg, weight: 400, style: 'normal' }, { name: 'Inter', data: interBold, weight: 700, style: 'normal' }, ], }) const png = new Resvg(svg, { fitTo: { mode: 'width', value: 1200 } }).render().asPng() await fs.writeFile(path.join(OUT, p.file), png) console.log('og →', p.file) } console.log('done')