https://github.com/solitudera/solitude-interface
A modern, high-performance personal blog interface built with Astro + React + TailwindCSS, powered by Ghost CMS as headless backend. Features multi-language support (zh/ja/en), dark/light themes, and multiple post types.
https://github.com/solitudera/solitude-interface
astro astro-theme blog ghost-cms headless-cms i18n react static-site tailwindcss typescipt
Last synced: 2 months ago
JSON representation
A modern, high-performance personal blog interface built with Astro + React + TailwindCSS, powered by Ghost CMS as headless backend. Features multi-language support (zh/ja/en), dark/light themes, and multiple post types.
- Host: GitHub
- URL: https://github.com/solitudera/solitude-interface
- Owner: SolitudeRA
- License: mit
- Created: 2024-12-29T12:04:25.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2026-03-30T02:42:42.000Z (3 months ago)
- Last Synced: 2026-03-30T05:33:43.410Z (3 months ago)
- Topics: astro, astro-theme, blog, ghost-cms, headless-cms, i18n, react, static-site, tailwindcss, typescipt
- Language: TypeScript
- Homepage: https://www.solitudera.com/
- Size: 13.4 MB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Solitude Interface





A modern personal blog interface built with Astro and powered by Ghost CMS API.
Read this in: English | [简体中文](docs/i18n/README.zh.md) | [日本語](docs/i18n/README.ja.md)
---
## 📑 Table of Contents
- [Features](#-features)
- [Screenshots](#-screenshots)
- [Quick Start](#-quick-start)
- [Content Publishing Guide](#-content-publishing-guide)
- [Multi-language Content](#-multi-language-content)
- [For Developers](#️-for-developers)
- [License](#-license)
---
## 🚀 Features
- High-performance static site built with Astro
- Ghost CMS integration (Headless)
- **Multi-language support (zh/ja/en)** with automatic fallback
- Responsive design with dark/light theme toggle
- Multiple post type displays (articles, gallery, video, music)
- SEO optimized (hreflang, canonical, html lang)
---
## 📸 Screenshots
Click to expand screenshots
### Home

### Post

### About Me

### Post Detail

---
## 📖 Documentation
| Document | Description |
| ----------------------------------------- | -------------------------------------------------------------------- |
| **README.md** (this file) | User guide - setup and content publishing |
| [**DEVELOPMENT.md**](docs/DEVELOPMENT.md) | Developer guide - architecture, testing, workflows, and contributing |
---
## 🚀 Quick Start
### 1. Install Dependencies
This project uses **pnpm**.
```bash
# (Recommended) Enable pnpm via Corepack
corepack enable pnpm
pnpm install
```
> If `corepack` is not available on your system, you can install pnpm globally with `npm i -g pnpm`.
### 2. Configure Environment
Create a `.env` file from the template:
```bash
cp .env.example .env
```
Edit `.env` with your Ghost instance information:
```env
GHOST_URL=https://your-ghost-instance.com
GHOST_CONTENT_KEY=your-content-api-key-here
GHOST_VERSION=v5.0
GHOST_TIMEOUT=5000
SITE_URL=https://your-site.example.com
IMAGE_HOST_URL=
GOOGLE_ANALYTICS_TAG_ID=
```
#### Environment Variables
##### Required
| Variable | Description |
| ------------------- | ------------------------------------------ |
| `GHOST_URL` | Base URL of your Ghost instance |
| `GHOST_CONTENT_KEY` | Ghost Content API key |
| `SITE_URL` | Public site URL for canonical and hreflang |
##### Optional
| Variable | Default | Description |
| ------------------------- | ------- | ------------------------------------------------------------------------------ |
| `GHOST_VERSION` | `v5.0` | Ghost Content API version |
| `GHOST_TIMEOUT` | `5000` | Ghost request timeout in milliseconds |
| `IMAGE_HOST_URL` | - | Image host/CDN used for remote image domain allowlist |
| `GOOGLE_ANALYTICS_TAG_ID` | - | Google tag / GA4 Measurement ID (e.g., `G-XXXX`). Leave empty to disable |
| `CF_ACCESS_CLIENT_ID` | - | Cloudflare Access Service Token Client ID (if Ghost is protected by CF Access) |
| `CF_ACCESS_CLIENT_SECRET` | - | Cloudflare Access Service Token Client Secret |
### Cloudflare Access Configuration (Optional)
If your Ghost instance is protected by [Cloudflare Access](https://developers.cloudflare.com/cloudflare-one/policies/access/), you need to configure Service Tokens to allow API access:
1. **Create a Service Token** in your Cloudflare Zero Trust dashboard:
- Go to **Access** → **Service Auth** → **Service Tokens**
- Click **Create Service Token**
- Copy the **Client ID** and **Client Secret**
2. **Add the token to your `.env`**:
```env
CF_ACCESS_CLIENT_ID=your-client-id.access
CF_ACCESS_CLIENT_SECRET=your-client-secret
```
3. **Add a bypass policy** in your Access Application:
- Go to **Access** → **Applications** → Your Ghost App
- Add a policy with **Action: Service Auth** and select your service token
> **Note**: The API client will automatically include `CF-Access-Client-Id` and `CF-Access-Client-Secret` headers when these environment variables are set.
### 3. Get Your Ghost Content API Key
1. Log in to your Ghost Admin panel
2. Navigate to **Settings** → **Integrations**
3. Click **Add custom integration**
4. Copy the **Content API Key** into your `.env` file
> **Tip**: Use the Ghost Demo API for testing:
>
> ```env
> GHOST_URL=https://demo.ghost.io
> GHOST_CONTENT_KEY=22444f78447824223cefc48062
> ```
### 4. Start Development Server
```bash
pnpm dev
```
Visit `http://localhost:4321` to see your site.
---
## 🔧 Common Commands
| Command | Description |
| ------------------ | ----------------------------------------------------------- |
| `pnpm dev` | Start the development server |
| `pnpm build` | Build the production site |
| `pnpm preview` | Preview the production build |
| `pnpm astro sync` | Generate type definitions (useful after env/schema changes) |
| `pnpm astro check` | Typecheck and validate Astro project |
| `pnpm test` | Run the test suite |
| `pnpm format` | Format the codebase |
---
## 📝 Content Publishing Guide
### Classification Tags
Use **regular tags** to classify your posts. The system recognizes special prefixes:
| Tag Prefix | Purpose | Example |
| ------------- | ----------------- | ---------------------------------------------------------- |
| `type-` | Post display type | `type-article`, `type-gallery`, `type-video`, `type-music` |
| `category-` | Content category | `category-tech`, `category-life`, `category-design` |
| `series-` | Article series | `series-astro-tutorial`, `series-web-dev-basics` |
| _(no prefix)_ | General tags | `JavaScript`, `React`, `Photography` |
#### Supported Post Types
| Type Tag | Display Style |
| -------------- | --------------------------- |
| `type-article` | Standard article layout |
| `type-gallery` | Image gallery with carousel |
| `type-video` | Video player embed |
| `type-music` | Audio player embed |
| _(default)_ | Default card layout |
---
## 🌐 Multi-language Content
### URL Structure
| Route | Description |
| -------------- | ------------------------------------------- |
| `/` | Auto-redirects to user's preferred language |
| `/zh/` | Chinese posts listing |
| `/ja/` | Japanese posts listing |
| `/en/` | English posts listing |
| `/zh/p/{key}/` | Chinese version of article |
| `/ja/p/{key}/` | Japanese version of article |
| `/en/p/{key}/` | English version of article |
### Required Tags for Multi-language
Use **internal tags** (starting with `#`) in Ghost:
| Internal Tag | Purpose | Example |
| ---------------- | ---------------------------- | ---------------------------------- |
| `#lang-{locale}` | Specify post language | `#lang-zh`, `#lang-ja`, `#lang-en` |
| `#i18n-{key}` | Translation group identifier | `#i18n-intro-to-solitude` |
> **Note**: In Ghost Content API, internal tags `#xxx` are converted to slug format `hash-xxx`.
📘 Step-by-Step Guide: Creating Multi-language Posts
**Important**: Each language version is a **separate post** in Ghost. They are linked together using the same `#i18n-{key}` tag.
#### Step 1: Plan your translation group key
Choose a unique key for your article, e.g., `astro-guide`. This key will be used in:
- The `#i18n-astro-guide` tag (to link all versions)
- The URL: `/zh/p/astro-guide`, `/ja/p/astro-guide`, `/en/p/astro-guide`
#### Step 2: Create the Chinese version
In Ghost Admin, create a new post:
1. Write your article content in Chinese
2. Open the **Post settings** panel (gear icon)
3. Scroll down to **Tags** section
4. Add these tags:
- `#lang-zh` (language tag - note the `#` prefix!)
- `#i18n-astro-guide` (translation group tag)
- `type-article` (optional: post type)
- `category-tech` (optional: category)
5. Publish the post
#### Step 3: Create the Japanese version
Create a **new, separate post** in Ghost:
1. Write your article content in Japanese
2. Add these tags:
- `#lang-ja` ← Different language
- `#i18n-astro-guide` ← **Same** translation key!
- `type-article`, `category-tech` (same as Chinese version)
3. Publish the post
#### Step 4: Create the English version
Create another **new, separate post** in Ghost:
1. Write your article content in English
2. Add these tags:
- `#lang-en` ← Different language
- `#i18n-astro-guide` ← **Same** translation key!
- `type-article`, `category-tech` (same as other versions)
3. Publish the post
#### Result
Now you have 3 separate posts in Ghost, all linked by `#i18n-astro-guide`:
- Chinese post → accessible at `/zh/p/astro-guide`
- Japanese post → accessible at `/ja/p/astro-guide`
- English post → accessible at `/en/p/astro-guide`
Users can switch between versions using the language switcher on the article page.
### Complete Example
| Post Title | Tags |
| -------------------------------------- | ---------------------------------------------------------------- |
| "Astro 入门指南" (Chinese) | `#lang-zh`, `#i18n-astro-guide`, `type-article`, `category-tech` |
| "Astro入門ガイド" (Japanese) | `#lang-ja`, `#i18n-astro-guide`, `type-article`, `category-tech` |
| "Getting Started with Astro" (English) | `#lang-en`, `#i18n-astro-guide`, `type-article`, `category-tech` |
### Fallback Behavior
- If a language version doesn't exist, the default language (Chinese) is shown
- A notice banner appears indicating the fallback
- Language switcher shows available/unavailable versions
---
## 🛠️ For Developers
See [**docs/DEVELOPMENT.md**](docs/DEVELOPMENT.md) for:
- 🔧 Tech Stack & Project Structure
- 🧞 Available Commands
- 📋 Testing Guide (Unit & Integration)
- 🏗️ Architecture & Code Reference
### Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
---
## 🙏 Acknowledgments
- [Astro](https://astro.build/) - The web framework for content-driven websites
- [Ghost](https://ghost.org/) - The professional publishing platform
- [TailwindCSS](https://tailwindcss.com/) - A utility-first CSS framework
- [React](https://react.dev/) - The library for web and native user interfaces
---
## 📄 License
This project is open source and available under the [MIT License](LICENSE).