{"id":24740825,"url":"https://github.com/solitudera/solitude-interface","last_synced_at":"2026-04-14T00:01:45.721Z","repository":{"id":274385190,"uuid":"909658944","full_name":"SolitudeRA/Solitude-Interface","owner":"SolitudeRA","description":"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.","archived":false,"fork":false,"pushed_at":"2026-03-30T02:42:42.000Z","size":14102,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-30T05:33:43.410Z","etag":null,"topics":["astro","astro-theme","blog","ghost-cms","headless-cms","i18n","react","static-site","tailwindcss","typescipt"],"latest_commit_sha":null,"homepage":"https://www.solitudera.com/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SolitudeRA.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-12-29T12:04:25.000Z","updated_at":"2026-03-30T02:42:37.000Z","dependencies_parsed_at":"2025-01-27T01:23:47.423Z","dependency_job_id":"536e3ef3-2605-4159-9afd-fd41c006193d","html_url":"https://github.com/SolitudeRA/Solitude-Interface","commit_stats":null,"previous_names":["solitudera/solitude-interface"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SolitudeRA/Solitude-Interface","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SolitudeRA%2FSolitude-Interface","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SolitudeRA%2FSolitude-Interface/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SolitudeRA%2FSolitude-Interface/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SolitudeRA%2FSolitude-Interface/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SolitudeRA","download_url":"https://codeload.github.com/SolitudeRA/Solitude-Interface/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SolitudeRA%2FSolitude-Interface/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31776013,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T20:17:16.280Z","status":"ssl_error","status_checked_at":"2026-04-13T20:17:08.216Z","response_time":93,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["astro","astro-theme","blog","ghost-cms","headless-cms","i18n","react","static-site","tailwindcss","typescipt"],"created_at":"2025-01-27T23:48:18.849Z","updated_at":"2026-04-14T00:01:45.715Z","avatar_url":"https://github.com/SolitudeRA.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Solitude Interface\n\n![thumbnail](docs/assets/thumbnail.png)\n\n![Node.js](https://img.shields.io/badge/Node.js-≥18-339933?logo=node.js\u0026logoColor=white)\n![pnpm](https://img.shields.io/badge/pnpm-≥9-F69220?logo=pnpm\u0026logoColor=white)\n![Astro](https://img.shields.io/badge/Astro-5.x-BC52EE?logo=astro\u0026logoColor=white)\n![License](https://img.shields.io/badge/License-MIT-blue)\n\nA modern personal blog interface built with Astro and powered by Ghost CMS API.\n\nRead this in: English | [简体中文](docs/i18n/README.zh.md) | [日本語](docs/i18n/README.ja.md)\n\n---\n\n## 📑 Table of Contents\n\n- [Features](#-features)\n- [Screenshots](#-screenshots)\n- [Quick Start](#-quick-start)\n- [Content Publishing Guide](#-content-publishing-guide)\n- [Multi-language Content](#-multi-language-content)\n- [For Developers](#️-for-developers)\n- [License](#-license)\n\n---\n\n## 🚀 Features\n\n- High-performance static site built with Astro\n- Ghost CMS integration (Headless)\n- **Multi-language support (zh/ja/en)** with automatic fallback\n- Responsive design with dark/light theme toggle\n- Multiple post type displays (articles, gallery, video, music)\n- SEO optimized (hreflang, canonical, html lang)\n\n---\n\n## 📸 Screenshots\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand screenshots\u003c/summary\u003e\n\n### Home\n\n![Home](docs/assets/home.png)\n\n### Post\n\n![Post](docs/assets/post.png)\n\n### About Me\n\n![About-Me](docs/assets/about-me.png)\n\n### Post Detail\n\n![Post-Detail](docs/assets/post-detail.png)\n\n\u003c/details\u003e\n\n---\n\n## 📖 Documentation\n\n| Document                                  | Description                                                          |\n| ----------------------------------------- | -------------------------------------------------------------------- |\n| **README.md** (this file)                 | User guide - setup and content publishing                            |\n| [**DEVELOPMENT.md**](docs/DEVELOPMENT.md) | Developer guide - architecture, testing, workflows, and contributing |\n\n---\n\n## 🚀 Quick Start\n\n### 1. Install Dependencies\n\nThis project uses **pnpm**.\n\n```bash\n# (Recommended) Enable pnpm via Corepack\ncorepack enable pnpm\n\npnpm install\n```\n\n\u003e If `corepack` is not available on your system, you can install pnpm globally with `npm i -g pnpm`.\n\n### 2. Configure Environment\n\nCreate a `.env` file from the template:\n\n```bash\ncp .env.example .env\n```\n\nEdit `.env` with your Ghost instance information:\n\n```env\nGHOST_URL=https://your-ghost-instance.com\nGHOST_CONTENT_KEY=your-content-api-key-here\nGHOST_VERSION=v5.0\nGHOST_TIMEOUT=5000\nSITE_URL=https://your-site.example.com\nIMAGE_HOST_URL=\nGOOGLE_ANALYTICS_TAG_ID=\n```\n\n#### Environment Variables\n\n##### Required\n\n| Variable            | Description                                |\n| ------------------- | ------------------------------------------ |\n| `GHOST_URL`         | Base URL of your Ghost instance            |\n| `GHOST_CONTENT_KEY` | Ghost Content API key                      |\n| `SITE_URL`          | Public site URL for canonical and hreflang |\n\n##### Optional\n\n| Variable                  | Default | Description                                                                    |\n| ------------------------- | ------- | ------------------------------------------------------------------------------ |\n| `GHOST_VERSION`           | `v5.0`  | Ghost Content API version                                                      |\n| `GHOST_TIMEOUT`           | `5000`  | Ghost request timeout in milliseconds                                          |\n| `IMAGE_HOST_URL`          | -       | Image host/CDN used for remote image domain allowlist                          |\n| `GOOGLE_ANALYTICS_TAG_ID` | -       | Google tag / GA4 Measurement ID (e.g., `G-XXXX`). Leave empty to disable       |\n| `CF_ACCESS_CLIENT_ID`     | -       | Cloudflare Access Service Token Client ID (if Ghost is protected by CF Access) |\n| `CF_ACCESS_CLIENT_SECRET` | -       | Cloudflare Access Service Token Client Secret                                  |\n\n### Cloudflare Access Configuration (Optional)\n\nIf 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:\n\n1. **Create a Service Token** in your Cloudflare Zero Trust dashboard:\n    - Go to **Access** → **Service Auth** → **Service Tokens**\n    - Click **Create Service Token**\n    - Copy the **Client ID** and **Client Secret**\n\n2. **Add the token to your `.env`**:\n\n    ```env\n    CF_ACCESS_CLIENT_ID=your-client-id.access\n    CF_ACCESS_CLIENT_SECRET=your-client-secret\n    ```\n\n3. **Add a bypass policy** in your Access Application:\n    - Go to **Access** → **Applications** → Your Ghost App\n    - Add a policy with **Action: Service Auth** and select your service token\n\n\u003e **Note**: The API client will automatically include `CF-Access-Client-Id` and `CF-Access-Client-Secret` headers when these environment variables are set.\n\n### 3. Get Your Ghost Content API Key\n\n1. Log in to your Ghost Admin panel\n2. Navigate to **Settings** → **Integrations**\n3. Click **Add custom integration**\n4. Copy the **Content API Key** into your `.env` file\n\n\u003e **Tip**: Use the Ghost Demo API for testing:\n\u003e\n\u003e ```env\n\u003e GHOST_URL=https://demo.ghost.io\n\u003e GHOST_CONTENT_KEY=22444f78447824223cefc48062\n\u003e ```\n\n### 4. Start Development Server\n\n```bash\npnpm dev\n```\n\nVisit `http://localhost:4321` to see your site.\n\n---\n\n## 🔧 Common Commands\n\n| Command            | Description                                                 |\n| ------------------ | ----------------------------------------------------------- |\n| `pnpm dev`         | Start the development server                                |\n| `pnpm build`       | Build the production site                                   |\n| `pnpm preview`     | Preview the production build                                |\n| `pnpm astro sync`  | Generate type definitions (useful after env/schema changes) |\n| `pnpm astro check` | Typecheck and validate Astro project                        |\n| `pnpm test`        | Run the test suite                                          |\n| `pnpm format`      | Format the codebase                                         |\n\n---\n\n## 📝 Content Publishing Guide\n\n### Classification Tags\n\nUse **regular tags** to classify your posts. The system recognizes special prefixes:\n\n| Tag Prefix    | Purpose           | Example                                                    |\n| ------------- | ----------------- | ---------------------------------------------------------- |\n| `type-`       | Post display type | `type-article`, `type-gallery`, `type-video`, `type-music` |\n| `category-`   | Content category  | `category-tech`, `category-life`, `category-design`        |\n| `series-`     | Article series    | `series-astro-tutorial`, `series-web-dev-basics`           |\n| _(no prefix)_ | General tags      | `JavaScript`, `React`, `Photography`                       |\n\n#### Supported Post Types\n\n| Type Tag       | Display Style               |\n| -------------- | --------------------------- |\n| `type-article` | Standard article layout     |\n| `type-gallery` | Image gallery with carousel |\n| `type-video`   | Video player embed          |\n| `type-music`   | Audio player embed          |\n| _(default)_    | Default card layout         |\n\n---\n\n## 🌐 Multi-language Content\n\n### URL Structure\n\n| Route          | Description                                 |\n| -------------- | ------------------------------------------- |\n| `/`            | Auto-redirects to user's preferred language |\n| `/zh/`         | Chinese posts listing                       |\n| `/ja/`         | Japanese posts listing                      |\n| `/en/`         | English posts listing                       |\n| `/zh/p/{key}/` | Chinese version of article                  |\n| `/ja/p/{key}/` | Japanese version of article                 |\n| `/en/p/{key}/` | English version of article                  |\n\n### Required Tags for Multi-language\n\nUse **internal tags** (starting with `#`) in Ghost:\n\n| Internal Tag     | Purpose                      | Example                            |\n| ---------------- | ---------------------------- | ---------------------------------- |\n| `#lang-{locale}` | Specify post language        | `#lang-zh`, `#lang-ja`, `#lang-en` |\n| `#i18n-{key}`    | Translation group identifier | `#i18n-intro-to-solitude`          |\n\n\u003e **Note**: In Ghost Content API, internal tags `#xxx` are converted to slug format `hash-xxx`.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e📘 Step-by-Step Guide: Creating Multi-language Posts\u003c/strong\u003e\u003c/summary\u003e\n\n**Important**: Each language version is a **separate post** in Ghost. They are linked together using the same `#i18n-{key}` tag.\n\n#### Step 1: Plan your translation group key\n\nChoose a unique key for your article, e.g., `astro-guide`. This key will be used in:\n\n- The `#i18n-astro-guide` tag (to link all versions)\n- The URL: `/zh/p/astro-guide`, `/ja/p/astro-guide`, `/en/p/astro-guide`\n\n#### Step 2: Create the Chinese version\n\nIn Ghost Admin, create a new post:\n\n1. Write your article content in Chinese\n2. Open the **Post settings** panel (gear icon)\n3. Scroll down to **Tags** section\n4. Add these tags:\n    - `#lang-zh` (language tag - note the `#` prefix!)\n    - `#i18n-astro-guide` (translation group tag)\n    - `type-article` (optional: post type)\n    - `category-tech` (optional: category)\n5. Publish the post\n\n#### Step 3: Create the Japanese version\n\nCreate a **new, separate post** in Ghost:\n\n1. Write your article content in Japanese\n2. Add these tags:\n    - `#lang-ja` ← Different language\n    - `#i18n-astro-guide` ← **Same** translation key!\n    - `type-article`, `category-tech` (same as Chinese version)\n3. Publish the post\n\n#### Step 4: Create the English version\n\nCreate another **new, separate post** in Ghost:\n\n1. Write your article content in English\n2. Add these tags:\n    - `#lang-en` ← Different language\n    - `#i18n-astro-guide` ← **Same** translation key!\n    - `type-article`, `category-tech` (same as other versions)\n3. Publish the post\n\n#### Result\n\nNow you have 3 separate posts in Ghost, all linked by `#i18n-astro-guide`:\n\n- Chinese post → accessible at `/zh/p/astro-guide`\n- Japanese post → accessible at `/ja/p/astro-guide`\n- English post → accessible at `/en/p/astro-guide`\n\nUsers can switch between versions using the language switcher on the article page.\n\n### Complete Example\n\n| Post Title                             | Tags                                                             |\n| -------------------------------------- | ---------------------------------------------------------------- |\n| \"Astro 入门指南\" (Chinese)             | `#lang-zh`, `#i18n-astro-guide`, `type-article`, `category-tech` |\n| \"Astro入門ガイド\" (Japanese)           | `#lang-ja`, `#i18n-astro-guide`, `type-article`, `category-tech` |\n| \"Getting Started with Astro\" (English) | `#lang-en`, `#i18n-astro-guide`, `type-article`, `category-tech` |\n\n\u003c/details\u003e\n\n### Fallback Behavior\n\n- If a language version doesn't exist, the default language (Chinese) is shown\n- A notice banner appears indicating the fallback\n- Language switcher shows available/unavailable versions\n\n---\n\n## 🛠️ For Developers\n\nSee [**docs/DEVELOPMENT.md**](docs/DEVELOPMENT.md) for:\n\n- 🔧 Tech Stack \u0026 Project Structure\n- 🧞 Available Commands\n- 📋 Testing Guide (Unit \u0026 Integration)\n- 🏗️ Architecture \u0026 Code Reference\n\n### Contributing\n\nContributions 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.\n\n---\n\n## 🙏 Acknowledgments\n\n- [Astro](https://astro.build/) - The web framework for content-driven websites\n- [Ghost](https://ghost.org/) - The professional publishing platform\n- [TailwindCSS](https://tailwindcss.com/) - A utility-first CSS framework\n- [React](https://react.dev/) - The library for web and native user interfaces\n\n---\n\n## 📄 License\n\nThis project is open source and available under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolitudera%2Fsolitude-interface","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsolitudera%2Fsolitude-interface","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolitudera%2Fsolitude-interface/lists"}