This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Personal blog "ไบฌๅ" (knotens.org) built on VitePress with a fully custom theme โ a personalized instance of vitepress-theme-curve (by imsyy). Site content is in Chinese. README.md is the upstream theme's documentation, not project-specific docs.
Uses pnpm (v9.15.4, Node >=20). .npmrc sets shamefully-hoist=true.
pnpm devโ dev server at http://127.0.0.1:9877pnpm buildโvitepress build, outputs to.vitepress/distpnpm previewโ serve the built sitepnpm lintโ ESLint (airbnb-base + vue3) with--fixpnpm formatโ Prettier write across the repopnpm upโ shortcut forgit add . && git commit -m "update blog" && git push
No test suite is configured.
Pushing to master triggers .github/workflows/ โ builds and publishes .vitepress/dist to the pages branch (GitHub Pages). vercel.json also configures a Vercel deployment (SPA-style rewrites, output .vitepress/dist).
Site customization lives in the root themeConfig.mjs (site title, nav, footer, comment system, search, etc.). .vitepress/init.mjs Object.assign-merges it over the default config at .vitepress/theme/assets/themeConfig.mjs.
- Edit the root
themeConfig.mjsfor all site settings. - Never rename or delete
.vitepress/theme/assets/themeConfig.mjsโ it is the fallback the merge starts from (.gitignoreexplicitly un-ignores it). - The merge is shallow: overriding a nested object in the root file replaces that whole object.
Build-time data layer. .vitepress/config.mjs calls getAllPosts() (theme/utils/getPostData.mjs), which globs posts/**.md, parses frontmatter with gray-matter, and derives tags/categories/archives. This data is injected into themeConfig.postData / tagsData / categoriesData / archivesData and consumed across the theme. RSS is generated in the buildEnd hook.
Custom theme โ .vitepress/theme/ is a complete custom theme:
index.mjsโ registers Pinia (withpinia-plugin-persistedstate), vue-instantsearch, and route guards.App.vueโ root layout. Page type is chosen by route, not router config:/posts/in the path โPostview;frontmatter.layout === 'home'โHome; otherwise โPage.components/andviews/are auto-imported (unplugin-vue-components); Vue + VitePress APIs are auto-imported too โ no explicitimportneeded in.vuefiles.store/index.jsโ single Pinia store (mainStore) for UI state (theme, player, scroll, menus).- Path alias
@โ.vitepress/theme.
posts/โ blog articles. File path = URL path. Frontmatter fields read by the data layer:title, date, categories, tags, description, top, cover(pluscopyright, referencesused by the post view).top: truepins an article; posts sort bytopthendatedescending.pages/โ site pages; each.mdmounts a view component (e.g.pages/about.mdโviews/About.vue).- Dynamic routes use VitePress
[param].paths.mjsfiles, all driven by post data:page/[num].md(home pagination,postSizeposts per page),pages/categories/[name].md,pages/tags/[name].md. public/โ static assets served at root (images/,fonts/,favicon.ico,robots.txt).
theme/utils/markdownConfig.mjs adds, beyond VitePress defaults:
- Custom containers:
:::timeline,:::radio,:::button,:::card - Obsidian-style admonitions via fenced code blocks:
```ad-note,ad-warning,ad-tip,ad-danger, etc. markdown-it-attrs, tabs plugin, math (MathJax3), line numbers, TOC levels 1โ3- Images are wrapped for the Fancybox lightbox (toggle via
fancybox.enable)
- ESLint and Prettier both enforce double quotes; Prettier: 2-space indent, semicolons,
printWidth100,trailingComma: all. ignoreDeadLinks: trueโ broken links will not fail the build.- Production builds strip
console.log(terserpure_funcs). srcExcludekeepsREADME.mdandTODO.mdfrom being built as pages.- External links are rewritten through a redirect interstitial (
jumpRedirect,public/redirect.html);cleanUrlsis on.