# qsgen3 Themes How-To Guide This guide explains how to create and customize themes for qsgen3, based on how the code actually interprets and processes themes. ## Table of Contents 1. [Theme Basics](#theme-basics) 2. [Theme Directory Structure](#theme-directory-structure) 3. [Creating Your First Theme](#creating-your-first-theme) 4. [Layout Templates](#layout-templates) 5. [Static Assets (CSS, JS, Images)](#static-assets-css-js-images) 6. [Theme Configuration](#theme-configuration) 7. [Advanced Theme Features](#advanced-theme-features) 8. [Theme Best Practices](#theme-best-practices) 9. [Troubleshooting](#troubleshooting) ## Theme Basics ### What is a Theme? A qsgen3 theme is a collection of layout templates and static assets (CSS, JavaScript, images) that define the visual appearance and structure of your generated website. Themes allow you to: - Customize the HTML structure of your pages - Apply custom CSS styling - Include JavaScript functionality - Override default layouts with theme-specific designs ### How qsgen3 Processes Themes When you specify a theme in your `site.conf`, qsgen3 follows this processing order: 1. **Theme Detection**: Looks for the theme directory at `themes/{theme_name}/` 2. **Layout Override**: If the theme has a `layouts/` directory, it **completely replaces** the default layouts 3. **Static File Copying**: Copies static files from both root `static/` and theme `static/` directories 4. **CSS Linking**: Automatically links the theme's main CSS file in generated HTML **Important**: When a theme provides layouts, qsgen3 uses **only** the theme's layouts. There is no fallback to default layouts for individual templates. If you want to use a theme, ensure it provides all necessary layout files (`index.html`, `post.html`, `page.html`, `rss.xml`). ### Included Example Theme qsgen3 includes a `minimal` theme that demonstrates the proper theme structure: ``` themes/minimal/ ├── layouts/ # Complete set of templates │ ├── index.html # Homepage layout │ ├── post.html # Blog post layout │ ├── page.html # Static page layout │ └── rss.xml # RSS feed template ├── static/ # Theme assets │ └── css/ │ └── style.css # Clean, minimal styling └── README.md # Theme documentation ``` To use the minimal theme: 1. Set `site_theme="minimal"` in your `site.conf` 2. Set `site_theme_css_file="css/style.css"` 3. Run `./bin/qsgen3` ## Theme Directory Structure ### Standard Theme Structure ``` themes/ └── your-theme-name/ ├── layouts/ # Optional: Custom layout templates │ ├── index.html # Homepage layout (overrides default) │ ├── post.html # Blog post layout (overrides default) │ ├── page.html # Static page layout (overrides default) │ └── rss.xml # RSS feed template (overrides default) └── static/ # Theme's static assets ├── css/ │ └── style.css # Main theme CSS ├── js/ │ └── theme.js # Theme JavaScript └── images/ └── logo.png # Theme images ``` **Important**: By default, qsgen3 uses the `layouts/` directory in your project root (as specified by `paths_layouts_dir` in `site.conf`). When a theme provides its own `layouts/` directory, it completely overrides the default layouts directory. ### Alternative Structure (Legacy Support) For themes that don't use the `static/` subdirectory: ``` themes/ └── your-theme-name/ ├── layouts/ # Optional: Custom layout templates ├── css/ # CSS files directly in theme root │ └── style.css ├── js/ # JavaScript files └── images/ # Image files ``` ### How Layout Override Works 1. **Default**: qsgen3 uses templates from your project's `layouts/` directory (configurable via `paths_layouts_dir`) 2. **Theme Override**: If `themes/your-theme/layouts/` exists, qsgen3 uses **only** those templates 3. **No Fallback**: If a theme provides layouts, there is no fallback to default layouts. The theme must provide all required templates. **Note**: The project root `layouts/` directory serves as default templates for projects not using themes, or as a fallback when no theme is specified. ## Creating Your First Theme ### Step 1: Create the Theme Directory ```bash mkdir -p themes/my-theme/static/css mkdir -p themes/my-theme/static/js mkdir -p themes/my-theme/layouts ``` ### Step 2: Create a Basic CSS File Create `themes/my-theme/static/css/style.css`: ```css /* Basic theme styles */ body { font-family: 'Arial', sans-serif; line-height: 1.6; margin: 0; padding: 0; background-color: #f4f4f4; } header { background: #333; color: white; padding: 1rem; text-align: center; } header h1 a { color: white; text-decoration: none; } main { max-width: 800px; margin: 2rem auto; padding: 0 1rem; background: white; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } article { padding: 2rem; } footer { text-align: center; padding: 1rem; background: #333; color: white; margin-top: 2rem; } ``` ### Step 3: Configure Your Site Update your `site.conf`: ```bash # Theme configuration site_theme="my-theme" site_theme_css_file="css/style.css" ``` ### Step 4: Test Your Theme ```bash ./bin/qsgen3 ``` Your site should now use your custom theme! ## Layout Templates ### Understanding Pandoc Templates qsgen3 uses Pandoc templates with special variable syntax: - `$variable$` - Simple variable substitution - `$if(variable)$...$endif$` - Conditional blocks - `$for(list)$...$endfor$` - Loop over lists - `$body$` - The main content (converted from Markdown) ### Available Variables #### Site-wide Variables (from site.conf) - `$site_name$` - Your site's name - `$site_tagline$` - Your site's tagline - `$site_url$` - Your site's URL - `$current_year$` - Current year (auto-generated) #### Content Variables (from Markdown frontmatter) - `$title$` - Page/post title - `$author$` - Content author - `$date$` - Publication date - `$description$` - Page description - `$body$` - The converted Markdown content #### Special Variables - `$css$` - CSS file paths (handled automatically) - `$math$` - Math rendering support (if enabled) ### Creating Custom Layouts #### Basic Post Layout (`layouts/post.html`) ```html $site_name$ - $title$ $if(date)$$endif$ $for(css)$ $endfor$

$site_name$

$site_tagline$

$title$

$if(author)$

By: $author$

$endif$ $if(date)$

Published: $date$

$endif$
$body$
``` #### Index Page Layout (`layouts/index.html`) ```html $site_name$ - $site_tagline$ $for(css)$ $endfor$

$site_name$

$site_tagline$

$body$
``` ## Static Assets (CSS, JS, Images) ### How Static Files Are Processed qsgen3 copies static files in this order: 1. **Root Static Files**: Copies from `static/` to `output/static/` 2. **Theme Static Files**: Copies from `themes/{theme}/static/` to `output/static/` (overwrites root files) This means theme files take precedence over root static files. ### CSS File Linking The main theme CSS file is automatically linked in all generated HTML pages using the `--css` flag passed to Pandoc. The CSS path is determined by: 1. `site_theme_css_file` setting in `site.conf` (recommended) 2. `site_theme_css_path` setting (legacy, deprecated) Example configuration: ```bash site_theme="my-theme" site_theme_css_file="css/style.css" # Relative to theme's static/ directory ``` This results in: - CSS file copied to: `output/static/css/style.css` - HTML links to: `/static/css/style.css` ### Adding Additional Assets #### JavaScript Files Create `themes/my-theme/static/js/theme.js`: ```javascript // Theme-specific JavaScript document.addEventListener('DOMContentLoaded', function() { console.log('My theme loaded!'); // Add smooth scrolling document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); document.querySelector(this.getAttribute('href')).scrollIntoView({ behavior: 'smooth' }); }); }); }); ``` Include in your layout: ```html ``` #### Images and Other Assets Place images in `themes/my-theme/static/images/` and reference them in your CSS or templates: ```css .logo { background-image: url('/static/images/logo.png'); } ``` ```html Hero image ``` ## Theme Configuration ### Required Configuration In your `site.conf`: ```bash # Minimum theme configuration site_theme="theme-name" # Name of theme directory site_theme_css_file="css/main.css" # Path to main CSS file ``` ### Optional Configuration ```bash # Optional: Override default paths paths_layouts_dir="layouts" # Will be overridden if theme has layouts/ paths_static_dir="static" # Root static directory paths_output_dir="output" # Output directory ``` ### Theme-Specific Variables You can add custom variables to your `site.conf` and use them in templates: ```bash # Custom theme variables theme_color_primary="#3498db" theme_color_secondary="#2c3e50" theme_font_family="'Roboto', sans-serif" ``` Use in templates: ```html ``` ## Advanced Theme Features ### Responsive Design Create responsive themes using CSS media queries: ```css /* Mobile-first approach */ .container { max-width: 100%; padding: 1rem; } @media (min-width: 768px) { .container { max-width: 750px; margin: 0 auto; } } @media (min-width: 1024px) { .container { max-width: 970px; } } ``` ### Dark Mode Support ```css /* Default (light) theme */ :root { --bg-color: #ffffff; --text-color: #333333; --accent-color: #3498db; } /* Dark mode */ @media (prefers-color-scheme: dark) { :root { --bg-color: #1a1a1a; --text-color: #e0e0e0; --accent-color: #5dade2; } } body { background-color: var(--bg-color); color: var(--text-color); } ``` ### Typography and Web Fonts ```css /* Import Google Fonts */ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap'); body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-weight: 400; line-height: 1.6; } h1, h2, h3, h4, h5, h6 { font-weight: 600; line-height: 1.2; } ``` ### Custom RSS Template Create `layouts/rss.xml` for custom RSS styling: ```xml $site_name$ $site_tagline$ $site_url$ en-us $build_date$ $for(posts)$ $it.post_title$ $it.post_description$ $it.post_url$ $it.post_url$ $it.post_date_rfc$ $endfor$ ``` ## Theme Best Practices ### 1. Design Principles - **Mobile-First**: Design for mobile devices first, then enhance for larger screens - **Accessibility**: Use semantic HTML, proper contrast ratios, and keyboard navigation - **Performance**: Optimize images, minimize CSS/JS, use efficient selectors - **Consistency**: Maintain consistent spacing, typography, and color schemes ### 2. File Organization ``` themes/my-theme/ ├── static/ │ ├── css/ │ │ ├── main.css # Main theme styles │ │ ├── components.css # Component-specific styles │ │ └── utilities.css # Utility classes │ ├── js/ │ │ ├── theme.js # Main theme JavaScript │ │ └── components/ # Component-specific JS │ └── images/ │ ├── icons/ # Icon files │ └── backgrounds/ # Background images └── layouts/ ├── index.html # Homepage layout ├── post.html # Blog post layout ├── page.html # Static page layout └── rss.xml # RSS feed template ``` ### 3. CSS Architecture Use a modular approach: ```css /* main.css */ @import url('base.css'); /* Reset and base styles */ @import url('layout.css'); /* Layout components */ @import url('components.css'); /* UI components */ @import url('utilities.css'); /* Utility classes */ ``` ### 4. Performance Optimization - **Minimize HTTP Requests**: Combine CSS/JS files when possible - **Optimize Images**: Use appropriate formats (WebP, SVG) and sizes - **Use CSS Custom Properties**: For maintainable theming - **Lazy Load**: Implement lazy loading for images and non-critical resources ### 5. Browser Compatibility Test your theme across different browsers and devices: ```css /* Provide fallbacks for modern CSS features */ .card { background: #ffffff; /* Fallback */ background: var(--card-bg, #ffffff); /* Custom property */ } .grid { display: block; /* Fallback */ display: grid; /* Modern */ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); } ``` ## Troubleshooting ### Common Issues #### 1. CSS Not Loading **Problem**: Your theme's CSS isn't being applied. **Solutions**: - Check that `site_theme_css_file` path is correct relative to theme's `static/` directory - Verify the CSS file exists at `themes/{theme}/static/{css_path}` - Check qsgen3 logs for CSS-related warnings - Ensure the theme directory name matches `site_theme` setting #### 2. Layouts Not Being Used **Problem**: Your custom layouts aren't being applied. **Solutions**: - Verify layouts exist in `themes/{theme}/layouts/` - Check that layout filenames match expected names (`index.html`, `post.html`, `page.html`) - Review qsgen3 logs for layout-related messages #### 3. Static Files Not Copying **Problem**: Images, JS, or other static files aren't appearing in output. **Solutions**: - Check that files are in `themes/{theme}/static/` directory - Verify file permissions are readable - Look for rsync/cp errors in qsgen3 logs - Ensure no .gitignore rules are excluding files #### 4. Template Variables Not Working **Problem**: Variables like `$site_name$` aren't being substituted. **Solutions**: - Check that variables are defined in `site.conf` - Verify variable names match exactly (case-sensitive) - Ensure Pandoc template syntax is correct - Test with a minimal template to isolate issues ### Debugging Tips #### 1. Enable Debug Logging Run qsgen3 with verbose output to see detailed processing information: ```bash # Enable debug logging (if supported by your qsgen3 version) QSG_LOG_LEVEL=DEBUG ./bin/qsgen3 ``` #### 2. Test with Minimal Theme Create a minimal theme to isolate issues: ```html $title$

$title$

$body$ ``` #### 3. Validate Generated HTML Check that your generated HTML is valid: ```bash # Use HTML validator tools htmlhint output/*.html # or w3c-validator output/index.html ``` #### 4. Check File Permissions Ensure qsgen3 can read your theme files: ```bash find themes/my-theme -type f -not -perm -644 find themes/my-theme -type d -not -perm -755 ``` ### Getting Help If you encounter issues not covered here: 1. Check the qsgen3 documentation and examples 2. Review existing themes in the `themes/` directory 3. Examine the qsgen3 source code for theme processing logic 4. Create a minimal reproduction case 5. Report issues with detailed logs and configuration --- ## Example: Complete Theme Creation Here's a complete example of creating a modern, responsive theme called "modern-blog": ### 1. Create Directory Structure ```bash mkdir -p themes/modern-blog/{layouts,static/{css,js,images}} ``` ### 2. Create Main CSS (`themes/modern-blog/static/css/style.css`) ```css /* Modern Blog Theme */ :root { --primary-color: #2563eb; --secondary-color: #64748b; --background-color: #ffffff; --text-color: #1e293b; --border-color: #e2e8f0; --shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); } * { box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: var(--text-color); background-color: var(--background-color); margin: 0; padding: 0; } .container { max-width: 800px; margin: 0 auto; padding: 0 1rem; } header { background: var(--background-color); border-bottom: 1px solid var(--border-color); padding: 2rem 0; } header h1 { margin: 0; font-size: 2rem; font-weight: 700; } header h1 a { color: var(--text-color); text-decoration: none; } header p { margin: 0.5rem 0 0 0; color: var(--secondary-color); } main { padding: 3rem 0; } article { background: var(--background-color); border-radius: 8px; box-shadow: var(--shadow); padding: 2rem; margin-bottom: 2rem; } article header h1 { margin: 0 0 1rem 0; color: var(--primary-color); } .meta { color: var(--secondary-color); font-size: 0.9rem; margin-bottom: 1.5rem; } .meta .author, .meta .date { display: inline-block; margin-right: 1rem; } footer { background: var(--text-color); color: var(--background-color); text-align: center; padding: 2rem 0; margin-top: 3rem; } footer a { color: var(--primary-color); } /* Responsive design */ @media (max-width: 768px) { .container { padding: 0 0.5rem; } header { padding: 1rem 0; } main { padding: 1.5rem 0; } article { padding: 1.5rem; margin-bottom: 1rem; } } ``` ### 3. Create Post Layout (`themes/modern-blog/layouts/post.html`) ```html $site_name$ - $title$ $if(date)$$endif$ $for(css)$ $endfor$

$site_name$

$site_tagline$

$title$

$if(author)$By: $author$$endif$ $if(date)$Published: $date$$endif$
$body$
``` ### 4. Configure Site (`site.conf`) ```bash site_theme="modern-blog" site_theme_css_file="css/style.css" ``` ### 5. Generate Site ```bash ./bin/qsgen3 ``` Your modern, responsive blog theme is now ready! --- ## Summary This guide covers everything you need to know about creating themes for qsgen3. Key points to remember: 1. **Complete Override**: When a theme provides layouts, it completely replaces default layouts 2. **No Partial Fallback**: Themes must provide all necessary templates (`index.html`, `post.html`, `page.html`, `rss.xml`) 3. **Static File Merging**: Theme static files are copied after root static files, allowing themes to override default assets 4. **CSS Automation**: The main theme CSS file is automatically linked in generated HTML Understanding this processing flow is key to creating effective themes that work reliably across different configurations.