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
| Source | Destination | Nav Title |
|---|---|---|
docs/user/user-guide.md | guide/user-guide.md | User Guide |
docs/developer/developer-guide.md | developer/developer-guide.md | Developer Guide |
docs/developer/dependencies.md | developer/dependencies.md | Dependencies |
docs/developer/external-apis.md | developer/external-apis.md | External APIs |
docs/developer/security-review.md | developer/security-review.md | Security Review |
docs/content-authoring.md | developer/content-authoring.md | Content Authoring |
docs/content/content-guide.md | developer/content-guide.md | Content Guide |
docs/mcp-server.md | developer/mcp-server.md | MCP Server |
docs/superpowers/specs/*.md | archive/specs/*.md | Auto-discovered at build time; title from # heading or filename |
docs/superpowers/plans/*.md | archive/plans/*.md | Auto-discovered at build time; title from # heading or filename |
Repository Structure
/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.jsonNavigation Structure
Shellbar (top)
[◻ sap-devs] Documentation v0.9.0 GitHubThe 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)
Sidebar — Getting Started
- Overview (homepage)
- User Guide
Sidebar — Developer
- Developer Guide
- Content Authoring
- Content Guide
- MCP Server
- Dependencies
- External APIs
- Security Review
Sidebar — Design Archive
- Specs (collapsed group, items sorted by date descending, auto-discovered)
- Items auto-generated by
copy-content.jsfrom filenames/headings
- Items auto-generated by
- Plans (collapsed group, items sorted by date descending, auto-discovered)
- Items auto-generated by
copy-content.jsfrom filenames/headings
- Items auto-generated by
Right Sidebar
"On this page" outline — VitePress built-in, styled with Fiori variables.
Sidebar Auto-Generation
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:
{
"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
{
"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
{
"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:
- Import
sap_horizon/css_variables.cssat:rootscope (light theme baseline) - In
style.css, manually re-declare thesap_horizon_darkvariable values underhtml.dark { ... }— approximately 20 key variables (listed in the table below) - 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):
| Token | Light (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 barside-navigation— sidebar with tree structurecard— feature cards on homepage and command gridbreadcrumb— page trailmessage-strip— info/warning calloutsbadge— status labelsbutton— shell actions and CTAsavatar— optional user icon in shellbaricon— 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:
: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— Overviewsap-icon--learning-assistant— User Guidesap-icon--developer-setting— Developer sectionsap-icon--documents— Design Archivesap-icon--connected— MCP Serversap-icon--stethoscope— Doctorsap-icon--sys-enter-2— Content Packs
Code Highlighting
- Dark mode: Shiki
vitesse-darktheme - Light mode: Shiki
vitesse-lighttheme
Homepage — Hero Banner + Feature Cards
Frontmatter
docs-site/index.md uses a fully custom layout:
---
layout: FioriHome
title: sap-devs Documentation
---Theme Registration
In docs-site/.vitepress/theme/index.ts, the FioriHome layout is registered:
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:
- Full-width banner with SAP Horizon brand gradient background (subtle blue gradient in light mode, dark slate in dark mode)
- SAP-style logo mark (grid icon, larger scale)
- Title: "sap-devs" in large Fiori heading (
sap-heading-h1) - Subtitle: "SAP developer knowledge, injected into your AI coding tools"
- Two CTA buttons (
fd-buttonstyling):- "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):
| Card | Icon | Title | Description | Links to |
|---|---|---|---|---|
| 1 | sap-icon--developer-setting | Inject | Push SAP context into Claude, Cursor, Copilot | User Guide |
| 2 | sap-icon--connected | MCP Server | 31 live tools for AI agents | MCP Server Guide |
| 3 | sap-icon--learning-assistant | Learn | Tutorials, journeys, and missions | Content Guide |
| 4 | sap-icon--stethoscope | Doctor | Check tools and project health | Developer Guide |
| 5 | sap-icon--sys-enter-2 | Content Packs | Author and customize SAP knowledge | Content Authoring |
| 6 | sap-icon--documents | Design Archive | Specs and plans behind every feature | Archive 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:
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}Job steps:
actions/checkoutactions/setup-node@v4— Node 20, npm cache pointed atdocs-site/npm ciindocs-site/node scripts/copy-content.jsindocs-site/npm run buildindocs-site/(vitepress build)actions/upload-pages-artifact@v3— uploadsdocs-site/.vitepress/dist/actions/deploy-pages@v4withid: deployment
VitePress base URL: /sap-devs-cli/ — required so asset paths resolve correctly under https://sap-samples.github.io/sap-devs-cli/.
Concurrency group:
concurrency:
group: pages
cancel-in-progress: falsePrevents 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.
Sidebar
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
| File | Action |
|---|---|
docs-site/package.json | Create |
docs-site/.gitignore | Create — ignores guide/, developer/, archive/, .vitepress/dist/, .vitepress/cache/, .vitepress/archive-sidebar.json, node_modules/ |
docs-site/.vitepress/config.mts | Create |
docs-site/.vitepress/theme/index.ts | Create |
docs-site/.vitepress/theme/style.css | Create |
docs-site/.vitepress/theme/components/FioriHome.vue | Create |
docs-site/.vitepress/theme/components/FioriShellbar.vue | Create |
docs-site/index.md | Create |
docs-site/scripts/copy-content.js | Create |
docs-site/public/ | Create — favicon, og-image |
.github/workflows/docs.yml | Create |