My personal website! Here, I share my projects, technical writing, and misc notes.
├── public/ # Static assets (images, favicon, etc.)
├── src/
│ ├── components/ # UI and layout components
│ ├── contents/ # Blog posts, notes, templates (Git submodule)
│ ├── lib/ # Utility and CMS logic
│ │ ├── cms/ # GraphQL CMS integration with Zod validation
│ │ ├── markdown/ # Custom remark/rehype plugins
│ │ ├── theme/ # Theme utilities and CSS variables
│ │ └── utils/ # Helper functions
│ ├── pages/ # Site pages and routes
│ └── styles/ # Global and modular CSS
├── astro.config.mjs # Astro configuration
├── package.json # Project dependencies and scripts
├── tsconfig.json # TypeScript configuration
Create a .env.local file in the root directory with your CMS credentials:
ADMIN_URL=https://your-cms-url.com
ADMIN_APIKEY=your-api-key-here
Install dependencies and initialize the content submodule:
npm install
git submodule update --init --recursive
Start the local development server:
npm run dev
Build for production:
npm run build
Preview the production build:
npm run preview
The site uses a hybrid content strategy with two data sources:
src/contents/ (Git Submodule)
↓
Content Collections Loader (glob pattern)
↓
Custom Markdown Loader (markdown-loader.ts)
↓
Remark Plugins (Markdown AST)
• remarkReferenceTranslation - Convert Obsidian links to routes
• remarkImageTranslation - Fix relative image paths
• remarkMath - Parse LaTeX math notation
↓
Rehype Plugins (HTML AST)
• rehypeExternalLinkAttr - Add attributes to external links
• rehypeHashStyleHeadings - Add hash-style heading IDs
• rehypeSectionize - Wrap content in semantic sections
• rehypeMathjax - Render mathematical expressions
↓
Static HTML Pages + Knowledge Graph Data
GraphQL CMS API
↓
graphqlFetch() - Error handling & validation
↓
Zod Schema Validation
↓
DTO → TypeScript Interface Transformation
↓
Astro Content Collections
↓
Static Project Pages
The markdown pipeline includes custom plugins for Obsidian compatibility:
blog/post.md → /blog/post and tracks internal links for the knowledge graphmedia/image.png → /src/contents/media/image.png<section> elements for table of contents generationAll CMS data fetching includes comprehensive error handling:
CMSError class