Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamic social share image #63

Merged
merged 9 commits into from
Apr 26, 2024
126 changes: 63 additions & 63 deletions src/assets/styles/__styles.11ty.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,52 +11,52 @@ const cssesc = require("cssesc")
const isProd = process.env.ELEVENTY_ENV === "production"

module.exports = class {
async data() {
const entryPath = path.join(__dirname, `/${ENTRY_FILE_NAME}`)
return {
permalink: `/assets/styles/main.css`,
eleventyExcludeFromCollections: true,
entryPath
}
}
async data() {
const entryPath = path.join(__dirname, `/${ENTRY_FILE_NAME}`)
return {
permalink: `/assets/styles/main.css`,
eleventyExcludeFromCollections: true,
entryPath
}
}

// Compile Sass to CSS,
// Embed Source Map in Development
async compile(config) {
return new Promise((resolve, reject) => {
if (!isProd) {
config.sourceMap = true
config.sourceMapEmbed = true
config.outputStyle = "compressed"
}
return sass.render(config, (err, result) => {
if (err) {
return reject(err)
}
resolve(result.css.toString())
})
})
}
// Compile Sass to CSS,
// Embed Source Map in Development
async compile(config) {
return new Promise((resolve, reject) => {
if (!isProd) {
config.sourceMap = true
config.sourceMapEmbed = true
config.outputStyle = "compressed"
}
return sass.render(config, (err, result) => {
if (err) {
return reject(err)
}
resolve(result.css.toString())
})
})
}

// Minify & Optimize with CleanCSS in Production
async minify(css) {
return new Promise((resolve, reject) => {
if (!isProd) {
resolve(css)
}
const minified = new CleanCSS().minify(css)
if (!minified.styles) {
return reject(minified.error)
}
resolve(minified.styles)
})
}
// Minify & Optimize with CleanCSS in Production
async minify(css) {
return new Promise((resolve, reject) => {
if (!isProd) {
resolve(css)
}
const minified = new CleanCSS().minify(css)
if (!minified.styles) {
return reject(minified.error)
}
resolve(minified.styles)
})
}

// display an error overlay when CSS build fails.
// this brilliant idea is taken from Mike Riethmuller / Supermaya
// @see https://github.com/MadeByMike/supermaya/blob/master/site/utils/compile-scss.js
renderError(error) {
return `
// display an error overlay when CSS build fails.
// this brilliant idea is taken from Mike Riethmuller / Supermaya
// @see https://github.com/MadeByMike/supermaya/blob/master/site/utils/compile-scss.js
renderError(error) {
return `
/* Error compiling stylesheet */
*,
*::before,
Expand Down Expand Up @@ -95,25 +95,25 @@ module.exports = class {
border: solid 2px red;
position: fixed;
}`
}
}

// render the CSS file
async render({ entryPath }) {
try {
const css = await this.compile({ file: entryPath })
const result = await this.minify(css)
return result
} catch (err) {
// if things go wrong
if (isProd) {
// throw and abort in production
throw new Error(err)
} else {
// otherwise display the error overlay
console.error(err)
const msg = err.formatted || err.message
return this.renderError(msg)
}
}
}
// render the CSS file
async render({ entryPath }) {
try {
const css = await this.compile({ file: entryPath })
const result = await this.minify(css)
return result
} catch (err) {
// if things go wrong
if (isProd) {
// throw and abort in production
throw new Error(err)
} else {
// otherwise display the error overlay
console.error(err)
const msg = err.formatted || err.message
return this.renderError(msg)
}
}
}
}
51 changes: 51 additions & 0 deletions src/assets/styles/components/_social-card.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
body.social-card {
background-color: $white;
color: $gray-950;
display: block;
margin: 0;

.box {
width: 1200px;
height: 630px;
position: relative;
background-color: $gray-50;
padding: 32px;
box-sizing: border-box;
display: flex;

.container {
background: $white;
color: $gray-950;
border-radius: 32px;
height: 100%;
width: 100%;
padding: 48px;
position: relative;
display: flex;

img {
border-radius: 100px;
position: absolute;
}

h1 {
width: 696px;
font-size: 70px;
display: flex;
align-items: center;
line-height: 5rem;
margin: 0;
}

p {
font-family: "Inter";
font-weight: 500;
font-size: 32px;
line-height: 3rem;
letter-spacing: -0.001em;
position: absolute;
bottom: 48px;
}
}
}
}
1 change: 1 addition & 0 deletions src/assets/styles/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
@import "components/checkbox";
@import "components/writing/article-card";
@import "components/writing/header";
@import "components/social-card";

// Pages
@import "pages/home";
Expand Down
62 changes: 44 additions & 18 deletions src/includes/meta.njk
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,73 @@ endset -%}
<meta property="og:url" content="{{ absolutePageUrl }}"/>
<meta property="og:type" content="website"/>
<meta
property="og:description"
content="{{ description or meta.description }}"
property="og:description"
content="{{ description or meta.description }}"
/>
<meta property="og:site_name" content="{{ meta.title }}"/>
<meta property="og:locale" content="{{ meta.locale }}"/>
<meta name="author" content="{{ author.name }}"/>
<meta
property="og:image"
content="{{ 'https://afnizarnur.com/assets/images/meta-image.png' | url }}"

{% if page
.url
.startsWith('/writing/') %}
{% if page.url == '/writing/' or
page
.url
.startsWith('/writing/tags/') %}
<meta
property="og:image"
content="{{ 'https://afnizarnur.com/assets/images/meta-image.png' | url }}"
/>

<meta
property="twitter:image"
content="{{ 'https://afnizarnur.com/assets/images/meta-image.png' | url }}"
/>
{% else %}
<meta property="og:image" content="{% openGraphScreenshotURL %}"/>
<meta property="twitter:image" content="{% openGraphScreenshotURL %}"/>
{% endif %}
{% else %}
<meta
property="og:image"
content="{{ 'https://afnizarnur.com/assets/images/meta-image.png' | url }}"
/>
<meta
property="twitter:image"
content="{{ 'https://afnizarnur.com/assets/images/meta-image.png' | url }}"
/>
{% endif %}

{# Twitter #}
<meta property="twitter:card" content="summary_large_image"/>
<meta name="twitter:site" content="@{{ author.social.twitter.name }}"/>
<meta name="twitter:creator" content="@{{ author.social.twitter.name }}"/>
<meta property="twitter:title" content="{{ title or meta.title }}"/>
<meta property="twitter:description" content="{{ description or meta.description }}"/>
<meta
property="twitter:image"
content="{{ 'https://afnizarnur.com/assets/images/meta-image.png' | url }}"
property="twitter:description"
content="{{ description or meta.description }}"
/>
<meta property="twitter:url" content="https://afnizarnur.com/"/>

{# Favicon #}
<link
rel="apple-touch-icon"
sizes="180x180"
href="{{ '/assets/images/favicon/apple-touch-icon.png' | url }}"
rel="apple-touch-icon"
sizes="180x180"
href="{{ '/assets/images/favicon/apple-touch-icon.png' | url }}"
/>
<link
rel="shortcut icon"
href="{{ '/assets/images/favicon/favicon.ico' | url }}"
sizes="any"
rel="shortcut icon"
href="{{ '/assets/images/favicon/favicon.ico' | url }}"
sizes="any"
/>
<link rel="manifest" href="{{ '/site.webmanifest' | url }}"/>
<meta name="theme-color" content="#191a1b"/>

{# RSS Feed #}
<link
type="application/atom+xml"
rel="alternate"
href="{{ meta.url }}/feed.xml"
title="{{ meta.title }}"
type="application/atom+xml"
rel="alternate"
href="{{ meta.url }}/feed.xml"
title="{{ meta.title }}"
/>
23 changes: 23 additions & 0 deletions src/pages/social-card.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
pagination:
data: collections.writing
size: 1
alias: post
permalink: "social-card/{{ post.url }}/"
eleventyExcludeFromCollections: true
---

<html>
<head>
<link rel="stylesheet" href="{{ '/assets/styles/main.css' | url }}"/>
</head>
<body class="social-card">
<div class="box">
<div class="container">
<img src="{{ '/assets/images/afnizar-nur-ghifari.png' | url }}" alt="Afnizar Nur Ghifari" height="70" width="70" decoding="async"/>
<h1 class="headline">{{ post.data.title }}</h1>
<p>Afnizar Nur Ghifari</p>
</div>
</div>
</body>
</html>
2 changes: 1 addition & 1 deletion src/pages/work-tags.njk
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ pagination:
data: collections
size: 1
alias: tag
addAllPagesToCollections: true
filter:
- works
- worksbyyear
- selected
eleventyComputed:
title: "{% set filteredWorks = collections.works | filterByTag(tag) %}{{ filteredWorks | length | pluralize('work') }} tagged with {{ tag }}"
permalink: /work/tags/{{ tag | slugify }}/
eleventyExcludeFromCollections: true
---

{% include "userinfo.njk" %}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/writing-tags.njk
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ pagination:
data: collections
size: 1
alias: tag
addAllPagesToCollections: true
filter:
- writing
eleventyComputed:
title: "{% set filteredWritings = collections.writing | filterByTag(tag) %}{{ filteredWritings | length | pluralize('post') }} tagged with {{ tag }}"
permalink: /writing/tags/{{ tag | slugify }}/
eleventyExcludeFromCollections: true
---

{% include "userinfo.njk" %}
Expand Down
1 change: 1 addition & 0 deletions src/robots.njk
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ eleventyExcludeFromCollections: true

User-agent: *
Disallow: /build.txt
Disallow: /social-card/*

Sitemap: {{ meta.url }}/sitemap.xml
7 changes: 7 additions & 0 deletions utils/shortcodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,12 @@ module.exports = {
} catch (error) {
return ""
}
},
openGraphScreenshotURL: function () {
const encodedURL = encodeURIComponent(
`https://afnizarnur.com/social-card${this.page.url}`
)
const cacheKey = `_${new Date().valueOf()}`
return `https://v1.screenshot.11ty.dev/${encodedURL}/opengraph/${cacheKey}`
}
}