diff --git a/astro.config.mjs b/astro.config.mjs index 00f6e0f14..71b0678c8 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -5,10 +5,10 @@ import swup from "@swup/astro"; import icon from "astro-icon"; import { defineConfig } from "astro/config"; import rehypeAutolinkHeadings from "rehype-autolink-headings"; -import rehypeComponents from "rehype-components"; /* Render the custom directive content */ +import rehypeComponents from "rehype-components";/* Render the custom directive content */ import rehypeKatex from "rehype-katex"; import rehypeSlug from "rehype-slug"; -import remarkDirective from "remark-directive"; /* Handle directives */ +import remarkDirective from "remark-directive";/* Handle directives */ import remarkGithubAdmonitionsToDirectives from "remark-github-admonitions-to-directives"; import remarkMath from "remark-math"; import remarkSectionize from "remark-sectionize"; @@ -20,107 +20,148 @@ import { parseDirectiveNode } from "./src/plugins/remark-directive-rehype.js"; import { remarkExcerpt } from "./src/plugins/remark-excerpt.js"; import { remarkReadingTime } from "./src/plugins/remark-reading-time.mjs"; +import expressiveCode from "astro-expressive-code"; + // https://astro.build/config export default defineConfig({ - site: "https://2x.nz", - base: "/", - trailingSlash: "always", - integrations: [ - tailwind({ - nesting: true, - }), - swup({ - theme: false, - animationClass: "transition-swup-", // see https://swup.js.org/options/#animationselector - // the default value `transition-` cause transition delay - // when the Tailwind class `transition-all` is used - containers: ["main", "#toc"], - smoothScrolling: true, - cache: true, - preload: true, - accessibility: true, - updateHead: true, - updateBodyClass: false, - globalInstance: true, - }), - icon({ - include: { - "preprocess: vitePreprocess(),": ["*"], - "fa6-brands": ["*"], - "fa6-regular": ["*"], - "fa6-solid": ["*"], - "simple-icons": ["*"], + site: "https://2x.nz", + base: "/", + trailingSlash: "always", + integrations: [tailwind({ + nesting: true, + }), swup({ + theme: false, + animationClass: "transition-swup-", // see https://swup.js.org/options/#animationselector + // the default value `transition-` cause transition delay + // when the Tailwind class `transition-all` is used + containers: ["main", "#toc"], + smoothScrolling: true, + cache: true, + preload: true, + accessibility: true, + updateHead: true, + updateBodyClass: false, + globalInstance: true, + }), icon({ + include: { + "preprocess: vitePreprocess(),": ["*"], + "fa6-brands": ["*"], + "fa6-regular": ["*"], + "fa6-solid": ["*"], + "simple-icons": ["*"], + }, + }), svelte(), sitemap(), + expressiveCode({ + themes: [expressiveCodeConfig.theme, expressiveCodeConfig.theme], + plugins: [ + pluginCollapsibleSections(), + pluginLineNumbers(), + pluginLanguageBadge(), + pluginCustomCopyButton() + ], + defaultProps: { + wrap: true, + overridesByLang: { + 'shellsession': { + showLineNumbers: false, + }, + }, }, + styleOverrides: { + codeBackground: "var(--codeblock-bg)", + borderRadius: "0.75rem", + borderColor: "none", + codeFontSize: "0.875rem", + codeFontFamily: "'JetBrains Mono Variable', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace", + codeLineHeight: "1.5rem", + frames: { + editorBackground: "var(--codeblock-bg)", + terminalBackground: "var(--codeblock-bg)", + terminalTitlebarBackground: "var(--codeblock-topbar-bg)", + editorTabBarBackground: "var(--codeblock-topbar-bg)", + editorActiveTabBackground: "none", + editorActiveTabIndicatorBottomColor: "var(--primary)", + editorActiveTabIndicatorTopColor: "none", + editorTabBarBorderBottomColor: "var(--codeblock-topbar-bg)", + terminalTitlebarBorderBottomColor: "none" + }, + textMarkers: { + delHue: 0, + insHue: 180, + markHue: 250 + } + }, + frames: { + showCopyToClipboardButton: false, + } }), - svelte(), - sitemap(), ], - markdown: { - remarkPlugins: [ - remarkMath, - remarkReadingTime, - remarkExcerpt, - remarkGithubAdmonitionsToDirectives, - remarkDirective, - remarkSectionize, - parseDirectiveNode, - ], - rehypePlugins: [ - rehypeKatex, - rehypeSlug, - [rehypeImageFallback, imageFallbackConfig], - [ - rehypeComponents, - { - components: { - github: GithubCardComponent, - note: (x, y) => AdmonitionComponent(x, y, "note"), - tip: (x, y) => AdmonitionComponent(x, y, "tip"), - important: (x, y) => AdmonitionComponent(x, y, "important"), - caution: (x, y) => AdmonitionComponent(x, y, "caution"), - warning: (x, y) => AdmonitionComponent(x, y, "warning"), - }, - }, - ], - [ - rehypeAutolinkHeadings, - { - behavior: "append", - properties: { - className: ["anchor"], - }, - content: { - type: "element", - tagName: "span", - properties: { - className: ["anchor-icon"], - "data-pagefind-ignore": true, - }, - children: [ - { - type: "text", - value: "#", - }, - ], - }, - }, - ], - ], - }, - vite: { - build: { - rollupOptions: { - onwarn(warning, warn) { - // temporarily suppress this warning - if ( - warning.message.includes("is dynamically imported by") && - warning.message.includes("but also statically imported by") - ) { - return; - } - warn(warning); - }, - }, - }, - }, -}); + markdown: { + remarkPlugins: [ + remarkMath, + remarkReadingTime, + remarkExcerpt, + remarkGithubAdmonitionsToDirectives, + remarkDirective, + remarkSectionize, + parseDirectiveNode, + ], + rehypePlugins: [ + rehypeKatex, + rehypeSlug, + [rehypeImageFallback, imageFallbackConfig], + [ + rehypeComponents, + { + components: { + github: GithubCardComponent, + note: (x, y) => AdmonitionComponent(x, y, "note"), + tip: (x, y) => AdmonitionComponent(x, y, "tip"), + important: (x, y) => AdmonitionComponent(x, y, "important"), + caution: (x, y) => AdmonitionComponent(x, y, "caution"), + warning: (x, y) => AdmonitionComponent(x, y, "warning"), + }, + }, + ], + [ + rehypeAutolinkHeadings, + { + behavior: "append", + properties: { + className: ["anchor"], + }, + content: { + type: "element", + tagName: "span", + properties: { + className: ["anchor-icon"], + "data-pagefind-ignore": true, + }, + children: [ + { + type: "text", + value: "#", + }, + ], + }, + }, + ], + ], + }, + vite: { + build: { + rollupOptions: { + onwarn(warning, warn) { + // temporarily suppress this warning + if ( + warning.message.includes("is dynamically imported by") && + warning.message.includes("but also statically imported by") + ) { + return; + } + warn(warning); + }, + }, + }, + }, +}); \ No newline at end of file diff --git a/package.json b/package.json index 34a0d835d..4ae5c7cf0 100644 --- a/package.json +++ b/package.json @@ -31,13 +31,13 @@ "@swup/astro": "^1.6.0", "@tailwindcss/typography": "^0.5.16", "astro": "5.7.9", + "astro-expressive-code": "^0.41.3", "astro-icon": "^1.1.5", "hastscript": "^9.0.1", "katex": "^0.16.22", "markdown-it": "^14.1.0", "mdast-util-to-string": "^4.0.0", "overlayscrollbars": "^2.11.1", - "photoswipe": "^5.4.4", "reading-time": "^1.5.0", "rehype-autolink-headings": "^7.1.0", @@ -65,7 +65,8 @@ "@types/mdast": "^4.0.4", "@types/sanitize-html": "^2.15.0", "postcss-import": "^16.1.0", - "postcss-nesting": "^13.0.1" + "postcss-nesting": "^13.0.1", + "rehype": "^13.0.2" }, "packageManager": "pnpm@9.14.4" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index adeb04b8e..8babd9b29 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ importers: astro: specifier: 5.7.9 version: 5.7.9(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0) + astro-expressive-code: + specifier: ^0.41.3 + version: 0.41.3(astro@5.7.9(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0)) astro-icon: specifier: ^1.1.5 version: 1.1.5 @@ -156,6 +159,9 @@ importers: postcss-nesting: specifier: ^13.0.1 version: 13.0.1(postcss@8.5.3) + rehype: + specifier: ^13.0.2 + version: 13.0.2 packages: @@ -826,28 +832,24 @@ packages: engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - libc: [musl] '@biomejs/cli-linux-arm64@1.9.4': resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - libc: [glibc] '@biomejs/cli-linux-x64-musl@1.9.4': resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - libc: [musl] '@biomejs/cli-linux-x64@1.9.4': resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - libc: [glibc] '@biomejs/cli-win32-arm64@1.9.4': resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} @@ -876,6 +878,10 @@ packages: peerDependencies: postcss-selector-parser: ^7.0.0 + '@ctrl/tinycolor@4.1.0': + resolution: {integrity: sha512-WyOx8cJQ+FQus4Mm4uPIZA64gbk3Wxh0so5Lcii0aJifqwoVOlfFtorjLE0Hen4OYyHZMXDWqMmaQemBhgxFRQ==} + engines: {node: '>=14'} + '@emmetio/abbreviation@2.3.3': resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} @@ -1053,6 +1059,18 @@ packages: cpu: [x64] os: [win32] + '@expressive-code/core@0.41.3': + resolution: {integrity: sha512-9qzohqU7O0+JwMEEgQhnBPOw5DtsQRBXhW++5fvEywsuX44vCGGof1SL5OvPElvNgaWZ4pFZAFSlkNOkGyLwSQ==} + + '@expressive-code/plugin-frames@0.41.3': + resolution: {integrity: sha512-rFQtmf/3N2CK3Cq/uERweMTYZnBu+CwxBdHuOftEmfA9iBE7gTVvwpbh82P9ZxkPLvc40UMhYt7uNuAZexycRQ==} + + '@expressive-code/plugin-shiki@0.41.3': + resolution: {integrity: sha512-RlTARoopzhFJIOVHLGvuXJ8DCEme/hjV+ZnRJBIxzxsKVpGPW4Oshqg9xGhWTYdHstTsxO663s0cdBLzZj9TQA==} + + '@expressive-code/plugin-text-markers@0.41.3': + resolution: {integrity: sha512-SN8tkIzDpA0HLAscEYD2IVrfLiid6qEdE9QLlGVSxO1KEw7qYvjpbNBQjUjMr5/jvTJ7ys6zysU2vLPHE0sb2g==} + '@fancyapps/ui@6.0.5': resolution: {integrity: sha512-pDowgTxM57wj8Q9XfgVbl4MKpr0Nb71LnGxSZIHngEXgkd7751+3tPdRyGzF1n2bXhted6zM9CQ7Q0SVV4cH2A==} @@ -1139,163 +1157,138 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm64@1.1.0': resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.1.0': resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.1.0': resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.1.0': resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.1.0': resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-arm64@1.1.0': resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.1.0': resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm64@0.34.1': resolution: {integrity: sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.34.1': resolution: {integrity: sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.34.1': resolution: {integrity: sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.34.1': resolution: {integrity: sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-arm64@0.34.1': resolution: {integrity: sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.34.1': resolution: {integrity: sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -1400,42 +1393,36 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [musl] '@parcel/watcher-win32-arm64@2.5.1': resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} @@ -1559,67 +1546,56 @@ packages: resolution: {integrity: sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.40.1': resolution: {integrity: sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.40.1': resolution: {integrity: sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.40.1': resolution: {integrity: sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.40.1': resolution: {integrity: sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-powerpc64le-gnu@4.40.1': resolution: {integrity: sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.40.1': resolution: {integrity: sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.40.1': resolution: {integrity: sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.40.1': resolution: {integrity: sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.40.1': resolution: {integrity: sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.40.1': resolution: {integrity: sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.40.1': resolution: {integrity: sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==} @@ -1953,6 +1929,11 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + astro-expressive-code@0.41.3: + resolution: {integrity: sha512-u+zHMqo/QNLE2eqYRCrK3+XMlKakv33Bzuz+56V1gs8H0y6TZ0hIi3VNbIxeTn51NLn+mJfUV/A0kMNfE4rANw==} + peerDependencies: + astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 + astro-icon@1.1.5: resolution: {integrity: sha512-CJYS5nWOw9jz4RpGWmzNQY7D0y2ZZacH7atL2K9DeJXJVaz7/5WrxeyIxO8KASk1jCM96Q4LjRx/F3R+InjJrw==} @@ -2031,6 +2012,9 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + bcp-47-match@2.0.3: + resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -2273,6 +2257,9 @@ packages: css-select@5.1.0: resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + css-selector-parser@3.1.3: + resolution: {integrity: sha512-gJMigczVZqYAk0hPVzx/M4Hm1D9QOtqkdQk9005TNzDIUGzo5cnHEDiKUT7jGPximL/oYb+LIitcHFQ4aKupxg==} + css-tree@1.1.3: resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} engines: {node: '>=8.0.0'} @@ -2417,6 +2404,10 @@ packages: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} + direction@2.0.1: + resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} + hasBin: true + dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -2576,6 +2567,9 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + expressive-code@0.41.3: + resolution: {integrity: sha512-YLnD62jfgBZYrXIPQcJ0a51Afv9h8VlWqEGK9uU2T5nL/5rb8SnA86+7+mgCZe5D34Tff5RNEA5hjNVJYHzrFg==} + exsolve@1.0.4: resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==} @@ -2827,6 +2821,9 @@ packages: hast-util-from-parse5@8.0.3: resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + hast-util-heading-rank@3.0.0: resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} @@ -2842,6 +2839,9 @@ packages: hast-util-raw@9.1.0: resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + hast-util-select@6.0.4: + resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} + hast-util-to-html@9.0.5: resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} @@ -3192,28 +3192,24 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.29.3: resolution: {integrity: sha512-dxakOk66pf7KLS7VRYFO7B8WOJLecE5OPL2YOk52eriFd/yeyxt2Km5H0BjLfElokIaR+qWi33gB8MQLrdAY3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.29.3: resolution: {integrity: sha512-ySZTNCpbfbK8rqpKJeJR2S0g/8UqqV3QnzcuWvpI60LWxnFN91nxpSSwCbzfOXkzKfar9j5eOuOplf+klKtINg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.29.3: resolution: {integrity: sha512-3pVZhIzW09nzi10usAXfIGTTSTYQ141dk88vGFNCgawIzayiIzZQxEcxVtIkdvlEq2YuFsL9Wcj/h61JHHzuFQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.29.3: resolution: {integrity: sha512-VRnkAvtIkeWuoBJeGOTrZxsNp4HogXtcaaLm8agmbYtLDOhQdpgxW6NjZZjDXbvGF+eOehGulXZ3C1TiwHY4QQ==} @@ -4210,6 +4206,9 @@ packages: rehype-components@0.3.0: resolution: {integrity: sha512-yl2bUkZi+sU0gxwVCun7IkjiDLPczSs1SKMKHmjlSLkk4mMryBd/aYba5J8suhJdquBEKSw6ZNxU3MvVQ9xqoQ==} + rehype-expressive-code@0.41.3: + resolution: {integrity: sha512-8d9Py4c/V6I/Od2VIXFAdpiO2kc0SV2qTJsRAaqSIcM9aruW4ASLNe2kOEo1inXAAkIhpFzAHTc358HKbvpNUg==} + rehype-katex@7.0.1: resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==} @@ -6131,6 +6130,8 @@ snapshots: dependencies: postcss-selector-parser: 7.1.0 + '@ctrl/tinycolor@4.1.0': {} + '@emmetio/abbreviation@2.3.3': dependencies: '@emmetio/scanner': 1.0.4 @@ -6239,6 +6240,31 @@ snapshots: '@esbuild/win32-x64@0.25.3': optional: true + '@expressive-code/core@0.41.3': + dependencies: + '@ctrl/tinycolor': 4.1.0 + hast-util-select: 6.0.4 + hast-util-to-html: 9.0.5 + hast-util-to-text: 4.0.2 + hastscript: 9.0.1 + postcss: 8.5.3 + postcss-nested: 6.2.0(postcss@8.5.3) + unist-util-visit: 5.0.0 + unist-util-visit-parents: 6.0.1 + + '@expressive-code/plugin-frames@0.41.3': + dependencies: + '@expressive-code/core': 0.41.3 + + '@expressive-code/plugin-shiki@0.41.3': + dependencies: + '@expressive-code/core': 0.41.3 + shiki: 3.3.0 + + '@expressive-code/plugin-text-markers@0.41.3': + dependencies: + '@expressive-code/core': 0.41.3 + '@fancyapps/ui@6.0.5': {} '@fontsource-variable/jetbrains-mono@5.2.5': {} @@ -7114,6 +7140,11 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + astro-expressive-code@0.41.3(astro@5.7.9(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0)): + dependencies: + astro: 5.7.9(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0) + rehype-expressive-code: 0.41.3 + astro-icon@1.1.5: dependencies: '@iconify/tools': 4.1.2 @@ -7298,6 +7329,8 @@ snapshots: base64-js@1.5.1: {} + bcp-47-match@2.0.3: {} + binary-extensions@2.3.0: {} blob-to-buffer@1.2.9: {} @@ -7563,6 +7596,8 @@ snapshots: domutils: 3.2.2 nth-check: 2.1.1 + css-selector-parser@3.1.3: {} + css-tree@1.1.3: dependencies: mdn-data: 2.0.14 @@ -7719,6 +7754,8 @@ snapshots: diff@5.2.0: {} + direction@2.0.1: {} + dlv@1.1.3: {} dom-serializer@1.4.1: @@ -7940,6 +7977,13 @@ snapshots: eventemitter3@5.0.1: {} + expressive-code@0.41.3: + dependencies: + '@expressive-code/core': 0.41.3 + '@expressive-code/plugin-frames': 0.41.3 + '@expressive-code/plugin-shiki': 0.41.3 + '@expressive-code/plugin-text-markers': 0.41.3 + exsolve@1.0.4: {} extend@3.0.2: {} @@ -8234,6 +8278,10 @@ snapshots: vfile-location: 5.0.3 web-namespaces: 2.0.1 + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-heading-rank@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -8266,6 +8314,24 @@ snapshots: web-namespaces: 2.0.1 zwitch: 2.0.4 + hast-util-select@6.0.4: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + bcp-47-match: 2.0.3 + comma-separated-tokens: 2.0.3 + css-selector-parser: 3.1.3 + devlop: 1.1.0 + direction: 2.0.1 + hast-util-has-property: 3.0.0 + hast-util-to-string: 3.0.1 + hast-util-whitespace: 3.0.0 + nth-check: 2.1.1 + property-information: 7.0.0 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + hast-util-to-html@9.0.5: dependencies: '@types/hast': 3.0.4 @@ -9851,6 +9917,10 @@ snapshots: hast-util-is-element: 3.0.0 unist-util-visit: 5.0.0 + rehype-expressive-code@0.41.3: + dependencies: + expressive-code: 0.41.3 + rehype-katex@7.0.1: dependencies: '@types/hast': 3.0.4 diff --git a/src/components/misc/Markdown.astro b/src/components/misc/Markdown.astro index 5dea32f18..10a415a04 100644 --- a/src/components/misc/Markdown.astro +++ b/src/components/misc/Markdown.astro @@ -14,51 +14,29 @@ const className = Astro.props.class; diff --git a/src/config.ts b/src/config.ts index 4a2af8e40..5b8c93335 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,4 +1,5 @@ import type { + ExpressiveCodeConfig, ImageFallbackConfig, LicenseConfig, NavBarConfig, @@ -119,3 +120,7 @@ export const umamiConfig: UmamiConfig = { shareId: "ZyDjOrmjaBTlmGtd", timezone: "Asia/Shanghai", }; + +export const expressiveCodeConfig: ExpressiveCodeConfig = { + theme: "github-light", +}; \ No newline at end of file diff --git a/src/content/posts/expressive-code.md b/src/content/posts/expressive-code.md new file mode 100644 index 000000000..3069c6b0b --- /dev/null +++ b/src/content/posts/expressive-code.md @@ -0,0 +1,348 @@ +--- +title: Expressive Code 代码块示例 +published: 2025-08-10 +description: 如何使用Expressive Code 代码块 +tags: [Markdown, Blogging, Demo] +category: Default +draft: false +--- + +:::note +原文链接:[Expressive Code Example](https://14131413.xyz/posts/default/expressive-code/) +::: + +Here, we'll explore how code blocks look using [Expressive Code](https://expressive-code.com/). The provided examples are based on the official documentation, which you can refer to for further details. +在这里,我们将探索使用 [Expressive Code](https://expressive-code.com/) 的代码块显示效果。提供的示例基于官方文档,您可以参考该文档获取更多细节。 + +## Expressive Code +## Expressive Code + +### Syntax Highlighting +### 语法高亮 + +[Syntax Highlighting](https://expressive-code.com/key-features/syntax-highlighting/) +[语法高亮](https://expressive-code.com/key-features/syntax-highlighting/) + +#### Regular syntax highlighting +#### 常规语法高亮 + +```js +console.log('This code is syntax highlighted!') +``` + +#### Rendering ANSI escape sequences +#### 渲染 ANSI 转义序列 + +```ansi +ANSI colors: +- Regular: Red Green Yellow Blue Magenta Cyan +- Bold: Red Green Yellow Blue Magenta Cyan +- Dimmed: Red Green Yellow Blue Magenta Cyan + +256 colors (showing colors 160-177): +160 161 162 163 164 165 +166 167 168 169 170 171 +172 173 174 175 176 177 + +Full RGB colors: +ForestGreen - RGB(34, 139, 34) + +Text formatting: Bold Dimmed Italic Underline +``` + +### Editor & Terminal Frames +### 编辑器与终端框架 + +[Editor & Terminal Frames](https://expressive-code.com/key-features/frames/) +[编辑器与终端框架](https://expressive-code.com/key-features/frames/) + +#### Code editor frames +#### 代码编辑器框架 + +```js title="my-test-file.js" +console.log('Title attribute example') +``` + +--- + +```html + +
File name comment example
+``` + +#### Terminal frames +#### 终端框架 + +```bash +echo "This terminal frame has no title" +``` + +--- + +```powershell title="PowerShell terminal example" +Write-Output "This one has a title!" +``` + +#### Overriding frame types +#### 覆盖框架类型 + +```sh frame="none" +echo "Look ma, no frame!" +``` + +--- + +```ps frame="code" title="PowerShell Profile.ps1" +# Without overriding, this would be a terminal frame +function Watch-Tail { Get-Content -Tail 20 -Wait $args } +New-Alias tail Watch-Tail +``` + +### Text & Line Markers +### 文本与行标记 + +[Text & Line Markers](https://expressive-code.com/key-features/text-markers/) +[文本与行标记](https://expressive-code.com/key-features/text-markers/) + +#### Marking full lines & line ranges +#### 标记整行与行范围 + +```js {1, 4, 7-8} +// Line 1 - targeted by line number +// Line 2 +// Line 3 +// Line 4 - targeted by line number +// Line 5 +// Line 6 +// Line 7 - targeted by range "7-8" +// Line 8 - targeted by range "7-8" +``` + +#### Selecting line marker types (mark, ins, del) +#### 选择行标记类型(mark, ins, del) + +```js title="line-markers.js" del={2} ins={3-4} {6} +function demo() { + console.log('this line is marked as deleted') + // This line and the next one are marked as inserted + console.log('this is the second inserted line') + + return 'this line uses the neutral default marker type' +} +``` + +#### Adding labels to line markers +#### 为行标记添加标签 + +```jsx {"1":5} del={"2":7-8} ins={"3":10-12} +// labeled-line-markers.jsx + +``` + +#### Adding long labels on their own lines +#### 在独立行添加长标签 + +```jsx {"1. Provide the value prop here:":5-6} del={"2. Remove the disabled and active states:":8-10} ins={"3. Add this to render the children inside the button:":12-15} +// labeled-line-markers.jsx + +``` + +#### Using diff-like syntax +#### 使用类似 diff 的语法 + +```diff ++this line will be marked as inserted +-this line will be marked as deleted +this is a regular line +``` + +--- + +```diff +--- a/README.md ++++ b/README.md +@@ -1,3 +1,4 @@ ++this is an actual diff file +-all contents will remain unmodified + no whitespace will be removed either +``` + +#### Combining syntax highlighting with diff-like syntax +#### 结合语法高亮与类似 diff 的语法 + +```diff lang="js" + function thisIsJavaScript() { + // This entire block gets highlighted as JavaScript, + // and we can still add diff markers to it! +- console.log('Old code to be removed') ++ console.log('New and shiny code!') + } +``` + +#### Marking individual text inside lines +#### 标记行内特定文本 + +```js "given text" +function demo() { + // Mark any given text inside lines + return 'Multiple matches of the given text are supported'; +} +``` + +#### Regular expressions +#### 正则表达式 + +```ts /ye[sp]/ +console.log('The words yes and yep will be marked.') +``` + +#### Escaping forward slashes +#### 转义正斜杠 + +```sh /\/ho.*\// +echo "Test" > /home/test.txt +``` + +#### Selecting inline marker types (mark, ins, del) +#### 选择行内标记类型(mark, ins, del) + +```js "return true;" ins="inserted" del="deleted" +function demo() { + console.log('These are inserted and deleted marker types'); + // The return statement uses the default marker type + return true; +} +``` + +### Word Wrap +### 自动换行 + +[Word Wrap](https://expressive-code.com/key-features/word-wrap/) +[自动换行](https://expressive-code.com/key-features/word-wrap/) + +#### Configuring word wrap per block +#### 按代码块配置自动换行 + +```js wrap +// Example with wrap +function getLongString() { + return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide' +} +``` + +--- + +```js wrap=false +// Example with wrap=false +function getLongString() { + return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide' +} +``` + +#### Configuring indentation of wrapped lines +#### 配置换行后的缩进 + +```js wrap preserveIndent +// Example with preserveIndent (enabled by default) +function getLongString() { + return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide' +} +``` + +--- + +```js wrap preserveIndent=false +// Example with preserveIndent=false +function getLongString() { + return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide' +} +``` + +## Collapsible Sections +## 可折叠部分 + +[Collapsible Sections](https://expressive-code.com/plugins/collapsible-sections/) +[可折叠部分](https://expressive-code.com/plugins/collapsible-sections/) + +```js collapse={1-5, 12-14, 21-24} +// All this boilerplate setup code will be collapsed +import { someBoilerplateEngine } from '@example/some-boilerplate' +import { evenMoreBoilerplate } from '@example/even-more-boilerplate' + +const engine = someBoilerplateEngine(evenMoreBoilerplate()) + +// This part of the code will be visible by default +engine.doSomething(1, 2, 3, calcFn) + +function calcFn() { + // You can have multiple collapsed sections + const a = 1 + const b = 2 + const c = a + b + + // This will remain visible + console.log(`Calculation result: ${a} + ${b} = ${c}`) + return c +} + +// All this code until the end of the block will be collapsed again +engine.closeConnection() +engine.freeMemory() +engine.shutdown({ reason: 'End of example boilerplate code' }) +``` + +## Line Numbers +## 行号 + +[Line Numbers](https://expressive-code.com/plugins/line-numbers/) +[行号](https://expressive-code.com/plugins/line-numbers/) + +### Displaying line numbers per block +### 按代码块显示行号 + +```js showLineNumbers +// This code block will show line numbers +console.log('Greetings from line 2!') +console.log('I am on line 3') +``` + +--- + +```js showLineNumbers=false +// Line numbers are disabled for this block +console.log('Hello?') +console.log('Sorry, do you know what line I am on?') +``` + +### Changing the starting line number +### 更改起始行号 + +```js showLineNumbers startLineNumber=5 +console.log('Greetings from line 5!') +console.log('I am on line 6') +``` diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 1d29e3b04..136ae2e2b 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -496,17 +496,7 @@ function initCustomScrollbar() { autoHideSuspend: false, }, }); - const preElements = document.querySelectorAll('pre'); - preElements.forEach((ele) => { - OverlayScrollbars(ele, { - scrollbars: { - theme: 'scrollbar-base scrollbar-dark px-2', - autoHide: 'leave', - autoHideDelay: 500, - autoHideSuspend: false - } - }); - }); + const katexElements = document.querySelectorAll('.katex-display') as NodeListOf; katexElements.forEach((ele) => { OverlayScrollbars(ele, { diff --git a/src/plugins/expressive-code/custom-copy-button.ts b/src/plugins/expressive-code/custom-copy-button.ts new file mode 100644 index 000000000..47e9cb759 --- /dev/null +++ b/src/plugins/expressive-code/custom-copy-button.ts @@ -0,0 +1,90 @@ +import { definePlugin } from "@expressive-code/core"; +import type { Element } from "hast"; + +export function pluginCustomCopyButton() { + return definePlugin({ + name: "Custom Copy Button", + hooks: { + postprocessRenderedBlock: (context) => { + function traverse(node: Element) { + if (node.type === "element" && node.tagName === "pre") { + processCodeBlock(node); + return; + } + if (node.children) { + for (const child of node.children) { + if (child.type === "element") traverse(child); + } + } + } + + function processCodeBlock(node: Element) { + const copyButton = { + type: "element" as const, + tagName: "button", + properties: { + className: ["copy-btn"], + "aria-label": "Copy code", + }, + children: [ + { + type: "element" as const, + tagName: "div", + properties: { + className: ["copy-btn-icon"], + }, + children: [ + { + type: "element" as const, + tagName: "svg", + properties: { + viewBox: "0 -960 960 960", + xmlns: "http://www.w3.org/2000/svg", + className: ["copy-btn-icon", "copy-icon"], + }, + children: [ + { + type: "element" as const, + tagName: "path", + properties: { + d: "M368.37-237.37q-34.48 0-58.74-24.26-24.26-24.26-24.26-58.74v-474.26q0-34.48 24.26-58.74 24.26-24.26 58.74-24.26h378.26q34.48 0 58.74 24.26 24.26 24.26 24.26 58.74v474.26q0 34.48-24.26 58.74-24.26 24.26-58.74 24.26H368.37Zm0-83h378.26v-474.26H368.37v474.26Zm-155 238q-34.48 0-58.74-24.26-24.26-24.26-24.26-58.74v-515.76q0-17.45 11.96-29.48 11.97-12.02 29.33-12.02t29.54 12.02q12.17 12.03 12.17 29.48v515.76h419.76q17.45 0 29.48 11.96 12.02 11.97 12.02 29.33t-12.02 29.54q-12.03 12.17-29.48 12.17H213.37Zm155-238v-474.26 474.26Z", + }, + children: [], + }, + ], + }, + { + type: "element" as const, + tagName: "svg", + properties: { + viewBox: "0 -960 960 960", + xmlns: "http://www.w3.org/2000/svg", + className: ["copy-btn-icon", "success-icon"], + }, + children: [ + { + type: "element" as const, + tagName: "path", + properties: { + d: "m389-377.13 294.7-294.7q12.58-12.67 29.52-12.67 16.93 0 29.61 12.67 12.67 12.68 12.67 29.53 0 16.86-12.28 29.14L419.07-288.41q-12.59 12.67-29.52 12.67-16.94 0-29.62-12.67L217.41-430.93q-12.67-12.68-12.79-29.45-.12-16.77 12.55-29.45 12.68-12.67 29.62-12.67 16.93 0 29.28 12.67L389-377.13Z", + }, + children: [], + }, + ], + }, + ], + }, + ], + } as Element; + + if (!node.children) { + node.children = []; + } + node.children.push(copyButton); + } + + traverse(context.renderData.blockAst); + }, + }, + }); +} diff --git a/src/plugins/expressive-code/language-badge.ts b/src/plugins/expressive-code/language-badge.ts new file mode 100644 index 000000000..e681ebbbb --- /dev/null +++ b/src/plugins/expressive-code/language-badge.ts @@ -0,0 +1,49 @@ +/** + * Based on the discussion at https://github.com/expressive-code/expressive-code/issues/153#issuecomment-2282218684 + */ +import { definePlugin } from "@expressive-code/core"; + +export function pluginLanguageBadge() { + return definePlugin({ + name: "Language Badge", + // @ts-ignore + baseStyles: ({ _cssVar }) => ` + [data-language]::before { + position: absolute; + z-index: 2; + right: 0.5rem; + top: 0.5rem; + padding: 0.1rem 0.5rem; + content: attr(data-language); + font-size: 0.75rem; + font-weight: bold; + text-transform: uppercase; + color: oklch(0.75 0.1 var(--hue)); + background: oklch(0.33 0.035 var(--hue)); + border-radius: 0.5rem; + pointer-events: none; + transition: opacity 0.3s; + opacity: 0; + } + .frame:not(.has-title):not(.is-terminal) { + @media (hover: none) { + & [data-language]::before { + opacity: 1; + margin-right: 3rem; + } + & [data-language]:active::before { + opacity: 0; + } + } + @media (hover: hover) { + & [data-language]::before { + opacity: 1; + } + &:hover [data-language]::before { + opacity: 0; + } + } + } + `, + }); +} diff --git a/src/styles/expressive-code.css b/src/styles/expressive-code.css new file mode 100644 index 000000000..12bb24c6b --- /dev/null +++ b/src/styles/expressive-code.css @@ -0,0 +1,3 @@ +.expressive-code .frame { + @apply !shadow-none; +} diff --git a/src/styles/main.css b/src/styles/main.css index f517d8c03..e5dee6683 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -110,22 +110,6 @@ .btn-regular-dark.success { @apply bg-[oklch(0.75_0.14_var(--hue))] dark:bg-[oklch(0.75_0.14_var(--hue))] } - - .copy-btn-icon { - @apply absolute top-1/2 left-1/2 transition -translate-x-1/2 -translate-y-1/2 - } - .copy-btn .copy-icon { - @apply opacity-100 fill-white dark:fill-white/75 - } - .copy-btn.success .copy-icon { - @apply opacity-0 fill-[var(--deep-text)] - } - .copy-btn .success-icon { - @apply opacity-0 - } - .copy-btn.success .success-icon { - @apply opacity-100 - } } .custom-md img, #post-cover img { diff --git a/src/styles/markdown.css b/src/styles/markdown.css index 5a4a6d8e9..1b2231eb0 100644 --- a/src/styles/markdown.css +++ b/src/styles/markdown.css @@ -60,16 +60,34 @@ } } - pre { - @apply bg-[var(--codeblock-bg)] !important; - @apply rounded-xl px-5; + .copy-btn { + all: initial; + @apply btn-regular-dark opacity-0 shadow-lg shadow-black/50 absolute active:scale-90 h-8 w-8 top-3 right-3 text-sm rounded-lg transition-all ease-in-out z-20 cursor-pointer; + } + .frame:hover .copy-btn { + opacity: 1; + } - code { - @apply bg-transparent text-inherit text-sm p-0; + .copy-btn-icon { + @apply absolute top-1/2 left-1/2 transition -translate-x-1/2 -translate-y-1/2 w-4 h-4 fill-white pointer-events-none; + } + .copy-btn .copy-icon { + @apply opacity-100 fill-white dark:fill-white/75; + } + .copy-btn.success .copy-icon { + @apply opacity-0 fill-[var(--deep-text)] + } + .copy-btn .success-icon { + @apply opacity-0 fill-white; + } + .copy-btn.success .success-icon { + @apply opacity-100 + } - ::selection { - @apply bg-[var(--codeblock-selection)]; - } + .expressive-code { + @apply my-4; + ::selection { + @apply bg-[var(--codeblock-selection)]; } } diff --git a/src/styles/variables.styl b/src/styles/variables.styl index 392b6fcfb..874d66d06 100644 --- a/src/styles/variables.styl +++ b/src/styles/variables.styl @@ -57,7 +57,8 @@ define({ --inline-code-color: var(--btn-content) --selection-bg: oklch(0.90 0.05 var(--hue)) oklch(0.40 0.08 var(--hue)) --codeblock-selection: oklch(0.40 0.08 var(--hue)) - --codeblock-bg: oklch(0.2 0.015 var(--hue)) oklch(0.17 0.015 var(--hue)) + --codeblock-bg: oklch(0.17 0.015 var(--hue)) oklch(0.17 0.015 var(--hue)) + --codeblock-topbar-bg: oklch(0.3 0.02 var(--hue)) oklch(0.12 0.015 var(--hue)) --license-block-bg: black(0.03) var(--codeblock-bg) diff --git a/src/types/config.ts b/src/types/config.ts index efc9dd6cc..4cafbb9ff 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -111,3 +111,7 @@ export type BlogPostData = { nextTitle?: string; nextSlug?: string; }; + +export type ExpressiveCodeConfig = { + theme: string; +}; \ No newline at end of file diff --git a/src/utils/setting-utils.ts b/src/utils/setting-utils.ts index 9a18f94ae..3cb55d891 100644 --- a/src/utils/setting-utils.ts +++ b/src/utils/setting-utils.ts @@ -1,3 +1,4 @@ +import { expressiveCodeConfig } from "@/config"; import type { LIGHT_DARK_MODE } from "@/types/config"; import { AUTO_MODE, @@ -42,6 +43,10 @@ export function applyThemeToDocument(theme: LIGHT_DARK_MODE) { } break; } + document.documentElement.setAttribute( + "data-theme", + expressiveCodeConfig.theme, + ); } export function setTheme(theme: LIGHT_DARK_MODE): void {