十年之约通过啦🎉!🎉
1153 字
6 分钟
增强Fuwari的代码块功能
AI 摘要
本文介绍如何为 Fuwari 博客引入 astro-expressive-code,实现更美观、强大的代码块展示效果,包括代码高亮、行号显示、折叠功能、主题切换等,提升阅读体验和代码可读性。
一、注释原代码块样式
---import "@fontsource-variable/jetbrains-mono";import "@fontsource-variable/jetbrains-mono/wght-italic.css";import path from 'node:path'import { getImage } from 'astro:assets'import { parseHTML } from 'linkedom'interface Props { class: string; basePath?: string}const { class: className, basePath = '/' } = Astro.props/**通常,“src”目录下的相对路径由Astro处理。*然而,插件无法处理的路径可能会出现在这里,并且需要单独处理。 */const html = await Astro.slots.render('default')const { document } = parseHTML(html)await (async () => { // biome-ignore lint/suspicious/noExplicitAny: <explanation> const modules: Record<string, any> = import.meta.glob( '../../**/*.{jpeg,jpg,png,tiff,webp,gif,svg,avif}', ) const re = /^(?![a-zA-Z]+:\/|\/)/ for (const img of document.querySelectorAll('img')) { const src = img.getAttribute('src') if (!src || !re.test(src)) continue const normalizedPath = path .normalize(path.join('../../', basePath, src)) .replaceAll('\\', '/') const moduleLoader = modules[normalizedPath] if (!moduleLoader) continue try { const module = await moduleLoader() const result = await getImage({ src: module.default }) img.setAttribute('src', result.src) } catch (error) { console.warn( `Skipping image "${normalizedPath}" due to processing error:`, error, ) } }})()---<div data-pagefind-body class={`prose dark:prose-invert prose-base !max-w-none custom-md ${className}`}> <!--<div class="prose dark:prose-invert max-w-none custom-md">--> <!--<div class="max-w-none custom-md">--> <slot/></div>
<!--禁用原代码块样式--><!--<script>--><!-- const observer = new MutationObserver(addPreCopyButton);--><!-- observer.observe(document.body, { childList: true, subtree: true });-->
<!-- function addPreCopyButton() {--><!-- observer.disconnect();-->
<!-- let codeBlocks = Array.from(document.querySelectorAll("pre"));-->
<!-- for (let codeBlock of codeBlocks) {--><!-- if (codeBlock.parentElement?.nodeName === "DIV" && codeBlock.parentElement?.classList.contains("code-block")) continue-->
<!-- let wrapper = document.createElement("div");--><!-- wrapper.className = "relative code-block";-->
<!-- let copyButton = document.createElement("button");--><!-- copyButton.className = "copy-btn btn-regular-dark absolute active:scale-90 h-8 w-8 top-2 right-2 opacity-75 text-sm p-1.5 rounded-lg transition-all ease-in-out";-->
<!-- codeBlock.setAttribute("tabindex", "0");--><!-- if (codeBlock.parentNode) {--><!-- codeBlock.parentNode.insertBefore(wrapper, codeBlock);--><!-- }-->
<!-- let copyIcon = `<svg class="copy-btn-icon copy-icon" xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px"><path 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"/></svg>`--><!-- let successIcon = `<svg class="copy-btn-icon success-icon" xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px"><path 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"/></svg>`--><!-- copyButton.innerHTML = `<div>${copyIcon} ${successIcon}</div>--><!-- `-->
<!-- wrapper.appendChild(codeBlock);--><!-- wrapper.appendChild(copyButton);-->
<!-- let timeout: ReturnType<typeof setTimeout>;--><!-- copyButton.addEventListener("click", async () => {--><!-- if (timeout) {--><!-- clearTimeout(timeout);--><!-- }--><!-- let text = codeBlock?.querySelector("code")?.innerText;--><!-- if (text === undefined) return;--><!-- await navigator.clipboard.writeText(text);--><!-- copyButton.classList.add("success");--><!-- timeout = setTimeout(() => {--><!-- copyButton.classList.remove("success");--><!-- }, 1000);--><!-- });--><!-- }-->
<!-- observer.observe(document.body, { childList: true, subtree: true });--><!-- }--><!--</script>-->
/* pre { @apply bg-[var(--codeblock-bg)] !important; @apply rounded-xl px-5;
code { @apply bg-transparent text-inherit text-sm p-0;
::selection { @apply bg-[var(--codeblock-selection)]; } } } */
function initCustomScrollbar() {18 collapsed lines
const bodyElement = document.querySelector('body'); if (!bodyElement) return; OverlayScrollbars( // docs say that a initialization to the body element would affect native functionality like window.scrollTo // but just leave it here for now { target: bodyElement, cancel: { nativeScrollbarsOverlaid: true, // don't initialize the overlay scrollbar if there is a native one } }, { scrollbars: { theme: 'scrollbar-base scrollbar-auto py-1', autoHide: 'move', autoHideDelay: 500, 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<HTMLElement>; katexElements.forEach((ele) => { OverlayScrollbars(ele, { scrollbars: { theme: 'scrollbar-base scrollbar-auto py-1', } }); });}
二、引入
pnpm astro add astro-expressive-code
三、配置文件中添加双主题
主题:https://expressive-code.com/guides/themes/#available-themes
- 在配置文件中添加双主题
export default defineConfig({ // ... integrations: [ // ... expressiveCode({ themes: ["catppuccin-frappe", "catppuccin-latte"], }) ]})
- 修改
LightDarkSwitch.svelte
文件中的onMount
和switchScheme
方法
onMount(() => { mode = getStoredTheme()
if (mode === DARK_MODE) { document.documentElement.setAttribute("data-theme", "catppuccin-frappe"); } else { document.documentElement.setAttribute("data-theme", "light-plus"); }
const darkModePreference = window.matchMedia('(prefers-color-scheme: dark)') const changeThemeWhenSchemeChanged: Parameters< typeof darkModePreference.addEventListener<'change'> >[1] = e => { applyThemeToDocument(mode) } darkModePreference.addEventListener('change', changeThemeWhenSchemeChanged) return () => { darkModePreference.removeEventListener( 'change', changeThemeWhenSchemeChanged, ) }})
function switchScheme(newMode: LIGHT_DARK_MODE) { mode = newMode setTheme(newMode)
if (mode === DARK_MODE) { document.documentElement.setAttribute("data-theme", "catppuccin-frappe"); } else { document.documentElement.setAttribute("data-theme", "light-plus"); }}
四、使用格式方法
标题
```js title="标题"console.log("Line 1");console.log("Line 2");let a = 1;let b = 2;
** 高亮指定行**
```js {2,4-5} ins={3,7}console.log("Line 1");console.log("Line 2");let a = 1;let b = 2;let c = 3;let d = 4;let e = 5;let f = 6;let g = 7;console.log(a + b);let h = 4;let i = 5;let j = 6;let k = 7;let l = 7;
** 新增/删除指定行**
```js ins={3,7} del={6}console.log("Line 1");console.log("Line 2");let a = 1;let b = 2;let c = 3;let d = 4;let e = 5;let f = 6;let g = 7;console.log(a + b);let h = 4;let i = 5;let j = 6;let k = 7;let l = 7;
高亮块
```js "a + b" del="let g = 7"//{2,4-5}高亮 ins={3,7}新增 del={6}删除console.log("Line 1");console.log("Line 2");let a = 1;let b = 2;let c = 3;let d = 4;let e = 5;let f = 6;let g = 7;console.log(a + b);let h = 4;let i = 5;let j = 6;let k = 7;let l = 7;
折叠代码/代码行数
需要引入
pnpm add @expressive-code/plugin-line-numbers //显示行数pnpm add @expressive-code/plugin-collapsible-sections //折叠
import { pluginLineNumbers } from '@expressive-code/plugin-line-numbers'import { pluginCollapsibleSections } from '@expressive-code/plugin-collapsible-sections'...expressiveCode({ themes: ["catppuccin-frappe", "catppuccin-latte"], plugins: [pluginLineNumbers(),pluginCollapsibleSections()],})],
例:
```js collapse={8-13, 15-16} startLineNumber=7//{2,4-5}高亮 ins={3,7}新增 del={6}删除console.log("Line 1");console.log("Line 2");let a = 1;let b = 2;let c = 3;let d = 4;let e = 5;let f = 6;let g = 7;console.log(a + b);let h = 4;let i = 5;let j = 6;let k = 7;let l = 7;
增强Fuwari的代码块功能
https://fuwari.vercel.app/posts/bjk/fuwari代码块主题/