What is GlowDoc?
GlowDoc is a modern, lightweight documentation template that presents a beautiful thoughtful space for your work. It's built with pure HTML, CSS, and minimal JavaScript to ensure fast loading times and easy customization.
Key Features
- Modern Design - Clean, professional appearance with attention to typography and spacing
- Dark Mode - Built-in dark mode support with smooth transitions
- Responsive - Works perfectly on desktop, tablet, and mobile devices
- Fast - Minimal dependencies and optimized for performance
- Accessible - Built with accessibility best practices
- Customizable - Easy to modify colors, fonts, and layout
Perfect For
GlowDoc is ideal for:
- Project documentation
- API documentation
- User guides and tutorials
- Knowledge bases
- Technical blogs
Philosophy
We believe documentation should be beautiful, fast, and accessible. GlowDoc follows these principles by providing a clean, distraction-free reading experience that focuses on your content.
Quick Start
Get up and running with GlowDoc in minutes. This comprehensive guide will walk you through installation, setup, and creating your first professional documentation site.
Prerequisites
Before you begin, ensure you have the following installed:
Required Software
Rust (Latest Stable)
# Install Rust using rustup (recommended)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Follow the on-screen instructions, then reload your shell
source ~/.cargo/env
# Verify installation
rustc --version
cargo --version
Git
# Check if Git is installed
git --version
# If not installed:
# macOS: Install Xcode Command Line Tools
xcode-select --install
# Windows: Download from https://git-scm.com/download/win
# Linux (Ubuntu/Debian): sudo apt-get install git
Python 3 (for local testing)
# Check Python installation
python3 --version
# Python is usually pre-installed on macOS/Linux
# Windows: Download from https://python.org
System Requirements
- Operating System: macOS, Linux, or Windows
- RAM: 512MB minimum, 1GB recommended
- Disk Space: 100MB for Rust toolchain + project files
- Network: Internet connection for dependencies (initial setup only)
Installation Options
Choose the installation method that best fits your workflow:
Option 1: Download Release (Quickest)
-
Download the latest release:
# Download and extract (replace URL with actual release)
curl -L https://github.com/username/glowdoc/archive/refs/heads/main.zip -o glowdoc.zip
unzip glowdoc.zip
cd glowdoc-main
-
Build immediately:
cargo run --release
Option 2: Clone Repository (Recommended for Development)
-
Clone the repository:
git clone https://github.com/username/glowdoc.git
cd glowdoc
-
Build the documentation:
cargo run --release
Option 3: Start Fresh Project
-
Create new project directory:
mkdir my-docs
cd my-docs
-
Copy GlowDoc source files:
# Copy src/ and docs/ directories from GlowDoc
# Copy Cargo.toml
-
Initialize your documentation:
cargo run init-config
Project Structure Overview
Understanding GlowDoc's structure helps you work effectively:
glowdoc/
├── Cargo.toml # Rust project configuration
├── src/ # Rust source code
│ ├── main.rs # Main application logic
│ └── config_builder.rs # Configuration builder
├── docs/ # Your documentation source
│ ├── config.yaml # Navigation configuration
│ ├── entry.md # Homepage content (optional)
│ ├── introduction/ # Documentation sections
│ │ ├── quick-start.md
│ │ └── what-is-glowdoc.md
│ ├── getting-started/
│ │ ├── installation.md
│ │ ├── configuration.md
│ │ └── first-steps.md
│ └── [more-sections]/
├── index.html # Generated documentation site
├── README.md # Project information
└── .gitignore # Git ignore rules
Key Directories
docs/
: Your markdown documentation files
src/
: GlowDoc's Rust source code (modify for customization)
index.html
: Generated single-file documentation site
5-Minute Setup
Follow these steps to have a working documentation site in 5 minutes:
Step 1: Build Your First Site (1 minute)
# After installation, build immediately
cargo run --release
# You should see output like:
# "Building documentation..."
# "Generated index.html successfully"
Step 2: Preview Your Site (30 seconds)
# Start local server
python3 -m http.server 8000
# Open in browser
# Visit: http://localhost:8000
Alternative server options:
# Node.js users
npx serve .
# PHP users
php -S localhost:8000
# Python 2 users
python -m SimpleHTTPServer 8000
Step 3: Verify Everything Works (30 seconds)
Check these features in your browser:
Step 4: Customize Your Content (3 minutes)
-
Update site information:
# Edit docs/config.yaml
vim docs/config.yaml # or your preferred editor
title: My Project Documentation
description: Comprehensive guide for My Project
theme: vibrant # or 'default' or 'purple'
-
Add your homepage content:
# Edit docs/entry.md
vim docs/entry.md
# My Project Documentation
Welcome to the comprehensive documentation for My Project.
## Getting Started
Follow our guides to get up and running quickly.
-
Add your first documentation page:
# Create a new page
echo "# My First Page\n\nThis is my first documentation page." > docs/introduction/my-first-page.md
-
Rebuild and see changes:
cargo run --release
# Refresh your browser
Configuration Walkthrough
Automatic Configuration (Recommended)
Let GlowDoc detect and configure your documentation structure automatically:
# Interactive configuration wizard
cargo run init-config
Example session:
GlowDoc Configuration Builder
============================
Scanning docs/ directory...
Found 3 sections: introduction, getting-started, advanced
Site title [GlowDoc]: My Project Docs
Description [modern docs for the modern world]: Complete guide for My Project
Theme [vibrant]: default
Detected sections:
1. introduction (2 files)
2. getting-started (3 files)
3. advanced (2 files)
Would you like to reorder sections? [y/N]: y
Enter new order (comma-separated): introduction,getting-started,advanced
Configuration saved to docs/config.yaml
Backup created: docs/config.yaml.backup
Manual Configuration
For precise control, edit docs/config.yaml
directly:
title: My Project Documentation
description: Everything you need to know about My Project
theme: vibrant
navigation:
- title: Introduction
id: introduction
items:
- title: Overview
id: overview
file: introduction/overview.md
- title: Quick Start
id: quick-start
file: introduction/quick-start.md
- title: User Guide
id: user-guide
items:
- title: Installation
id: installation
file: guide/installation.md
- title: Configuration
id: configuration
file: guide/configuration.md
Command-Line Configuration
For automated workflows, use CLI arguments:
# Complete automated setup
cargo run init-config \
--title "My Project Docs" \
--description "Comprehensive project documentation" \
--section-order introduction,guide,api,advanced \
--rename-section guide="User Guide" \
--rename-section api="API Reference" \
--page-order guide=installation.md,configuration.md,usage.md \
--exclude-section drafts
Content Creation Guide
Writing Effective Documentation
Markdown Basics
GlowDoc supports GitHub-flavored markdown with extensions:
# Page Title (H1 - use only once per page)
## Section Heading (H2)
### Subsection (H3)
**Bold text** and *italic text*
- Bullet points
- Another item
1. Numbered lists
2. Sequential items
`inline code` and:
```javascript
// Code blocks with syntax highlighting
function example() {
return "Hello, World!";
}
Blockquotes for important information
Links to other pages
External links
Tables | Are | Supported |
Cell 1 | Cell 2 | Cell 3 |
#### Page Structure Best Practices
```markdown
# Clear, Descriptive Page Title
Brief introduction paragraph explaining what this page covers.
## Main Concepts
Explain the core concepts first.
### Detailed Subsection
Break down complex topics into digestible sections.
## Examples
Provide practical examples:
```bash
# Command examples
cargo run --release
Next Steps
Guide readers to related pages or next actions.
### Organizing Your Content
#### Recommended Structure
docs/
├── config.yaml
├── entry.md # Homepage content
├── introduction/ # High-level overview
│ ├── overview.md # What is your project?
│ ├── quick-start.md # This page
│ └── concepts.md # Core concepts
├── guides/ # Step-by-step instructions
│ ├── installation.md
│ ├── configuration.md
│ ├── first-project.md
│ └── troubleshooting.md
├── reference/ # Detailed technical info
│ ├── api.md
│ ├── cli.md
│ └── configuration-reference.md
└── advanced/ # Advanced topics
├── customization.md
├── plugins.md
└── deployment.md
#### Content Guidelines
1. **Start with user goals**: What does the reader want to accomplish?
2. **Use progressive disclosure**: Basic info first, details later
3. **Include examples**: Show, don't just tell
4. **Test your instructions**: Verify steps work as documented
5. **Update regularly**: Keep content current with your project
### Adding New Pages
1. **Create the markdown file:**
```bash
# Create in appropriate section
touch docs/guides/new-feature.md
-
Add content with H1 title:
# New Feature Guide
This guide explains how to use the new feature.
-
Update configuration:
# Auto-detect and add to navigation
cargo run init-config
# Or manually edit docs/config.yaml
-
Rebuild documentation:
cargo run --release
Theme Customization
Built-in Themes
GlowDoc includes three professionally designed themes:
# In docs/config.yaml
theme: default # Clean, professional
theme: purple # Purple accents
theme: vibrant # Colorful, energetic
Quick Theme Preview
# Try different themes quickly
sed -i 's/theme: .*/theme: purple/' docs/config.yaml && cargo run --release
sed -i 's/theme: .*/theme: vibrant/' docs/config.yaml && cargo run --release
sed -i 's/theme: .*/theme: default/' docs/config.yaml && cargo run --release
Dark Mode
All themes include automatic dark mode:
- System preference detection: Respects user's OS setting
- Manual toggle: Click the theme button in header
- Persistent choice: Remembers user preference
Development Workflow
Efficient Development Loop
# 1. Edit your markdown files
vim docs/guides/new-page.md
# 2. Rebuild (takes ~1-3 seconds)
cargo run --release
# 3. Refresh browser (server keeps running)
# No need to restart python server
File Watching (Optional)
For automatic rebuilds on file changes:
# Install cargo-watch
cargo install cargo-watch
# Watch for changes and rebuild
cargo watch -x "run --release"
Version Control Integration
# Initialize git repository
git init
# Add files (excluding generated content)
git add .
git commit -m "Initial documentation setup"
# .gitignore should include:
echo "target/" >> .gitignore
echo "index.html" >> .gitignore # Generated file
Testing Your Documentation
Pre-Deployment Checklist
# 1. Build successfully
cargo run --release
# 2. Check file size (should be reasonable)
ls -lh index.html
# 3. Validate HTML (optional)
# Install html-validate: npm install -g html-validate
html-validate index.html
# 4. Test locally
python3 -m http.server 8000
Manual Testing
Visit http://localhost:8000
and verify:
Accessibility Testing
# Install axe-core CLI (optional)
npm install -g @axe-core/cli
# Test accessibility
axe http://localhost:8000
Common Issues and Solutions
Build Problems
"cargo: command not found"
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
"No such file or directory: docs/config.yaml"
# Generate configuration
cargo run init-config
Build errors after editing config.yaml
# Validate YAML syntax
python3 -c "import yaml; yaml.safe_load(open('docs/config.yaml'))"
# Check file references exist
ls docs/introduction/quick-start.md
Server Issues
"Address already in use"
# Find and kill process using port 8000
lsof -ti:8000 | xargs kill
# Or use different port
python3 -m http.server 8080
Browser shows "No such file or directory"
# Ensure you're in the correct directory
ls index.html
# Rebuild if missing
cargo run --release
Content Problems
Page not appearing in navigation
# Ensure file is referenced in config.yaml
grep -r "filename.md" docs/config.yaml
# Or regenerate config
cargo run init-config
Search not finding content
# Rebuild to update search index
cargo run --release
# Check file has H1 heading
head -5 docs/section/page.md
Next Steps
Congratulations! You now have a working GlowDoc site. Here's what to explore next:
-
Add Your Content
- Replace sample content with your documentation
- Update
docs/entry.md
with your project information
- Add pages for your specific use cases
-
Customize Appearance
- Try different themes in
config.yaml
- Explore advanced styling options
- Add your logo or branding
-
Test Thoroughly
- Verify all navigation works
- Test search functionality
- Check mobile responsiveness
Advanced Features
-
Learn Configuration Management
- Read the Configuration Guide
- Understand navigation structure options
- Explore CLI automation features
-
Explore Customization
-
Plan Deployment
-
Extend Functionality
Community and Support
- Documentation: Continue with First Steps
- Examples: Browse sample configurations and setups
- Issues: Report problems or request features
- Contributions: Help improve GlowDoc
Pro Tips
- Keep It Simple: Start with basic setup, add complexity gradually
- Test Early: Preview changes frequently during development
- Version Control: Commit documentation changes regularly
- User Focus: Write for your audience, not yourself
- Iterate: Improve documentation based on user feedback
You're now ready to create professional, beautiful documentation with GlowDoc. Happy documenting!
First Steps
Now that you have GlowDoc installed, let's build your first documentation site step by step.
1. Initialize Your Project
Start by setting up the basic structure for your documentation:
# Create a new project directory
mkdir my-docs
cd my-docs
# Download or clone GlowDoc
# Then copy the src/ and docs/ folders to your project
2. Generate Your Configuration
Use the interactive config builder to set up your site structure:
# Interactive mode - walks you through setup
cargo run init-config
This will:
- Scan any existing markdown files in
docs/
- Extract page titles from H1 headers
- Generate a
docs/config.yaml
file
- Create a backup of any existing configuration
Example Interactive Session
GlowDoc Configuration Builder
============================
Site title [GlowDoc]: My Project Documentation
Description [modern docs for the modern world]: Comprehensive guide for My Project
Found 3 sections in docs/:
1. introduction (2 files)
2. getting-started (3 files)
3. api (1 file)
Would you like to reorder sections? [y/N]: y
Enter section order (comma-separated): introduction,getting-started,api
Configuration saved to docs/config.yaml
3. Create Your Content
Homepage Content
Create or edit docs/entry.md
for your homepage:
# My Project Documentation
Welcome to the comprehensive documentation for My Project.
## Getting Started
Follow our step-by-step guides to get up and running quickly.
## Key Features
- Feature 1: Description
- Feature 2: Description
- Feature 3: Description
Add Documentation Pages
Create markdown files in organized folders:
docs/
├── entry.md
├── config.yaml
├── introduction/
│ ├── overview.md
│ └── installation.md
├── guides/
│ ├── quick-start.md
│ ├── configuration.md
│ └── advanced-usage.md
└── reference/
└── api.md
Each markdown file should start with an H1 header:
# Page Title
Your content here...
## Section
More content...
4. Start Development Server
For the best development experience, use the built-in development server with hot reload:
# Start development server (recommended)
cargo run watch
This will:
- Build your documentation site
- Start HTTP server at http://localhost:8000
- Watch for file changes in
docs/
- Automatically rebuild and refresh your browser when files change
- Serve images and static assets from your docs folder
Alternative: One-time Build
If you prefer to build once and serve with a separate server:
# Build the complete site once
cargo run --release
# Serve with any static server
python3 -m http.server 8000
Visit http://localhost:8000
to see your documentation site.
5. Add Images and Assets
Place images and other static files in your docs/
directory:
docs/
├── images/
│ ├── logo.png
│ └── screenshots/
│ └── demo.jpg
├── assets/
│ └── diagram.svg
└── getting-started/
└── tutorial.md
Reference them in your markdown:



The development server (cargo run watch
) automatically serves these assets. Supported formats include:
- Images: PNG, JPG, GIF, SVG, WebP
- Documents: PDF, TXT, MD
- Media: MP3, MP4, WebM
- Fonts: WOFF, TTF, OTF
6. Customize the Appearance
Edit docs/config.yaml
to customize your site:
title: My Project Documentation
description: Everything you need to know about My Project
theme: vibrant # or 'default'
Adjust Navigation
Reorder sections and pages by editing the navigation structure:
navigation:
- title: Introduction
id: introduction
items:
- title: Overview
id: overview
file: introduction/overview.md
- title: Installation
id: installation
file: introduction/installation.md
Rebuild After Changes
With Development Server (Recommended):
- Changes are automatically detected and applied
- Browser refreshes automatically
- No manual rebuilding needed
With Manual Builds:
cargo run --release
7. Development Workflow
Hot Reload Development (Recommended)
Use the development server for the fastest workflow:
# Start development server
cargo run watch
# Then edit files in docs/ - changes appear instantly!
Features:
- Instant rebuilds when you save files
- Automatic browser refresh
- Static asset serving (images, fonts, etc.)
- Error reporting in console
- Debounced updates (prevents duplicate builds)
Manual Build Workflow
For production builds or when you prefer manual control:
# 1. Edit markdown files in docs/
# 2. Rebuild the site
cargo run --release
# 3. Refresh browser to see changes
# (No need to restart the server)
Adding New Pages
With Development Server:
- Create the markdown file in the appropriate
docs/
subfolder
- Run the config generator to update navigation:
cargo run init-config
- The site rebuilds automatically - no manual rebuild needed!
With Manual Builds:
- Create the markdown file in the appropriate
docs/
subfolder
- Run the config generator to update navigation:
cargo run init-config
- Rebuild the site:
cargo run --release
Reorganizing Content
Use CLI options for batch updates:
# Reorder sections and rename them
cargo run init-config \
--section-order intro,guide,reference \
--rename-section intro="Getting Started" \
--rename-section guide="User Guide"
Next Steps
Now that you have a working documentation site:
- Explore Customization: Learn about theming and styling options
- Add More Content: Expand your documentation with additional pages
- Deploy Your Site: Set up hosting for your documentation
- Advanced Features: Explore plugins and advanced configuration
Common Tasks
Adding a New Section
- Create a new folder in
docs/
: mkdir docs/new-section
- Add markdown files to the folder
- Run
cargo run init-config
to detect the new section
- Rebuild:
cargo run --release
Reordering Pages
cargo run init-config --page-order section=page1.md,page2.md,page3.md
Excluding Draft Content
cargo run init-config --exclude-section drafts
Custom Page Titles
Override auto-detected titles in docs/config.yaml
:
- title: Custom Navigation Title
id: page-id
file: section/actual-filename.md
Troubleshooting
Build errors: Check that all files referenced in config.yaml
exist and paths are correct.
Missing navigation: Ensure your markdown files have H1 headers and are included in the config.
Styling issues: Verify the theme setting in config.yaml and rebuild the site.
Server not accessible: Check that the server is running and try http://localhost:8000
instead of 127.0.0.1
.
Installation
GlowDoc is designed to be simple to set up. Choose the method that works best for your workflow.
Download Template
The easiest way to get started is to download the template directly:
# Download and extract
wget https://github.com/paradise-runner/glowdoc/archive/main.zip
unzip main.zip
cd glowdoc-main
Clone Repository
If you prefer to clone the repository:
# Clone the repository
git clone https://github.com/paradise-runner/glowdoc.git
cd glowdoc
# Remove git history (optional)
rm -rf .git
git init
Use as Template
Create a new repository using GlowDoc as a template on GitHub, then clone your new repository.
Configuration
GlowDoc provides flexible configuration options to customize your documentation site. All configuration is managed through the docs/config.yaml
file.
config.yaml Overview
The configuration file controls your site's structure, navigation, and appearance:
title: GlowDoc
description: modern docs for the modern world
theme: vibrant
navigation:
- title: Introduction
id: introduction
items:
- title: What is GlowDoc?
id: what-is-glowdoc
file: introduction/what-is-glowdoc.md
Auto-Generate Configuration
The easiest way to create or update your configuration is using the built-in generator:
Interactive Mode
cargo run init-config
This launches an interactive wizard that:
- Scans your
docs/
folder structure
- Detects existing markdown files
- Extracts page titles from H1 headers
- Guides you through customization options
- Backs up your existing config before generating a new one
Command-Line Mode
For automated workflows, use CLI arguments:
cargo run init-config \
--title "My Project" \
--description "Comprehensive project documentation" \
--section-order introduction,guide,api,advanced \
--rename-section guide="User Guide" \
--rename-page guide/setup.md="Installation Guide" \
--page-order guide=setup.md,configuration.md,usage.md \
--exclude-section drafts
Available CLI Options
--title "Site Title"
- Set the site title
--description "Description"
- Set the site description
--section-order folder1,folder2
- Reorder sections by folder names
--rename-section old=new
- Rename section titles in navigation
--rename-page section/file.md="New Title"
- Override page titles
--page-order section=file1.md,file2.md
- Reorder pages within sections
--exclude-section folder
- Exclude folders from navigation
--help
- Show complete usage guide
Manual Configuration
Basic Settings
title: Your Project Name
description: Brief description for SEO and page meta
theme: vibrant # or 'default'
Navigation Structure
Navigation follows a hierarchical structure with sections and items:
navigation:
- title: Section Name
id: unique-section-id
items:
- title: Page Title
id: unique-page-id
file: folder/filename.md
Key Rules:
- Section
id
must be unique across all sections
- Page
id
must be unique across all pages
file
path is relative to the docs/
folder
- Pages are displayed in the order they appear in the config
Themes
GlowDoc includes built-in themes:
default
- Clean, professional appearance
vibrant
- Bold colors with enhanced contrast
File Organization
Recommended Structure
docs/
├── config.yaml # Navigation configuration
├── entry.md # Homepage content (optional)
├── introduction/
│ ├── overview.md
│ └── quick-start.md
├── guides/
│ ├── installation.md
│ └── configuration.md
└── reference/
├── api.md
└── cli.md
Markdown Files
Each markdown file should start with an H1 header:
# Page Title
Content goes here...
The H1 title is automatically extracted during config generation and used as the default page title.
Advanced Configuration
Custom Page Titles
Override the auto-detected title from the markdown H1:
- title: Custom Page Title # Shows in navigation
id: custom-page
file: section/actual-filename.md # H1 in file can be different
Section Ordering
Control the order sections appear in navigation:
cargo run init-config --section-order introduction,tutorial,reference,advanced
Page Ordering
Control the order pages appear within each section:
cargo run init-config --page-order tutorial=setup.md,basics.md,advanced.md
Development Workflow
- Edit Configuration: Modify
docs/config.yaml
or use cargo run init-config
- Update Content: Edit markdown files in the
docs/
folder
- Rebuild Site: Run
cargo run --release
to regenerate index.html
- Preview Changes: Use
python3 -m http.server 8000
to serve locally
Troubleshooting
Common Issues
Config validation errors: Ensure all id
fields are unique and all referenced files exist.
Missing pages: Check that file paths in config.yaml are correct and relative to the docs/
folder.
Build failures: Verify YAML syntax in config.yaml using a YAML validator.
Backup and Recovery
The config generator automatically creates backups:
docs/config.yaml.backup
- Created before generating new config
- Manual backup:
cp docs/config.yaml docs/config.yaml.manual-backup
Theming
GlowDoc features a sophisticated theming system built on CSS custom properties, supporting multiple color schemes and seamless dark mode switching.
Built-in Themes
GlowDoc includes three professionally designed themes:
Default Theme
Clean, neutral design perfect for professional documentation:
# In docs/config.yaml
theme: default
Purple Theme
Purple-accented design with elegant color tones:
theme: purple
Vibrant Theme
Colorful, energetic design with bold accents:
theme: vibrant
Color System Architecture
GlowDoc uses a semantic color system with HSL values for precise color control and smooth transitions.
Core Color Properties
All themes use the same CSS custom property structure:
:root {
/* Background colors */
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
/* Component backgrounds */
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
/* Semantic colors */
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96%;
--secondary-foreground: 222.2 84% 4.9%;
--muted: 210 40% 96%;
--muted-foreground: 215.4 16.3% 46.9%;
/* Interactive elements */
--accent: 210 40% 96%;
--accent-foreground: 222.2 84% 4.9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
/* UI elements */
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
Dark Mode Support
Each theme automatically includes dark mode variants:
[data-theme="dark"] {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
/* ... other dark mode overrides */
}
Dark Mode Features:
- Automatic system preference detection
- Manual toggle with LocalStorage persistence
- Smooth 0.3s transitions between themes
- Optimized contrast ratios for readability
Typography System
Font Stack
GlowDoc uses a carefully selected system font stack for optimal performance and cross-platform consistency:
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "Helvetica Neue", Arial, sans-serif;
Typography Scale
Homepage Typography:
- Main Heading (H1): 3rem (48px), weight 800, gradient text effect
- Section Headings (H2): 1.75rem (28px), weight 600
- Body Text: 1.125rem (18px) for enhanced readability
Content Typography:
- Page Titles (H1): 2.5rem (40px), weight 700
- Section Headings (H2): 1.75rem (28px), weight 600
- Body Text: 1rem (16px) for optimal reading
- Navigation: 0.875rem (14px), weight 500-600
- Code: 0.875rem (14px) monospace
Special Typography Effects
Gradient Text (Homepage):
background: linear-gradient(135deg,
hsl(var(--primary)),
hsl(var(--accent))
);
-webkit-background-clip: text;
color: transparent;
Spacing System
GlowDoc uses a consistent spacing scale based on rem units:
/* Spacing scale */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-16: 4rem; /* 64px */
Common Usage:
- Small margins:
0.25rem
(4px)
- Button padding:
0.5rem
(8px)
- Standard spacing:
1rem
(16px)
- Section gaps:
1.5rem
(24px)
- Content padding:
2rem
(32px)
- Large sections:
4rem
(64px)
Custom Theme Creation
1. Modify Existing Theme
To customize an existing theme, you'll need to modify the CSS generation in the Rust source:
Location: src/main.rs
in the generate_css()
function
2. Color Customization
Update the HSL values for any theme:
:root {
/* Change primary brand color */
--primary: 220 70% 50%; /* Blue instead of dark gray */
--primary-foreground: 0 0% 100%;
/* Adjust accent color */
--accent: 160 60% 45%; /* Teal accent */
--accent-foreground: 0 0% 100%;
}
3. Typography Customization
Custom Font Integration:
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
Custom Font Sizes:
/* Larger base font size */
.main-content {
font-size: 1.125rem;
line-height: 1.75;
}
/* Custom heading sizes */
h1 { font-size: 3rem; }
h2 { font-size: 2rem; }
h3 { font-size: 1.5rem; }
Advanced Theming
Custom CSS Properties
Add your own custom properties for consistent theming:
:root {
/* Custom brand colors */
--brand-blue: 220 90% 56%;
--brand-green: 142 71% 45%;
--brand-orange: 25 95% 53%;
/* Custom spacing */
--content-width: 900px;
--sidebar-width: 320px;
/* Custom shadows */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
}
Responsive Design Variables
:root {
--mobile-breakpoint: 768px;
--sidebar-width: 280px;
--mobile-padding: 1rem;
--desktop-padding: 2rem;
}
@media (max-width: 768px) {
.main-content {
padding: var(--mobile-padding);
}
}
Animation Customization
:root {
/* Transition speeds */
--transition-fast: 0.15s;
--transition-normal: 0.2s;
--transition-slow: 0.3s;
/* Easing functions */
--ease-out: cubic-bezier(0.0, 0.0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0.0, 0.2, 1);
}
/* Apply to interactive elements */
.nav-link {
transition: all var(--transition-normal) var(--ease-out);
}
Theme Implementation Details
Theme Switching Mechanism
GlowDoc implements theme switching through:
- Data attribute:
data-theme="light|dark"
on the <html>
element
- JavaScript toggle: Smooth transitions between light/dark modes
- LocalStorage: Persistent user preference storage
- System detection: Automatic theme based on user's OS preference
Color Accessibility
All themes maintain WCAG AA contrast ratios:
- Normal text: 4.5:1 contrast ratio
- Large text: 3:1 contrast ratio
- Interactive elements: Enhanced focus states
- CSS custom properties enable instant theme switching
- No additional HTTP requests for theme assets
- Optimized for both light and dark viewing conditions
- Smooth transitions without layout shifts
Troubleshooting
Theme not applying: Ensure the theme name in config.yaml
matches exactly: default
, purple
, or vibrant
.
Dark mode not working: Check that JavaScript is enabled and the browser supports CSS custom properties.
Custom colors not showing: Verify HSL values are properly formatted: 220 70% 50%
(without hsl()
wrapper).
Typography issues: Ensure font declarations come after the base stylesheet in the build process.
Components
GlowDoc is built with a comprehensive component system that provides consistent, accessible, and responsive UI elements throughout your documentation site.
Layout Components
The main header provides navigation and theme switching functionality:
Structure:
<header class="header-content">
<div class="container">
<div class="logo">Site Title</div>
<button class="theme-toggle" aria-label="Toggle theme">
<!-- Theme toggle icon -->
</button>
</div>
</header>
Features:
- Sticky positioning with backdrop blur effect
- 80px fixed height
- Responsive container with max-width of 1200px
- Integrated theme toggle button
The collapsible sidebar houses the main navigation and search functionality:
Structure:
<aside class="sidebar">
<div class="search-container">
<input type="text" class="search-input" placeholder="Search...">
<div class="search-results"></div>
</div>
<nav class="navigation">
<div class="nav-section">
<button class="nav-section-title">Section Name</button>
<div class="nav-section-content">
<a href="#page" class="nav-link">Page Title</a>
</div>
</div>
</nav>
</aside>
Features:
- Fixed 280px width on desktop
- Collapsible sections with smooth animations
- Integrated search with live results
- Mobile-responsive with overlay behavior
Main Content Area
The primary content container with optimal reading layout:
Structure:
<main class="main-content">
<div class="content-section" id="page-id">
<h1>Page Title</h1>
<p>Content goes here...</p>
</div>
</main>
Features:
- Flexible layout that grows to fill available space
- 800px max-width for optimal reading
- Responsive padding (2rem desktop, 1rem mobile)
- Centered content with proper spacing
Navigation Components
Navigation Links
Individual navigation items with active state support:
CSS Classes:
.nav-link {
/* Base navigation link styles */
display: block;
padding: 0.5rem 1rem;
color: hsl(var(--muted-foreground));
text-decoration: none;
border-radius: 0.375rem;
transition: all 0.2s ease;
}
.nav-link:hover {
background-color: hsl(var(--accent));
color: hsl(var(--accent-foreground));
}
.nav-link.active {
background-color: hsl(var(--primary));
color: hsl(var(--primary-foreground));
font-weight: 600;
}
Usage:
- Automatically marked as
.active
based on current page
- Left border accent on hover and active states
- Smooth color transitions
- Accessible keyboard navigation
Collapsible section headers in the navigation:
Structure:
<button class="nav-section-title" data-section="section-id">
<span>Section Name</span>
<svg class="chevron-icon"><!-- Chevron icon --></svg>
</button>
Features:
- Click to expand/collapse section content
- Animated chevron icon rotation
- Maintains expanded state in LocalStorage
- Proper ARIA attributes for accessibility
Interactive Components
Theme Toggle
The dark/light mode switcher with system preference detection:
Structure:
<button class="theme-toggle" aria-label="Toggle theme">
<svg class="sun-icon"><!-- Sun icon --></svg>
<svg class="moon-icon"><!-- Moon icon --></svg>
</button>
Features:
- Automatic system preference detection on first visit
- Smooth icon transitions between light/dark states
- LocalStorage persistence for user preference
- 0.3s transition for theme switching
Search Component
Live search functionality with instant results:
Structure:
<div class="search-container">
<div class="search-input-wrapper">
<svg class="search-icon"><!-- Search icon --></svg>
<input type="text" class="search-input" placeholder="Search documentation...">
</div>
<div class="search-results">
<div class="search-result" data-target="page-id">
<div class="search-result-title">Page Title</div>
<div class="search-result-excerpt">Matching content...</div>
</div>
</div>
</div>
Features:
- Real-time search as you type (300ms debounce)
- Searches through all page titles and content
- Highlighted search terms in results
- Keyboard navigation support (arrow keys, Enter)
- Click or Enter to navigate to results
Responsive navigation for mobile devices:
Structure:
<button class="mobile-menu-toggle">
<span class="hamburger-line"></span>
<span class="hamburger-line"></span>
<span class="hamburger-line"></span>
</button>
Features:
- Animated hamburger menu icon
- Transforms sidebar into full-screen overlay
- Smooth slide-in animation from left
- Closes on backdrop click or page navigation
Content Components
Code Blocks
Syntax-highlighted code blocks with proper formatting:
Markdown Usage:
```javascript
function greetUser(name) {
console.log(`Hello, ${name}!`);
}
```
Generated HTML:
<pre><code class="language-javascript">
function greetUser(name) {
console.log(`Hello, ${name}!`);
}
</code></pre>
Features:
- Automatic syntax highlighting via CSS
- Consistent background and padding
- Horizontal scrolling for long lines
- Copy-friendly formatting
Content Sections
Organized content areas for each documentation page:
Structure:
<div class="content-section" id="unique-page-id">
<h1>Page Title</h1>
<p>Introduction paragraph...</p>
<h2>Section Heading</h2>
<p>Section content...</p>
</div>
Features:
- Hidden by default (only active page shown)
- Smooth fade-in transitions when activated
- Proper heading hierarchy (H1 for page title, H2+ for sections)
- Semantic HTML structure for accessibility
Search Result Highlighting
Dynamic highlighting of search terms in content:
Generated Markup:
<p>This is some <mark class="search-highlight">highlighted</mark> text.</p>
CSS Styling:
.search-highlight {
background-color: hsl(var(--primary) / 0.2);
color: hsl(var(--primary-foreground));
padding: 0.125rem 0.25rem;
border-radius: 0.25rem;
}
Responsive Behavior
Breakpoint System
GlowDoc uses a mobile-first approach with a single breakpoint:
/* Mobile styles (default) */
.sidebar {
position: fixed;
left: -100%;
transition: left 0.3s ease;
}
/* Desktop styles */
@media (min-width: 768px) {
.sidebar {
position: fixed;
left: 0;
}
}
Mobile Adaptations
Sidebar Behavior:
- Becomes full-screen overlay on mobile
- Slide-in animation from left edge
- Backdrop blur and dark overlay
- Closes on outside click or page navigation
Content Layout:
- Single-column layout on mobile
- Reduced padding (1rem vs 2rem)
- Optimized touch targets (44px minimum)
- Larger font sizes for better readability
Navigation:
- Collapsible sections remain functional
- Touch-optimized interactive areas
- Simplified hover states for touch devices
Accessibility Features
Keyboard Navigation
Navigation Support:
- Tab order follows logical content flow
- Arrow keys navigate search results
- Enter key activates links and buttons
- Escape key closes mobile menu and search
Focus Management:
- Visible focus indicators on all interactive elements
- Focus trapped within mobile menu when open
- Focus restored when closing overlays
Screen Reader Support
ARIA Labels:
<button aria-label="Toggle theme" class="theme-toggle">
<input aria-label="Search documentation" class="search-input">
<nav aria-label="Main navigation" class="navigation">
Semantic Structure:
- Proper heading hierarchy (H1 → H2 → H3)
- Landmark roles for main sections
- Descriptive link text
- Form labels associated with inputs
Color and Contrast
WCAG AA Compliance:
- 4.5:1 contrast ratio for normal text
- 3:1 contrast ratio for large text
- Enhanced focus states with both color and outline
- Color is not the only means of conveying information
CSS Architecture
Efficient Selectors:
- Class-based selectors for performance
- Minimal nesting depth
- Optimized specificity
Transition Performance:
- GPU-accelerated transforms
- Efficient property animations (opacity, transform)
- Reasonable transition durations (0.2s-0.3s)
JavaScript Optimization
Search Debouncing:
- 300ms delay to reduce excessive searches
- Efficient DOM queries using data attributes
- Minimal DOM manipulation
Event Handling:
- Event delegation for dynamic content
- Passive event listeners where appropriate
- Memory leak prevention
Customization Examples
Custom Navigation Styling
.nav-link {
/* Add custom styles */
border-left: 3px solid transparent;
margin-bottom: 0.25rem;
}
.nav-link:hover {
border-left-color: hsl(var(--primary));
background: linear-gradient(90deg,
hsl(var(--primary) / 0.1),
transparent
);
}
.nav-link.active {
border-left-color: hsl(var(--primary));
background-color: hsl(var(--primary) / 0.15);
}
Custom Search Styling
.search-container {
/* Custom search appearance */
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: 0.75rem;
padding: 1rem;
margin-bottom: 1.5rem;
}
.search-input {
/* Enhanced input styling */
background: hsl(var(--background));
border: 2px solid hsl(var(--border));
border-radius: 0.5rem;
padding: 0.75rem 1rem 0.75rem 2.5rem;
}
.search-input:focus {
border-color: hsl(var(--primary));
box-shadow: 0 0 0 3px hsl(var(--primary) / 0.1);
}
Custom Content Styling
.content-section {
/* Enhanced content presentation */
line-height: 1.75;
max-width: 900px; /* Wider content area */
}
.content-section h1 {
/* Custom heading styles */
border-bottom: 2px solid hsl(var(--border));
padding-bottom: 1rem;
margin-bottom: 2rem;
}
.content-section h2 {
/* Section heading enhancements */
margin-top: 3rem;
margin-bottom: 1.5rem;
color: hsl(var(--primary));
}
This component system provides a solid foundation for building beautiful, functional documentation sites while maintaining consistency and accessibility across all interface elements.
Custom Styling
Advanced styling techniques and customization patterns for creating unique GlowDoc designs that match your brand and requirements.
Architecture Overview
GlowDoc's CSS architecture is designed for maximum customization while maintaining performance and accessibility. Understanding the core structure enables powerful customizations.
CSS Organization
The generated stylesheet follows this structure:
/* 1. CSS Reset & Base Styles */
/* 2. CSS Custom Properties (Design Tokens) */
/* 3. Layout Components */
/* 4. Navigation Components */
/* 5. Content Components */
/* 6. Interactive Components */
/* 7. Responsive Media Queries */
/* 8. Theme Variations */
Modification Approach
Since GlowDoc generates a single HTML file with embedded CSS, customizations should be added to the Rust source in the generate_css()
function:
Location: src/main.rs
- Look for the generate_css()
function
Advanced Styling Techniques
Custom Brand Integration
Brand Color System
Create a comprehensive brand color palette:
:root {
/* Primary brand colors */
--brand-primary: 220 90% 56%;
--brand-primary-dark: 220 90% 45%;
--brand-primary-light: 220 90% 65%;
/* Secondary brand colors */
--brand-secondary: 160 60% 45%;
--brand-accent: 25 95% 53%;
--brand-neutral: 220 10% 50%;
/* Semantic color mappings */
--primary: var(--brand-primary);
--accent: var(--brand-secondary);
/* Brand gradients */
--brand-gradient: linear-gradient(135deg,
hsl(var(--brand-primary)),
hsl(var(--brand-secondary))
);
}
Logo and Brand Assets
Integrate custom logos and brand elements:
.logo {
background-image: url('data:image/svg+xml;base64,...');
background-size: contain;
background-repeat: no-repeat;
width: 120px;
height: 40px;
text-indent: -9999px; /* Hide text */
}
/* Alternative: Custom font logo */
.logo {
font-family: 'Your Brand Font', sans-serif;
font-weight: 700;
font-size: 1.5rem;
color: hsl(var(--brand-primary));
}
Advanced Layout Customizations
Multi-Column Content Layout
Create complex content layouts:
.content-section {
display: grid;
grid-template-columns: 1fr 300px;
gap: 2rem;
max-width: 1200px;
}
.content-main {
min-width: 0; /* Prevent grid blowout */
}
.content-sidebar {
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: 0.5rem;
padding: 1.5rem;
height: fit-content;
position: sticky;
top: 100px; /* Account for header height */
}
@media (max-width: 1024px) {
.content-section {
grid-template-columns: 1fr;
}
.content-sidebar {
order: -1; /* Move sidebar above content on mobile */
}
}
Custom Navigation Layouts
Enhanced sidebar with custom sections:
.sidebar {
display: grid;
grid-template-rows: auto 1fr auto;
gap: 1rem;
}
.sidebar-header {
padding: 1rem;
border-bottom: 1px solid hsl(var(--border));
}
.sidebar-content {
overflow-y: auto;
padding: 0 1rem;
}
.sidebar-footer {
padding: 1rem;
border-top: 1px solid hsl(var(--border));
background: hsl(var(--muted) / 0.5);
}
/* Custom navigation grouping */
.nav-group {
margin-bottom: 2rem;
}
.nav-group-title {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: hsl(var(--muted-foreground));
margin-bottom: 0.5rem;
padding: 0 1rem;
}
Typography Enhancement
Custom Font Integration
Professional typography with web fonts:
/* Import custom fonts */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');
:root {
/* Typography system */
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
--font-mono: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
/* Type scale */
--text-xs: 0.75rem; /* 12px */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
--text-3xl: 1.875rem; /* 30px */
--text-4xl: 2.25rem; /* 36px */
--text-5xl: 3rem; /* 48px */
}
body {
font-family: var(--font-sans);
}
code, pre {
font-family: var(--font-mono);
}
Advanced Typography Styles
Rich text formatting and hierarchy:
.content-section {
/* Enhanced reading experience */
font-size: var(--text-lg);
line-height: 1.7;
color: hsl(var(--foreground));
}
.content-section h1 {
font-size: var(--text-4xl);
font-weight: 800;
line-height: 1.1;
margin-bottom: 1.5rem;
background: var(--brand-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.content-section h2 {
font-size: var(--text-2xl);
font-weight: 700;
margin-top: 3rem;
margin-bottom: 1rem;
position: relative;
}
.content-section h2::before {
content: '';
position: absolute;
left: -2rem;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 1.5rem;
background: hsl(var(--primary));
border-radius: 2px;
}
/* Enhanced blockquotes */
.content-section blockquote {
border-left: 4px solid hsl(var(--primary));
padding-left: 1.5rem;
margin: 2rem 0;
font-style: italic;
font-size: var(--text-xl);
color: hsl(var(--muted-foreground));
}
/* Improved lists */
.content-section ul {
list-style: none;
padding-left: 0;
}
.content-section li {
position: relative;
padding-left: 1.5rem;
margin-bottom: 0.5rem;
}
.content-section li::before {
content: '→';
position: absolute;
left: 0;
color: hsl(var(--primary));
font-weight: 600;
}
Interactive Element Enhancements
Custom button system with multiple variants:
/* Button base styles */
.btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 0.5rem;
font-weight: 600;
font-size: var(--text-sm);
text-decoration: none;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
overflow: hidden;
}
/* Primary button */
.btn-primary {
background: hsl(var(--primary));
color: hsl(var(--primary-foreground));
}
.btn-primary:hover {
background: hsl(var(--primary) / 0.9);
transform: translateY(-1px);
box-shadow: 0 4px 12px hsl(var(--primary) / 0.3);
}
/* Gradient button */
.btn-gradient {
background: var(--brand-gradient);
color: white;
position: relative;
}
.btn-gradient::before {
content: '';
position: absolute;
inset: 0;
background: var(--brand-gradient);
opacity: 0;
transition: opacity 0.2s ease;
}
.btn-gradient:hover::before {
opacity: 0.1;
}
/* Outline button */
.btn-outline {
background: transparent;
border: 2px solid hsl(var(--primary));
color: hsl(var(--primary));
}
.btn-outline:hover {
background: hsl(var(--primary));
color: hsl(var(--primary-foreground));
}
Professional form controls:
.form-group {
margin-bottom: 1.5rem;
}
.form-label {
display: block;
font-weight: 600;
font-size: var(--text-sm);
color: hsl(var(--foreground));
margin-bottom: 0.5rem;
}
.form-input {
width: 100%;
padding: 0.75rem 1rem;
border: 2px solid hsl(var(--border));
border-radius: 0.5rem;
background: hsl(var(--background));
color: hsl(var(--foreground));
font-size: var(--text-base);
transition: all 0.2s ease;
}
.form-input:focus {
outline: none;
border-color: hsl(var(--primary));
box-shadow: 0 0 0 3px hsl(var(--primary) / 0.1);
}
.form-input::placeholder {
color: hsl(var(--muted-foreground));
}
Animation and Micro-Interactions
Page Transition Effects
Smooth page transitions:
.content-section {
opacity: 0;
transform: translateY(20px);
transition: all 0.3s ease;
}
.content-section.active {
opacity: 1;
transform: translateY(0);
}
/* Staggered animation for navigation items */
.nav-link {
opacity: 0;
transform: translateX(-20px);
animation: slideInLeft 0.3s ease forwards;
}
.nav-link:nth-child(1) { animation-delay: 0.1s; }
.nav-link:nth-child(2) { animation-delay: 0.15s; }
.nav-link:nth-child(3) { animation-delay: 0.2s; }
/* ... continue pattern */
@keyframes slideInLeft {
to {
opacity: 1;
transform: translateX(0);
}
}
Hover Effects and Micro-Interactions
Engaging interactive feedback:
/* Card hover effects */
.card {
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: 0.75rem;
padding: 1.5rem;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.card::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(45deg,
hsl(var(--primary) / 0.1),
hsl(var(--accent) / 0.1)
);
opacity: 0;
transition: opacity 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px hsl(var(--foreground) / 0.1);
border-color: hsl(var(--primary));
}
.card:hover::before {
opacity: 1;
}
/* Ripple effect for buttons */
.btn {
position: relative;
overflow: hidden;
}
.btn::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.btn:active::after {
width: 300px;
height: 300px;
}
Responsive Design Patterns
Advanced Responsive Typography
Fluid typography that scales smoothly:
:root {
/* Fluid typography using clamp() */
--text-fluid-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
--text-fluid-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-fluid-lg: clamp(1.125rem, 1rem + 0.625vw, 1.25rem);
--text-fluid-xl: clamp(1.25rem, 1.1rem + 0.75vw, 1.5rem);
--text-fluid-2xl: clamp(1.5rem, 1.3rem + 1vw, 2rem);
--text-fluid-3xl: clamp(1.875rem, 1.5rem + 1.875vw, 2.5rem);
--text-fluid-4xl: clamp(2.25rem, 1.8rem + 2.25vw, 3rem);
}
body {
font-size: var(--text-fluid-base);
}
h1 { font-size: var(--text-fluid-4xl); }
h2 { font-size: var(--text-fluid-3xl); }
h3 { font-size: var(--text-fluid-2xl); }
Container Queries (Future-Forward)
Modern responsive design using container queries:
.content-section {
container-type: inline-size;
}
/* Adjust layout based on container width, not viewport */
@container (min-width: 600px) {
.content-grid {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 2rem;
}
}
@container (min-width: 900px) {
.content-grid {
grid-template-columns: 1fr 2fr 1fr;
}
}
Dark Mode Advanced Customizations
Theme-Aware Components
Components that adapt intelligently to theme changes:
/* Light theme specific styles */
[data-theme="light"] .hero-section {
background: linear-gradient(135deg,
hsl(var(--background)),
hsl(var(--secondary))
);
}
/* Dark theme specific styles */
[data-theme="dark"] .hero-section {
background: linear-gradient(135deg,
hsl(var(--background)),
hsl(var(--card))
);
}
/* Theme-aware shadows */
.elevated-card {
box-shadow:
0 4px 6px hsl(var(--foreground) / 0.1),
0 1px 3px hsl(var(--foreground) / 0.05);
}
[data-theme="dark"] .elevated-card {
box-shadow:
0 4px 6px rgba(0, 0, 0, 0.3),
0 1px 3px rgba(0, 0, 0, 0.2);
}
Efficient CSS Architecture
Optimized styles for better performance:
/* Use CSS custom properties for frequently changing values */
:root {
--animation-speed: 0.2s;
--animation-easing: cubic-bezier(0.4, 0, 0.2, 1);
}
/* Optimize animations for 60fps */
.animated-element {
will-change: transform, opacity;
transform: translateZ(0); /* Force hardware acceleration */
transition: transform var(--animation-speed) var(--animation-easing);
}
/* Efficient selectors */
.nav-link { /* Good: class selector */ }
nav > ul > li > a { /* Avoid: deep nesting */ }
* { /* Avoid: universal selector */ }
Critical CSS Patterns
Inline critical styles for immediate rendering:
/* Critical above-the-fold styles */
.layout,
.header-content,
.sidebar,
.main-content {
/* Essential layout properties only */
display: flex;
position: relative;
}
/* Non-critical styles can be loaded later */
.fancy-animations,
.decorative-elements {
/* Complex animations and decorative styles */
}
Custom Styling Workflow
1. Planning Your Customizations
Before modifying styles:
- Audit existing styles: Understand the current CSS architecture
- Define your design system: Colors, typography, spacing, components
- Plan responsive behavior: Mobile-first approach
- Consider accessibility: Maintain contrast ratios and focus states
2. Implementation Strategy
Recommended approach:
- Start with CSS custom property overrides
- Add new component styles
- Implement responsive variations
- Test across themes (light/dark)
- Validate accessibility compliance
3. Testing Checklist
Troubleshooting Custom Styles
Styles not applying: Check CSS specificity and ensure your styles come after the base styles in the build order.
Theme conflicts: Verify that custom styles work with both light and dark modes.
Performance issues: Minimize complex selectors and excessive animations.
Responsive problems: Test on actual devices, not just browser dev tools.
Accessibility concerns: Use tools like axe-core to validate accessibility compliance.
API Reference
Comprehensive JavaScript API reference for programmatic control and customization of GlowDoc documentation sites.
Overview
GlowDoc generates a single-page application with a rich JavaScript API for navigation, search, theming, and customization. All functionality is embedded within the generated HTML file, providing a complete client-side documentation experience.
Core Navigation API
showContent(contentId, updateUrl = true)
Displays a specific documentation page by content ID.
Parameters:
contentId
(string) - The unique identifier for the content section
updateUrl
(boolean, optional) - Whether to update browser URL and history (default: true)
Returns: void
Example:
// Show the installation page
showContent('installation');
// Show content without updating URL (for programmatic navigation)
showContent('api-reference', false);
Behavior:
- Switches from homepage to documentation layout if needed
- Hides all content sections and displays the target section
- Updates active state in navigation sidebar
- Updates browser URL and history (unless
updateUrl
is false)
- Automatically closes mobile sidebar
- Logs content display for debugging
showHomepage()
Displays the homepage content and hides documentation layout.
Parameters: None
Returns: void
Example:
// Return to homepage
showHomepage();
Behavior:
- Shows homepage element, hides documentation layout
- Updates browser URL to root path
- Uses HTML5 History API for navigation
showDocs()
Switches the interface to documentation mode (internal function).
Parameters: None
Returns: void
Usage: Typically called internally by showContent()
, but available for custom implementations.
showContentFromSearch(contentId)
Displays content selected from search results and clears search state.
Parameters:
contentId
(string) - The content ID to display
Returns: void
Example:
// Show search result and clear search
showContentFromSearch('quick-start');
Behavior:
- Clears search input field
- Hides search results, shows navigation
- Calls
showContent()
to display the selected page
Theme Management API
toggleTheme()
Toggles between light and dark theme modes.
Parameters: None
Returns: void
Example:
// Toggle theme
toggleTheme();
// Programmatically check current theme
const currentTheme = document.documentElement.getAttribute('data-theme');
console.log('Current theme:', currentTheme); // 'light' or 'dark'
Behavior:
- Toggles
data-theme
attribute between 'light' and 'dark'
- Saves theme preference to localStorage
- Provides smooth transitions via CSS
- Respects system preferences on first visit
Theme Persistence:
// Theme is automatically saved to localStorage
localStorage.getItem('theme'); // Returns 'light' or 'dark'
toggleSidebar()
Toggles sidebar visibility (primarily for mobile interfaces).
Parameters: None
Returns: void
Example:
// Toggle mobile sidebar
toggleSidebar();
// Check sidebar state
const sidebar = document.querySelector('.sidebar');
const isVisible = sidebar.classList.contains('visible');
Behavior:
- Toggles 'visible' class on sidebar element
- Provides slide-in animation on mobile devices
- Automatically handled for responsive breakpoints
toggleSection(sectionId)
Expands or collapses navigation sections in the sidebar.
Parameters:
sectionId
(string) - The ID of the section to toggle
Returns: void
Example:
// Toggle a navigation section
toggleSection('getting-started');
// Check section state
const section = document.querySelector('[data-section="getting-started"]');
const isCollapsed = section.classList.contains('collapsed');
Behavior:
- Toggles 'collapsed' class on section and its toggle icon
- Provides smooth expand/collapse animations
- State persisted for user experience
Search API
performSearch()
Performs real-time search across all documentation content.
Parameters: None (reads from search input element)
Returns: void
Example:
// Trigger search programmatically
document.querySelector('.search-input').value = 'installation';
performSearch();
// Search is automatically triggered on input
Search Features:
- Real-time Results: Updates as user types
- Content Indexing: Searches titles, sections, and full content
- Result Ranking: Title matches rank higher than content matches
- Snippet Generation: Shows relevant content excerpts
- Keyword Highlighting: Highlights matching terms in results
Search Index Structure:
// Global searchIndex object
const searchIndex = {
"page-id": {
"title": "Page Title",
"section": "Section Name",
"content": "Full searchable content..."
}
// ... more pages
};
Custom Search Integration
// Access search index for custom functionality
function customSearch(query) {
const results = [];
for (const [id, data] of Object.entries(searchIndex)) {
if (data.title.toLowerCase().includes(query.toLowerCase())) {
results.push({ id, ...data });
}
}
return results;
}
// Example: Find all pages in a specific section
function findBySection(sectionName) {
return Object.entries(searchIndex)
.filter(([id, data]) => data.section === sectionName)
.map(([id, data]) => ({ id, ...data }));
}
URL and History Management
loadFromUrl()
Loads appropriate content based on current URL hash.
Parameters: None
Returns: void
Example:
// Load content based on URL
loadFromUrl();
// Handle URL changes
window.addEventListener('hashchange', loadFromUrl);
URL Format:
- Homepage:
#
or no hash
- Content pages:
#page-id
- Automatically handles invalid page IDs
History Management:
// Navigation automatically updates browser history
// Back/forward buttons work seamlessly
window.addEventListener('popstate', (event) => {
if (event.state?.contentId) {
showContent(event.state.contentId, false);
} else if (event.state?.page === 'home') {
showHomepage();
}
});
Event System
Built-in Event Listeners
GlowDoc automatically registers several event listeners:
// Navigation clicks
document.addEventListener('click', (e) => {
if (e.target.hasAttribute('data-content-id')) {
e.preventDefault();
showContent(e.target.getAttribute('data-content-id'));
}
});
// Browser navigation
window.addEventListener('popstate', (event) => {
// Handle back/forward navigation
});
// Initial load
document.addEventListener('DOMContentLoaded', () => {
loadFromUrl();
});
// Mobile sidebar - outside clicks
document.addEventListener('click', (e) => {
// Close sidebar when clicking outside on mobile
});
Custom Event Handling
// Listen for content changes
function onContentChange(contentId) {
console.log('Content changed to:', contentId);
// Custom logic here
}
// Override or extend existing functions
const originalShowContent = showContent;
showContent = function(contentId, updateUrl = true) {
onContentChange(contentId);
return originalShowContent(contentId, updateUrl);
};
Configuration and Customization
Global Configuration
// Access current state
const getCurrentContent = () => {
const activeSection = document.querySelector('.content-section:not([style*="display: none"])');
return activeSection?.id;
};
const getCurrentTheme = () => {
return document.documentElement.getAttribute('data-theme');
};
// Get navigation state
const getNavigationState = () => {
const collapsedSections = Array.from(document.querySelectorAll('.nav-section.collapsed'))
.map(section => section.dataset.section);
return { collapsedSections };
};
DOM Element Access
Required Elements:
// Core layout elements
const homepage = document.getElementById('homepage');
const docsLayout = document.getElementById('docs-layout');
const sidebar = document.querySelector('.sidebar');
// Search elements
const searchInput = document.querySelector('.search-input');
const searchResults = document.querySelector('.search-results');
const searchResultsList = document.querySelector('.search-results-list');
// Navigation elements
const navigationContainer = document.querySelector('.navigation-container');
const contentSections = document.querySelectorAll('.content-section');
const navLinks = document.querySelectorAll('.nav-link');
Data Attributes:
data-content-id
: Links navigation items to content sections
data-section
: Identifies collapsible navigation sections
data-theme
: Current theme state on document element
Advanced Customization
Custom Navigation
// Add custom navigation item
function addCustomNavItem(sectionId, title, contentId) {
const navSection = document.querySelector(`[data-section="${sectionId}"] .nav-section-content`);
if (navSection) {
const link = document.createElement('a');
link.href = `#${contentId}`;
link.className = 'nav-link';
link.setAttribute('data-content-id', contentId);
link.textContent = title;
navSection.appendChild(link);
}
}
// Custom content injection
function addCustomContent(contentId, title, htmlContent) {
const contentSection = document.createElement('div');
contentSection.className = 'content-section';
contentSection.id = contentId;
contentSection.style.display = 'none';
contentSection.innerHTML = `<h1>${title}</h1>${htmlContent}`;
document.querySelector('.main-content').appendChild(contentSection);
// Add to search index
searchIndex[contentId] = {
title: title,
section: 'Custom',
content: contentSection.textContent
};
}
Theme Customization
// Custom theme switching
function setCustomTheme(themeName) {
document.documentElement.setAttribute('data-theme', themeName);
localStorage.setItem('theme', themeName);
}
// Theme change detection
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.attributeName === 'data-theme') {
const newTheme = document.documentElement.getAttribute('data-theme');
console.log('Theme changed to:', newTheme);
// Custom theme change logic
}
});
});
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['data-theme']
});
Search Customization
// Custom search implementation
function customPerformSearch() {
const query = document.querySelector('.search-input').value.toLowerCase().trim();
const resultsContainer = document.querySelector('.search-results-list');
if (!query) {
// Hide search results
document.querySelector('.search-results').style.display = 'none';
document.querySelector('.navigation-container').style.display = 'block';
return;
}
const results = [];
// Custom search logic
for (const [id, data] of Object.entries(searchIndex)) {
let score = 0;
// Title match (highest priority)
if (data.title.toLowerCase().includes(query)) score += 10;
// Section match (medium priority)
if (data.section.toLowerCase().includes(query)) score += 5;
// Content match (lower priority)
if (data.content.toLowerCase().includes(query)) score += 1;
if (score > 0) {
results.push({ id, ...data, score });
}
}
// Sort by score (descending)
results.sort((a, b) => b.score - a.score);
// Display results
displaySearchResults(results, query);
}
function displaySearchResults(results, query) {
const resultsContainer = document.querySelector('.search-results-list');
if (results.length === 0) {
resultsContainer.innerHTML = '<div class="no-results">No results found</div>';
} else {
resultsContainer.innerHTML = results.map(result => {
const snippet = generateSnippet(result.content, query);
return `
<div class="search-result" onclick="showContentFromSearch('${result.id}')">
<div class="search-result-title">${highlightText(result.title, query)}</div>
<div class="search-result-section">${result.section}</div>
<div class="search-result-snippet">${snippet}</div>
</div>
`;
}).join('');
}
// Show search results
document.querySelector('.search-results').style.display = 'block';
document.querySelector('.navigation-container').style.display = 'none';
}
function generateSnippet(content, query, maxLength = 150) {
const queryIndex = content.toLowerCase().indexOf(query.toLowerCase());
if (queryIndex === -1) {
return content.substring(0, maxLength) + (content.length > maxLength ? '...' : '');
}
const start = Math.max(0, queryIndex - 50);
const end = Math.min(content.length, queryIndex + query.length + 50);
const snippet = content.substring(start, end);
return (start > 0 ? '...' : '') +
highlightText(snippet, query) +
(end < content.length ? '...' : '');
}
function highlightText(text, query) {
const regex = new RegExp(`(${query})`, 'gi');
return text.replace(regex, '<mark class="search-highlight">$1</mark>');
}
Debounced Search
// Implement search debouncing
let searchTimeout;
function debouncedSearch() {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(performSearch, 300);
}
// Replace default search input handler
document.querySelector('.search-input').addEventListener('input', debouncedSearch);
Lazy Loading
// Lazy load content sections
const observerOptions = {
root: null,
rootMargin: '100px',
threshold: 0.1
};
const contentObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Load heavy content when section becomes visible
loadSectionAssets(entry.target);
}
});
}, observerOptions);
// Observe all content sections
document.querySelectorAll('.content-section').forEach(section => {
contentObserver.observe(section);
});
Error Handling and Debugging
Debug Mode
// Enable debug mode
window.GLOWDOC_DEBUG = true;
// Enhanced showContent with debugging
function debugShowContent(contentId, updateUrl = true) {
if (window.GLOWDOC_DEBUG) {
console.log('Showing content:', contentId);
console.log('Available content IDs:', Object.keys(searchIndex));
console.log('Update URL:', updateUrl);
}
const contentElement = document.getElementById(contentId);
if (!contentElement) {
console.error(`Content element with ID '${contentId}' not found`);
return;
}
return showContent(contentId, updateUrl);
}
Error Recovery
// Handle missing content gracefully
function safeShowContent(contentId, fallbackId = 'introduction') {
const contentElement = document.getElementById(contentId);
if (!contentElement) {
console.warn(`Content '${contentId}' not found, showing fallback`);
return showContent(fallbackId);
}
return showContent(contentId);
}
// Validate navigation state
function validateNavigation() {
const issues = [];
// Check for orphaned navigation links
document.querySelectorAll('[data-content-id]').forEach(link => {
const contentId = link.getAttribute('data-content-id');
if (!document.getElementById(contentId)) {
issues.push(`Navigation link points to missing content: ${contentId}`);
}
});
// Check for content without navigation
document.querySelectorAll('.content-section').forEach(section => {
const contentId = section.id;
const navLink = document.querySelector(`[data-content-id="${contentId}"]`);
if (!navLink) {
issues.push(`Content section has no navigation link: ${contentId}`);
}
});
return issues;
}
Browser Compatibility
Supported Features:
- ES6+ JavaScript (const, let, arrow functions, template literals)
- HTML5 History API
- CSS Custom Properties
- LocalStorage
- Modern DOM APIs
Minimum Browser Versions:
- Chrome 49+
- Firefox 44+
- Safari 10+
- Edge 12+
Graceful Degradation:
// Feature detection
if (!window.history?.pushState) {
console.warn('History API not supported, using hash navigation');
// Fallback to hash-based navigation
}
if (!window.localStorage) {
console.warn('LocalStorage not supported, theme preference will not persist');
// Use session-based theme storage
}
This comprehensive API reference provides complete control over GlowDoc's functionality, enabling deep customization while maintaining the system's performance and user experience benefits.
Deployment
Comprehensive guide to deploying your GlowDoc documentation site across various hosting platforms, from simple static hosting to advanced CI/CD pipelines.
Overview
GlowDoc generates a single index.html
file containing your entire documentation site, making deployment simple and flexible. This approach offers several advantages:
- Single File Deployment: No complex directory structures or dependencies
- Universal Compatibility: Works with any static hosting service
- Fast Loading: All assets embedded, no additional HTTP requests
- Easy Backup: Single file contains everything
- CDN Friendly: Perfect for content delivery networks
Pre-Deployment Checklist
Before deploying your documentation:
1. Build Verification
# Build your documentation
cargo run --release
# Verify the build succeeded
ls -la index.html
# Test locally
python3 -m http.server 8000
# Visit http://localhost:8000 to verify everything works
2. Content Review
# Check file size (typical range: 500KB - 2MB)
du -h index.html
# Optional: Minify if needed (for very large sites)
# Note: GlowDoc output is already optimized
GitHub Pages
Deploy directly from your GitHub repository with automated builds.
Method 1: GitHub Actions (Recommended)
Create .github/workflows/deploy.yml
:
name: Deploy GlowDoc
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build documentation
run: cargo run --release
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: .
publish_branch: gh-pages
force_orphan: true
enable_jekyll: false
exclude_assets: |
.github
.gitignore
Cargo.toml
Cargo.lock
src
docs
target
README.md
Method 2: Manual Upload
# Build locally
cargo run --release
# Create gh-pages branch
git checkout --orphan gh-pages
git rm -rf .
git add index.html
git commit -m "Deploy documentation"
git push origin gh-pages
# Return to main branch
git checkout main
GitHub Pages Configuration
- Go to your repository → Settings → Pages
- Set Source to "Deploy from a branch"
- Select
gh-pages
branch
- Choose
/ (root)
folder
- Save settings
Custom Domain Setup:
# Add CNAME file to repository root
echo "docs.yoursite.com" > CNAME
git add CNAME
git commit -m "Add custom domain"
git push
Netlify
Professional hosting with advanced features and global CDN.
Method 1: Git Integration (Recommended)
-
Connect Repository:
- Sign up at netlify.com
- Click "New site from Git"
- Connect your GitHub/GitLab repository
-
Build Configuration:
# netlify.toml
[build]
command = "cargo run --release"
publish = "."
[build.environment]
RUST_VERSION = "1.70"
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
X-Content-Type-Options = "nosniff"
Referrer-Policy = "strict-origin-when-cross-origin"
[[redirects]]
from = "/docs/*"
to = "/#:splat"
status = 200
-
Deploy Settings:
- Build command:
cargo run --release
- Publish directory:
.
(root)
- Node version: Latest LTS
Method 2: Manual Upload
# Build documentation
cargo run --release
# Deploy via Netlify CLI
npm install -g netlify-cli
netlify login
netlify deploy --prod --dir=.
Advanced Netlify Features
Form Handling:
<!-- Add to your documentation for feedback forms -->
<form name="feedback" method="POST" data-netlify="true">
<input type="hidden" name="form-name" value="feedback" />
<input type="text" name="name" placeholder="Your name" required />
<textarea name="message" placeholder="Feedback" required></textarea>
<button type="submit">Send Feedback</button>
</form>
Analytics Integration:
// Add to your custom JavaScript
if (window.netlifyIdentity) {
window.netlifyIdentity.on('init', user => {
if (!user) {
window.netlifyIdentity.on('login', () => {
document.location.href = '/admin/';
});
}
});
}
Vercel
Zero-configuration deployment with excellent performance.
Method 1: Git Integration
-
Connect Repository:
- Sign up at vercel.com
- Import your Git repository
- Vercel auto-detects the setup
-
Configuration File:
{
"version": 2,
"name": "glowdoc-docs",
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "/index.html"
}
],
"env": {
"RUST_VERSION": "1.70"
}
}
-
Package.json for Build:
{
"name": "glowdoc-site",
"scripts": {
"build": "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && source ~/.cargo/env && cargo run --release"
}
}
Method 2: Vercel CLI
# Install Vercel CLI
npm install -g vercel
# Build and deploy
cargo run --release
vercel --prod
Cloudflare Pages
High-performance hosting with global edge network.
Setup Process:
-
Connect Repository:
-
Build Configuration:
- Build command:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && source ~/.cargo/env && cargo run --release
- Build output directory:
.
- Environment variables:
RUST_VERSION=1.70
-
Custom Domains:
# Configure custom domain in Cloudflare Dashboard
# DNS automatically managed
Firebase Hosting
Google's hosting platform with global CDN.
Setup Process:
# Install Firebase CLI
npm install -g firebase-tools
# Initialize Firebase
firebase login
firebase init hosting
# Configure firebase.json
{
"hosting": {
"public": ".",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**",
"src/**",
"docs/**",
"target/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
],
"headers": [
{
"source": "**/*.@(js|css)",
"headers": [
{
"key": "Cache-Control",
"value": "max-age=31536000"
}
]
}
]
}
}
# Build and deploy
cargo run --release
firebase deploy
Traditional Web Hosting
Apache Configuration
For traditional web hosting with Apache:
# .htaccess
RewriteEngine On
# Handle client-side routing
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
# Security headers
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
Header always set X-XSS-Protection "1; mode=block"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
# Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css application/javascript
</IfModule>
# Caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html "access plus 1 hour"
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
</IfModule>
Nginx Configuration
For Nginx hosting:
server {
listen 80;
listen [::]:80;
server_name yourdomain.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yourdomain.com;
# SSL configuration
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
# Document root
root /var/www/glowdoc;
index index.html;
# Handle client-side routing
location / {
try_files $uri $uri/ /index.html;
}
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
# Compression
gzip on;
gzip_types text/html text/css application/javascript;
# Caching
location ~* \.(css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
Content Delivery Networks (CDN)
Cloudflare CDN
Enhance performance with Cloudflare:
-
DNS Setup:
- Add your domain to Cloudflare
- Update nameservers
- Enable "Proxied" status
-
Optimization Settings:
- Auto Minify: HTML, CSS, JS
- Brotli compression: Enabled
- Rocket Loader: Enabled
- Cache Level: Standard
-
Page Rules:
yourdomain.com/*
- Cache Level: Cache Everything
- Edge Cache TTL: 1 month
- Browser Cache TTL: 1 day
AWS CloudFront
Enterprise-grade CDN with AWS integration:
{
"Distribution": {
"Origins": [
{
"Id": "S3-glowdoc",
"DomainName": "your-bucket.s3.amazonaws.com",
"S3OriginConfig": {
"OriginAccessIdentity": ""
}
}
],
"DefaultCacheBehavior": {
"TargetOriginId": "S3-glowdoc",
"ViewerProtocolPolicy": "redirect-to-https",
"Compress": true,
"CachePolicyId": "managed-caching-optimized"
},
"CustomErrorResponses": [
{
"ErrorCode": 404,
"ResponseCode": 200,
"ResponsePagePath": "/index.html"
}
]
}
}
Automation and CI/CD
GitHub Actions Advanced Workflow
Complete CI/CD pipeline with testing and deployment:
name: Build, Test, and Deploy
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
CARGO_TERM_COLOR: always
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Run tests
run: cargo test --verbose
- name: Check formatting
run: cargo fmt -- --check
- name: Run clippy
run: cargo clippy -- -D warnings
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build documentation
run: cargo run --release
- name: Validate HTML
run: |
npm install -g html-validate
html-validate index.html
- name: Check file size
run: |
SIZE=$(stat -c%s index.html)
echo "Generated file size: $SIZE bytes"
if [ $SIZE -gt 5242880 ]; then
echo "Warning: File size exceeds 5MB"
exit 1
fi
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: documentation
path: index.html
deploy-staging:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: documentation
- name: Deploy to staging
run: |
# Deploy to staging environment
echo "Deploying to staging..."
deploy-production:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: documentation
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: .
force_orphan: true
- name: Notify deployment
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
-H 'Content-type: application/json' \
--data '{"text":"📚 Documentation deployed successfully!"}'
GitLab CI/CD
# .gitlab-ci.yml
stages:
- test
- build
- deploy
variables:
RUST_VERSION: "1.70"
before_script:
- apt-get update -qq
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- source ~/.cargo/env
test:
stage: test
script:
- cargo test --verbose
- cargo fmt -- --check
- cargo clippy -- -D warnings
only:
- merge_requests
- main
build:
stage: build
script:
- cargo run --release
artifacts:
paths:
- index.html
expire_in: 1 hour
only:
- main
pages:
stage: deploy
script:
- mkdir public
- cp index.html public/
artifacts:
paths:
- public
only:
- main
Domain and SSL Configuration
Custom Domain Setup
DNS Configuration:
# A Records for root domain
@ 3600 IN A 185.199.108.153
@ 3600 IN A 185.199.109.153
@ 3600 IN A 185.199.110.153
@ 3600 IN A 185.199.111.153
# CNAME for www subdomain
www 3600 IN CNAME your-username.github.io.
# CNAME for docs subdomain
docs 3600 IN CNAME your-site.netlify.app.
SSL Certificate Setup:
Most modern hosting platforms provide automatic SSL:
- GitHub Pages: Automatic with custom domains
- Netlify: Automatic Let's Encrypt certificates
- Vercel: Automatic SSL for all deployments
- Cloudflare: Universal SSL included
Manual SSL Configuration
For traditional hosting:
# Generate Let's Encrypt certificate
certbot certonly --webroot -w /var/www/glowdoc -d yourdomain.com
# Auto-renewal
echo "0 12 * * * /usr/bin/certbot renew --quiet" | crontab -
Build Optimization
# Optimize for production
RUSTFLAGS="-C target-cpu=native" cargo run --release
# Profile build performance
cargo build --release --timings
Content Optimization
- Image Optimization: Use optimized images in markdown
- Font Subsetting: Include only needed font weights
- Code Splitting: Implement lazy loading for large sections
Monitoring and Analytics
// Add to your custom JavaScript
function trackPerformance() {
window.addEventListener('load', () => {
const perfData = performance.timing;
const loadTime = perfData.loadEventEnd - perfData.navigationStart;
// Send to analytics
gtag('event', 'page_load_time', {
value: loadTime,
custom_parameter: 'documentation_site'
});
});
}
Uptime Monitoring:
Set up monitoring with services like:
- StatusCake: Free uptime monitoring
- Pingdom: Comprehensive monitoring suite
- UptimeRobot: Free and paid monitoring options
Security Considerations
Content Security Policy
<!-- Add to your HTML head -->
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.googletagmanager.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https:;
connect-src 'self' https://www.google-analytics.com;
">
Implement security headers across all hosting platforms:
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Troubleshooting Deployment Issues
Common Problems
Build Failures:
# Check Rust version compatibility
rustc --version
# Verify dependencies
cargo check
# Clean and rebuild
cargo clean && cargo run --release
Routing Issues:
- Ensure hosting platform supports SPA routing
- Configure redirects for client-side routing
- Verify base URL configuration
Performance Issues:
- Check file size (should be under 5MB)
- Verify compression is enabled
- Test CDN configuration
SSL Certificate Problems:
- Verify DNS propagation
- Check certificate chain
- Ensure HTTPS redirects are configured
Debug Deployment
# Test local build
cargo run --release
python3 -m http.server 8000
# Validate HTML
html-validate index.html
# Check file permissions
ls -la index.html
# Test from different networks
curl -I https://yourdomain.com
Best Practices
- Version Control: Always commit before deploying
- Staging Environment: Test changes before production
- Automated Backups: Regular backup of source files
- Performance Monitoring: Track load times and uptime
- Security Updates: Keep hosting platform updated
- Documentation: Document deployment process for team
- Rollback Plan: Maintain ability to quickly revert changes
This comprehensive deployment guide ensures your GlowDoc documentation is accessible, performant, and secure across any hosting platform.
Plugins and Extensions
Extend GlowDoc's functionality with custom plugins, third-party integrations, and advanced features to enhance your documentation experience.
Plugin Architecture Overview
GlowDoc's modular architecture allows for various extension points and integration patterns. While GlowDoc doesn't have a formal plugin system, you can extend functionality through several approaches:
Extension Methods
- CSS and JavaScript Extensions: Add custom functionality through the Rust build process
- Third-Party Integrations: Embed external services and tools
- Build Process Extensions: Modify the Rust source for custom features
- External Tool Integration: Combine GlowDoc with other documentation tools
Syntax Highlighting Enhancements
Advanced Code Highlighting
While GlowDoc includes basic syntax highlighting, you can enhance it with external libraries:
Prism.js Integration
Add advanced syntax highlighting with Prism.js:
// Add to the JavaScript section in src/main.rs
function initializePrism() {
// Load Prism.js dynamically
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js';
script.onload = function() {
// Load additional language support
const languages = ['rust', 'javascript', 'python', 'bash', 'yaml'];
languages.forEach(lang => {
const langScript = document.createElement('script');
langScript.src = `https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-${lang}.min.js`;
document.head.appendChild(langScript);
});
// Load Prism CSS
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css';
document.head.appendChild(link);
// Re-highlight all code blocks
Prism.highlightAll();
};
document.head.appendChild(script);
}
// Call during page initialization
initializePrism();
Custom Syntax Highlighting
Create custom highlighting for domain-specific languages:
function customHighlighter() {
document.querySelectorAll('pre code').forEach(block => {
const language = block.className.match(/language-(\w+)/);
if (language && language[1] === 'custom-dsl') {
highlightCustomDSL(block);
}
});
}
function highlightCustomDSL(codeBlock) {
let html = codeBlock.innerHTML;
// Define custom syntax patterns
const patterns = [
{ regex: /\b(function|if|else|return)\b/g, class: 'keyword' },
{ regex: /\b\d+\b/g, class: 'number' },
{ regex: /"[^"]*"/g, class: 'string' },
{ regex: /\/\/.*$/gm, class: 'comment' }
];
patterns.forEach(pattern => {
html = html.replace(pattern.regex, `<span class="${pattern.class}">$&</span>`);
});
codeBlock.innerHTML = html;
}
Code Copy Functionality
Add copy-to-clipboard buttons for code blocks:
function addCopyButtons() {
document.querySelectorAll('pre').forEach(pre => {
const button = document.createElement('button');
button.className = 'copy-button';
button.textContent = 'Copy';
button.onclick = () => copyToClipboard(pre.textContent, button);
pre.style.position = 'relative';
pre.appendChild(button);
});
}
function copyToClipboard(text, button) {
navigator.clipboard.writeText(text).then(() => {
const originalText = button.textContent;
button.textContent = 'Copied!';
button.classList.add('copied');
setTimeout(() => {
button.textContent = originalText;
button.classList.remove('copied');
}, 2000);
});
}
// CSS for copy button
const copyButtonCSS = `
.copy-button {
position: absolute;
top: 0.5rem;
right: 0.5rem;
padding: 0.25rem 0.5rem;
background: hsl(var(--primary));
color: hsl(var(--primary-foreground));
border: none;
border-radius: 0.25rem;
font-size: 0.75rem;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s ease;
}
pre:hover .copy-button {
opacity: 1;
}
.copy-button.copied {
background: hsl(var(--accent));
}
`;
Search Enhancements
Advanced Search Integration
Algolia DocSearch
Integrate Algolia's DocSearch for powerful search capabilities:
function initializeAlgoliaSearch() {
// Load Algolia DocSearch
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/@docsearch/js@3';
script.onload = function() {
docsearch({
appId: 'YOUR_APP_ID',
apiKey: 'YOUR_SEARCH_API_KEY',
indexName: 'YOUR_INDEX_NAME',
container: '#docsearch',
searchParameters: {
facetFilters: ['language:en'],
},
});
};
document.head.appendChild(script);
// Replace existing search input
const searchContainer = document.querySelector('.search-container');
searchContainer.innerHTML = '<div id="docsearch"></div>';
}
Lunr.js Client-Side Search
Implement advanced client-side search with Lunr.js:
function initializeLunrSearch() {
// Build search index from content
const documents = [];
document.querySelectorAll('.content-section').forEach((section, idx) => {
documents.push({
id: idx,
title: section.querySelector('h1')?.textContent || '',
content: section.textContent,
url: section.id
});
});
// Create Lunr index
const idx = lunr(function () {
this.ref('id');
this.field('title', { boost: 10 });
this.field('content');
documents.forEach((doc) => {
this.add(doc);
});
});
// Enhanced search function
function performSearch(query) {
const results = idx.search(query);
return results.map(result => {
const doc = documents[result.ref];
return {
...doc,
score: result.score,
excerpt: generateExcerpt(doc.content, query)
};
});
}
function generateExcerpt(content, query, maxLength = 150) {
const index = content.toLowerCase().indexOf(query.toLowerCase());
if (index === -1) return content.substring(0, maxLength) + '...';
const start = Math.max(0, index - 50);
const end = Math.min(content.length, index + query.length + 50);
const excerpt = content.substring(start, end);
return (start > 0 ? '...' : '') + excerpt + (end < content.length ? '...' : '');
}
}
Search Analytics
Track search behavior and popular queries:
function trackSearchAnalytics() {
const searchInput = document.querySelector('.search-input');
searchInput.addEventListener('input', debounce((e) => {
const query = e.target.value;
if (query.length > 2) {
// Track search queries
gtag('event', 'search', {
search_term: query,
page_title: document.title
});
}
}, 1000));
// Track search result clicks
document.addEventListener('click', (e) => {
if (e.target.classList.contains('search-result')) {
gtag('event', 'search_result_click', {
search_term: searchInput.value,
result_title: e.target.textContent
});
}
});
}
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
Analytics and Tracking
Google Analytics 4 Integration
Implement comprehensive analytics tracking:
function initializeAnalytics() {
// Load Google Analytics
const script1 = document.createElement('script');
script1.async = true;
script1.src = 'https://www.googletagmanager.com/gtag/js?id=YOUR_GA_ID';
document.head.appendChild(script1);
const script2 = document.createElement('script');
script2.innerHTML = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'YOUR_GA_ID', {
page_title: document.title,
page_location: window.location.href
});
`;
document.head.appendChild(script2);
}
function trackUserBehavior() {
// Track page navigation
document.addEventListener('click', (e) => {
if (e.target.classList.contains('nav-link')) {
gtag('event', 'page_view', {
page_title: e.target.textContent,
page_location: window.location.href + '#' + e.target.getAttribute('href').substring(1)
});
}
});
// Track theme changes
document.querySelector('.theme-toggle').addEventListener('click', () => {
const currentTheme = document.documentElement.getAttribute('data-theme');
gtag('event', 'theme_change', {
theme: currentTheme === 'dark' ? 'light' : 'dark'
});
});
// Track scroll depth
let maxScroll = 0;
window.addEventListener('scroll', debounce(() => {
const scrollPercent = Math.round((window.scrollY + window.innerHeight) / document.body.scrollHeight * 100);
if (scrollPercent > maxScroll) {
maxScroll = scrollPercent;
if (maxScroll % 25 === 0) { // Track at 25%, 50%, 75%, 100%
gtag('event', 'scroll_depth', {
percent: maxScroll,
page_title: document.title
});
}
}
}, 500));
}
Hotjar Integration
Add user behavior tracking with Hotjar:
function initializeHotjar() {
const script = document.createElement('script');
script.innerHTML = `
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:YOUR_HOTJAR_ID,hjsv:6};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
`;
document.head.appendChild(script);
}
Accessibility Enhancements
Screen Reader Improvements
Enhance accessibility with ARIA attributes and screen reader support:
function enhanceAccessibility() {
// Add skip navigation
const skipLink = document.createElement('a');
skipLink.href = '#main-content';
skipLink.textContent = 'Skip to main content';
skipLink.className = 'skip-link';
document.body.insertBefore(skipLink, document.body.firstChild);
// Improve navigation ARIA labels
document.querySelectorAll('.nav-section-title').forEach(title => {
const sectionId = title.getAttribute('data-section');
title.setAttribute('aria-expanded', 'false');
title.setAttribute('aria-controls', sectionId + '-content');
const content = title.nextElementSibling;
if (content) {
content.setAttribute('id', sectionId + '-content');
content.setAttribute('aria-labelledby', sectionId + '-title');
}
});
// Announce page changes to screen readers
const announcer = document.createElement('div');
announcer.setAttribute('aria-live', 'polite');
announcer.setAttribute('aria-atomic', 'true');
announcer.className = 'sr-only';
document.body.appendChild(announcer);
// Announce when content changes
function announcePageChange(title) {
announcer.textContent = `Navigated to ${title}`;
setTimeout(() => announcer.textContent = '', 1000);
}
return { announcePageChange };
}
// CSS for accessibility
const accessibilityCSS = `
.skip-link {
position: absolute;
top: -40px;
left: 6px;
background: hsl(var(--primary));
color: hsl(var(--primary-foreground));
padding: 8px;
text-decoration: none;
border-radius: 0 0 4px 4px;
z-index: 1000;
}
.skip-link:focus {
top: 0;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
`;
Keyboard Navigation Enhancement
Improve keyboard navigation throughout the documentation:
function enhanceKeyboardNavigation() {
let focusedSearchResult = -1;
document.addEventListener('keydown', (e) => {
// Search result navigation
if (e.target.classList.contains('search-input')) {
const results = document.querySelectorAll('.search-result');
switch (e.key) {
case 'ArrowDown':
e.preventDefault();
focusedSearchResult = Math.min(focusedSearchResult + 1, results.length - 1);
updateSearchResultFocus(results);
break;
case 'ArrowUp':
e.preventDefault();
focusedSearchResult = Math.max(focusedSearchResult - 1, -1);
updateSearchResultFocus(results);
break;
case 'Enter':
if (focusedSearchResult >= 0 && results[focusedSearchResult]) {
e.preventDefault();
results[focusedSearchResult].click();
}
break;
case 'Escape':
e.target.blur();
document.querySelector('.search-results').style.display = 'none';
break;
}
}
// Global shortcuts
if (e.ctrlKey || e.metaKey) {
switch (e.key) {
case 'k':
e.preventDefault();
document.querySelector('.search-input').focus();
break;
case '/':
e.preventDefault();
document.querySelector('.search-input').focus();
break;
}
}
});
function updateSearchResultFocus(results) {
results.forEach((result, index) => {
result.classList.toggle('focused', index === focusedSearchResult);
});
if (focusedSearchResult >= 0 && results[focusedSearchResult]) {
results[focusedSearchResult].scrollIntoView({ block: 'nearest' });
}
}
}
Lazy Loading and Code Splitting
Implement performance optimizations:
function implementLazyLoading() {
// Lazy load heavy components
const observerOptions = {
root: null,
rootMargin: '100px',
threshold: 0.1
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const section = entry.target;
loadSectionAssets(section);
observer.unobserve(section);
}
});
}, observerOptions);
// Observe content sections for lazy loading
document.querySelectorAll('.content-section').forEach(section => {
observer.observe(section);
});
function loadSectionAssets(section) {
// Load section-specific assets
const codeBlocks = section.querySelectorAll('pre code');
if (codeBlocks.length > 0) {
loadSyntaxHighlighting(codeBlocks);
}
const diagrams = section.querySelectorAll('.mermaid');
if (diagrams.length > 0) {
loadMermaidDiagrams(diagrams);
}
}
}
function implementServiceWorker() {
if ('serviceWorker' in navigator) {
const swContent = `
const CACHE_NAME = 'glowdoc-v1';
const urlsToCache = [
'/',
'/index.html'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => cache.addAll(urlsToCache))
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
return response || fetch(event.request);
})
);
});
`;
const blob = new Blob([swContent], { type: 'application/javascript' });
const swURL = URL.createObjectURL(blob);
navigator.serviceWorker.register(swURL)
.then((registration) => {
console.log('ServiceWorker registered:', registration);
})
.catch((error) => {
console.log('ServiceWorker registration failed:', error);
});
}
}
Diagram and Visualization Support
Mermaid Diagrams
Add support for Mermaid diagrams:
function initializeMermaid() {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js';
script.onload = function() {
mermaid.initialize({
startOnLoad: false,
theme: document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'default',
securityLevel: 'loose'
});
// Process Mermaid diagrams
document.querySelectorAll('.language-mermaid').forEach(async (element, index) => {
const graphDefinition = element.textContent;
const graphId = `mermaid-graph-${index}`;
try {
const { svg } = await mermaid.render(graphId, graphDefinition);
const wrapper = document.createElement('div');
wrapper.className = 'mermaid-wrapper';
wrapper.innerHTML = svg;
element.closest('pre').replaceWith(wrapper);
} catch (error) {
console.error('Mermaid rendering error:', error);
}
});
};
document.head.appendChild(script);
}
// Update Mermaid theme when user changes theme
function updateMermaidTheme() {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.attributeName === 'data-theme') {
const newTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'default';
if (window.mermaid) {
mermaid.initialize({ theme: newTheme });
// Re-render existing diagrams
document.querySelectorAll('.mermaid-wrapper').forEach(async (wrapper, index) => {
// Re-render logic here
});
}
}
});
});
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['data-theme']
});
}
Chart.js Integration
Add interactive charts and graphs:
function initializeCharts() {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/chart.js';
script.onload = function() {
document.querySelectorAll('.chart-container').forEach(container => {
const config = JSON.parse(container.dataset.config);
const canvas = document.createElement('canvas');
container.appendChild(canvas);
new Chart(canvas, {
...config,
options: {
...config.options,
responsive: true,
plugins: {
...config.options?.plugins,
legend: {
...config.options?.plugins?.legend,
labels: {
color: getComputedStyle(document.documentElement)
.getPropertyValue('--foreground')
}
}
}
}
});
});
};
document.head.appendChild(script);
}
Plugin Development Guide
Creating Custom Extensions
Structure for building your own GlowDoc extensions:
// In src/main.rs, add to the generate_javascript() function
pub fn generate_custom_plugin_javascript() -> String {
r#"
// Custom Plugin Framework
class GlowDocPlugin {
constructor(name, options = {}) {
this.name = name;
this.options = options;
this.hooks = {};
this.initialized = false;
}
// Register event hooks
on(event, callback) {
if (!this.hooks[event]) {
this.hooks[event] = [];
}
this.hooks[event].push(callback);
return this;
}
// Trigger event hooks
trigger(event, data) {
if (this.hooks[event]) {
this.hooks[event].forEach(callback => callback(data));
}
}
// Initialize plugin
init() {
if (this.initialized) return;
this.trigger('beforeInit', this.options);
this.setup();
this.initialized = true;
this.trigger('afterInit', this.options);
}
// Override in subclasses
setup() {
throw new Error('Plugin must implement setup() method');
}
}
// Plugin registry
window.GlowDocPlugins = {
plugins: new Map(),
register(plugin) {
this.plugins.set(plugin.name, plugin);
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => plugin.init());
} else {
plugin.init();
}
},
get(name) {
return this.plugins.get(name);
}
};
// Example plugin
class ExamplePlugin extends GlowDocPlugin {
setup() {
this.on('beforeInit', (options) => {
console.log('Example plugin initializing with options:', options);
});
// Add custom functionality
this.addCustomButton();
}
addCustomButton() {
const button = document.createElement('button');
button.textContent = 'Custom Action';
button.onclick = () => this.trigger('customAction', 'Hello from plugin!');
document.querySelector('.header-content').appendChild(button);
}
}
// Auto-register plugins
document.addEventListener('DOMContentLoaded', () => {
// Register built-in plugins
const examplePlugin = new ExamplePlugin('example', { debug: true });
GlowDocPlugins.register(examplePlugin);
});
"#.to_string()
}
Plugin Configuration
Allow users to configure plugins through config.yaml:
// Add to Config struct in src/main.rs
#[derive(Debug, Deserialize, Serialize)]
struct PluginConfig {
name: String,
enabled: bool,
options: HashMap<String, serde_yaml::Value>,
}
#[derive(Debug, Deserialize, Serialize)]
struct Config {
title: String,
description: String,
navigation: Vec<NavigationSection>,
theme: String,
plugins: Option<Vec<PluginConfig>>,
}
Best Practices for Extensions
- Lazy Loading: Only load plugins when needed
- Code Splitting: Separate plugin code from core functionality
- Memory Management: Clean up event listeners and resources
- Minimal Dependencies: Keep external dependencies lightweight
Security Guidelines
- Input Validation: Sanitize all user inputs
- Content Security Policy: Implement CSP headers
- External Resources: Use integrity hashes for CDN resources
- User Data: Handle user data securely
Accessibility Standards
- ARIA Support: Provide proper ARIA attributes
- Keyboard Navigation: Ensure all functionality is keyboard accessible
- Screen Reader Compatibility: Test with screen readers
- Color Contrast: Maintain adequate contrast ratios
Troubleshooting Plugins
Plugin not loading: Check browser console for JavaScript errors and verify script URLs.
Conflicts between plugins: Implement proper namespacing and avoid global variable conflicts.
Performance issues: Profile plugin performance and optimize heavy operations.
Theme compatibility: Ensure plugins work with all themes and dark mode.
Mobile responsiveness: Test plugin functionality on mobile devices.