Docship Theme Development Checklist¶
⚠️ Critical Rules¶
No Advertisements Policy¶
NEVER use any theme or plugin that contains ads
Some official themes (e.g.,
@vuepress/theme-vue) contain sponsor/advertisement content - DO NOT USEAlways check if theme contains ads, sponsor links, or donation prompts before using
When in doubt, use the framework’s default theme
Known themes/plugins with ads (DO NOT USE):
Framework |
Theme/Plugin |
Issue |
|---|---|---|
VuePress |
|
Contains sponsor/advertisement content |
Recommended ad-free alternatives:
Framework |
Recommended Theme |
|---|---|
VuePress |
Default theme (built-in |
User Content Respect¶
Never restrict user filenames (e.g.,
index.md,temp.mdare all valid)User markdown content must never break builds regardless of validity
Invalid image paths, links, etc. should be ignored, not cause errors
Markdown Compatibility¶
[ ] Use
markdown.format: 'md'instead of MDX to avoid JSX parsing errors (Docusaurus)Users may have
${},<>,{}in their markdown contentMDX will treat these as JSX expressions and fail
[ ] VitePress is more lenient with
${}but double curly braces will be treated as Vue template[ ] Don’t restrict filenames - users can use any name like
temp.md[ ] Handle files with special characters in content gracefully
Docusaurus Configuration¶
[ ] Don’t use
navbar.logowithoutlogo.src- it will throw validation error[ ] Remove
sidebarPathto let Docusaurus auto-generate sidebar from file structure[ ] Use
onBrokenLinks: 'ignore'to prevent build failures on broken links[ ] Use
markdown.hooks.onBrokenMarkdownLinks: 'ignore'(new location in v3.9+)[ ] Don’t include deprecated options like root-level
onBrokenMarkdownLinks[ ] For local search, use
@easyops-cn/docusaurus-search-local(no API key needed)[ ] Algolia search requires API key - not suitable for generic themes
VitePress Configuration¶
[ ] Use
ignoreDeadLinks: trueto prevent build failures on broken/dead links[ ] VitePress does NOT auto-generate sidebar - need custom script or manual config
[ ]
sidebar: 'auto'does NOT work like Docusaurus - only shows current page headings[ ] Output directory is
.vitepress/dist(notbuild)[ ] Use
srcDir: 'docs'to specify source directory[ ] Exclude
node_modulesin content backup[ ] For local search, use
search: { provider: 'local' }(built-in)[ ]
logo.linkdoes NOT support external URLs - need custom theme to override
Homepage Selection Logic¶
Priority order:
docs/index.mdorcontent/index.md- explicit homepagedocs/README.mdorcontent/README.md- common conventionFirst
.mdfile (sorted alphabetically) - fallback
[ ] Always use
sortbeforehead -1for consistent results[ ] For Docusaurus: check if
slug: /already exists before adding frontmatter[ ] For VitePress:
index.mdis automatically the homepage, no frontmatter needed
GitHub Actions / Reusable Workflows¶
[ ] Reusable workflows MUST be in
.github/workflows/directory[ ] Use
on: workflow_callfor workflows that should only be called by others[ ] Caller workflow must declare
permissionsfor the called workflow to use[ ] Remove
pushandworkflow_dispatchtriggers if workflow should not run directly
Content Backup¶
[ ] Exclude
README.mdfrom root (usually not documentation)[ ] Exclude hidden directories (
.git,.github, etc.)[ ] Exclude
node_modulesdirectory[ ] Copy all user folders to preserve structure
[ ] Handle empty content directory - create default welcome page
Build & Deploy¶
[ ] GitHub Pages keeps old version online during build (atomic deployment)
[ ] First deployment shows blank page until complete - this is normal
[ ] Public repos have unlimited GitHub Actions minutes
[ ] Add npm cache to speed up builds:
actions/cache@v4with~/.npmpath
Shell Script Best Practices (GitHub Actions)¶
[ ] Don’t use
sed -i '1s/^/...\n.../'-\nmay not work on all systems[ ] Don’t use heredoc (
<< EOF) inside YAMLrun:blocks - causes syntax errors[ ] Use
printf '%s\n' 'line1' 'line2'for multi-line content[ ] Use temp files +
cat+mvto prepend content to files[ ] Always quote variables:
"$TARGET"not$TARGET
Logo & Branding¶
[ ] Use
https://github.com/USERNAME.pngto get user/org avatar[ ] VitePress: need custom theme (
enhanceApp) to make logo link to external URL[ ] Docusaurus:
logo.href+logo.target: '_blank'works for external links[ ] Set favicon with
head: [['link', { rel: 'icon', href: '...' }]](VitePress)[ ] Docusaurus favicon can be external URL directly
Testing Scenarios¶
Before releasing a theme, test with:
[ ] Empty repository (no markdown files)
[ ] Single markdown file
[ ] Nested folder structure
[ ] Files with
${}syntax in content[ ] Files with JSX-like syntax
<Component />[ ] Files with curly braces
{}[ ] Files with Vue template syntax (VitePress specific)
[ ] Unicode/special characters in filenames
[ ] Very long filenames
[ ] Files starting with
_(usually ignored by default)[ ] Files containing
localhostURLs (dead link check)[ ] Repository without
index.md(homepage fallback logic)
Starlight (Astro) Configuration¶
[ ] Use
npm create astro@latest -- --template starlightfor correct project structure[ ] Starlight v0.33.0+ changed
socialconfig from object to array formatOld:
social: { github: 'url' }New:
social: [{ icon: 'github', label: 'GitHub', href: 'url' }]
[ ] Every
.mdfile MUST havetitlein frontmatter - Starlight will fail without it[ ] Sidebar
slugmust be lowercase - uppercase will cause “slug does not exist” error[ ]
autogenerate: { directory: '.' }doesn’t work well - use specific directory names[ ] Content goes in
src/content/docs/directory[ ] Output directory is
dist[ ] Use
.mdxextension for index file if needed
Rspress Configuration¶
[ ] Public assets go in
docs/public/(not project rootpublic/)[ ] Sidebar
itemsmust be an array, not'auto'string[ ] Output directory is
doc_build[ ] Exclude
publicdirectory from sidebar generation[ ] Config file is
rspress.config.ts(TypeScript)
Common Errors & Solutions¶
Error |
Cause |
Solution |
|---|---|---|
|
Using |
Remove |
|
MDX parsing |
Use |
|
Missing |
Add |
|
Caller missing permissions |
Add |
|
Old config location |
Move to |
|
Broken links in markdown |
Use |
|
VitePress doesn’t auto-generate |
Write custom sidebar script |
|
Missing |
Add frontmatter to first doc |
|
Heredoc in YAML run block |
Use |
|
Starlight v0.33.0+ API change |
Use array format for social links |
|
Missing frontmatter title |
Auto-add title from filename |
|
Uppercase slug in sidebar |
Convert slug to lowercase |
|
No valid index page |
Ensure index.md/mdx exists with frontmatter |
|
Rspress sidebar |
Use array of items, not string |
|
Wrong public directory path |
Put assets in |
|
Invalid image path in markdown |
Set |
|
Nextra v4 API changed |
Use new |
|
Simplified source.ts missing exports |
Delete files that depend on removed exports (e.g., |
|
Downloaded repo folder treated as submodule |
Add folder to |
|
GitHub Actions shallow clone |
Warning only, can ignore or use |
|
Empty or malformed toc.yml |
Delete invalid toc.yml from subdirectories |
Logo/favicon not showing (DocFX) |
External URL in |
Use custom template JS to inject external URLs |
Homepage 404 (VuePress) |
Using |
Rename |
|
VuePress auto only shows headings |
Generate sidebar config via Node.js script |
Theme has ads/sponsors (VuePress) |
Using |
Use default theme (built-in, no ads) |
|
Nuxt can’t crawl to doc pages |
Add routes to |
404 on |
Uppercase filename in route |
Convert routes to lowercase |
Blank page on root (Docus) |
|
Create |
|
MCP needs server |
Warning only, can ignore |
|
robots module conflict |
Set |
No sidebar on homepage (Docus) |
|
Put docs in |
Fumadocs Configuration¶
[ ] Fumadocs is based on Next.js - requires
output: 'export'for static build[ ] Use
basePathfor GitHub Pages deployment (e.g.,/${REPO_NAME})[ ] Set
images: { unoptimized: true }for static export[ ] Content goes in
content/docs/directory[ ] Output directory is
out(Next.js static export default)[ ] Every
.mdxfile should have frontmatter withtitleanddescription[ ] Use
create-fumadocs-appwith--template +next+fuma-docs-mdx+staticfor static export[ ] Fumadocs MDX is the official content source
[ ] Config file is
next.config.mjs(ESM)[ ] Requires
fumadocs-mdx/nextplugin wrapper[ ] Set
remarkImageOptions: falseinsource.config.tsto prevent build failures from invalid image paths[ ] Delete
app/llms-full.txtandapp/ogdirectories (they depend on exports not in simplified source.ts)[ ] Clear template’s default
content/docs/*before copying user content (removes Hello World page)
Nextra Configuration¶
[ ] Nextra v4 uses App Router - structure is
src/app/andsrc/content/[ ] Requires
output: 'export'andimages: { unoptimized: true }for static build[ ] Use
basePathvia environment variable for GitHub Pages[ ] Content goes in
src/content/directory[ ] Output directory is
out[ ] Need
mdx-components.jsat project root for MDX components[ ] Use
nextra-theme-docsfor documentation theme[ ] Config uses
nextra()wrapper withcontentDirBasePathoption[ ] Homepage redirect to
/docssince content is under/docsroute[ ] Nextra uses MDX - user content with
${},<>,{}may cause JSX parsing errors[ ] Set
staticImage: falseto prevent build failures from invalid image paths
VuePress Configuration¶
[ ] VuePress 1.x is Vue 2 based - use
vuepress@^1.9.10[ ] ⚠️ DO NOT USE
@vuepress/theme-vue- it contains sponsor/advertisement content[ ] Use default theme
@vuepress/theme-default(built-in, no ads)[ ] Content goes in
docs/directory[ ] Output directory is
docs/.vuepress/dist[ ] Config file is
docs/.vuepress/config.js[ ] Use
base: '/${REPO_NAME}/'for GitHub Pages subdirectory[ ]
themeConfig.logosupports external URLs directly[ ]
themeConfig.sidebar: 'auto'only shows current page headings - need Node.js script for full sidebar[ ] Homepage is
docs/README.md(notindex.md) - must renameindex.mdtoREADME.md[ ] Use
themeConfig.repofor GitHub link in navbar[ ] Custom styles go in
docs/.vuepress/styles/index.styl(Stylus)[ ] Use
enhanceApp.jsfor client-side customizations (e.g., footer injection)[ ] Favicon via
head: [['link', { rel: 'icon', href: 'URL' }]]- supports external URLs[ ] VuePress uses Vue template syntax - double curly braces in markdown will be parsed as Vue expressions
[ ] Use
@vuepress/plugin-back-to-topfor back-to-top button (built-in plugin)[ ] VuePress 1.x does NOT have native dark mode toggle - custom implementation is complex
[ ] Green scrollbar: apply only to
.sidebarselector, not whole page
DocFX Configuration¶
[ ] DocFX is a .NET-based documentation framework - uses
dotnet tool install -g docfx[ ] Content goes in
docs/directory[ ] Output directory is
_site[ ] Config file is
docfx.json[ ] Uses
toc.ymlfor navigation structure (root for navbar, docs/ for sidebar)[ ]
_appLogoPathand_appFaviconPathdo NOT support external URLs - need custom template[ ] Use custom template with JavaScript to inject external avatar as logo/favicon
[ ] Remove root
toc.ymlto hide navbar tabs (e.g., “Docs” tab) when only one section[ ] Use
redirect_urlfrontmatter inindex.mdto redirect homepage to docs[ ] Set
_disableContribution: trueto hide “Edit this page” link[ ] Set
_appFooterto customize or remove footer[ ] Sidebar toc.yml format:
- name: Title+href: file.md[ ] Delete invalid
toc.ymlfiles from user content subdirectories[ ] Exclude framework source folders in backup (fumadocs/, nextra/, docute/, etc.)
Docute Configuration¶
[ ] Docute is a pure frontend framework - no build process needed
[ ] Only needs
index.html+ markdown files[ ] Uses CDN for docute.js and docute.css (
unpkg.com/docute@4)[ ] URL routing:
/=>/README.md,/foo=>/foo.md,/foo/=>/foo/README.md[ ] Sidebar must be manually configured or auto-generated via script
[ ] Logo is a Vue template string - use
<span>wrapper with flex layout for avatar + text[ ] Use
darkThemeToggler: truefor dark mode toggle[ ] No npm cache needed since no build process
mdBook Configuration¶
[ ] mdBook is a Rust-based documentation tool - install via pre-built binary or
cargo install mdbook[ ] Content goes in
src/directory[ ] Output directory is
book/[ ] Config file is
book.toml(TOML format)[ ] Requires
src/SUMMARY.mdto define table of contents structure[ ] Homepage is
src/README.md(linked as[Introduction](README.md)in SUMMARY.md)[ ] SUMMARY.md format:
- [Title](path/to/file.md)for chapters[ ] Use
#headers in SUMMARY.md to create section separators[ ]
[output.html]section in book.toml for HTML output settings[ ]
site-urlin book.toml for base path (GitHub Pages subdirectory)[ ] Custom theme via
theme/directory - can overrideindex.hbs,head.hbs, CSS files[ ] Favicon and logo require custom theme modifications (no direct config option)
[ ] Built-in themes: light, rust, coal, navy, ayu
[ ]
default-themeandpreferred-dark-themein[output.html]section[ ] Supports MathJax via
mathjax-support = true[ ] Built-in search functionality (no additional config needed)
Eleventy Configuration¶
[ ] Eleventy (11ty) is a JavaScript-based static site generator
[ ] Install via
npm install @11ty/eleventy[ ] Config file is
eleventy.config.jsor.eleventy.js[ ] Default input directory is
.(project root)[ ] Default output directory is
_site[ ] Supports multiple template languages: Liquid, Nunjucks, Markdown, HTML, JavaScript
[ ] Use
dir.inputanddir.outputin config to customize directories[ ] Use
pathPrefixfor GitHub Pages subdirectory deployment[ ] Layouts go in
_includes/directory by default[ ] Data files go in
_data/directory (JSON, JS, or YAML)[ ] Use frontmatter
layoutto specify template layout[ ] Collections are auto-generated from tags or can be custom defined
[ ] Use
eleventyConfig.addPassthroughCopy()for static assets[ ] Markdown files need frontmatter with
layoutto use templates[ ] No built-in theme - requires custom CSS/layout
Sphinx Configuration¶
[ ] Sphinx is a Python-based documentation generator
[ ] Install via
pip install sphinx furo myst-parser[ ] Config file is
conf.py(Python)[ ] Default source directory is
docs/or project root[ ] Default output directory is
_build/html/[ ] Use
myst-parserextension to support Markdown (default is reStructuredText)[ ] Furo is a modern, clean theme (BSD license)
[ ] Use
toctreedirective to define navigation structure[ ]
html_theme = 'furo'to use Furo theme[ ]
html_logoandhtml_faviconfor branding[ ]
html_theme_optionsfor theme customization[ ] Custom CSS goes in
_static/directory[ ] Build with
sphinx-build -b html docs docs/_build/html[ ] License is BSD (Sphinx) + MIT (Furo) - very permissive
Docus Configuration¶
[ ] Docus is a Nuxt 4-based documentation framework (MIT license)
[ ] Install via
npm install docus nuxt better-sqlite3[ ] Config file is
nuxt.config.tswithextends: ['docus'][ ] Content goes in
content/directory with number prefixes for ordering (e.g.,1.docs/,2.guide/)[ ] Output directory is
.output/public/[ ] Use
nuxt generatefor static build[ ] Homepage is special -
content/index.mdrenders as landing page without sidebar[ ] Documentation pages need subdirectory - put docs in
content/1.docs/to get sidebar layout[ ] Number prefixes in filenames control order:
1.index.md,2.guide.md→/index,/guide[ ] Use
.navigation.ymlin directories to set section titles[ ] Frontmatter
titleis required for each page[ ]
app.config.tsgoes inapp/directory for theme configuration[ ]
header.titleandheader.logofor branding[ ]
socials.githubfor GitHub link in header[ ] Custom components override defaults - put in
app/components/app/[ ]
AppHeaderLogo.vue- customize logo + title display[ ]
AppFooterLeft.vue- customize footer left (attribution)[ ]
AppFooterRight.vue- customize footer right (social icons, theme toggle)[ ] Set empty
AppFooterRight.vueto remove duplicate theme toggle[ ] Logo click should link to
/docsnot/(overrideAppHeaderLogo.vuewith<NuxtLink to="/docs">)[ ] Favicon via
app.head.linkinnuxt.config.ts[ ] Prerendering issue: Nuxt only prerenders routes it can crawl from homepage
[ ] Must explicitly list routes in
nitro.prerender.routesor generate dynamically[ ] Convert filenames to lowercase for routes (uppercase causes 404)
[ ] Create
index.htmlredirect after build for root →/docs[ ]
robots: { robotsTxt: false }to avoid base URL error[ ]
@nuxtjs/mcp-toolkitwarning is normal - not compatible with static generate
General Lessons Learned¶
Framework Categories¶
Build-required frameworks (need npm install + build):
Docusaurus, VitePress, Starlight, Rspress, Fumadocs, Nextra
Need npm cache for faster builds
Output to specific directories (build/, dist/, out/, doc_build/)
Pure frontend frameworks (no build, CDN-based):
Docsify, Docute
Just HTML + markdown files
Faster deployment, simpler setup
Next.js-based frameworks:
Fumadocs, Nextra
Require
output: 'export'for static buildRequire
images: { unoptimized: true }for static exportUse
basePathfor GitHub Pages subdirectory
Common Pitfalls¶
[ ] Image handling: MDX/Next.js frameworks try to import images - disable with
remarkImageOptions: falseorstaticImage: false[ ] Template default content: Many templates include “Hello World” or demo content - clear before copying user content
[ ] CLI argument changes: Framework CLIs change frequently - check latest docs (e.g.,
create-fumadocs-appchanged from--name --template --srcto--template +next+fuma-docs-mdx+static)[ ] API version changes: Check for breaking changes (e.g., Starlight social config changed from object to array)
[ ] Sidebar in sidebar: Some frameworks show index page in sidebar - use
index: truefrontmatter to hide it
Branding Consistency¶
For all frameworks, implement:
[ ] Logo: User avatar +
username/reponamein top-left[ ] Favicon: User’s GitHub avatar (
https://github.com/USERNAME.png)[ ] GitHub link: Icon or text link to repository (right side of navbar)
[ ] Title:
username/reponamein browser tab[ ] Footer:
Powered by NekoTick · {Framework}with links to both projects
Logo Implementation Patterns¶
Framework |
Logo Config |
|---|---|
Docusaurus |
|
VitePress |
|
Fumadocs |
|
Nextra |
|
Docute |
|
DocFX |
Custom template JS to replace |
VuePress |
|
Starlight |
|
Docus |
Custom |
Hugo |
|
Testing Checklist (Updated)¶
[ ] Files with invalid image paths (should not break build)
[ ] Files with special markdown syntax (
${},<>,{})[ ] Empty repository (should show welcome page)
[ ] Nested folder structure (should generate proper sidebar)
[ ] Repository without index.md (should use first doc as homepage)
Multi-Language Support¶
[ ] VitePress/Docusaurus i18n is static - requires manual translation files
[ ] No automatic translation built-in
[ ] Options: browser translation, or integrate translation API (costs money)
[ ] Structure:
docs/en/,docs/zh/etc. for each language
Adding New Framework¶
When adding a new documentation framework to Docship:
1. Create Workflow File¶
[ ] Create
.github/workflows/{framework}.yml[ ] Use
on: workflow_callwithbase_path_suffixanddeployinputs[ ] Follow existing workflow structure for consistency
3. Update Showcase¶
[ ] Add build job in
showcase.ymlwithname: {framework}[ ] Add to
needsarray incombinejob[ ] Add build result env variable (e.g.,
BUILD_FRAMEWORK)[ ] Add to
RESULTSarray in combine step[ ] Add entry in
showcase/frameworks.jsonwith GitHub link(s)
frameworks.json format:
{
"framework-name": {
"links": ["https://github.com/org/repo"]
},
"framework-with-theme": {
"links": ["https://github.com/org/framework", "https://github.com/org/theme"]
}
}
4. Update Documentation¶
[ ] Add framework to README.md supported frameworks table
[ ] Add framework-specific notes to CHECKLIST.md if needed