Remove pug and use Preact for templating
This commit is contained in:
parent
9fd97d17d8
commit
4b7c669ad0
|
@ -1,4 +1,3 @@
|
||||||
import { compileFile } from "pug";
|
|
||||||
import { readFileSync } from "node:fs";
|
import { readFileSync } from "node:fs";
|
||||||
import { env } from "node:process";
|
import { env } from "node:process";
|
||||||
import { join, basename, dirname } from "node:path";
|
import { join, basename, dirname } from "node:path";
|
||||||
|
@ -16,6 +15,12 @@ import rehypeExternalLinks from "rehype-external-links";
|
||||||
import visit from "unist-util-visit";
|
import visit from "unist-util-visit";
|
||||||
import { src, dest } from "gulp";
|
import { src, dest } from "gulp";
|
||||||
import { readAssetManifest } from "../hash.js";
|
import { readAssetManifest } from "../hash.js";
|
||||||
|
import renderLayout from "../../src/layout.js";
|
||||||
|
import renderArticleLayout from "../../src/article.js";
|
||||||
|
import renderIndex from "../../src/index.js";
|
||||||
|
import { renderToStaticMarkup } from "preact-render-to-string";
|
||||||
|
import { SITE_TITLE, SITE_DESCRIPTION } from "../../src/constants.js";
|
||||||
|
import { JSX } from "preact/jsx-runtime";
|
||||||
|
|
||||||
const Asciidoctor = asciidoctor();
|
const Asciidoctor = asciidoctor();
|
||||||
const EXTENSION_REGISTRY = Asciidoctor.Extensions.create();
|
const EXTENSION_REGISTRY = Asciidoctor.Extensions.create();
|
||||||
|
@ -29,18 +34,6 @@ EXTENSION_REGISTRY.inlineMacro("abbr", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const SITE_TITLE = "Ad\xE6dra's blog";
|
|
||||||
const SITE_DESCRIPTION = [
|
|
||||||
"Ad\xE6dra",
|
|
||||||
"Software Developper in Paris, France",
|
|
||||||
"Rust, Ruby, Typescript, Linux",
|
|
||||||
].join(" \u2022 ");
|
|
||||||
const SITE_DEFAULT_META = {
|
|
||||||
"og:image": "https://adaedra.blob.core.windows.net/blog-assets/og_preview.png",
|
|
||||||
"og:image:alt": "Ad\xE6dra's mascot",
|
|
||||||
"og:locale": "en_GB",
|
|
||||||
};
|
|
||||||
|
|
||||||
function extractImages(gulp: Transform, file: File) {
|
function extractImages(gulp: Transform, file: File) {
|
||||||
return function () {
|
return function () {
|
||||||
return function (tree) {
|
return function (tree) {
|
||||||
|
@ -61,10 +54,12 @@ function extractImages(gulp: Transform, file: File) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderDocument(root: JSX.Element): Buffer {
|
||||||
|
return Buffer.concat([Buffer.from("<!doctype html>"), Buffer.from(renderToStaticMarkup(root))]);
|
||||||
|
}
|
||||||
|
|
||||||
function renderArticle() {
|
function renderArticle() {
|
||||||
const allArticles: [string, DateTime, Document][] = [];
|
const allArticles: [string, DateTime, Document][] = [];
|
||||||
const renderLayout = compileFile("src/layout.pug");
|
|
||||||
const renderArticleLayout = compileFile("src/article.pug");
|
|
||||||
const assetManifest = readAssetManifest();
|
const assetManifest = readAssetManifest();
|
||||||
|
|
||||||
const asset = (path: string) => {
|
const asset = (path: string) => {
|
||||||
|
@ -103,31 +98,28 @@ function renderArticle() {
|
||||||
.use(rehypeStringify)
|
.use(rehypeStringify)
|
||||||
.process(article.convert());
|
.process(article.convert());
|
||||||
const content = renderLayout({
|
const content = renderLayout({
|
||||||
SITE_TITLE,
|
|
||||||
asset,
|
asset,
|
||||||
title: article.getDoctitle({}),
|
title: article.getDoctitle({}) as string,
|
||||||
meta: Object.assign({}, SITE_DEFAULT_META, {
|
meta: {
|
||||||
description: article.getAttribute("description"),
|
description: article.getAttribute("description"),
|
||||||
keywords: article.getAttribute("keywords"),
|
keywords: article.getAttribute("keywords"),
|
||||||
"og:title": article.getDoctitle({}),
|
"og:title": article.getDoctitle({}) as string,
|
||||||
"og:type": "article",
|
"og:type": "article",
|
||||||
"og:article:published_time": article.getAttribute("docdate"),
|
"og:article:published_time": article.getAttribute("docdate"),
|
||||||
"og:url": `https://adaedra.eu/${slug}/`,
|
"og:url": `https://adaedra.eu/${slug}/`,
|
||||||
"og:description": article.getAttribute("description"),
|
"og:description": article.getAttribute("description"),
|
||||||
"og:site_name": SITE_TITLE,
|
"og:site_name": SITE_TITLE,
|
||||||
}),
|
},
|
||||||
render() {
|
Content: () =>
|
||||||
return renderArticleLayout({
|
renderArticleLayout({
|
||||||
asset,
|
asset,
|
||||||
article,
|
article,
|
||||||
date,
|
date,
|
||||||
DateTime,
|
|
||||||
body: vfile.toString(),
|
body: vfile.toString(),
|
||||||
});
|
}),
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
file.contents = Buffer.from(content);
|
file.contents = renderDocument(content);
|
||||||
file.path = join(slug, "index.html");
|
file.path = join(slug, "index.html");
|
||||||
file.base = null;
|
file.base = null;
|
||||||
|
|
||||||
|
@ -140,22 +132,23 @@ function renderArticle() {
|
||||||
final(callback) {
|
final(callback) {
|
||||||
try {
|
try {
|
||||||
allArticles.sort(([, a], [, b]) => b.diff(a).toMillis());
|
allArticles.sort(([, a], [, b]) => b.diff(a).toMillis());
|
||||||
const renderIndex = compileFile("src/index.pug");
|
|
||||||
const contents = renderLayout({
|
const contents = renderLayout({
|
||||||
SITE_TITLE,
|
|
||||||
asset,
|
asset,
|
||||||
meta: Object.assign({}, SITE_DEFAULT_META, {
|
meta: {
|
||||||
description: SITE_DESCRIPTION,
|
description: SITE_DESCRIPTION,
|
||||||
"og:title": SITE_TITLE,
|
"og:title": SITE_TITLE,
|
||||||
"og:type": "website",
|
"og:type": "website",
|
||||||
"og:url": `https://adaedra.eu`,
|
"og:url": `https://adaedra.eu`,
|
||||||
}),
|
|
||||||
render() {
|
|
||||||
return renderIndex({ articles: allArticles, asset });
|
|
||||||
},
|
},
|
||||||
|
Content: () => renderIndex({ articles: allArticles, asset }),
|
||||||
});
|
});
|
||||||
|
|
||||||
this.push(new File({ path: "index.html", contents: Buffer.from(contents) }));
|
this.push(
|
||||||
|
new File({
|
||||||
|
path: "index.html",
|
||||||
|
contents: renderDocument(contents),
|
||||||
|
}),
|
||||||
|
);
|
||||||
callback(null);
|
callback(null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|
116
package-lock.json
generated
116
package-lock.json
generated
|
@ -19,7 +19,8 @@
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"postcss-import": "^16.1.0",
|
"postcss-import": "^16.1.0",
|
||||||
"postcss-nesting": "^12.1.5",
|
"postcss-nesting": "^12.1.5",
|
||||||
"pug": "^3.0.3",
|
"preact": "^10.22.0",
|
||||||
|
"preact-render-to-string": "^6.5.5",
|
||||||
"rehype": "^13.0.1",
|
"rehype": "^13.0.1",
|
||||||
"rehype-external-links": "^3.0.0",
|
"rehype-external-links": "^3.0.0",
|
||||||
"rehype-preset-minify": "^7.0.0",
|
"rehype-preset-minify": "^7.0.0",
|
||||||
|
@ -28,12 +29,10 @@
|
||||||
"unified": "^11.0.4"
|
"unified": "^11.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.21",
|
|
||||||
"@types/glob": "^8.1.0",
|
"@types/glob": "^8.1.0",
|
||||||
"@types/gulp": "^4.0.17",
|
"@types/gulp": "^4.0.17",
|
||||||
"@types/gulp-postcss": "^8.0.6",
|
"@types/gulp-postcss": "^8.0.6",
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/pug": "^2.0.10",
|
|
||||||
"@types/tmp": "^0.2.6",
|
"@types/tmp": "^0.2.6",
|
||||||
"prettier": "^3.3.1"
|
"prettier": "^3.3.1"
|
||||||
}
|
}
|
||||||
|
@ -374,55 +373,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
||||||
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="
|
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/body-parser": {
|
|
||||||
"version": "1.19.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
|
|
||||||
"integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@types/connect": "*",
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/connect": {
|
|
||||||
"version": "3.4.38",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
|
||||||
"integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/expect": {
|
"node_modules/@types/expect": {
|
||||||
"version": "1.20.4",
|
"version": "1.20.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz",
|
||||||
"integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==",
|
"integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/express": {
|
|
||||||
"version": "4.17.21",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
|
|
||||||
"integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@types/body-parser": "*",
|
|
||||||
"@types/express-serve-static-core": "^4.17.33",
|
|
||||||
"@types/qs": "*",
|
|
||||||
"@types/serve-static": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/express-serve-static-core": {
|
|
||||||
"version": "4.19.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.3.tgz",
|
|
||||||
"integrity": "sha512-KOzM7MhcBFlmnlr/fzISFF5vGWVSvN6fTd4T+ExOt08bA/dA5kpSzY52nMsI1KDFmUREpJelPYyuslLRSjjgCg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "*",
|
|
||||||
"@types/qs": "*",
|
|
||||||
"@types/range-parser": "*",
|
|
||||||
"@types/send": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/glob": {
|
"node_modules/@types/glob": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz",
|
||||||
|
@ -474,12 +430,6 @@
|
||||||
"@types/unist": "^2"
|
"@types/unist": "^2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/http-errors": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
|
|
||||||
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/luxon": {
|
"node_modules/@types/luxon": {
|
||||||
"version": "3.4.2",
|
"version": "3.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz",
|
||||||
|
@ -494,12 +444,6 @@
|
||||||
"@types/unist": "*"
|
"@types/unist": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/mime": {
|
|
||||||
"version": "1.3.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
|
||||||
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/minimatch": {
|
"node_modules/@types/minimatch": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
|
||||||
|
@ -520,45 +464,6 @@
|
||||||
"integrity": "sha512-Yll76ZHikRFCyz/pffKGjrCwe/le2CDwOP5F210KQo27kpRE46U2rDnzikNlVn6/ezH3Mhn46bJMTfeVTtcYMg==",
|
"integrity": "sha512-Yll76ZHikRFCyz/pffKGjrCwe/le2CDwOP5F210KQo27kpRE46U2rDnzikNlVn6/ezH3Mhn46bJMTfeVTtcYMg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/pug": {
|
|
||||||
"version": "2.0.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz",
|
|
||||||
"integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/qs": {
|
|
||||||
"version": "6.9.15",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz",
|
|
||||||
"integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/range-parser": {
|
|
||||||
"version": "1.2.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
|
|
||||||
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/send": {
|
|
||||||
"version": "0.17.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
|
||||||
"integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@types/mime": "^1",
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/serve-static": {
|
|
||||||
"version": "1.15.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz",
|
|
||||||
"integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@types/http-errors": "*",
|
|
||||||
"@types/node": "*",
|
|
||||||
"@types/send": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/streamx": {
|
"node_modules/@types/streamx": {
|
||||||
"version": "2.9.5",
|
"version": "2.9.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/streamx/-/streamx-2.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/streamx/-/streamx-2.9.5.tgz",
|
||||||
|
@ -4341,6 +4246,23 @@
|
||||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/preact": {
|
||||||
|
"version": "10.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/preact/-/preact-10.22.0.tgz",
|
||||||
|
"integrity": "sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw==",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/preact"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/preact-render-to-string": {
|
||||||
|
"version": "6.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.5.tgz",
|
||||||
|
"integrity": "sha512-KiMFTKNTmT/ccE79BURR/r6XRc2I2TCTZ0MpeWqHW2XnllbeghXvwGsdAfF/MzMilUcTfODtSmMxgoRFL9TM5g==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"preact": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"postcss-import": "^16.1.0",
|
"postcss-import": "^16.1.0",
|
||||||
"postcss-nesting": "^12.1.5",
|
"postcss-nesting": "^12.1.5",
|
||||||
"pug": "^3.0.3",
|
"preact": "^10.22.0",
|
||||||
|
"preact-render-to-string": "^6.5.5",
|
||||||
"rehype": "^13.0.1",
|
"rehype": "^13.0.1",
|
||||||
"rehype-external-links": "^3.0.0",
|
"rehype-external-links": "^3.0.0",
|
||||||
"rehype-preset-minify": "^7.0.0",
|
"rehype-preset-minify": "^7.0.0",
|
||||||
|
@ -24,12 +25,10 @@
|
||||||
"unified": "^11.0.4"
|
"unified": "^11.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.21",
|
|
||||||
"@types/glob": "^8.1.0",
|
"@types/glob": "^8.1.0",
|
||||||
"@types/gulp": "^4.0.17",
|
"@types/gulp": "^4.0.17",
|
||||||
"@types/gulp-postcss": "^8.0.6",
|
"@types/gulp-postcss": "^8.0.6",
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/pug": "^2.0.10",
|
|
||||||
"@types/tmp": "^0.2.6",
|
"@types/tmp": "^0.2.6",
|
||||||
"prettier": "^3.3.1"
|
"prettier": "^3.3.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
nav
|
|
||||||
a(href="/" title="Back to home page")
|
|
||||||
img(src=asset("avatar.avif") alt="Adædra's avatar")
|
|
||||||
| Adædra
|
|
||||||
|
|
||||||
article
|
|
||||||
header.article-header
|
|
||||||
= date.toLocaleString(DateTime.DATE_FULL)
|
|
||||||
h1!= article.getDocumentTitle()
|
|
||||||
|
|
||||||
main
|
|
||||||
a(name="content")
|
|
||||||
!= body
|
|
28
src/article.tsx
Normal file
28
src/article.tsx
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { Document } from "asciidoctor";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
article: Document;
|
||||||
|
date: DateTime;
|
||||||
|
body: string;
|
||||||
|
asset(path: string): string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ({ asset, article, date, body }: Props) => (
|
||||||
|
<>
|
||||||
|
<nav>
|
||||||
|
<a href="/" title="Back to home page">
|
||||||
|
<img src={asset("avatar.avif")} alt="Adædra's avatar" />
|
||||||
|
Adædra
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
<article>
|
||||||
|
<header class="article-header">
|
||||||
|
{date.toLocaleString(DateTime.DATE_FULL)}
|
||||||
|
<h1 dangerouslySetInnerHTML={{ __html: article.getDocumentTitle() as string }} />
|
||||||
|
</header>
|
||||||
|
<a name="content" />
|
||||||
|
<main dangerouslySetInnerHTML={{ __html: body }} />
|
||||||
|
</article>
|
||||||
|
</>
|
||||||
|
);
|
13
src/constants.ts
Normal file
13
src/constants.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
export const SITE_TITLE = "Ad\xE6dra's blog";
|
||||||
|
export const SITE_DESCRIPTION = [
|
||||||
|
"Ad\xE6dra",
|
||||||
|
"Software Developper in Paris, France",
|
||||||
|
"Rust, Ruby, Typescript, Linux",
|
||||||
|
].join(" \u2022 ");
|
||||||
|
export const SITE_DEFAULT_META = {
|
||||||
|
viewport: "width=device-width, initial-scale=1",
|
||||||
|
"theme-color": "#DDCBA3",
|
||||||
|
"og:image": "https://adaedra.blob.core.windows.net/blog-assets/og_preview.png",
|
||||||
|
"og:image:alt": "Ad\xE6dra's mascot",
|
||||||
|
"og:locale": "en_GB",
|
||||||
|
};
|
|
@ -1,39 +0,0 @@
|
||||||
header.index-header
|
|
||||||
div(style="flex: 1;")
|
|
||||||
h1 Adædra
|
|
||||||
| Software developper<br />
|
|
||||||
| Rust, Ruby, TypeScript, Linux<br />
|
|
||||||
| Paris, France
|
|
||||||
img(src=asset("cariboudev.avif") alt="Adædra's mascot")/
|
|
||||||
|
|
||||||
h2 Latest articles
|
|
||||||
ul.index-list
|
|
||||||
- for ([slug, date, article] of articles)
|
|
||||||
li
|
|
||||||
= date.toISODate()
|
|
||||||
|
|
|
||||||
a(href=`/${slug}/`)!= article.getDocumentTitle()
|
|
||||||
|
|
||||||
h2 Find me elsewhere
|
|
||||||
ul.index-list
|
|
||||||
li: a(href="https://gitea.adaedra.eu/adaedra" target="_blank")
|
|
||||||
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" aria-label="Git Logo"): use(href="/logos.svg#git")/
|
|
||||||
| Gitea
|
|
||||||
li: a(href="https://nerdculture.de/@adaedra" target="_blank" rel="noopener")
|
|
||||||
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" aria-label="Mastodon Logo"): use(href="/logos.svg#mastodon")/
|
|
||||||
| Mastodon
|
|
||||||
li: a(href="https://www.linkedin.com/in/thibault-hamel/" target="_blank" rel="noopener")
|
|
||||||
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" aria-label="LinkedIn Logo"): use(href="/logos.svg#linkedin")/
|
|
||||||
| LinkedIn
|
|
||||||
|
|
||||||
footer.index-footer
|
|
||||||
| Mascot drawn by
|
|
||||||
a(href="https://linktr.ee/cutepencilcase" target="_blank" rel="noopener") CutePencilCase
|
|
||||||
| <br />Font
|
|
||||||
a(href="https://github.com/be5invis/Iosevka" target="_blank" rel="noopener") Iosevka
|
|
||||||
| • Color theme
|
|
||||||
a(href="https://github.com/morhetz/gruvbox-contrib" target="_blank" rel="noopener") Gruvbox
|
|
||||||
| • Social icons
|
|
||||||
a(href="https://icons8.com/" target="_blank" rel="noopener") Icons8
|
|
||||||
br/
|
|
||||||
a(href="https://gitea.adaedra.eu/adaedra/blog" target="_blank") Source code
|
|
84
src/index.tsx
Normal file
84
src/index.tsx
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import { Document } from "asciidoctor";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
|
||||||
|
type HeaderProps = {
|
||||||
|
asset(path: string): string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Header = ({ asset }: HeaderProps) => (
|
||||||
|
<header class="index-header">
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<h1>Adædra</h1>
|
||||||
|
Software developer
|
||||||
|
<br />
|
||||||
|
Rust, Ruby, TypeScript, Linux
|
||||||
|
<br />
|
||||||
|
Paris, France
|
||||||
|
</div>
|
||||||
|
<img src={asset("cariboudev.avif")} alt="Adaedra's mascot" />
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
|
||||||
|
type ArticleProps = {
|
||||||
|
articles: [string, DateTime, Document][];
|
||||||
|
};
|
||||||
|
|
||||||
|
const Articles = ({ articles }: ArticleProps) => (
|
||||||
|
<>
|
||||||
|
<h2>Latest articles</h2>
|
||||||
|
<ul class="index-list">
|
||||||
|
{articles.map(([slug, date, article]) => (
|
||||||
|
<li>
|
||||||
|
{date.toISODate()}
|
||||||
|
<a
|
||||||
|
href={`/${slug}/`}
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: article.getDocumentTitle() as string,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
type Props = HeaderProps & ArticleProps;
|
||||||
|
|
||||||
|
const SOCIALS: [string, string, string][] = [
|
||||||
|
["Gitea", "https://gitea.adaedra.eu", "git"],
|
||||||
|
["Mastodon", "https://nerdculture.de/@adaedra", "mastodon"],
|
||||||
|
["LinkedIn", "https://www.linkedin.com/in/thibault-hamel/", "linkedin"],
|
||||||
|
];
|
||||||
|
|
||||||
|
const Socials = () => (
|
||||||
|
<>
|
||||||
|
<h2>Find me elsewhere</h2>
|
||||||
|
<ul class="index-list">
|
||||||
|
{SOCIALS.map(([name, url, svgId]) => (
|
||||||
|
<li>
|
||||||
|
<a href={url} target="_blank" rel="noopener">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 32 32"
|
||||||
|
aria-label={`${name} Logo`}
|
||||||
|
>
|
||||||
|
<use href={`/logos.svg#${svgId}`} />
|
||||||
|
</svg>
|
||||||
|
{name}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Footer = () => <footer class="index-footer"></footer>;
|
||||||
|
|
||||||
|
export default ({ asset, articles }: Props) => (
|
||||||
|
<>
|
||||||
|
<Header asset={asset} />
|
||||||
|
<Articles articles={articles} />
|
||||||
|
<Socials />
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
);
|
|
@ -1,15 +0,0 @@
|
||||||
doctype html
|
|
||||||
html(lang="en")
|
|
||||||
head
|
|
||||||
meta(charset="utf-8")/
|
|
||||||
title
|
|
||||||
if title
|
|
||||||
!= `${title} – `
|
|
||||||
= SITE_TITLE
|
|
||||||
meta(name="viewport" content="width=device-width, initial-scale=1")/
|
|
||||||
meta(name="theme-color" content="#DDCBA3")/
|
|
||||||
- for([name, content] of Object.entries(meta))
|
|
||||||
meta(name=name content=content)/
|
|
||||||
link(rel="stylesheet" type="text/css" href=asset("index.css"))/
|
|
||||||
body: .main
|
|
||||||
!= render()
|
|
38
src/layout.tsx
Normal file
38
src/layout.tsx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { SITE_DEFAULT_META, SITE_TITLE } from "./constants.js";
|
||||||
|
import { JSX } from "preact/jsx-runtime";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
title?: string;
|
||||||
|
meta?: { [name: string]: string };
|
||||||
|
asset(path: string): string;
|
||||||
|
} & ({ content: string } | { Content(): JSX.Element });
|
||||||
|
|
||||||
|
export default (props: Props) => {
|
||||||
|
const metaTags = Object.entries(Object.assign({}, SITE_DEFAULT_META, props.meta || {})).map(
|
||||||
|
([name, value]) => <meta name={name} value={value} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: [props.title, SITE_TITLE].filter(Boolean).join(" – "),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{metaTags}
|
||||||
|
<link rel="stylesheet" type="text/css" href={props.asset("index.css")} />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{"Content" in props ? (
|
||||||
|
<div class="main">
|
||||||
|
<props.Content />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div class="main" dangerouslySetInnerHTML={{ __html: props.content }} />
|
||||||
|
)}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
};
|
|
@ -7,5 +7,7 @@
|
||||||
},
|
},
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "preact"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user