Files
ridebus-website/lib/og-template.mjs
Zakhar Timoshenko 142ec97959 feat: add Open Graph image generation and SEO metadata
- Introduced `PageSeo` component for managing page metadata for social sharing.
- Created Open Graph image templates using SVG and static fonts for better visual representation.
- Implemented service alert management with functions to check active alerts and format route numbers.
- Added utility functions for generating and watching alert validity.
- Developed a script to generate Open Graph images dynamically based on page content.
- Included tests for service alert functionalities to ensure correctness and reliability.
2026-10-05 13:02:06 +03:00

180 lines
4.9 KiB
JavaScript

import { createElement as h } from 'react';
// ImageResponse uses flex and inline styles, independently of browser CSS,
// animation and the landing's Webpack loaders.
const box = (style, ...children) =>
h('div', { style: { display: 'flex', ...style } }, ...children);
const picture = (src, width, height, style = {}) =>
h('img', { src, width, height, style });
export function createOgImage(page, locale, assets) {
const copy = page[locale];
const handwritten = ['schedule', 'community'].includes(page.illustration);
const privacy = page.illustration === 'privacy';
const accent = page.illustration === 'terms' ? '#715573' : '#1d4fac';
const headingSize = locale === 'ru' && privacy ? 58 : 76;
const secondSize = locale === 'ru' && privacy ? 52 : handwritten ? 100 : 76;
const illustrations = {
schedule: assets.logo,
community: assets.love,
privacy: assets.shield,
terms: assets.note,
};
return box(
{
position: 'relative',
width: '100%',
height: '100%',
padding: 32,
color: '#242424',
backgroundColor: '#fff',
fontFamily: 'Manrope',
fontWeight: 600,
},
box(
{
position: 'relative',
width: '100%',
height: '100%',
borderRadius: 36,
overflow: 'hidden',
backgroundColor: '#f5f7fc',
},
picture(assets.background, 1136, 566, {
position: 'absolute',
left: 0,
top: 0,
}),
picture(assets.star6, 350, 365, {
position: 'absolute',
right: -60,
top: 122,
opacity: 0.72,
transform: 'rotate(16deg)',
}),
picture(assets.star5, 170, 170, {
position: 'absolute',
right: 237,
bottom: 21,
opacity: 0.48,
transform: 'rotate(-15deg)',
}),
picture(assets.thinStar, 148, 148, {
position: 'absolute',
left: -71,
bottom: -60,
opacity: 0.32,
transform: 'rotate(10deg)',
}),
box(
{
position: 'relative',
flexDirection: 'column',
justifyContent: 'space-between',
width: '100%',
height: '100%',
padding: '38px 44px',
},
box(
{ alignItems: 'center', justifyContent: 'space-between' },
box(
{ alignItems: 'center', gap: 12 },
picture(assets.logo, 48, 48),
h('span', { style: { fontSize: 32, fontWeight: 800 } }, 'ridebus')
),
box(
{
padding: '12px 22px',
borderRadius: 40,
fontSize: 18,
color: accent,
backgroundColor: '#ffffffb3',
},
copy.label
)
),
box(
{ flexDirection: 'column', width: 730, marginTop: 10 },
h(
'div',
{
style: {
fontSize: headingSize,
lineHeight: 1.16,
fontWeight: 800,
letterSpacing: '-2.5px',
},
},
copy.heading[0]
),
h(
'div',
{
style: {
fontFamily: handwritten ? 'Caveat' : 'Manrope',
fontSize: secondSize,
fontWeight: handwritten ? 700 : 800,
lineHeight: handwritten ? 1.1 : 1.2,
letterSpacing: handwritten ? '-1px' : '-2px',
color: handwritten ? '#715573' : accent,
marginTop: handwritten ? -2 : 4,
},
},
copy.heading[1]
),
box(
{
marginTop: 22,
maxWidth: 665,
fontSize: 24,
lineHeight: 1.5,
color: '#526079',
},
copy.caption
)
),
box(
{ alignItems: 'center', justifyContent: 'space-between' },
box(
{ gap: 10 },
...copy.tags.map((tag) =>
box(
{
padding: '10px 18px',
borderRadius: 18,
backgroundColor: '#ffffffb3',
fontSize: 17,
color: '#526079',
},
tag
)
)
),
h('span', { style: { fontSize: 20, color: accent } }, 'ridebus.by')
)
),
box(
{
position: 'absolute',
right: 44,
top: 197,
width: 236,
height: 236,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 60,
backgroundColor: '#ffffffdb',
border: '2px solid #ffffff',
transform: 'rotate(-9deg)',
},
picture(
illustrations[page.illustration],
page.illustration === 'schedule' ? 164 : 126,
page.illustration === 'schedule' ? 164 : 126
)
)
)
);
}