{"id":30347998,"url":"https://github.com/sredevopsorg/sredevopsorg-ghost-theme","last_synced_at":"2026-05-17T01:05:04.229Z","repository":{"id":259585424,"uuid":"862449996","full_name":"sredevopsorg/sredevopsorg-ghost-theme","owner":"sredevopsorg","description":"A Ghost v6 Theme made for SREDevOps.org based on Tailwind CSS with sidebar navigation and dark theme by default.","archived":false,"fork":false,"pushed_at":"2026-05-16T23:26:02.000Z","size":3879,"stargazers_count":9,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-16T23:27:14.921Z","etag":null,"topics":["ghost","ghost-blog","ghost-cms","ghost-theme"],"latest_commit_sha":null,"homepage":"https://www.sredevops.org/","language":"Handlebars","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/sredevopsorg.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-09-24T16:08:49.000Z","updated_at":"2026-05-16T21:09:24.000Z","dependencies_parsed_at":"2025-03-23T18:27:45.629Z","dependency_job_id":"a12cd9c6-9a25-43fd-90d3-9762c2bb5baf","html_url":"https://github.com/sredevopsorg/sredevopsorg-ghost-theme","commit_stats":null,"previous_names":["sredevopsorg/sredevopsorg-ghost-theme"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/sredevopsorg/sredevopsorg-ghost-theme","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sredevopsorg%2Fsredevopsorg-ghost-theme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sredevopsorg%2Fsredevopsorg-ghost-theme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sredevopsorg%2Fsredevopsorg-ghost-theme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sredevopsorg%2Fsredevopsorg-ghost-theme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sredevopsorg","download_url":"https://codeload.github.com/sredevopsorg/sredevopsorg-ghost-theme/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sredevopsorg%2Fsredevopsorg-ghost-theme/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33124143,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T18:38:32.183Z","status":"ssl_error","status_checked_at":"2026-05-16T18:38:29.903Z","response_time":115,"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":["ghost","ghost-blog","ghost-cms","ghost-theme"],"created_at":"2025-08-18T17:30:16.390Z","updated_at":"2026-05-17T01:05:04.222Z","avatar_url":"https://github.com/sredevopsorg.png","language":"Handlebars","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SREDevOps.org Ghost Theme\n\n\u003e **Ghost v6 Theme** for [SREDevOps.org](https://www.sredevops.org) — Multi-locale, Tailwind CSS v3, responsive, dark-mode first, with SVG icons, sidebar navigation, and tag-based language filtering.\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Ghost Compatibility](https://img.shields.io/badge/Ghost-%3E%3D6.0.0-lightgrey)](https://ghost.org)\n[![Node Engine](https://img.shields.io/badge/Node-%3E%3D22-green)](https://nodejs.org)\n\n---\n\n## 🌐 Multi-Locale Architecture\n\nThis theme implements a **template inheritance + tag-based routing strategy** to serve distinct content per locale without requiring separate Ghost instances. This approach aligns with community workarounds discussed in the [Ghost Forum](https://forum.ghost.org/t/different-locales-with-different-content/62836).\n\n### Template Inheritance Pattern\n\n```\n┌─────────────────────────────────────┐\n│ routes.yaml                          │\n│ • /en/* → home-en.hbs               │\n│ • /es/* → home-es.hbs               │\n│ • /br/* → home-br.hbs               │\n└─────────┬───────────────────────────┘\n          │\n          ▼\n┌─────────────────────────────────────┐\n│ home-*.hbs (collection template)    │\n│ • Defines collection query/filter   │\n│ • Renders post list via partials    │\n│ • {{!\u003c default-*.hbs}} inheritance  │\n└─────────┬───────────────────────────┘\n          │\n          ▼\n┌─────────────────────────────────────┐\n│ custom-*.hbs (post/page template)   │\n│ • Locale-specific post layout       │\n│ • Localized metadata, TOC, comments │\n│ • {{!\u003c default-*.hbs}} inheritance  │\n└─────────┬───────────────────────────┘\n          │\n          ▼\n┌─────────────────────────────────────┐\n│ default-*.hbs (layout shell)        │\n│ • \u003chtml lang=\"*\"\u003e attribute         │\n│ • Common \u003chead\u003e, assets, footer     │\n│ • {{{body}}} injection point        │\n└─────────────────────────────────────┘\n```\n\n\u003e 💡 **Key Insight**: Each locale uses its own `default-*.hbs` layout shell to ensure proper `lang` attributes, meta tags, and localized UI strings. The `{{{body}}}` Handlebars placeholder in `default-*.hbs` receives the rendered output from `custom-*.hbs` or `home-*.hbs`.\n\n### Language Routing \u0026 Tag Filtering\n\n| Locale | URL Pattern | Required Tags | Exclusion Tags | Layout Shell |\n|--------|-------------|---------------|----------------|--------------|\n| **English (default)** | `/` or `/en/{slug}/` | `en`, `hash-en` | `-es`, `-br` | `default.hbs` |\n| **Spanish** | `/es/{slug}/` | `es`, `hash-es` | `-en`, `-br` | `default-es.hbs` |\n| **Portuguese (BR)** | `/br/{slug}/` | `br`, `hash-br` | `-en`, `-es` | `default-br.hbs` |\n\n\u003e ⚠️ **Critical**: The **default locale (English)** is configured in **Ghost Admin → Settings → General → Publication language**. All root-level routes (`/`, `/page/2/`, etc.) serve English content unless explicitly routed otherwise.\n\n### `routes.yaml` Core Configuration\n\n```yaml\ncollections:\n  /es/:\n    template: home-es\n    permalink: /es/{slug}/\n    filter: tag:es+tag:-en+tag:-br\n    data: tag.es\n\n  /en/:\n    template: home-en\n    permalink: /en/{slug}/\n    filter: tag:en+tag:-es+tag:-br\n    data: tag.en\n\n  /br/:\n    template: home-br\n    permalink: /br/{slug}/\n    filter: tag:br+tag:-es+tag:-en\n    data: tag.br\n\n# Fallback: English as default locale (configured in Ghost Admin)\ntaxonomies:\n  tag: /tag/{slug}/\n  author: /author/{slug}/\n```\n\n✅ **Why this works**: Ghost's `filter` syntax supports boolean logic (`+` for AND, `-` for NOT), enabling precise content segregation per locale while maintaining a single content database. The `template` directive ensures each collection uses its locale-specific layout chain.\n\n---\n\n## 📋 Table of Contents\n\n- [Prerequisites](#-prerequisites)\n- [Installation](#-installation)\n- [Development Workflow](#-development-workflow)\n- [Locale Content Authoring](#-locale-content-authoring)\n- [Template Architecture](#-template-architecture)\n- [Theme Configuration](#-theme-configuration)\n- [Testing \u0026 Validation](#-testing--validation)\n- [Deployment](#-deployment)\n- [Contributing](#-contributing)\n- [License](#-license)\n\n---\n\n## 🔧 Prerequisites\n\n| Dependency | Version | Purpose |\n|------------|---------|---------|\n| **Node.js** | `\u003e=22` | Runtime for build tooling |\n| **Yarn** | `\u003e=1.22` | Package management (preferred over npm) |\n| **Ghost** | `\u003e=6.0` | Local development server |\n| **Docker** *(optional)* | Latest | Run Ghost via official container |\n\n\u003e 🐳 **Ghost Local Setup**: Follow the [official Docker guide](https://docs.ghost.org/install/docker/) for a reproducible dev environment.\n\n---\n\n## 🚀 Installation\n\n### 1. Clone \u0026 Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/sredevopsorg/sredevopsorg-ghost-theme.git\ncd sredevopsorg-ghost-theme\n\n# Install dependencies (Yarn required)\nyarn install\n```\n\n### 2. Configure Ghost\n\n1. Start your local Ghost instance:\n\n   ```bash\n   # If using Docker Compose (recommended)\n   docker compose up -d\n   \n   # Or via Ghost-CLI\n   ghost start\n   ```\n\n2. Upload `routes.yaml` to **Ghost Admin → Settings → Routing**\n\n3. Upload the theme:\n   - Via Admin: **Settings → Design → Upload theme**\n   - Or symlink for development:\n\n     ```bash\n     ln -s /path/to/sredevopsorg-ghost-theme \\\n       /path/to/ghost/content/themes/sredevopsorg-ghost-theme\n     ```\n\n4. **Critical**: Set your default locale in **Ghost Admin → Settings → General → Publication language** (e.g., `en` for English). This determines which templates serve root-level routes.\n\n5. Activate the theme in **Ghost Admin → Design**\n\n### 3. Start Development Server\n\n```bash\nyarn dev\n```\n\nThis triggers:\n\n- Tailwind CSS compilation with `@tailwindcss/forms` and `@tailwindcss/typography`\n- Asset bundling via Gulp\n- LiveReload for template/CSS changes\n\n\u003e 🔁 **Hot reload** is enabled for `.hbs`, `.css`, and `.js` files. Browser refreshes automatically on save.\n\n---\n\n## ✍️ Locale Content Authoring\n\n### Tagging Posts for Language Filtering\n\nWhen creating content in Ghost Admin or via Markdown import:\n\n```yaml\n---\ntitle: \"My Post Title\"\nslug: \"my-post-slug\"\ntags:\n  - en          # Primary language slug (required)\n  - hash-en     # Required for filter consistency\n  - Kubernetes  # Topic tags\n  - SRE\n---\n```\n\n⚠️ **Critical**: Omitting either `en`/`es`/`br` **or** its `hash-*` counterpart will cause the post to not appear in locale-specific collections due to the `filter` logic in `routes.yaml`.\n\n### Template Resolution Flow\n\n```mermaid\ngraph LR\n    A[Request: /es/my-post/] --\u003e B[routes.yaml filter]\n    B --\u003e C{tag:es AND NOT en/br?}\n    C --\u003e|Yes| D[home-es.hbs]\n    D --\u003e E[{{!\u003c default-es.hbs}}]\n    E --\u003e F[\u003chtml lang='es'\u003e + assets]\n    F --\u003e G[{{{body}}} ← custom-es.hbs content]\n```\n\n### Creating Locale-Specific Templates\n\n1. **Copy the base template**:\n\n   ```bash\n   cp default.hbs default-es.hbs\n   cp custom.hbs custom-es.hbs\n   cp home.hbs home-es.hbs\n   ```\n\n2. **Update the layout shell** (`default-es.hbs`):\n\n   ```handlebars\n   \u003c!DOCTYPE html\u003e\n   \u003chtml lang=\"es\"\u003e {{!-- Critical for SEO/accessibility --}}\n   \u003chead\u003e\n     \u003cmeta charset=\"utf-8\"\u003e\n     \u003ctitle\u003e{{meta_title}}\u003c/title\u003e\n     {{!-- Spanish-specific OG tags --}}\n     \u003cmeta property=\"og:locale\" content=\"es_CL\"\u003e\n     {{ghost_head}}\n   \u003c/head\u003e\n   \u003cbody class=\"{{body_class}}\"\u003e\n     {{\u003e\"components/nav-es\"}} {{!-- Optional: localized nav --}}\n     {{{body}}} {{!-- Injects custom-es.hbs content --}}\n     {{\u003e\"components/footer\"}}\n   \u003c/body\u003e\n   \u003c/html\u003e\n   ```\n\n3. **Customize content templates** (`custom-es.hbs`):\n   - Localize UI strings (\"Autor\", \"Publicado\", \"Índice\")\n   - Adjust date formats (`{{date published_at format=\"DD MMM YYYY\"}}`)\n   - Conditionally render locale-specific components\n\n---\n\n## 🏗️ Template Architecture Reference\n\n| File | Role | Inheritance | Locale Scope |\n|------|------|-------------|--------------|\n| `default.hbs` | Base HTML shell for English | None (root) | English (default) |\n| `default-es.hbs` | Base HTML shell for Spanish | None (root) | Spanish |\n| `default-br.hbs` | Base HTML shell for Portuguese | None (root) | Portuguese (BR) |\n| `custom.hbs` | Post/page content layout | `{{!\u003c default}}` | English |\n| `custom-es.hbs` | Post/page content layout | `{{!\u003c default-es}}` | Spanish |\n| `home.hbs` | Collection/listing template | `{{!\u003c default}}` | English |\n| `home-es.hbs` | Collection/listing template | `{{!\u003c default-es}}` | Spanish |\n| `post-card-es.hbs` | Post preview partial | Standalone | Spanish |\n\n\u003e 🔄 **Inheritance Syntax**: `{{!\u003c filename}}` at the top of a template tells Ghost: *\"Render this file's content inside the `{{{body}}}` placeholder of `filename`\"*.\n\n---\n\n## ⚙️ Theme Configuration\n\nCustomize behavior via **Ghost Admin → Settings → Theme**:\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `background_color` | Color | `#0f172a` | Base background for dark theme |\n| `lazy_images` | Boolean | `false` | Enable native lazy-loading on homepage |\n| `share_buttons` | Boolean | `true` | Show social share UI on posts |\n| `show_langs` | Boolean | `false` | Display language switcher in sidebar |\n| `show_sso` | Boolean | `false` | Show SSO login option in sidebar |\n\n### Image Size Presets\n\nConfigured in `package.json` → `config.image_sizes`:\n\n```json\n\"image_sizes\": {\n  \"xs\": { \"width\": 100 },\n  \"s\":  { \"width\": 220 },\n  \"m\":  { \"width\": 300 },\n  \"l\":  { \"width\": 600 },\n  \"xl\": { \"width\": 900 }\n}\n```\n\nUse in templates: `{{img_url feature_image size=\"l\"}}`\n\n---\n\n## 🧪 Testing \u0026 Validation\n\n### Local Testing\n\n```bash\n# Build production assets\nyarn build\n\n# Validate theme against Ghost spec\nyarn test:dev    # Verbose output\nyarn test:ci     # Fail on warnings (for CI)\n```\n\n### Locale-Specific Validation\n\n```bash\n# Test Spanish routing locally\ncurl -I http://localhost:2368/es/ | grep \"lang\"\n# Expected: \u003chtml lang=\"es\"\u003e\n\n```\n\n### Lighthouse Audits\n\nThe theme targets:\n\n- ✅ Performance ≥ 90 (with lazy loading enabled)\n- ✅ Accessibility ≥ 95 (proper `lang` attributes per locale)\n- ✅ SEO ≥ 100 (with localized meta tags and hreflang)\n\nRun via Chrome DevTools\n\n---\n\n## 🚢 Deployment\n\n### Option 1: Ghost Admin Upload\n\n1. Build assets:\n\n   ```bash\n   yarn build\n   ```\n\n2. Zip the theme:\n\n   ```bash\n   zip -r sredevopsorg-ghost-theme.zip . \\\n     -x \"*.git*\" \"node_modules/*\" \".github/*\"\n   ```\n\n3. Upload via **Ghost Admin → Design → Upload theme**\n\n### Option 2: GitHub Actions (Recommended)\n\nThis repo includes a [Deploy Ghost Theme Action](.github/workflows/deploy.yml) that:\n\n- Builds assets on push to `main`\n- Deploys via Ghost Admin API\n- Supports environment-specific config (staging/prod)\n\nConfigure secrets:\n\n- `GHOST_ADMIN_API_URL`\n- `GHOST_ADMIN_API_KEY`\n\n---\n\n## 🤝 Contributing\n\nWe welcome contributions aligned with our [Code of Conduct](CODE_OF_CONDUCT.md).\n\n### Development Guidelines\n\n- **Branching**: Use feature branches (`feat/locale-switcher`, `fix/og-tags-es`)\n- **Commits**: Follow [Conventional Commits](https://www.conventionalcommits.org/)\n- **PRs**: Include screenshots for UI changes; update README if behavior changes\n- **Testing**: Run `yarn test:ci` before submitting\n\n### Adding a New Locale (e.g., `pt` for Portugal)\n\n1. **Create layout shell**:\n\n   ```bash\n   cp default.hbs default-pt.hbs\n   # Edit: \u003chtml lang=\"pt\"\u003e, OG locale, localized strings\n   ```\n\n2. **Create content templates**:\n\n   ```bash\n   cp custom.hbs custom-pt.hbs\n   cp home.hbs home-pt.hbs\n   # Localize UI text, date formats, component partials\n   ```\n\n3. **Update `routes.yaml`**:\n\n   ```yaml\n   /pt/:\n     template: home-pt\n     permalink: /pt/{slug}/\n     filter: tag:pt+tag:-en+tag:-es+tag:-br\n     data: tag.pt\n   ```\n\n4. **Update documentation**:\n   - Add row to the [Language Routing table](#language-routing--tag-filtering)\n   - Document any locale-specific partials (e.g., `nav-pt.hbs`)\n\n5. **Test thoroughly**:\n   - Verify `lang=\"pt\"` in rendered HTML\n   - Confirm tag filtering excludes other locales\n   - Validate SEO meta tags with `og:locale=\"pt_PT\"`\n\n---\n\n## 📜 License\n\n- **Code**: [MIT License](LICENSE) — use, modify, distribute freely\n- **Content**: CC BY 4.0 (for SREDevOps.org editorial content)\n- **Third-party assets**: Respect upstream licenses (Tailwind CSS: MIT, Ghost: MIT)\n\n---\n\n## 🙏 Credits\n\n- **Author**: Nicolás Georger ([@ngeorger](https://github.com/ngeorger)) — SRE/DevOps practitioner, Santiago, Chile\n- **Inspiration**:\n  - [Priority Vision's \"Aspect\" Theme](https://priority.vision)\n  - [@TryGhost \"Source\" Theme](https://github.com/TryGhost/Source)\n- **Community**: Ghost Forum contributors for multi-locale pattern validation\n- **Tooling**: Tailwind CSS, Gulp, PostCSS, GScan\n\n---\n\n\u003e 🌎 **LatAm Note**: This theme was built with LatAm infrastructure constraints in mind — minimal external dependencies, optimized asset delivery, and community-driven localization patterns. For questions about deploying in Chile/Argentina/Brazil contexts, open an issue or reach out via [SREDevOps.org](https://www.sredevops.org).\n\n*Last updated: May 2026 | Ghost v6 compatible*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsredevopsorg%2Fsredevopsorg-ghost-theme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsredevopsorg%2Fsredevopsorg-ghost-theme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsredevopsorg%2Fsredevopsorg-ghost-theme/lists"}