Skip to content

Commit 20c41f9

Browse files
committed
Finish writings setup
- Add first writings entry - Add MDX support - Add JPG optimization support - Add monospace font for code - Update article styles - Configure Markdown options - Setup code light and dark themes - Other minor updates and fixes
1 parent fd03eb3 commit 20c41f9

17 files changed

Lines changed: 4041 additions & 2410 deletions

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ My personal website, built with [Astro](https://astro.build) and deployed on [Gi
44

55
## Third-party assets and attributions
66

7-
- [Inter](https://rsms.me/inter) ([1](public/fonts/inter-v13-latin-400.woff2), [2](public/fonts/inter-v13-latin-500.woff2)) is licensed under the [SIL Open Font License (OFL)](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL).
8-
- [Raleway](https://github.com/impallari/Raleway) ([1](public/fonts/raleway-v29-latin-500.woff2), [2](public/fonts/raleway-v29-latin-600.woff2)) is licensed under the [SIL Open Font License (OFL)](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL).
9-
- [`avatar.png`](src/assets/avatar.png) was created by [Marga Hernandez](https://margahernandez.dorik.io).
10-
- The menu and mode SVGs used in [`header.astro`](src/components/page/header.astro) is taken and modified from [Tempo's Quill Icons](https://github.com/yourtempo/tempo-quill-icons) and [Jay Newey's Charm Icons](https://github.com/jaynewey/charm-icons), respectively.
7+
- [Inter](https://rsms.me/inter) ([1](public/fonts/inter-v13-latin-400.woff2), [2](public/fonts/inter-v13-latin-500.woff2)) is licensed under the [SIL Open Font License (OFL)](https://github.com/rsms/inter/blob/master/LICENSE.txt).
8+
- [Raleway](https://github.com/impallari/Raleway) ([1](public/fonts/raleway-v29-latin-500.woff2), [2](public/fonts/raleway-v29-latin-600.woff2)) is licensed under the [SIL Open Font License (OFL)](https://github.com/impallari/Raleway/blob/master/OFL.txt).
9+
- [Kode Mono](https://kodemono.com) ([1](public/fonts/kode-mono-v2-latin-400.woff2)) is licensed under the [SIL Open Font License (OFL)](https://github.com/isaozler/kode-mono/blob/main/OFL.txt).
10+
- [`avatar.png`](src/assets/avatar.png) was created by [Marga Hernandez](https://margahernandez.framer.website).
11+
- The menu and mode SVGs used in [`header.astro`](src/components/page/header.astro) were taken and modified from [Tempo's Quill Icons](https://github.com/yourtempo/tempo-quill-icons) and [Jay Newey's Charm Icons](https://github.com/jaynewey/charm-icons), respectively.
1112

1213
## License
1314

astro.config.ts

Lines changed: 100 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import type { RehypePlugin } from "@astrojs/markdown-remark";
12
import type { AstroIntegration, AstroUserConfig } from "astro";
3+
import type { Options } from "rehype-class-names";
24
import type {
35
LegacyAsyncImporter,
46
LegacySharedOptions,
57
LegacySyncImporter
68
} from "sass";
9+
import type { ShikiTransformer } from "shiki";
710
import type { PluginOption } from "vite";
811

912
import cp from "node:child_process";
@@ -12,15 +15,92 @@ import path from "node:path";
1215
import nodeUrl from "node:url";
1316
import util from "node:util";
1417

18+
import mdx from "@astrojs/mdx";
1519
import { addExtension, createFilter, dataToEsm } from "@rollup/pluginutils";
1620
import compress from "astro-compress";
1721
import { walk } from "estree-walker";
1822
import findCacheDirectory from "find-cache-dir";
1923
import gifsicle from "gifsicle";
2024
import { customAlphabet } from "nanoid";
25+
import rehypeClassNames from "rehype-class-names";
2126
import sharp from "sharp";
2227
sharp.cache(false);
2328

29+
//==================================================
30+
// Astro - Shiki and rehype
31+
//==================================================
32+
33+
const classNamesTransformer: ShikiTransformer = {
34+
name: "class-names",
35+
line(node) {
36+
node.properties.class = "block-code-line";
37+
},
38+
span(node) {
39+
node.properties.class = "block-code-token";
40+
}
41+
};
42+
const classNamesPlugin: [RehypePlugin, Options] = [
43+
rehypeClassNames,
44+
{ ":not(pre) > code": "inline-code" }
45+
];
46+
47+
// Workaround since 'shikiConfig' does not support 'defaultColor' and
48+
// 'cssVariablePrefix' options yet. This manually does what happens when
49+
// 'defaultColor' is set to 'false' and 'cssVariablePrefix' is set to
50+
// '--c-code-'.
51+
// https://github.com/withastro/astro/issues/11238#issuecomment-2165715631
52+
function replaceShikiProperty(
53+
style: string,
54+
property: "background-color" | "--shiki-dark-bg" | "color" | "--shiki-dark"
55+
) {
56+
const regex = new RegExp(`${property}:(?<hex>#[0-9a-z]{3,8})`, "i");
57+
58+
let variableName: string;
59+
switch (property) {
60+
case "background-color": {
61+
variableName = "--c-code-light-bg";
62+
break;
63+
}
64+
case "--shiki-dark-bg": {
65+
variableName = "--c-code-dark-bg";
66+
break;
67+
}
68+
case "color": {
69+
variableName = "--c-code-light";
70+
break;
71+
}
72+
case "--shiki-dark": {
73+
variableName = "--c-code-dark";
74+
break;
75+
}
76+
}
77+
78+
const hex = style.match(regex)!.groups!.hex;
79+
80+
return style.replace(regex, `${variableName}:${hex}`);
81+
}
82+
const themeTransformer: ShikiTransformer = {
83+
name: "theme",
84+
pre(node) {
85+
let style = node.properties.style as string;
86+
87+
style = replaceShikiProperty(style, "background-color");
88+
style = replaceShikiProperty(style, "--shiki-dark-bg");
89+
style = replaceShikiProperty(style, "color");
90+
style = replaceShikiProperty(style, "--shiki-dark");
91+
92+
node.properties.style = style;
93+
},
94+
span(node) {
95+
let style = node.properties.style as string;
96+
97+
style = replaceShikiProperty(style, "color");
98+
style = replaceShikiProperty(style, "--shiki-dark");
99+
100+
node.properties.style = style;
101+
}
102+
};
103+
24104
//==================================================
25105
// Astro - Integrations
26106
//==================================================
@@ -93,16 +173,17 @@ const optimizeImagesIntegration: AstroIntegration = {
93173
name: "astro-optimize-images",
94174
create: true
95175
}) as string;
96-
const sharpOptions = { limitInputPixels: false };
176+
const sharpOptions = { limitInputPixels: false, unlimited: true };
97177
const imageOptions = {
98178
png: { compressionLevel: 9, quality: 80 },
179+
jpg: { mozjpeg: true },
99180
webp: { effort: 6 }
100181
};
101182
for (let { original, webp, resize } of images) {
102183
original = path.join(distDir, original);
103184
webp = webp.map((filePath) => path.join(distDir, filePath));
104185

105-
const format = path.extname(original).slice(1) as "gif" | "png";
186+
const format = path.extname(original).slice(1) as "gif" | "jpg" | "png";
106187
const image = sharp(original, {
107188
...sharpOptions,
108189
animated: format === "gif"
@@ -154,8 +235,8 @@ const optimizeImagesIntegration: AstroIntegration = {
154235
...imageOptions.webp,
155236
// For some reason, using lossless compression mode on large
156237
// GIFs increase their WebP size but reduces the size of
157-
// smaller GIFs, so it is turned on for GIFs smaller than 1MB.
158-
lossless: (await fs.stat(original)).size / 1000 < 1000
238+
// smaller GIFs, so it is turned on for GIFs smaller than 2MB.
239+
lossless: (await fs.stat(original)).size / 2000 < 2000
159240
})
160241
.toFile(webp[i] as string);
161242
}
@@ -184,10 +265,11 @@ const optimizeImagesIntegration: AstroIntegration = {
184265
break;
185266
}
186267

187-
case "png": {
268+
case "png":
269+
case "jpg": {
188270
await fs.writeFile(
189271
original,
190-
await image.png(imageOptions.png).toBuffer(),
272+
await image.toFormat(format, imageOptions[format]).toBuffer(),
191273
"binary"
192274
);
193275

@@ -307,9 +389,18 @@ const generateIdsPlugin: PluginOption = {
307389

308390
export default <AstroUserConfig>{
309391
site: "https://mce.codes",
310-
scopedStyleStrategy: "class",
311-
compressHTML: false,
312-
integrations: [optimizeImagesIntegration, compress({ Image: false })],
392+
devToolbar: { enabled: false },
313393
server: { host: true, port: 6001 },
394+
compressHTML: false,
395+
scopedStyleStrategy: "class",
396+
markdown: {
397+
smartypants: false,
398+
shikiConfig: {
399+
themes: { light: "slack-ochin", dark: "slack-dark" },
400+
transformers: [classNamesTransformer, themeTransformer]
401+
},
402+
rehypePlugins: [classNamesPlugin]
403+
},
404+
integrations: [mdx(), optimizeImagesIntegration, compress({ Image: false })],
314405
vite: { css: { preprocessorOptions: { scss } }, plugins: [generateIdsPlugin] }
315406
};

0 commit comments

Comments
 (0)