|
|
@ -184,7 +184,16 @@ async function generateResourceOpenGraph() { |
|
|
|
|
|
|
|
|
|
|
|
for (const resource of resources) { |
|
|
|
for (const resource of resources) { |
|
|
|
if (!resource.image) { |
|
|
|
if (!resource.image) { |
|
|
|
const template = getRoadmapDefaultTemplate(resource); |
|
|
|
let template = getRoadmapDefaultTemplate(resource); |
|
|
|
|
|
|
|
if ( |
|
|
|
|
|
|
|
hasSpecialCharacters(resource.title) || |
|
|
|
|
|
|
|
hasSpecialCharacters(resource.description) |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
// For some reason special characters are not being rendered properly
|
|
|
|
|
|
|
|
// https://github.com/natemoo-re/satori-html/issues/20
|
|
|
|
|
|
|
|
// So we need to unescape the html
|
|
|
|
|
|
|
|
template = JSON.parse(unescapeHtml(JSON.stringify(template))); |
|
|
|
|
|
|
|
} |
|
|
|
await generateOpenGraph( |
|
|
|
await generateOpenGraph( |
|
|
|
template, |
|
|
|
template, |
|
|
|
resource.type, |
|
|
|
resource.type, |
|
|
@ -193,19 +202,29 @@ async function generateResourceOpenGraph() { |
|
|
|
); |
|
|
|
); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
const image = await fs.readFile(resource.image); |
|
|
|
const image = await fs.readFile(resource.image); |
|
|
|
|
|
|
|
|
|
|
|
const dimensions = imageSize(image); |
|
|
|
const dimensions = imageSize(image); |
|
|
|
|
|
|
|
|
|
|
|
const widthRatio = 1200 / dimensions.width; |
|
|
|
const widthRatio = 1200 / dimensions.width; |
|
|
|
let width = dimensions.width * widthRatio * 0.85; |
|
|
|
let width = dimensions.width * widthRatio * 0.85; |
|
|
|
let height = dimensions.height * widthRatio * 0.85; |
|
|
|
let height = dimensions.height * widthRatio * 0.85; |
|
|
|
|
|
|
|
|
|
|
|
const template = getRoadmapImageTemplate({ |
|
|
|
let template = getRoadmapImageTemplate({ |
|
|
|
...resource, |
|
|
|
...resource, |
|
|
|
image: `data:image/${dimensions.type};base64,${image.toString('base64')}`, |
|
|
|
image: `data:image/${dimensions.type};base64,${image.toString('base64')}`, |
|
|
|
width, |
|
|
|
width, |
|
|
|
height, |
|
|
|
height, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( |
|
|
|
|
|
|
|
hasSpecialCharacters(resource.title) || |
|
|
|
|
|
|
|
hasSpecialCharacters(resource.description) |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
// For some reason special characters are not being rendered properly
|
|
|
|
|
|
|
|
// https://github.com/natemoo-re/satori-html/issues/20
|
|
|
|
|
|
|
|
// So we need to unescape the html
|
|
|
|
|
|
|
|
template = JSON.parse(unescapeHtml(JSON.stringify(template))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
await generateOpenGraph(template, resource.type, resource.id + '.png'); |
|
|
|
await generateOpenGraph(template, resource.type, resource.id + '.png'); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -236,6 +255,15 @@ async function generateGuideOpenGraph() { |
|
|
|
? image |
|
|
|
? image |
|
|
|
: `data:image/${authorImageExtention};base64,${authorAvatar.toString('base64')}`, |
|
|
|
: `data:image/${authorImageExtention};base64,${authorAvatar.toString('base64')}`, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
if ( |
|
|
|
|
|
|
|
hasSpecialCharacters(guide.title) || |
|
|
|
|
|
|
|
hasSpecialCharacters(guide.description) |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
// For some reason special characters are not being rendered properly
|
|
|
|
|
|
|
|
// https://github.com/natemoo-re/satori-html/issues/20
|
|
|
|
|
|
|
|
// So we need to unescape the html
|
|
|
|
|
|
|
|
template = JSON.parse(unescapeHtml(JSON.stringify(template))); |
|
|
|
|
|
|
|
} |
|
|
|
await generateOpenGraph(template, 'guides', guide.id + '.png'); |
|
|
|
await generateOpenGraph(template, 'guides', guide.id + '.png'); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -451,7 +479,9 @@ function getRoadmapImageTemplate({ title, description, image, height, width }) { |
|
|
|
|
|
|
|
|
|
|
|
<div tw="flex flex-col px-[90px] pt-[90px]"> |
|
|
|
<div tw="flex flex-col px-[90px] pt-[90px]"> |
|
|
|
<div tw="flex flex-col pb-0"> |
|
|
|
<div tw="flex flex-col pb-0"> |
|
|
|
<div tw="text-[70px] leading-[70px] tracking-tight">${title}</div> |
|
|
|
<div tw="text-[70px] leading-[70px] tracking-tight"> |
|
|
|
|
|
|
|
${title?.replace('&', `{"&"}`)} |
|
|
|
|
|
|
|
</div> |
|
|
|
<div |
|
|
|
<div |
|
|
|
tw="mt-[16px] text-[30px] leading-[36px] tracking-tight opacity-80" |
|
|
|
tw="mt-[16px] text-[30px] leading-[36px] tracking-tight opacity-80" |
|
|
|
> |
|
|
|
> |
|
|
@ -509,3 +539,16 @@ function getGuideTemplate({ title, description, authorName, authorAvatar }) { |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> `; |
|
|
|
</div> `; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function unescapeHtml(html) { |
|
|
|
|
|
|
|
return html |
|
|
|
|
|
|
|
.replace(/&/g, '&') |
|
|
|
|
|
|
|
.replace(/</g, '<') |
|
|
|
|
|
|
|
.replace(/>/g, '>') |
|
|
|
|
|
|
|
.replace(/"/g, '"') |
|
|
|
|
|
|
|
.replace(/'/g, "'"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function hasSpecialCharacters(str) { |
|
|
|
|
|
|
|
return /[&<>"]/.test(str); |
|
|
|
|
|
|
|
} |
|
|
|