Skip to content

VitePress Documentation Site with Fiori Styling — Design Spec

Date: 2026-04-21 Status: Approved Repo: sap-devs-cli


Overview

Build a VitePress documentation site for the sap-devs-cli repository, deployed to GitHub Pages via a GitHub Actions workflow. The site surfaces content from docs/ (user guide, developer guide, content guides, MCP server guide) and the full design archive from docs/superpowers/ (specs + plans, auto-discovered at build time). The theme uses SAP Fundamental Styles and @sap-theming for an authentic Fiori look-and-feel with sap_horizon (light) and sap_horizon_dark (dark) theme support.


Site Location & Content Pipeline

The VitePress project lives at /docs-site/ in the repo root. Content markdown files are not committed to /docs-site/ — they are copied at build time from their canonical locations in /docs/. This keeps the original documentation as the single source of truth.

A Node.js script at docs-site/scripts/copy-content.js handles all copying before VitePress runs. Destination directories (docs-site/guide/, docs-site/developer/, docs-site/archive/) are git-ignored.

Content Mapping

SourceDestinationNav Title
docs/user/user-guide.mdguide/user-guide.mdUser Guide
docs/developer/developer-guide.mddeveloper/developer-guide.mdDeveloper Guide
docs/developer/dependencies.mddeveloper/dependencies.mdDependencies
docs/developer/external-apis.mddeveloper/external-apis.mdExternal APIs
docs/developer/security-review.mddeveloper/security-review.mdSecurity Review
docs/content-authoring.mddeveloper/content-authoring.mdContent Authoring
docs/content/content-guide.mddeveloper/content-guide.mdContent Guide
docs/mcp-server.mddeveloper/mcp-server.mdMCP Server
docs/superpowers/specs/*.mdarchive/specs/*.mdAuto-discovered at build time; title from # heading or filename
docs/superpowers/plans/*.mdarchive/plans/*.mdAuto-discovered at build time; title from # heading or filename

Repository Structure

text
/docs-site/
├── .vitepress/
│   ├── config.mts                  # Nav, sidebar, theme config, base URL
│   └── theme/
│       ├── index.ts                # Extends default theme; registers FioriHome layout
│       ├── style.css               # Fundamental Styles overrides + SAP Horizon variable bridge
│       └── components/
│           ├── FioriHome.vue       # Hero banner + feature cards homepage component
│           └── FioriShellbar.vue   # Shellbar component replacing VitePress navbar
├── public/                         # Static assets (SAP logo, favicon, og-image)
├── scripts/
│   └── copy-content.js             # Build-time content copy + sidebar generation
├── index.md                        # Homepage (layout: FioriHome)
├── guide/                          # git-ignored, populated at build time
├── developer/                      # git-ignored, populated at build time
├── archive/                        # git-ignored, populated at build time
│   ├── specs/                      # Design specs (auto-discovered)
│   └── plans/                      # Implementation plans (auto-discovered)
├── .gitignore                      # Ignores copied dirs, dist/, cache/, node_modules/
└── package.json

Shellbar (top)

text
[◻ sap-devs]  Documentation                              v0.9.0  GitHub

The shellbar uses the Fundamental Styles fd-shellbar component with:

  • SAP logo mark and "sap-devs" title with "Documentation" subtitle
  • Version badge (right side)
  • GitHub link (right side)
  • Overview (homepage)
  • User Guide
  • Developer Guide
  • Content Authoring
  • Content Guide
  • MCP Server
  • Dependencies
  • External APIs
  • Security Review
  • Specs (collapsed group, items sorted by date descending, auto-discovered)
    • Items auto-generated by copy-content.js from filenames/headings
  • Plans (collapsed group, items sorted by date descending, auto-discovered)
    • Items auto-generated by copy-content.js from filenames/headings

"On this page" outline — VitePress built-in, styled with Fiori variables.

The copy-content.js script reads each spec/plan markdown file, extracts the title from the first # heading (or falls back to a cleaned-up filename), and generates a VitePress sidebar configuration file at docs-site/.vitepress/archive-sidebar.json. The main config.mts imports this file. No manual maintenance is needed when new specs or plans are added.

The generated JSON follows VitePress's sidebar format:

json
{
  "specs": [
    { "text": "Tutorial Instructor Skill", "link": "/archive/specs/2026-04-21-tutorial-instructor-skill-design" }
  ],
  "plans": [
    { "text": "Tutorial Guided Execution", "link": "/archive/plans/2026-04-21-tutorial-guided-execution" }
  ]
}

Items are sorted by date descending (newest first). The config.mts wraps each array in a { text: 'Specs', collapsed: true, items: [...] } group. The generated file is a build artifact and is listed in docs-site/.gitignore.


Theme Design

Dependencies

json
{
  "devDependencies": {
    "vitepress": "^1.6.0",
    "vue": "^3.5.0",
    "fundamental-styles": "^0.39.0",
    "@sap-theming/theming-base-content": "^11.18.0"
  }
}

No runtime dependencies. The copy script uses only Node.js built-ins (fs, path).

npm Scripts

json
{
  "scripts": {
    "dev": "node scripts/copy-content.js && vitepress dev",
    "build": "vitepress build",
    "preview": "vitepress preview"
  }
}

The build script does not include the copy step — in CI, copy-content.js runs as a separate step (step 4) before npm run build (step 5) so build failures are isolated. The dev script includes the copy for convenience during local development.

CSS Strategy — Three Layers

Layer 1: SAP Theming Base

Import sap_horizon and sap_horizon_dark CSS variable files from @sap-theming/theming-base-content. These provide all --sap* variables as the design foundation.

Dark mode integration: The @sap-theming package ships both themes as flat :root CSS files. Since VitePress toggles dark mode via an html.dark class, we cannot import both files directly (they'd conflict). The approach:

  1. Import sap_horizon/css_variables.css at :root scope (light theme baseline)
  2. In style.css, manually re-declare the sap_horizon_dark variable values under html.dark { ... } — approximately 20 key variables (listed in the table below)
  3. All Fundamental Styles components and the VitePress bridge automatically inherit the correct values via CSS custom property cascade

This avoids build-time CSS transforms or Vite plugins. The manual dark-mode block is ~40 lines of CSS and only needs updating if SAP changes the Horizon Dark palette (rare, tracked by the @sap-theming package version).

Key variables (light / dark):

TokenLight (sap_horizon)Dark (sap_horizon_dark)
--sapBackgroundColor#f5f6f7#12171c
--sapBaseColor#fff#1d232a
--sapBrandColor#0070f2#0070f2
--sapHighlightColor#0064d9#4db1ff
--sapTextColor#131e29#f5f6f7
--sapShell_Background#354a5f#1d232a
--sapShell_TextColor#fff#f5f6f7
--sapShell_Navigation_SelectedColor#0064d9#4db1ff
--sapGroup_ContentBorderColor#d9d9d9#323c48
--sapHoverColor#eaecee#283340
--sapLinkColor#0064d9#008fff

Layer 2: Fundamental Styles Components

Cherry-picked component CSS imports (not the full bundle):

  • shellbar — top header bar
  • side-navigation — sidebar with tree structure
  • card — feature cards on homepage and command grid
  • breadcrumb — page trail
  • message-strip — info/warning callouts
  • badge — status labels
  • button — shell actions and CTAs
  • avatar — optional user icon in shellbar
  • icon — SAP icon font (sap-icon--*)
  • Utility classes — margin, padding, typography, flex

Layer 3: VitePress Bridge

A style.css that maps --sap* variables to VitePress's --vp-c-* custom properties so the markdown content area, search, and VitePress internals inherit Fiori colors automatically:

css
:root {
  --vp-c-brand-1: var(--sapBrandColor);
  --vp-c-brand-2: var(--sapHighlightColor);
  --vp-c-bg: var(--sapBackgroundColor);
  --vp-c-bg-soft: var(--sapContent_ForegroundColor);
  --vp-c-text-1: var(--sapTextColor);
  --vp-c-text-2: var(--sapShell_Navigation_TextColor);
  --vp-c-divider: var(--sapGroup_ContentBorderColor);
  --vp-font-family-base: var(--sapFontFamily);
}

Dark mode switches via VitePress's html.dark class, which activates the sap_horizon_dark variable overrides declared in style.css (see Layer 1 above for the mechanism).

SAP Icon Font

Loaded from the fundamental-styles package (the icon component CSS import in Layer 2), which bundles the SAP icon font (SAP-icons.woff2) and defines the sap-icon--* CSS classes. The @sap-theming package provides only CSS variables, not icons. Key icons used:

  • sap-icon--home — Overview
  • sap-icon--learning-assistant — User Guide
  • sap-icon--developer-setting — Developer section
  • sap-icon--documents — Design Archive
  • sap-icon--connected — MCP Server
  • sap-icon--stethoscope — Doctor
  • sap-icon--sys-enter-2 — Content Packs

Code Highlighting

  • Dark mode: Shiki vitesse-dark theme
  • Light mode: Shiki vitesse-light theme

Homepage — Hero Banner + Feature Cards

Frontmatter

docs-site/index.md uses a fully custom layout:

yaml
---
layout: FioriHome
title: sap-devs Documentation
---

Theme Registration

In docs-site/.vitepress/theme/index.ts, the FioriHome layout is registered:

ts
import DefaultTheme from 'vitepress/theme'
import FioriHome from './components/FioriHome.vue'
import './style.css'

export default {
  extends: DefaultTheme,
  enhanceApp({ app }) {
    app.component('FioriHome', FioriHome)
  },
}

FioriHome.vue Behaviour

Hero section:

  1. Full-width banner with SAP Horizon brand gradient background (subtle blue gradient in light mode, dark slate in dark mode)
  2. SAP-style logo mark (grid icon, larger scale)
  3. Title: "sap-devs" in large Fiori heading (sap-heading-h1)
  4. Subtitle: "SAP developer knowledge, injected into your AI coding tools"
  5. Two CTA buttons (fd-button styling):
    • "Get Started" (primary, filled) → links to User Guide
    • "View on GitHub" (secondary, outlined) → links to repository

Feature cards section below the fold: Six fd-card tiles in a responsive 3×2 grid (collapses to 2×3 then 1×6 on smaller screens):

CardIconTitleDescriptionLinks to
1sap-icon--developer-settingInjectPush SAP context into Claude, Cursor, CopilotUser Guide
2sap-icon--connectedMCP Server31 live tools for AI agentsMCP Server Guide
3sap-icon--learning-assistantLearnTutorials, journeys, and missionsContent Guide
4sap-icon--stethoscopeDoctorCheck tools and project healthDeveloper Guide
5sap-icon--sys-enter-2Content PacksAuthor and customize SAP knowledgeContent Authoring
6sap-icon--documentsDesign ArchiveSpecs and plans behind every featureArchive index

Cards are clickable (whole card is a link) with hover shadow elevation.


GitHub Actions Deployment

Workflow file: .github/workflows/docs.yml

Triggers: Push to main matching any of:

  • docs-site/**
  • docs/**
  • .github/workflows/docs.yml

Job-level configuration:

yaml
permissions:
  pages: write
  id-token: write

environment:
  name: github-pages
  url: ${{ steps.deployment.outputs.page_url }}

Job steps:

  1. actions/checkout
  2. actions/setup-node@v4 — Node 20, npm cache pointed at docs-site/
  3. npm ci in docs-site/
  4. node scripts/copy-content.js in docs-site/
  5. npm run build in docs-site/ (vitepress build)
  6. actions/upload-pages-artifact@v3 — uploads docs-site/.vitepress/dist/
  7. actions/deploy-pages@v4 with id: deployment

VitePress base URL: /sap-devs-cli/ — required so asset paths resolve correctly under https://sap-samples.github.io/sap-devs-cli/.

Concurrency group:

yaml
concurrency:
  group: pages
  cancel-in-progress: false

Prevents overlapping Pages deployments from rapid consecutive pushes.

GitHub Pages config: Repository Settings → Pages → Source: "GitHub Actions" (not branch deploy).


Custom Layout Strategy

VitePress's default Layout is extended, not replaced. The approach:

Shellbar (FioriShellbar.vue)

A custom Vue component at docs-site/.vitepress/theme/components/FioriShellbar.vue replaces VitePress's default navbar. It is rendered in the theme's Layout wrapper slot (VitePress provides a layout-top slot for content above the default layout). The VitePress default .VPNav is hidden via display: none in style.css.

The shellbar includes a search trigger button that programmatically opens VitePress's built-in search overlay (calls document.querySelector('.VPNavBarSearch button')?.click() or uses VitePress's useSearchBox() composable). This preserves the full VitePress search experience (miniSearch-based local search) despite hiding the default navbar where the search button normally lives.

The sidebar uses VitePress's built-in sidebar component with Fiori CSS variable overrides — not a full Fundamental Styles fd-side-nav replacement. This is the same approach proven in the SWAPI site and avoids reimplementing:

  • Mobile sidebar toggle and responsive behavior
  • Active-link highlighting on route changes
  • Collapsed group state management
  • Keyboard navigation

The Fiori look is achieved by mapping VitePress's sidebar CSS custom properties (--vp-sidebar-*) to SAP Horizon values in style.css, plus targeted CSS overrides for:

  • Selected item left-border accent (3px --sapShell_Navigation_SelectedColor)
  • Group label uppercase styling
  • Hover backgrounds matching --sapHoverColor)
  • SAP font family

Content Area

The default theme's content rendering, dark mode toggle, and "On this page" outline remain intact. Fiori styling is applied via the CSS variable bridge (Layer 3).

This approach minimizes maintenance burden — VitePress upgrades won't break content rendering, and the Fiori chrome is isolated to the theme layer.


Files Created / Modified

FileAction
docs-site/package.jsonCreate
docs-site/.gitignoreCreate — ignores guide/, developer/, archive/, .vitepress/dist/, .vitepress/cache/, .vitepress/archive-sidebar.json, node_modules/
docs-site/.vitepress/config.mtsCreate
docs-site/.vitepress/theme/index.tsCreate
docs-site/.vitepress/theme/style.cssCreate
docs-site/.vitepress/theme/components/FioriHome.vueCreate
docs-site/.vitepress/theme/components/FioriShellbar.vueCreate
docs-site/index.mdCreate
docs-site/scripts/copy-content.jsCreate
docs-site/public/Create — favicon, og-image
.github/workflows/docs.ymlCreate