From 4bab7d0d863afd36d5a84ac5cc5c983009ddf825 Mon Sep 17 00:00:00 2001 From: vorpax Date: Mon, 5 Jan 2026 22:41:39 +0100 Subject: [PATCH] Configure Quartz for production --- .gitea/workflows/build-deploy.yml | 67 ++++++++ DEPLOYMENT.md | 221 ++++++++++++++++++++++++++ Dockerfile => Dockerfile.dev | 0 Dockerfile.prod | 35 ++++ content/blog/index.md | 19 +++ content/homelab/Proxmox hosts.md | 11 ++ content/homelab/hardware/fatman.md | 42 +++++ content/homelab/hardware/littleboy.md | 35 ++++ content/homelab/hardware/optiplex.md | 35 ++++ content/homelab/index.md | 8 + content/index.md | 25 ++- content/templates/blog-post.md | 40 +++++ content/templates/guide.md | 81 ++++++++++ content/templates/homelab-doc.md | 79 +++++++++ content/templates/page.md | 10 ++ docker-compose.yml | 19 +++ nginx.conf | 43 +++++ quartz.config.ts | 8 +- quartz.layout.ts | 9 +- 19 files changed, 778 insertions(+), 9 deletions(-) create mode 100644 .gitea/workflows/build-deploy.yml create mode 100644 DEPLOYMENT.md rename Dockerfile => Dockerfile.dev (100%) create mode 100644 Dockerfile.prod create mode 100644 content/blog/index.md create mode 100644 content/homelab/Proxmox hosts.md create mode 100644 content/homelab/hardware/fatman.md create mode 100644 content/homelab/hardware/littleboy.md create mode 100644 content/homelab/hardware/optiplex.md create mode 100644 content/homelab/index.md create mode 100644 content/templates/blog-post.md create mode 100644 content/templates/guide.md create mode 100644 content/templates/homelab-doc.md create mode 100644 content/templates/page.md create mode 100644 docker-compose.yml create mode 100644 nginx.conf diff --git a/.gitea/workflows/build-deploy.yml b/.gitea/workflows/build-deploy.yml new file mode 100644 index 0000000..4d35720 --- /dev/null +++ b/.gitea/workflows/build-deploy.yml @@ -0,0 +1,67 @@ +name: Build and Push Quartz Wiki + +on: + push: + branches: + - v4 + +env: + REGISTRY: "gitea.vorpax.dev" + IMAGE_NAME: "vorpax/quartz-wiki" + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ gitea.actor }} + password: ${{ secrets.REGISTRY_TOKEN }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=sha,prefix= + type=raw,value=latest,enable=${{ gitea.ref == format('refs/heads/{0}', 'v4') }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile.prod + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Image digest + run: echo "Image built and pushed successfully" + + # Optional: Add deployment step + # Uncomment and configure this section if you want automatic deployment + # deploy: + # runs-on: ubuntu-latest + # needs: build-and-push + # steps: + # - name: Deploy to server + # uses: appleboy/ssh-action@v1.0.0 + # with: + # host: ${{ secrets.DEPLOY_HOST }} + # username: ${{ secrets.DEPLOY_USER }} + # key: ${{ secrets.DEPLOY_SSH_KEY }} + # script: | + # cd /path/to/quartz + # docker compose pull + # docker compose up -d diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..0975c92 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,221 @@ +# Déploiement Quartz Wiki + +Ce document explique comment déployer le site Quartz sur votre infrastructure homelab. + +## 📋 Prérequis + +- Instance Gitea avec Gitea Actions activé +- Gitea Container Registry configuré +- Secret `REGISTRY_TOKEN` configuré dans votre dépôt Gitea +- Serveur avec Docker et Docker Compose +- Traefik configuré comme reverse proxy (réseau `public`) + +## 🔧 Configuration Initiale + +### 1. Créer le Token Registry Gitea + +1. Aller dans **Settings → Applications** de votre compte Gitea +2. Créer un nouveau token avec les permissions `write:package` +3. Ajouter ce token comme secret `REGISTRY_TOKEN` dans votre dépôt + +### 2. Configurer Traefik (Optionnel) + +Si vous utilisez Traefik, ajoutez ces labels dans `docker-compose.yml`: + +```yaml +services: + quartz: + image: gitea.vorpax.dev/vorpax/quartz-wiki:latest + container_name: quartz-wiki + restart: unless-stopped + + networks: + - public + + labels: + # Enable Traefik + - "traefik.enable=true" + + # HTTP Router + - "traefik.http.routers.quartz.rule=Host(`wiki.vorpax.dev`)" + - "traefik.http.routers.quartz.entrypoints=websecure" + - "traefik.http.routers.quartz.tls=true" + - "traefik.http.routers.quartz.tls.certresolver=letsencrypt" + + # Service + - "traefik.http.services.quartz.loadbalancer.server.port=80" + + # HTTP to HTTPS redirect + - "traefik.http.routers.quartz-http.rule=Host(`wiki.vorpax.dev`)" + - "traefik.http.routers.quartz-http.entrypoints=web" + - "traefik.http.routers.quartz-http.middlewares=redirect-to-https" +``` + +## 🚀 Déploiement + +### Workflow Automatique (Recommandé) + +1. **Commit et Push vers v4**: + ```bash + git add . + git commit -m "Update content" + git push origin v4 + ``` + +2. **Le workflow Gitea Actions va automatiquement**: + - Builder l'image Docker + - Pusher vers `gitea.vorpax.dev/vorpax/quartz-wiki` + - Tagger avec `latest`, `v4`, et le SHA du commit + +3. **Sur votre serveur de production**: + ```bash + # Se connecter au registry Gitea + docker login gitea.vorpax.dev + + # Pull la nouvelle image + docker compose pull + + # Redémarrer le container + docker compose up -d + ``` + +### Build Local (Pour Testing) + +```bash +# Build l'image localement +docker compose build + +# Ou utiliser Dockerfile.prod directement +docker build -f Dockerfile.prod -t quartz-wiki:local . + +# Lancer +docker compose up -d +``` + +### Développement Local + +Pour le développement avec hot-reload: + +```bash +# Option 1: npx quartz +npx quartz build --serve +# Accessible sur http://localhost:8080 + +# Option 2: Docker dev +docker build -f Dockerfile.dev -t quartz-dev . +docker run -p 8080:8080 quartz-dev +``` + +## 📁 Structure du Projet + +``` +. +├── content/ # Contenu du site +│ ├── blog/ # Articles de blog +│ ├── homelab/ # Documentation homelab +│ │ ├── hardware/ # Pages hardware +│ │ ├── infrastructure/ # Infra docs +│ │ ├── services/ # Services docs +│ │ └── guides/ # Guides +│ └── templates/ # Templates Templater (non publiés) +├── quartz/ # Code source Quartz +├── quartz.config.ts # Configuration Quartz +├── quartz.layout.ts # Layout et composants +├── Dockerfile.prod # Dockerfile production (Nginx) +├── Dockerfile.dev # Dockerfile dev (--serve) +├── nginx.conf # Config Nginx +├── docker-compose.yml # Orchestration Docker +└── .gitea/workflows/ # CI/CD Gitea Actions +``` + +## 🔄 Workflow de Publication + +### Avec Obsidian + +1. **Éditer dans Obsidian**: + - Ouvrir le vault pointant vers `/content` + - Utiliser les templates dans `content/templates/` + - Ajouter `publish: true` dans le frontmatter + +2. **Utiliser Templater**: + - Installer le plugin Templater dans Obsidian + - Configurer le dossier de templates: `content/templates` + - Créer une nouvelle note avec un template (Ctrl+P → "Templater: Create new note from template") + +3. **Publier**: + ```bash + git add content/ + git commit -m "Add new blog post" + git push origin v4 + ``` + +### Sans Obsidian + +Créer un fichier markdown dans `content/blog/` ou `content/homelab/`: + +```yaml +--- +title: "Mon Article" +publish: true +date: 2026-01-05 +tags: + - homelab + - docker +description: "Description courte" +--- + +# Contenu ici +``` + +## 🏷️ Tags d'Images Disponibles + +Le workflow crée plusieurs tags: + +- `gitea.vorpax.dev/vorpax/quartz-wiki:latest` - Dernière version de la branche v4 +- `gitea.vorpax.dev/vorpax/quartz-wiki:v4` - Tag de branche +- `gitea.vorpax.dev/vorpax/quartz-wiki:` - Tag par commit SHA + +## 🔍 Troubleshooting + +### L'image ne se build pas dans Gitea Actions + +Vérifier que: +- Le secret `REGISTRY_TOKEN` est configuré +- Gitea Container Registry est activé +- Le runner Gitea Actions fonctionne + +### Les changements n'apparaissent pas + +```bash +# Forcer un nouveau pull +docker compose down +docker compose pull +docker compose up -d + +# Vérifier les logs +docker logs quartz-wiki +``` + +### 404 sur certaines pages + +Vérifier que: +- La page a `publish: true` dans le frontmatter +- Le fichier est dans `content/` +- Les wikilinks utilisent le bon chemin + +## 📊 Métriques + +Le site est configuré avec Plausible Analytics sur `wiki.vorpax.dev`. Vérifiez `quartz.config.ts:15-17` pour la configuration. + +## 🔐 Sécurité + +- Les fichiers dans `content/templates/` ne sont jamais publiés +- Les fichiers dans `content/private/` sont exclus du build +- Le dossier `.obsidian/` n'est pas versionné +- Nginx inclut des headers de sécurité (X-Frame-Options, X-Content-Type-Options, etc.) + +## 📚 Resources + +- [Documentation Quartz](https://quartz.jzhao.xyz/) +- [Gitea Actions Docs](https://docs.gitea.com/usage/actions/overview) +- [Gitea Container Registry](https://docs.gitea.com/usage/packages/container) diff --git a/Dockerfile b/Dockerfile.dev similarity index 100% rename from Dockerfile rename to Dockerfile.dev diff --git a/Dockerfile.prod b/Dockerfile.prod new file mode 100644 index 0000000..dbebd4c --- /dev/null +++ b/Dockerfile.prod @@ -0,0 +1,35 @@ +# Stage 1: Build Quartz site +FROM node:22-slim AS builder + +WORKDIR /usr/src/app + +# Copy package files +COPY package.json package-lock.json* ./ + +# Install dependencies +RUN npm ci + +# Copy source code +COPY . . + +# Build Quartz (this generates the static site in /public) +RUN npx quartz build + +# Stage 2: Serve with Nginx +FROM nginx:alpine + +# Copy the built static files from builder stage +COPY --from=builder /usr/src/app/public /usr/share/nginx/html + +# Copy custom nginx configuration +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Expose port 80 +EXPOSE 80 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1 + +# Start nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/content/blog/index.md b/content/blog/index.md new file mode 100644 index 0000000..4f3f5e1 --- /dev/null +++ b/content/blog/index.md @@ -0,0 +1,19 @@ +--- +title: Blog +publish: true +--- + +Welcome to my technical blog! Here you'll find articles, tutorials, and writeups on various topics including: + +- System Administration +- DevOps & Automation +- Containerization (Docker, Kubernetes) +- Self-hosting & Homelab +- Networking & Security +- Programming & Scripting + +All blog posts are listed below, sorted by date. You can also use tags to filter content by topic. + +--- + +> **Note**: This is a folder page. All blog posts in the `blog/` directory will be automatically listed below by Quartz. diff --git a/content/homelab/Proxmox hosts.md b/content/homelab/Proxmox hosts.md new file mode 100644 index 0000000..b019bb8 --- /dev/null +++ b/content/homelab/Proxmox hosts.md @@ -0,0 +1,11 @@ +--- +publish: true +title: My Physical Nodes +--- + +# All my nodes + +My main cluster is composed of 3 Physical Nodes : +- [[hardware/littleboy|Littleboy]] which is a Firebat T8 Pro Plus +- [[hardware/optiplex|Optiplex]] which is an Optiplex 7070 SFF with an i7-9700 and 64GB of RAM +- [[hardware/fatman|Fatman]] which is a custom built gaming PC repurposed into a beefy GPU workhorse \ No newline at end of file diff --git a/content/homelab/hardware/fatman.md b/content/homelab/hardware/fatman.md new file mode 100644 index 0000000..a8628ba --- /dev/null +++ b/content/homelab/hardware/fatman.md @@ -0,0 +1,42 @@ +--- +title: Fatman - GPU Workhorse +publish: true +tags: + - homelab + - hardware + - proxmox + - gpu +--- + +# Fatman + +**Type**: Custom built gaming PC repurposed as GPU workhorse + +## Specifications + +- **CPU**: +- **RAM**: +- **GPU**: +- **Storage**: +- **Network**: + +## Role in Cluster + +This node is part of the main Proxmox cluster, serving as a GPU-accelerated workstation for compute-intensive tasks. + +## Services Running + +- GPU-accelerated workloads +- List specific services/VMs/containers + +## GPU Passthrough + +Configuration details for GPU passthrough if applicable. + +## Notes + +Add any additional notes, configuration details, or special considerations for this node. + +--- + +Back to [[Proxmox hosts|Physical Nodes]] diff --git a/content/homelab/hardware/littleboy.md b/content/homelab/hardware/littleboy.md new file mode 100644 index 0000000..b2bfe14 --- /dev/null +++ b/content/homelab/hardware/littleboy.md @@ -0,0 +1,35 @@ +--- +title: Littleboy - Firebat T8 Pro Plus +publish: true +tags: + - homelab + - hardware + - proxmox +--- + +# Littleboy + +**Model**: Firebat T8 Pro Plus + +## Specifications + +- **CPU**: +- **RAM**: +- **Storage**: +- **Network**: + +## Role in Cluster + +This node is part of the main Proxmox cluster. + +## Services Running + +- List services/VMs/containers running on this node + +## Notes + +Add any additional notes, configuration details, or special considerations for this node. + +--- + +Back to [[Proxmox hosts|Physical Nodes]] diff --git a/content/homelab/hardware/optiplex.md b/content/homelab/hardware/optiplex.md new file mode 100644 index 0000000..68715b9 --- /dev/null +++ b/content/homelab/hardware/optiplex.md @@ -0,0 +1,35 @@ +--- +title: Optiplex - Dell Optiplex 7070 SFF +publish: true +tags: + - homelab + - hardware + - proxmox +--- + +# Optiplex + +**Model**: Dell Optiplex 7070 SFF + +## Specifications + +- **CPU**: Intel Core i7-9700 +- **RAM**: 64GB +- **Storage**: +- **Network**: + +## Role in Cluster + +This node is part of the main Proxmox cluster. + +## Services Running + +- List services/VMs/containers running on this node + +## Notes + +Add any additional notes, configuration details, or special considerations for this node. + +--- + +Back to [[Proxmox hosts|Physical Nodes]] diff --git a/content/homelab/index.md b/content/homelab/index.md new file mode 100644 index 0000000..25afc48 --- /dev/null +++ b/content/homelab/index.md @@ -0,0 +1,8 @@ +--- +title: Everything related to my homelab +publish: true +--- + +# Here are all the things related to my Homelab !!! + +Hiii \ No newline at end of file diff --git a/content/index.md b/content/index.md index 2bdfd83..d4ca254 100644 --- a/content/index.md +++ b/content/index.md @@ -1,6 +1,25 @@ --- -title: Welcome to Quartz +title: Welcome to Vorpax Wiki +publish: true --- -This is a blank Quartz installation. -See the [documentation](https://quartz.jzhao.xyz) for how to get started. +Welcome to my personal wiki and technical blog! This site serves as both documentation for my homelab infrastructure and a platform to share technical insights, guides, and experiences. + +## 🏠 [[homelab/index|Homelab]] + +Explore the architecture, services, and infrastructure of my self-hosted homelab cluster. From virtualization to networking, find detailed documentation on how everything is set up and maintained. + +## 📝 [[blog/index|Blog]] + +Technical articles, tutorials, and writeups on various topics including system administration, DevOps, containerization, and more. + +## 🔍 What You'll Find Here + +- **Infrastructure Documentation**: Detailed specs and configurations of my homelab hardware and software +- **Service Guides**: How-to guides for deploying and managing self-hosted services +- **Technical Articles**: Deep dives into interesting technical topics and solutions +- **Project Writeups**: Documentation of personal projects and experiments + +--- + +*Use the search bar above or the explorer on the left to navigate through the wiki.* diff --git a/content/templates/blog-post.md b/content/templates/blog-post.md new file mode 100644 index 0000000..d92d1ea --- /dev/null +++ b/content/templates/blog-post.md @@ -0,0 +1,40 @@ +--- +title: "<% tp.file.title %>" +publish: true +date: <% tp.date.now("YYYY-MM-DD") %> +tags: + - +description: +--- + +# <% tp.file.title %> + +> **TL;DR**: Brief summary of the article + +## Introduction + +Introduce the topic and what the reader will learn. + +## Main Content + +### Section 1 + +Content goes here. + +### Section 2 + +More content. + +## Conclusion + +Wrap up the article and key takeaways. + +## References + +- Links to related resources +- Documentation +- Related articles + +--- + +*Published on <% tp.date.now("MMMM DD, YYYY") %>* diff --git a/content/templates/guide.md b/content/templates/guide.md new file mode 100644 index 0000000..0d4d13a --- /dev/null +++ b/content/templates/guide.md @@ -0,0 +1,81 @@ +--- +title: "<% tp.file.title %>" +publish: true +date: <% tp.date.now("YYYY-MM-DD") %> +tags: + - guide +description: +--- + +# <% tp.file.title %> + +## Overview + +What this guide covers and what you'll accomplish. + +## Prerequisites + +- Requirement 1 +- Requirement 2 +- Required knowledge + +## What You'll Need + +- Hardware/software requirements +- Tools +- Access requirements + +## Steps + +### Step 1: Setup + +Detailed instructions for the first step. + +```bash +# Example commands +``` + +### Step 2: Configuration + +Continue with configuration steps. + +```bash +# More commands +``` + +### Step 3: Verification + +How to verify everything is working. + +```bash +# Verification commands +``` + +## Troubleshooting + +### Issue 1 + +**Problem**: Description of the problem + +**Solution**: How to fix it + +### Issue 2 + +**Problem**: Description + +**Solution**: Fix + +## Next Steps + +- What to do after completing this guide +- Related guides +- Advanced configurations + +## References + +- Links to documentation +- Related resources + +--- + +*Created: <% tp.date.now("YYYY-MM-DD") %>* diff --git a/content/templates/homelab-doc.md b/content/templates/homelab-doc.md new file mode 100644 index 0000000..2c65763 --- /dev/null +++ b/content/templates/homelab-doc.md @@ -0,0 +1,79 @@ +--- +title: "<% tp.file.title %>" +publish: true +tags: + - homelab +description: +--- + +# <% tp.file.title %> + +## Overview + +Brief description of this service/infrastructure component. + +## Specifications + +- **Type**: +- **Version**: +- **Hardware**: +- **OS**: +- **Resources**: + - CPU: + - RAM: + - Storage: + +## Configuration + +### Installation + +Steps or notes on how this was installed. + +### Configuration Files + +Important configuration details. + +```yaml +# Example configuration +``` + +### Environment Variables + +```bash +KEY=value +``` + +## Network Configuration + +- **IP Address**: +- **Ports**: +- **Domain**: +- **Access**: + +## Services/Features + +- Feature 1 +- Feature 2 + +## Maintenance + +### Backup Strategy + +How this service is backed up. + +### Update Procedure + +How to update this service. + +## Related Services + +- Links to related documentation +- Dependencies + +## Troubleshooting + +Common issues and solutions. + +--- + +*Last updated: <% tp.date.now("YYYY-MM-DD") %>* diff --git a/content/templates/page.md b/content/templates/page.md new file mode 100644 index 0000000..eda5e00 --- /dev/null +++ b/content/templates/page.md @@ -0,0 +1,10 @@ +--- +title: "<% tp.file.title %>" +publish: true +tags: + - +--- + +# <% tp.file.title %> + +Content goes here. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..675734a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,19 @@ +services: + quartz: + # Option 1: Pull from Gitea Container Registry (recommended for production) + image: gitea.vorpax.dev/vorpax/quartz-wiki:latest + + # Option 2: Build locally (uncomment for local development) + # build: + # context: . + # dockerfile: Dockerfile.prod + + container_name: quartz-wiki + restart: unless-stopped + + networks: + - public + +networks: + public: + external: true diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..a6dedda --- /dev/null +++ b/nginx.conf @@ -0,0 +1,43 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + # Custom 404 page + error_page 404 /404.html; + + # Compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript; + gzip_disable "MSIE [1-6]\."; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Cache static assets + location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Main location block + # Quartz generates URLs without .html extension, so we need to handle that + location / { + # Try to serve the file directly, then with .html extension, + # then as a directory, finally 404 + try_files $uri $uri.html $uri/ =404; + } + + # Disable access to hidden files + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } +} diff --git a/quartz.config.ts b/quartz.config.ts index b3db3d6..4d598b3 100644 --- a/quartz.config.ts +++ b/quartz.config.ts @@ -8,15 +8,15 @@ import * as Plugin from "./quartz/plugins" */ const config: QuartzConfig = { configuration: { - pageTitle: "Quartz 4", - pageTitleSuffix: "", + pageTitle: "Vorpax Wiki", + pageTitleSuffix: " | Vorpax Wiki", enableSPA: true, enablePopovers: true, analytics: { provider: "plausible", }, locale: "en-US", - baseUrl: "quartz.jzhao.xyz", + baseUrl: "wiki.vorpax.dev", ignorePatterns: ["private", "templates", ".obsidian"], defaultDateType: "modified", theme: { @@ -73,7 +73,7 @@ const config: QuartzConfig = { Plugin.Description(), Plugin.Latex({ renderEngine: "katex" }), ], - filters: [Plugin.RemoveDrafts()], + filters: [Plugin.RemoveDrafts(), Plugin.ExplicitPublish()], emitters: [ Plugin.AliasRedirects(), Plugin.ComponentResources(), diff --git a/quartz.layout.ts b/quartz.layout.ts index 970a5be..9511d39 100644 --- a/quartz.layout.ts +++ b/quartz.layout.ts @@ -8,8 +8,7 @@ export const sharedPageComponents: SharedLayout = { afterBody: [], footer: Component.Footer({ links: { - GitHub: "https://github.com/jackyzha0/quartz", - "Discord Community": "https://discord.gg/cRFFHYye7t", + // Add your custom links here }, }), } @@ -41,6 +40,12 @@ export const defaultContentPageLayout: PageLayout = { Component.Explorer(), ], right: [ + Component.RecentNotes({ + title: "Recent Posts", + limit: 5, + filter: (page) => page.slug?.startsWith("blog/") ?? false, + linkToMore: "blog" as any, + }), Component.Graph(), Component.DesktopOnly(Component.TableOfContents()), Component.Backlinks(),