Skip to content

Repository files navigation

IceHome

Personal website and blog built with Astro, Tailwind CSS v4, and deployed on Cloudflare Pages.

Features

  • Static site generation (zero client-side JS framework)
  • Internationalization (English & Traditional Chinese) with hreflang + localized sitemap
  • Dark mode with system preference detection
  • Blog from Markdown files with syntax highlighting, table of contents, and prev/next navigation
  • Optimized responsive images via astro:assets (WebP, lazy loading)
  • RSS feeds per locale (/en/rss.xml, /zh/rss.xml)
  • Tag archive pages (/en/tags/..., /zh/tags/...)
  • SEO: canonical URLs, Open Graph, JSON-LD structured data, sitemap
  • Self-hosted Inter font + system CJK font stack
  • Responsive design with shadcn/ui aesthetic

Local Development

npm install
npm run dev      # Start dev server at http://localhost:4321
npm run build    # Build static site to dist/
npm run preview  # Preview the build locally

Cloudflare Pages Deployment

  1. Push this repo to GitHub
  2. In Cloudflare Pages, create a new project and connect the repo
  3. Configure:
    • Build command: npm run build
    • Output directory: dist
    • Node.js version: 20 (set via environment variable NODE_VERSION=20)

Redirects (including the //en root redirect and legacy URL redirects) live in public/_redirects.

Adding Blog Posts

Create a .md file in the /blog/ directory with this frontmatter:

---
title: "Your Post Title"
description: "A brief description (used for SEO and RSS)"
date: 2025-03-01
locale: "en"          # "en" or "zh"
tags: ["tag1", "tag2"]
image: "./images/your-post/cover.jpg"  # optional, relative to /blog/
imageAlt: "What the cover shows"       # optional
draft: false                           # optional, defaults to false
---

Your markdown content here...

Posts are automatically discovered — no manual route registration needed.

Bilingual pairing: name the files my-post.md (en) and my-post-zh.md (zh). Both share the URL slug my-post; the language switcher links between them automatically.

Images

Put post images in blog/images/<post-name>/ and reference them relatively so Astro optimizes them (resizing, WebP, lazy loading):

![Alt text](./images/my-post/photo.jpg "Optional caption rendered as figcaption")

Compress large photos first (resizes to 1600px, ~80% quality):

node scripts/optimize-images.mjs   # edit MAPPINGS inside for new files

Use ASCII file names (no spaces or CJK characters).

i18n

  • All routes are prefixed: /en/* and /zh/*
  • The root / redirects to /en (server-side via _redirects)
  • Set locale: "en" or locale: "zh" in blog post frontmatter
  • The language switcher preserves the current path and falls back to the blog index when a translation doesn't exist
  • UI strings live in src/i18n/ui.ts

Project Structure

IceHome/
├── blog/              # Markdown blog posts
│   └── images/        # Post images (optimized at build time)
├── public/            # Static assets served as-is (_redirects, robots.txt, og-default.png)
├── scripts/           # optimize-images.mjs, generate-og-default.mjs
├── src/
│   ├── components/    # Astro components
│   ├── i18n/          # Translations and i18n utilities
│   ├── layouts/       # Page layouts
│   ├── lib/           # posts.ts (translation pairing), utils.ts
│   ├── pages/         # File-based routes (en/, zh/, rss.xml per locale)
│   ├── plugins/       # rehype-figure (caption rendering)
│   └── styles/        # Global CSS (design tokens, CJK typography)
├── astro.config.mjs
└── package.json

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages