Compare commits

...

14 Commits

Author SHA1 Message Date
7521c744bd Improve qsgen3 theme system: complete theme override and new minimal theme
- Remove legacy themes (black-orange, minimal) with old .tpl structure
- Create new minimal theme with proper qsgen3 structure:
  - Complete layouts/ directory with all required templates
  - Modern CSS with responsive design and clean styling
  - Proper theme documentation in README.md
- Update THEMES-HOWTO.md to accurately reflect theme behavior:
  - Clarify complete layout override (no fallback to defaults)
  - Document included minimal theme example
  - Correct layout processing documentation
- Update site.conf to use new minimal theme CSS path
- Ensure themes are complete packages when specified
2025-05-31 03:14:36 +02:00
81ffa53d70 Add comprehensive theme documentation and improve migration script
- Add THEMES-HOWTO.md: Complete guide for creating and customizing themes
- Remove theme sections from how-it-works.md to avoid duplication
- Update migration script to place all blog posts in single directory
- Streamline documentation structure for better organization
2025-05-31 03:00:50 +02:00
f72fe18873 Implement file preservation system for output directory cleaning
- Add sophisticated file preservation functionality to _clean_output_dir()
- Support .qsgen3_preserve file with shell glob patterns for selective preservation
- Preserve shared articles and important files during site regeneration
- Maintain backward compatibility (no preserve file = complete cleaning)
- Add comprehensive documentation in how-it-works.md
- Include example preserve file (.qsgen3_preserve.example)
- Remove legacy images directory and update documentation
- Fix workflow documentation formatting issues
2025-05-31 02:04:06 +02:00
ed7ed0ee18 feat: Add comprehensive minification system for HTML, CSS, and XML files
- Implement _minify_html(), _minify_css(), and _minify_xml() functions
- Add _minify_file() and _minify_output_directory() orchestration functions
- Add build_options_minify_html, build_options_minify_css, build_options_minify_xml config options
- Integrate minification into main workflow after content generation
- Provide detailed logging with file size reduction statistics
- Achieve 25-35% HTML, 5-15% CSS, and 5-10% XML size reductions
- Update site.conf.example with documented minification options
- Non-destructive implementation using temporary files with error handling
2025-05-31 01:31:44 +02:00
5266559f26 docs: Rewrite README with compelling storytelling approach
Transform the README from a technical feature list into an engaging narrative that:

- Opens with a relatable problem story that developers/bloggers recognize
- Positions qsgen3 as the solution born from shared frustration
- Uses conversational storytelling tone throughout
- Organizes benefits as a narrative journey
- Clearly identifies target audiences with personas
- Provides actionable getting-started steps
- Ends with a compelling call to action

The new README focuses on why qsgen3 exists and what problems it solves, making it much more compelling for potential users while remaining informative and honest.
2025-05-31 01:22:37 +02:00
4b95426256 feat(qsgen3): Enhance output naming, URL structure, and sitemap
Implements several improvements to the qsgen3 site generator:

- **Filename Sanitization**: Introduces robust sanitization for output HTML filenames, converting to lowercase, replacing special characters with hyphens, and ensuring clean names.
- **Blog Post URL Structure**: Blog posts from content/posts/ are now generated with a blog/YYYY/MM/DD/ URL structure if a valid date is present in frontmatter. Defaults to blog/filename.html if no valid date.
- **Improved Title Fallback**: Uses the original filename (before sanitization) as a fallback title if not specified in frontmatter.
- **Enhanced Pandoc Error Handling**: Better logging for Pandoc execution and explicit check of its exit code, allowing the script to continue on single file errors.
- **Sitemap Integration**: Adds successfully generated pages to sitemap URL list.
- **Non-fatal Sitemap Generation**: Sitemap generation failures are now logged as warnings and do not halt the script.

Also, unignores the /scripts/ directory in .gitignore to include migration scripts in the repository.
2025-05-31 01:15:18 +02:00
1283eb30cb feat(migration): Add #showimg, #linkimg, #ytvideo conversion
Adds logic to migrate_qs2_to_qs3.py to convert:
- #showimg to Markdown image syntax ![alt](src).
- #linkimg to Markdown linked image syntax [![alt](src)](src).
- #ytvideo to HTML iframe embed for YouTube videos.

Image path processing handles absolute URLs and prepends /images/
for relative paths, aligning with previous qsgen2 behavior but
omitting hardcoded styling attributes for Markdown output.
2025-05-31 01:13:55 +02:00
f5d6d0eb49 docs: Enhance explanations in site.conf.example
Updated site.conf.example to provide clearer and more detailed descriptions for each configuration variable, improving usability for new users.
2025-05-31 00:14:51 +02:00
1b8898ae2e chore: Remove extraneous 'home' directory from project root 2025-05-31 00:07:30 +02:00
681857225b chore: Remove old qsgen2 files and directories
Deleted legacy files and directories from the previous qsgen2 system, including:
- Root qsgen3 script (qsgen2)
- HOWTO.md, THEME-HOWTO.md, qsg2-square.png
- include/ directory
- Suspicious quoted 'output' directory
2025-05-31 00:06:37 +02:00
47a4c04d96 refactor: Standardize theme structure and update configs
- Restructured 'minimal' theme to use 'static/css' and 'static/js' subdirectories for assets, aligning with qsgen3's expected theme structure.
- Moved 'minimaltemplate-v1.css' to 'themes/minimal/static/css/'.
- Moved JS files from 'themes/minimal/css/' to 'themes/minimal/static/js/'.
- Updated 'site.conf.example' to reflect 'minimal' theme usage and correct 'site_theme_css_file' path relative to the theme's static directory.
- Cleaned up redundant CSS variable definitions in 'bin/qsgen3' (_generate_index_page function).
2025-05-31 00:05:05 +02:00
8ffd19a0c4 refactor: Remove redundant root CSS files
Removed layouts/css/default.css and static/css/style.css as themes now provide their own CSS, making these files obsolete.
2025-05-31 00:03:08 +02:00
3dad33a939 build: Add output/ to .gitignore and untrack existing output dir 2025-05-31 00:01:19 +02:00
c470ac40c0 feat: Implement robust theme system and document architecture
- Implement flexible theme switching via site.conf (site_theme, site_theme_css_file).
- Ensure correct copying of theme static assets, with theme assets overriding root assets.
- Resolve CSS linking issues by checking file existence after static copy and using correct paths for Pandoc.
- Refactor path construction to prevent duplication when using absolute/relative output paths.
- Create comprehensive how-it-works.md detailing system architecture, theme creation, and overall workflow.
- Clarify design philosophy: qsgen3 remains design-agnostic, only linking main theme CSS automatically.
2025-05-31 00:00:21 +02:00
53 changed files with 4102 additions and 5705 deletions

4
.gitignore vendored
View File

@ -18,8 +18,10 @@ include/qsgen2/lang/*.new
include/qsgen2/lang/*.txt
include/qsgen2/lang/*.en
# Generated site output
output/
# Scripts directory (temporary/conversion scripts)
/scripts/
/tools/
# Build output

40
.qsgen3_preserve.example Normal file
View File

@ -0,0 +1,40 @@
# qsgen3 Preserve File
#
# This file specifies patterns for files that should be preserved during
# output directory cleaning. This is useful for keeping shared articles
# or other content that should remain accessible even after title changes.
#
# Format:
# - One pattern per line
# - Supports shell glob patterns (*, ?, [])
# - Lines starting with # are comments
# - Empty lines are ignored
# - Patterns are relative to the output directory
#
# Examples:
# Preserve specific files by exact name
# posts/my-important-shared-article.html
# about.html
# Preserve files by pattern
# posts/legacy-*.html
# *.pdf
# Preserve entire directories
# archive/*
# downloads/*
# Preserve files with specific extensions in certain directories
# posts/*.html
# docs/*.pdf
# Example: Preserve a specific shared article
# posts/how-to-setup-qsgen3.html
# Example: Preserve all files in a legacy directory
# legacy/*
# Example: Preserve important documents
# important-*.html
# *.pdf

220
HOWTO.md
View File

@ -1,220 +0,0 @@
# Quick Site Generator 2 (qsgen2) - User Guide
## Table of Contents
1. [Introduction](#introduction)
2. [Installation](#installation)
3. [Quick Start](#quick-start)
4. [Project Structure](#project-structure)
5. [Content Creation](#content-creation)
- [Pages](#pages)
- [Blog Posts](#blog-posts)
6. [Markup Languages](#markup-languages)
- [QSTags](#qstags)
- [Markdown](#markdown)
- [Conversion Between Formats](#conversion-between-formats)
7. [Themes and Templates](#themes-and-templates)
8. [Configuration](#configuration)
9. [Command Reference](#command-reference)
10. [Advanced Usage](#advanced-usage)
11. [Troubleshooting](#troubleshooting)
12. [Contributing](#contributing)
## Introduction
Quick Site Generator 2 (qsgen2) is a powerful static site generator written in Zsh. It's designed to be fast, flexible, and easy to use, with support for both custom QSTags and standard Markdown syntax.
## Installation
1. Clone the repository:
```bash
git clone https://github.com/kekePower/qsgen2.git
cd qsgen2
```
2. Make the script executable:
```bash
chmod +x qsgen2
```
3. Add to your PATH (optional):
```bash
echo 'export PATH="$PATH:'$(pwd)'"' >> ~/.zshrc
source ~/.zshrc
```
## Quick Start
1. Create a new site:
```bash
./qsgen2 new my-site
cd my-site
```
2. Build the site:
```bash
./qsgen2 build
```
3. Preview the site:
```bash
./qsgen2 serve
```
## Project Structure
```
my-site/
├── config # Site configuration
├── content/ # Source content
│ ├── pages/ # Static pages
│ └── blog/ # Blog posts
├── themes/ # Site themes
├── static/ # Static files (images, CSS, JS)
└── output/ # Generated site (created on build)
```
## Content Creation
### Pages
Create a new page:
```bash
./qsgen2 new page about
```
Pages use the `.qst` extension and can include QSTags or Markdown.
### Blog Posts
Create a new blog post:
```bash
./qsgen2 new post my-first-post
```
Blog posts use the `.blog` extension and support the same markup as pages.
## Markup Languages
### QSTags
QSTags is a simple markup language used by qsgen2. Example:
```
#H1 Welcome to My Site#EH1
#P This is a paragraph with #BDbold#EBD and #Iitalic#EI text.#EP
```
### Markdown
Markdown is also supported:
```markdown
# Welcome to My Site
This is a paragraph with **bold** and *italic* text.
```
### Conversion Between Formats
Convert a single file to Markdown:
```bash
./qsgen2 convert --to-markdown content/pages/about.qst content/pages/about.md
```
Convert all files to Markdown:
```bash
./qsgen2 convert --to-markdown --all
```
Convert back to QSTags:
```bash
./qsgen2 convert --to-qstags --all
```
## Themes and Templates
Themes are stored in the `themes` directory. Each theme can include:
- Page templates
- Blog post templates
- CSS/JavaScript
- Assets
## Configuration
Edit `config/site.conf` to customize your site:
```ini
site_name = "My Awesome Site"
site_url = "https://example.com"
site_author = "Your Name"
theme = "default"
```
## Command Reference
### Build Commands
- `build`: Build the site
- `clean`: Remove generated files
- `serve`: Start a local server
### Content Management
- `new page <name>`: Create a new page
- `new post <title>`: Create a new blog post
- `convert`: Convert between markup formats
### Utility Commands
- `version`: Show version information
- `help`: Show help message
## Advanced Usage
### Custom Build Scripts
Create a `build.zsh` file in your project root:
```bash
#!/usr/bin/env zsh
# Custom build script
# Clean previous build
./qsgen2 clean
# Convert all content to Markdown for editing
./qsgen2 convert --to-markdown --all
# Build the site
./qsgen2 build
# Optimize images
find output -name "*.jpg" -exec jpegoptim --strip-all {} \;
```
## Troubleshooting
### Common Issues
1. **Permission Denied**
```bash
chmod +x qsgen2
```
2. **Command Not Found**
Add qsgen2 to your PATH or use `./qsgen2`
3. **Build Errors**
Check for syntax errors in your content files
## Contributing
1. Fork the repository
2. Create a feature branch
3. Commit your changes
4. Push to the branch
5. Create a Pull Request
## License
MIT License - See LICENSE for details.
---
*Quick Site Generator 2 - A fast, flexible static site generator*

178
README.md
View File

@ -1,70 +1,132 @@
<img src="qsg2-square.png" width="150" align="left">
# qsgen3 - A Static Site Generator Born from Frustration
# Quick Site Generator 2
## The Problem We All Know Too Well
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
You've been there. You want to start a blog, build a portfolio, or create documentation. You research static site generators and find yourself drowning in choices, each promising to be "the one." You pick one, spend hours configuring it, wrestling with themes that almost work, and fighting build systems that break when you breathe on them wrong.
Quick Site Generator 2 is a powerful static website generator written in Zsh, inspired by [Nikola](https://github.com/getnikola/nikola). It's designed to be fast, flexible, and easy to use, with support for both custom QSTags and standard Markdown syntax.
Three months later, you're spending more time maintaining your site generator than writing content.
## Features
**There had to be a better way.**
- 🚀 Blazing fast static site generation
- 📝 Supports both QSTags and Markdown content
- 🌍 Multi-language support (en_US, en_UK, es_ES, fr_FR, nb_NO)
- 🎨 Themeable with custom templates (see [THEME-HOWTO.md](THEME-HOWTO.md))
- 📱 Responsive design ready
- 🔍 SEO friendly
- 🔄 Automatic rebuild on file changes
## The Story Behind qsgen3
## Quick Start
qsgen3 was born from a simple realization: most static site generators have forgotten their primary job—turning your words into websites. Instead, they've become complex platforms that impose their opinions on everything from your CSS framework to your folder structure.
We asked ourselves: *What if a static site generator just... generated static sites?*
What if it didn't care whether you prefer Bootstrap or write your own CSS? What if it didn't force you to learn a new templating language or adopt someone else's idea of how a blog should work? What if it was fast, reliable, and got out of your way?
That's qsgen3.
## How qsgen3 is Different
### It Respects Your Choices
Unlike generators that come with strong opinions about design, qsgen3 is **completely design-agnostic**. It doesn't ship with CSS frameworks, doesn't impose HTML structures, and doesn't make assumptions about how your site should look. Your content, your design, your rules.
### It Values Your Time
Built in Zsh with minimal dependencies, qsgen3 builds sites in seconds, not minutes. No waiting for Ruby gems to compile, no Node.js dependency hell, no Python virtual environments to manage. Just Pandoc, standard Unix tools, and your content.
### It Speaks Standard Languages
Your content is written in **pure Markdown with YAML frontmatter**—the same format used by GitHub, GitLab, and most modern documentation systems. No proprietary tags to learn, no custom syntax to remember. Your content works everywhere, not just with qsgen3.
### It Grows With You
Start with the included minimal theme, then customize it however you want. Themes are just HTML templates and CSS files—no complex build systems or framework lock-in. When you outgrow a theme, you can switch or build your own without rewriting a single blog post.
## What You Actually Get
When you use qsgen3, you get a tool that handles the boring stuff so you can focus on what matters—your content.
**For Your Writing:**
- Clean Markdown processing with full Pandoc power
- Automatic RSS feeds that just work
- SEO-friendly sitemaps
- Smart permalinks for blog posts (`/blog/2024/01/15/my-post/`)
- Draft support for work-in-progress content
**For Your Workflow:**
- Git-friendly (no generated files cluttering your repo)
- One command builds everything: `./bin/qsgen3`
- Migration tools for converting legacy content
- Static asset handling that preserves your file organization
**For Your Peace of Mind:**
- Minimal dependencies that won't break
- Standard formats that will outlive any framework
- Complete control over your site's appearance and behavior
- No vendor lock-in—your content is always portable
## Who This is For
**You're a blogger** who wants to write, not wrestle with technology. You need something that handles the technical details while giving you complete creative control.
**You're a developer** who appreciates tools that do one thing well. You want the power of Pandoc without the complexity of enterprise-grade site generators.
**You're migrating** from WordPress, Jekyll, Hugo, or a custom solution. You're tired of fighting your tools and want something that just works.
**You value simplicity** over features. You'd rather have a tool that does the essentials perfectly than one that does everything poorly.
## Getting Started is Actually Simple
Unlike other generators that require extensive setup, qsgen3 works out of the box:
1. **Installation**
```bash
git clone https://github.com/kekePower/qsgen2.git
cd qsgen2
chmod +x qsgen2
```
# Get qsgen3
git clone https://git.kekepower.com/kekePower/qsgen3.git
cd qsgen3
2. **Create a new site**
```bash
./qsgen2 new my-site
cd my-site
```
3. **Build and serve**
```bash
./qsgen2 build
./qsgen2 serve
```
For detailed documentation, see the [HOWTO.md](HOWTO.md) guide.
## Recent Changes
- Added Norwegian (nb_NO) language support
- Improved internationalization (i18n) system
- Cleaned up temporary and backup files
- Updated documentation
- Added comprehensive HOWTO guide
## Requirements
- Zsh 5.8 or later
- Pandoc (for Markdown support)
- Basic Unix tools (sed, grep, etc.)
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Contributing
Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) before submitting pull requests.
## Support
For support, please [open an issue](https://github.com/kekePower/qsgen2/issues) on GitHub.
# Configure your site
cp site.conf.example site.conf
# Edit site.conf with your details
# Write your first post
echo "---
title: Hello World
date: 2024-01-15
---
# My First Post
Welcome to my new site!" > content/posts/hello-world.md
*Created with ❤️ by kekePower*
# Build your site
./bin/qsgen3
# Deploy anywhere
rsync -av output/ user@yourserver:/var/www/yoursite/
```
That's it. No package managers, no build tools, no configuration files to debug.
## The Technical Details (For Those Who Care)
**Structure:**
```
qsgen3/
├── bin/qsgen3 # The build script (one file, ~500 lines)
├── site.conf # Your site configuration
├── content/ # Your Markdown content
├── layouts/ # HTML templates (yours to customize)
├── themes/ # Optional themes (just templates + CSS)
├── static/ # Your assets (copied as-is)
├── output/ # Generated site
└── scripts/ # Migration utilities
```
**Dependencies:**
- Zsh (already on your system)
- Pandoc (for Markdown processing)
- Standard Unix tools (grep, sed, find)
No Ruby. No Node.js. No Python virtual environments. No dependency management nightmares.
## The Philosophy
We believe your static site generator should be like a good editor—powerful when you need it, invisible when you don't. It should turn your words into websites without imposing its personality on your content.
qsgen3 doesn't try to be everything to everyone. It's a focused tool for people who want to publish content on the web without fighting their tools.
**Your content deserves better than being locked into someone else's vision of how the web should work.**
## Ready to Take Back Control?
If you're tired of complex site generators that do everything except what you actually need, qsgen3 might be exactly what you're looking for.
**[Get started with qsgen3](https://git.kekepower.com/kekePower/qsgen3)** and see what it feels like to have a site generator that actually gets out of your way.

View File

@ -1,194 +0,0 @@
# Creating Themes for Quick Site Generator 2
This guide explains how to create and customize themes for Quick Site Generator 2 (qsgen2). The theming system is designed to be simple yet flexible, allowing you to create beautiful, responsive websites with minimal effort.
## Table of Contents
1. [Theme Structure](#theme-structure)
2. [Template Files](#template-files)
- [pages.tpl](#pagestpl)
- [blogs.tpl](#blogstpl)
- [blog_index.tpl](#blog_indextpl)
- [blog_list.tpl](#blog_listtpl)
3. [Template Variables](#template-variables)
4. [Creating a New Theme](#creating-a-new-theme)
5. [Best Practices](#best-practices)
6. [Example Theme](#example-theme)
## Theme Structure
A qsgen2 theme consists of the following files:
```
theme-name/
├── pages.tpl # Template for regular pages
├── blogs.tpl # Template for blog posts
├── blog_index.tpl # Template for blog index page
├── blog_list.tpl # Template for blog post listings
└── css/ # Stylesheets and assets
├── style.css # Main stylesheet
└── webfont.js # Web font loader (optional)
```
## Template Files
### pages.tpl
This template is used for regular static pages. It should include the basic HTML structure, head section, and placeholders for dynamic content.
Key placeholders:
- `#sitename` - Site name from configuration
- `#pagetitle` - Title of the current page
- `#tagline` - Site tagline from configuration
- `BODY` - Main content area
### blogs.tpl
This template is used for individual blog posts. It includes placeholders for blog-specific content.
Key placeholders:
- `BLOGTITLE` - Title of the blog post
- `CALADAY` - Day of the month (numeric)
- `CALNDAY` - Day of the week (name)
- `CALMONTH` - Month name
- `CALYEAR` - Year
- `INGRESS` - Blog post excerpt/intro
- `BODY` - Main blog post content
### blog_index.tpl
This template is used for the blog index/archive page that lists all blog posts.
Key placeholders:
- `#sitename` - Site name from configuration
- `#tagline` - Site tagline from configuration
- `BODY` - Contains the list of blog posts (generated from blog_list.tpl)
### blog_list.tpl
This template defines how individual blog posts are displayed in the blog index.
Key placeholders:
- `BLOGURL` - URL of the blog post
- `BLOGTITLE` - Title of the blog post
- `INGRESS` - Blog post excerpt/intro
- `BLOGDATE` - Formatted date of the blog post
## Template Variables
These variables can be used in any template:
- `#sitename` - Site name from configuration
- `#tagline` - Site tagline from configuration
- `#pagetitle` - Current page title
- `#siteurl` - Base URL of the site
- `#currentyear` - Current year (for copyright notices)
## Creating a New Theme
1. **Create a new directory** in the `themes` folder with your theme name.
2. **Copy the template files** from the `minimal` theme as a starting point:
```bash
cp -r themes/minimal/* themes/your-theme-name/
```
3. **Customize the templates**:
- Edit the HTML structure in the `.tpl` files
- Update the CSS in the `css` directory
- Replace placeholder images with your own
4. **Test your theme** by setting it in your `site.conf`:
```ini
theme = "your-theme-name"
```
5. **Build your site** to see the changes:
```bash
./qsgen2 build
```
## Best Practices
1. **Responsive Design**
- Use responsive CSS frameworks or media queries
- Test on different screen sizes
2. **Performance**
- Minify CSS and JavaScript
- Optimize images
- Use web fonts sparingly
3. **Accessibility**
- Use semantic HTML5 elements
- Include alt text for images
- Ensure sufficient color contrast
4. **Browser Compatibility**
- Test in multiple browsers
- Use vendor prefixes for CSS properties
## Example Theme
Here's a minimal example of a theme structure:
```
my-theme/
├── pages.tpl
├── blogs.tpl
├── blog_index.tpl
├── blog_list.tpl
└── css/
└── style.css
```
### pages.tpl (example)
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>#sitename - #pagetitle</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/css/style.css" rel="stylesheet">
</head>
<body>
<header>
<h1>#sitename</h1>
<p>#tagline</p>
<nav>
<a href="/">Home</a>
<a href="/blog/">Blog</a>
</nav>
</header>
<main>
BODY
</main>
<footer>
<p>&copy; #currentyear #sitename. All rights reserved.</p>
</footer>
</body>
</html>
```
### blog_list.tpl (example)
```html
<article class="blog-post">
<h2><a href="BLOGURL">BLOGTITLE</a></h2>
<div class="post-meta">
<time datetime="BLOGDATE">BLOGDATE</time>
</div>
<div class="post-excerpt">
INGRESS
<a href="BLOGURL" class="read-more">Read more →</a>
</div>
</article>
```
## Conclusion
Creating themes for qsgen2 is straightforward once you understand the template system. Start with the minimal theme as a base, and customize it to match your design. Remember to test your theme thoroughly and follow web development best practices for the best results.
For more advanced theming options, refer to the official documentation or check out the source code of existing themes.

865
THEMES-HOWTO.md Normal file
View File

@ -0,0 +1,865 @@
# 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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$site_name$ - $title$</title>
<meta name="author" content="$author$">
<meta name="description" content="$description$">
$if(date)$<meta name="date" content="$date$">$endif$
$for(css)$
<link rel="stylesheet" href="$css$">
$endfor$
</head>
<body>
<header>
<h1><a href="/">$site_name$</a></h1>
<p>$site_tagline$</p>
</header>
<main>
<article>
<header>
<h1>$title$</h1>
$if(author)$<p class="author">By: $author$</p>$endif$
$if(date)$<p class="date">Published: $date$</p>$endif$
</header>
$body$
</article>
</main>
<footer>
<p>&copy; $current_year$ $site_name$. Generated by qsgen3.</p>
</footer>
</body>
</html>
```
#### Index Page Layout (`layouts/index.html`)
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$site_name$ - $site_tagline$</title>
<meta name="description" content="$site_tagline$">
$for(css)$
<link rel="stylesheet" href="$css$">
$endfor$
</head>
<body>
<header>
<h1>$site_name$</h1>
<p>$site_tagline$</p>
</header>
<main>
$body$
</main>
<footer>
<p>&copy; $current_year$ $site_name$. Generated by qsgen3.</p>
</footer>
</body>
</html>
```
## 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
<script src="/static/js/theme.js"></script>
```
#### 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
<img src="/static/images/hero.jpg" alt="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
<style>
:root {
--primary-color: $theme_color_primary$;
--secondary-color: $theme_color_secondary$;
--font-family: $theme_font_family$;
}
</style>
```
## 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
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>$site_name$</title>
<description>$site_tagline$</description>
<link>$site_url$</link>
<atom:link href="$site_url$/rss.xml" rel="self" type="application/rss+xml"/>
<language>en-us</language>
<lastBuildDate>$build_date$</lastBuildDate>
$for(posts)$
<item>
<title>$it.post_title$</title>
<description>$it.post_description$</description>
<link>$it.post_url$</link>
<guid>$it.post_url$</guid>
<pubDate>$it.post_date_rfc$</pubDate>
</item>
$endfor$
</channel>
</rss>
```
## 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
<!-- minimal-test.html -->
<!DOCTYPE html>
<html>
<head>
<title>$title$</title>
<style>body { font-family: Arial; margin: 2rem; }</style>
</head>
<body>
<h1>$title$</h1>
$body$
</body>
</html>
```
#### 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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$site_name$ - $title$</title>
<meta name="author" content="$author$">
<meta name="description" content="$description$">
$if(date)$<meta name="date" content="$date$">$endif$
$for(css)$
<link rel="stylesheet" href="$css$">
$endfor$
</head>
<body>
<header>
<div class="container">
<h1><a href="/">$site_name$</a></h1>
<p>$site_tagline$</p>
</div>
</header>
<main>
<div class="container">
<article>
<header>
<h1>$title$</h1>
<div class="meta">
$if(author)$<span class="author">By: $author$</span>$endif$
$if(date)$<span class="date">Published: $date$</span>$endif$
</div>
</header>
$body$
</article>
</div>
</main>
<footer>
<div class="container">
<p>&copy; $current_year$ $site_name$. Generated by qsgen3.</p>
<p><a href="$site_url$">$site_url$</a></p>
</div>
</footer>
</body>
</html>
```
### 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.

1542
bin/qsgen3 Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,30 @@
---
title: "Hello, World!"
date: "2024-05-30"
author: "qsgen3"
draft: false
summary: "My first post using the qsgen3 static site generator."
---
Welcome to qsgen3!
This is your first post. You can edit it or delete it and start writing your own content.
## Markdown Features
Qsgen3 supports standard Markdown features, including:
- Headings
- **Bold** and *italic* text
- Lists:
- Unordered
- Ordered
- [Links](https://example.com)
- `Inline code`
```bash
# Code blocks
echo "Hello from a code block!"
```
Enjoy creating your site!

528
how-it-works.md Normal file
View File

@ -0,0 +1,528 @@
# How qsgen3 Works
## Table of Contents
1. [Philosophy and Design Principles](#philosophy-and-design-principles)
2. [Project Structure](#project-structure)
3. [Configuration System](#configuration-system)
4. [Content Processing Pipeline](#content-processing-pipeline)
5. [Static File Handling](#static-file-handling)
6. [Template System](#template-system)
7. [Output Generation](#output-generation)
8. [Command Line Interface](#command-line-interface)
9. [Dependencies and Requirements](#dependencies-and-requirements)
10. [Detailed Workflow](#detailed-workflow)
11. [Troubleshooting and Debugging](#troubleshooting-and-debugging)
## Philosophy and Design Principles
### Core Philosophy
qsgen3 is designed to be **100% design-agnostic**. It does not impose any specific CSS frameworks, JavaScript libraries, or HTML structures on users. The generator's role is strictly to:
1. Process Markdown content into HTML
2. Combine content with user-chosen templates and styling
3. Generate a complete static site structure
### Key Principles
- **Minimal Dependencies**: Only requires Pandoc for content processing
- **In-Memory Operations**: All content manipulation occurs in memory to improve performance and reduce storage wear
- **Flexible Theme System**: Supports easy switching between themes via configuration
- **Template Agnostic**: Works with any Pandoc-compatible HTML templates
- **No Forced Assets**: Only automatically links the main theme CSS; all other asset inclusion is explicit
## Project Structure
A typical qsgen3 project follows this structure:
```
project-root/
├── bin/
│ └── qsgen3 # Main generator script
├── site.conf # Main configuration file
├── .qsgen3_preserve # Optional: File preservation patterns
├── content/ # Markdown content
│ ├── posts/ # Blog posts
│ │ └── hello-world.md
│ └── pages/ # Static pages
├── layouts/ # Pandoc HTML templates
│ ├── index.html # Homepage template
│ ├── post.html # Blog post template
│ └── rss.xml # RSS feed template
├── static/ # Static assets (CSS, images, etc.)
│ ├── css/
│ └── images/
├── output/ # Generated site (created by qsgen3)
├── index.html
├── rss.xml
├── posts/
└── static/
```
## Configuration System
### Primary Configuration: `site.conf`
The `site.conf` file uses a simple key-value format:
```bash
# Site Metadata
site_name="My Awesome Site"
site_tagline="A brief description of my site"
site_url="http://localhost:8000"
# Directory Paths
paths_content_dir="content"
paths_output_dir="output"
paths_layouts_dir="layouts"
paths_static_dir="static"
# Build Options
build_options_generate_rss=true
build_options_generate_sitemap=true
build_options_process_drafts=false
```
### Configuration Loading Process
1. **File Location**: Defaults to `$PROJECT_ROOT/site.conf`
2. **Override**: Can be specified with `-c <file>` or `--config <file>`
3. **Parsing**: Simple line-by-line parsing of `key="value"` pairs
4. **Storage**: Values stored in `QSG_CONFIG` associative array
5. **Validation**: Basic validation for required keys and file existence
### Key Configuration Variables
- **`site_name`**: Name of the site
- **`site_url`**: Base URL for the site (used in RSS and absolute links)
- **`paths_*`**: Directory paths (can be relative or absolute)
- **`build_options_*`**: Boolean flags for optional features
## Content Processing Pipeline
### Markdown Processing
1. **Discovery**: Recursively scans `paths_content_dir` for `.md` files
2. **Metadata Extraction**: Parses YAML front matter for post metadata
3. **Content Conversion**: Uses Pandoc to convert Markdown to HTML
4. **Template Application**: Applies appropriate template based on content type
5. **Output Generation**: Writes processed HTML to corresponding location in `output/`
### Content Types
- **Posts**: Files in `content/posts/``output/posts/`
- **Pages**: Files in `content/pages/``output/`
- **Index**: Generated from post metadata → `output/index.html`
- **RSS**: Generated from post metadata → `output/rss.xml`
### Metadata Handling
Each Markdown file can include YAML front matter:
```yaml
---
title: "Post Title"
date: "2023-01-01"
author: "Author Name"
description: "Post description"
draft: false
---
# Post Content
Your markdown content here...
```
## Static File Handling
### Copy Strategy
Static files are copied in a specific order to handle theme overrides:
1. **Root Static Files**: Copy from `paths_static_dir` to `output/static/`
2. **Theme Static Files**: Copy from theme's static source to `output/static/`
3. **Override Behavior**: Theme files overwrite root files with same names
### Copy Implementation
- **Primary Tool**: `rsync` with `-av --delete` flags
- **Fallback**: `cp -R` if rsync is unavailable
- **Preservation**: Maintains directory structure and file permissions
### CSS File Linking
1. **Availability**: Theme CSS files are copied to `output/static/`
2. **Verification**: Script checks for CSS file existence after copying
3. **Pandoc Integration**: CSS path passed to Pandoc via `--css` flag
4. **Path Format**: Uses site-root-relative paths (e.g., `/static/css/style.css`)
## Template System
### Template Types
qsgen3 uses Pandoc templates with specific purposes:
- **`index.html`**: Homepage template (receives post list metadata)
- **`post.html`**: Individual post template (receives post content and metadata)
- **`rss.xml`**: RSS feed template (receives post list for syndication)
### Template Variables
Templates receive data through Pandoc's variable system:
#### Post Templates
- `$title$`: Post title from front matter
- `$date$`: Post date
- `$author$`: Post author
- `$body$`: Converted HTML content
- Custom variables from YAML front matter
#### Index Template
- `$site_name$`: From site.conf
- `$site_tagline$`: From site.conf
- `$posts$`: Array of post metadata for listing
#### RSS Template
- `$site_url$`: Base URL for absolute links
- `$posts$`: Array of post data with URLs and content
### Template Resolution
1. **Theme Override**: If theme provides templates, use theme's `layouts/`
2. **Default**: Use project's `layouts/` directory
3. **Fallback**: Error if required template not found
## Output Generation
### Directory Structure
Generated output maintains a clean, predictable structure:
```
output/
├── index.html # Homepage
├── rss.xml # RSS feed
├── posts/ # Individual post pages
│ └── post-name.html
├── static/ # All static assets
│ ├── css/ # Stylesheets
│ ├── js/ # JavaScript (if provided by theme)
│ └── images/ # Images and media
└── css/ # Legacy: Index-specific CSS location
└── theme.css # Copy of main theme CSS for index page
```
### File Naming
- **Posts**: `content/posts/hello-world.md``output/posts/hello-world.html`
- **Pages**: `content/pages/about.md``output/about.html`
- **Index**: Generated → `output/index.html`
- **RSS**: Generated → `output/rss.xml`
### URL Structure
- **Posts**: `/posts/post-name.html`
- **Pages**: `/page-name.html`
- **Static Assets**: `/static/path/to/asset`
- **CSS**: `/static/css/style.css` (for posts), `/css/theme.css` (for index)
## Command Line Interface
### Basic Usage
```bash
./bin/qsgen3 [options]
```
### Available Options
- **`-h, --help`**: Display usage information and exit
- **`-V, --version`**: Show script name and version, then exit
- **`-c <file>, --config <file>`**: Specify custom configuration file path
### Path Resolution
- **`PROJECT_ROOT`**: Defaults to current working directory (`$PWD`)
- **`CONFIG_FILE`**: Defaults to `$PROJECT_ROOT/site.conf`
- **Relative Paths**: Configuration file path can be relative to project root
### Exit Codes
- **0**: Successful generation
- **1**: Error (missing dependencies, configuration issues, processing failures)
## Dependencies and Requirements
### Required Dependencies
- **Pandoc**: Core dependency for Markdown processing and HTML generation
- **Zsh**: Shell interpreter (script written in Zsh)
### Optional Dependencies
- **rsync**: Preferred tool for efficient file copying (falls back to `cp`)
### System Requirements
- **Operating System**: Linux/Unix-like systems
- **File System**: Support for standard Unix file permissions
- **Memory**: Minimal requirements (all processing in memory)
### Environment Setup
The script configures a consistent environment:
```bash
LC_ALL=C
LANG=C
umask 0022
```
## Detailed Workflow
### 1. Initialization Phase
```
Start qsgen3
├── Parse command line arguments
├── Set PROJECT_ROOT (default: $PWD)
├── Determine CONFIG_FILE path
├── Set environment variables (LC_ALL, LANG, umask)
└── Initialize QSG_CONFIG array
```
### 2. Configuration Loading
```
Load Configuration
├── Check if CONFIG_FILE exists
├── Parse key="value" pairs line by line
├── Strip quotes from values
├── Store in QSG_CONFIG associative array
└── Validate required configuration keys
```
### 3. Dependency Checking
```
Check Dependencies
├── Verify Pandoc is available
├── Check Pandoc version compatibility
├── Verify other required tools
└── Exit with error if dependencies missing
```
### 4. Output Preparation
```
Prepare Output Directory
├── Check for .qsgen3_preserve file in project root
├── If preserve file exists:
│ ├── Read file patterns (shell glob patterns)
│ ├── Create temporary backup directory
│ ├── Find and backup matching files from output directory
│ ├── Remove entire output directory
│ ├── Recreate clean output directory
│ ├── Restore preserved files maintaining directory structure
│ └── Clean up temporary backup directory
├── If no preserve file:
│ ├── Remove entire output directory
│ └── Create fresh output directory
└── Log preservation and cleaning operations
```
#### File Preservation System
qsgen3 supports preserving specific files during the cleaning process to handle cases where content has been shared or bookmarked and should remain accessible even after title changes.
**Preserve File Format (`.qsgen3_preserve`):**
- Located in project root directory
- One pattern per line using shell glob patterns (`*`, `?`, `[]`)
- Lines starting with `#` are comments
- Empty lines are ignored
- Patterns are relative to the output directory
**Example preserve patterns:**
```bash
# Preserve specific shared articles
posts/my-important-shared-article.html
posts/viral-blog-post.html
# Preserve files by pattern
posts/legacy-*.html
archive/*
# Preserve all PDFs and downloads
*.pdf
downloads/*
```
**Benefits:**
- Maintains stable URLs for shared content
- Prevents broken links when content is renamed
- Flexible pattern matching for various preservation needs
- Backward compatible (no preserve file = complete cleaning)
### 5. Static File Processing
```
Copy Static Files
├── Copy from paths_static_dir to output/static/
│ ├── Use rsync -av --delete if available
│ └── Fallback to cp -R
├── Copy from theme static source to output/static/
│ ├── Theme files overwrite root files
│ └── Preserve directory structure
└── Log copy operations and results
```
### 6. CSS Path Determination
```
Determine CSS Linking
├── Read site_theme_css_file from configuration
├── Construct expected CSS file path in output/static/
├── Verify CSS file exists after copying
├── Set QSG_CONFIG[pandoc_css_path_arg] for Pandoc
└── Log CSS path decisions and warnings
```
### 7. Content Processing
```
Process Markdown Content
├── Scan paths_content_dir recursively for .md files
├── For each Markdown file:
│ ├── Extract YAML front matter
│ ├── Determine output path and template
│ ├── Run Pandoc with appropriate template and CSS
│ ├── Write generated HTML to output directory
│ └── Log processing results
└── Collect metadata for index and RSS generation
```
### 8. Index Generation
```
Generate Index Page
├── Collect all post metadata
├── Create YAML metadata file for Pandoc
├── Run Pandoc with index template
├── Apply CSS styling
├── Write output/index.html
└── Clean up temporary files
```
### 9. RSS Generation
```
Generate RSS Feed
├── Collect post metadata with URLs
├── Create YAML metadata for RSS template
├── Run Pandoc with RSS template
├── Generate absolute URLs using site_url
├── Write output/rss.xml
└── Clean up temporary files
```
### 10. Finalization
```
Complete Generation
├── Log final directory structure
├── Report generation success
├── Clean up any remaining temporary files
└── Exit with status code 0
```
## Troubleshooting and Debugging
### Common Issues
#### 1. CSS Not Applied
**Symptoms**: Generated HTML doesn't show theme styling
**Causes**:
- Incorrect `site_theme_css_file` path in site.conf
- CSS file doesn't exist in theme's static assets
- Theme static directory structure mismatch
**Solutions**:
- Verify CSS file path relative to theme's static source
- Check theme directory structure
- Enable debug logging to trace CSS path resolution
#### 2. Template Errors
**Symptoms**: Pandoc errors during HTML generation
**Causes**:
- Missing required templates
- Template syntax errors
- Incompatible template variables
**Solutions**:
- Verify all required templates exist
- Check Pandoc template syntax
- Review template variable usage
#### 3. Static File Copy Issues
**Symptoms**: Assets missing from output directory
**Causes**:
- Permission issues
- Disk space problems
- Path resolution errors
**Solutions**:
- Check file permissions
- Verify available disk space
- Review path configurations for absolute vs. relative paths
#### 4. File Preservation Issues
**Symptoms**: Expected files not preserved during cleaning, or preservation not working
**Causes**:
- Incorrect patterns in `.qsgen3_preserve` file
- File paths don't match patterns
- Permission issues with temporary backup directory
- Malformed preserve file format
**Solutions**:
- Verify patterns use shell glob syntax (`*`, `?`, `[]`)
- Check that patterns are relative to output directory
- Ensure `.qsgen3_preserve` file is in project root
- Test patterns with `find output/ -name "pattern"` before adding to preserve file
- Enable debug logging to see preservation process details
- Verify file permissions allow temporary directory creation
**Example debugging:**
```bash
# Test if your pattern matches files
find output/ -name "posts/legacy-*.html"
# Enable debug logging to see preservation process
QSG_DEBUG=1 ./bin/qsgen3
```
### Debug Logging
Enable detailed logging by modifying the `_log` function or adding debug statements:
```bash
# Enable debug logging
QSG_DEBUG=1 ./bin/qsgen3
```
### Path Debugging
The script includes path resolution logic to handle both relative and absolute paths. If experiencing path issues:
1. Check that `PROJECT_ROOT` is correctly set
2. Verify configuration paths are relative to project root
3. Review log messages for path construction details
### Configuration Validation
Ensure site.conf follows the correct format:
- Use double quotes for values: `key="value"`
- No spaces around the equals sign
- One configuration per line
- Comments start with `#`
---

View File

@ -1,3 +0,0 @@
Copy this directory to your **www_root**
**$www_root/images/**

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" zoomAndPan="magnify" viewBox="0 0 224.87999 225" height="300" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><clipPath id="ec549c68f3"><path d="M 44.976562 24 L 201 24 L 201 179.964844 L 44.976562 179.964844 Z M 44.976562 24 " clip-rule="nonzero"/></clipPath><clipPath id="f9fb9407ba"><path d="M 109 0.0585938 L 224.761719 0.0585938 L 224.761719 116 L 109 116 Z M 109 0.0585938 " clip-rule="nonzero"/></clipPath></defs><g clip-path="url(#ec549c68f3)"><path fill="#000000" d="M 191.742188 84.863281 C 187.179688 84.863281 183.46875 88.574219 183.46875 93.136719 L 183.46875 163.425781 L 61.507812 163.425781 L 61.507812 41.460938 L 131.792969 41.460938 C 136.359375 41.460938 140.070312 37.75 140.070312 33.1875 C 140.070312 28.625 136.359375 24.914062 131.792969 24.914062 L 53.25 24.914062 C 48.6875 24.914062 44.976562 28.625 44.976562 33.1875 L 44.976562 171.679688 C 44.976562 176.242188 48.6875 179.953125 53.25 179.953125 L 191.742188 179.953125 C 196.308594 179.953125 200.019531 176.242188 200.019531 171.679688 L 200.019531 93.136719 C 200.019531 88.574219 196.308594 84.863281 191.742188 84.863281 Z M 191.742188 84.863281 " fill-opacity="1" fill-rule="nonzero"/></g><g clip-path="url(#f9fb9407ba)"><path fill="#000000" d="M 216.585938 0.0703125 L 166.710938 0.0703125 C 162.148438 0.0703125 158.4375 3.78125 158.4375 8.34375 C 158.4375 12.90625 162.128906 16.617188 166.710938 16.617188 L 196.628906 16.617188 L 111.4375 101.789062 C 108.199219 105.027344 108.199219 110.253906 111.4375 113.472656 C 113.046875 115.082031 115.167969 115.898438 117.289062 115.898438 C 119.410156 115.898438 121.53125 115.082031 123.140625 113.472656 L 208.332031 28.28125 L 208.332031 58.21875 C 208.332031 62.78125 212.023438 66.496094 216.605469 66.496094 C 221.167969 66.496094 224.878906 62.78125 224.878906 58.21875 L 224.878906 8.34375 C 224.859375 3.78125 221.148438 0.0703125 216.585938 0.0703125 Z M 216.585938 0.0703125 " fill-opacity="1" fill-rule="nonzero"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,88 +0,0 @@
# Here you set the colors you want in the output of view and search
#
# Black 0;30 Dark Gray 1;30
# Blue 0;34 Light Blue 1;34
# Green 0;32 Light Green 1;32
# Cyan 0;36 Light Cyan 1;36
# Red 0;31 Light Red 1;31
# Purple 0;35 Light Purple 1;35
# Brown 0;33 Yellow 1;33
# Light Gray 0;37 White 1;37
BLACK="\033[0;30m"
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
BLUE="\033[0;34m"
MAGENTA="\033[0;35m"
CYAN="\033[0;36m"
WHITE="\033[0;37m"
BOLD_BLACK="\033[1;30m"
BOLD_RED="\033[1;31m"
BOLD_GREEN="\033[1;32m"
BOLD_YELLOW="\033[1;33m"
BOLD_BLUE="\033[1;34m"
BOLD_MAGENTA="\033[1;35m"
BOLD_CYAN="\033[1;36m"
BOLD_WHITE="\033[1;37m"
BLACK_BG="\033[40m"
RED_BG="\033[41m"
GREEN_BG="\033[42m"
YELLOW_BG="\033[43m"
BLUE_BG="\033[44m"
MAGENTA_BG="\033[45m"
CYAN_BG="\033[46m"
WHITE_BG="\033[47m"
END="\033[0m"
Black="\033[0;30m"
Red="\033[0;31m"
Green="\033[0;32m"
Yellow="\033[0;33m"
Blue="\033[0;34m"
Magenta="\033[0;35m"
Cyan="\033[0;36m"
White="\033[0;37m"
Bold_Black="\033[1;30m"
Bold_Red="\033[1;31m"
Bold_Green="\033[1;32m"
Bold_Yellow="\033[1;33m"
Bold_Blue="\033[1;34m"
Bold_Magenta="\033[1;35m"
Bold_Cyan="\033[1;36m"
Bold_White="\033[1;37m"
Black_bg="\033[40m"
Red_bg="\033[41m"
Green_bg="\033[42m"
Yellow_bg="\033[43m"
Blue_bg="\033[44m"
Magenta_bg="\033[45m"
Cyan_bg="\033[46m"
White_bg="\033[47m"
End="\033[0m"
black="\033[0;30m"
red="\033[0;31m"
green="\033[0;32m"
yellow="\033[0;33m"
blue="\033[0;34m"
magenta="\033[0;35m"
cyan="\033[0;36m"
white="\033[0;37m"
bold_black="\033[1;30m"
bold_red="\033[1;31m"
bold_green="\033[1;32m"
bold_yellow="\033[1;33m"
bold_blue="\033[1;34m"
bold_magenta="\033[1;35m"
bold_cyan="\033[1;36m"
bold_white="\033[1;37m"
black_bg="\033[40m"
red_bg="\033[41m"
green_bg="\033[42m"
yellow_bg="\033[43m"
blue_bg="\033[44m"
magenta_bg="\033[45m"
cyan_bg="\033[46m"
white_bg="\033[47m"
end="\033[0m"

View File

@ -1,15 +0,0 @@
function include() {
# This function is used to include other functions that will normally be in
# ${HOME}/bin/include/
# Edit this path to reflect your installation
local inc_file=${HOME}/bin/include/${1}.inc
if [[ ! -f ${inc_file} ]]; then
local inc_opt=$( echo ${1} | cut -d\/ -f2 )
echo "Supplied option \"${inc_opt}\" is not a valid include."
else
builtin source ${inc_file} ${2}
fi
}

View File

@ -1,11 +0,0 @@
# Converts a --with=option,option2 into an array
# Usage: InputToArray <input-string>
# Returns: $InputArray
function InputToArray () {
if [[ ${@} =~ "--with" ]]; then
InputArray=( $( echo ${@} | cut -d= -f2 | sed -e 's/\,/\ /g' ) )
fi
}

View File

@ -1,7 +0,0 @@
# Function: LOGGER
# Usage: loggy <message>
function loggy () {
echo "$$ - $(date +%T) - ${KODIVERSION} - ${@}" >> ${LOGGYLOGFILE}
}

View File

@ -1,9 +0,0 @@
# This function creates an array of a *nix path
# Example: /home/user/bin becomes an array of ( home user bin )
function slash_to_array () {
sta=( $( echo ${1} | sed -e "s/\//\ /g" ) )
# return ${sta}
}

View File

@ -1,39 +0,0 @@
# zini function to parse INI files and store their content in an associative array
zini() {
local ini_path="$1"
typeset -gA config
# Check if the file exists
if [[ ! -f "$ini_path" ]]; then
echo "Configuration file not found: $ini_path"
return 1
fi
local current_section=""
local line key value composite_key
# Read the INI file line by line
while IFS= read -r line || [[ -n $line ]]; do
line=$(echo $line | xargs) # Trim whitespace
# Skip empty lines and comments
[[ -z "$line" || "$line" == \;* ]] && continue
# Detect section headers
if [[ "$line" == \[*\]* ]]; then
current_section="${line:1:-1}"
else
# Parse key-value pairs
key=${line%%=*}
value=${line#*=}
key=$(echo $key | xargs) # Trim key
value=$(echo $value | xargs) # Trim value
# Store in associative array with 'section_key' format
composite_key="${current_section}_${key}"
config[$composite_key]="$value"
fi
done < "$ini_path"
# echo "Configuration loaded."
}

View File

@ -1,217 +0,0 @@
# Quick Site Generator 2 - English Language File
# This file contains all user-facing strings for the application
# Error Messages
error.missing_dependencies = "Missing required dependencies: %s"
error.config_validation_failed = "Configuration validation failed. Please check your configuration files."
error.config_missing_key = "Missing required configuration: %s"
error.invalid_url = "site_url must start with http:// or https://"
error.directory_not_found = "Directory does not exist: %s"
error.theme_not_found = "Theme directory not found: %s"
error.theme_config_not_found = "Theme configuration not found: %s"
error.theme_config_creation_failed = "Failed to create theme configuration: %s"
error.config_parse = "Failed to parse config file: %s"
error.invalid_path = "Invalid path: %s"
error.write_failed = "Failed to write to temporary file: %s"
error.move_failed = "Failed to move temporary file to: %s"
error.config_load_failed = "Failed to load configuration file: %s"
error.config_not_found = "No valid configuration file found."
error.create_blog_index_failed = "Failed to create blog index at: %s"
error.create_sample_post_failed = "Failed to create sample blog post at: %s"
error.create_sample_page_failed = "Failed to create sample page at: %s"
error.engine_not_found = "Engine not found or not executable: %s"
error.unknown_generator = "Unknown generator: %s"
error.unknown_option = "Unknown option: %s"
error.directory_not_empty = "Directory '%s' already exists and is not empty."
error.theme_creation_failed = "Failed to create theme: %s"
error.config_creation_failed = "Failed to create configuration file: %s"
error.directory_creation_failed = "Failed to create directory: %s"
error.file_creation_failed = "Failed to create file: %s"
error.layout_creation_failed = "Failed to create layout file: %s"
error.stylesheet_creation_failed = "Failed to create stylesheet: %s"
error.script_creation_failed = "Failed to create script file: %s"
# Warning Messages
warning.optional_dependency = "Optional tool '%s' is required for %s but not found"
warning.dependency_version = "%s version %s is below the recommended version %s"
warning.legacy_config = "Using legacy config file. Consider renaming '%s' to 'site.conf'"
warning.git_repo = "Warning: Running in a git repository directory. Make sure this is intended."
warning.outdated_dependencies = "Some dependencies are outdated:"
# Info Messages
info.legacy_config = "Warning: Using legacy '%s' file. Consider renaming to 'site.conf'"
info.legacy_config_used = "Using legacy config file. Consider renaming 'config' to 'site.conf'"
info.config_help = "Please create 'site.conf' in your project directory."
info.config_template = "You can use 'config.example' as a template."
info.git_repo_help = "If you want to generate the site, run from the project root directory."
info.usage = "Usage: %s <command> [options]"
info.engine_usage = "Usage: _run_engine <input>"
info.creating_blog_index = "Creating blog index file..."
info.creating_sample_post = "Creating sample blog post..."
info.creating_sample_page = "Creating sample page..."
info.setting_up_project = "Setting up project structure..."
info.creating_directories = "Creating project directories..."
info.initializing_blog = "Initializing blog..."
info.initializing_pages = "Initializing pages..."
info.initializing_theme = "Initializing theme..."
info.initializing_config = "Initializing configuration..."
info.initializing_complete = "Initialization complete!"
info.initializing_aborted = "Initialization aborted."
info.use_force_option = "Use --force to overwrite the existing directory."
info.get_started_instructions = "To get started"
info.happy_coding = "Happy coding!"
info.initializing_project = "Initializing project..."
info.initializing_blog_cache = "Initializing blog cache..."
info.initializing_pages_cache = "Initializing pages cache..."
# Debug Messages
debug.loading_config = "Loading config file: %s"
debug.loaded_config = "=== Loaded Configuration ==="
debug.config_value = "%s: %s"
debug.config_end = "==========================="
debug.raw_config = "=== Raw Config File ==="
debug.raw_config_end = "======================"
debug.blog_cache_update = "Updating blog cache at %s"
debug.blog_cache_bytes = "Blog cache updated with %d bytes"
debug.blog_cache_loading = "Loading blog index from cache"
debug.blog_cache_stale_new = "Blog cache stale: New or updated blogs detected"
debug.blog_cache_stale_missing = "Blog cache stale: Cache file does not exist"
debug.blog_cache_stale_old = "Blog cache stale: Cache is older than 1 hour"
debug.blog_cache_fresh = "Blog cache is fresh"
debug.pages_cache_update = "Updating pages cache at %s"
debug.pages_cache_bytes = "Pages cache updated with %d bytes"
debug.pages_cache_loading = "Loading pages index from cache"
debug.pages_cache_stale_new = "Pages cache stale: New or updated pages detected"
debug.pages_cache_stale_missing = "Pages cache stale: Cache file does not exist"
debug.pages_cache_stale_old = "Pages cache stale: Cache is older than 1 hour"
debug.pages_cache_fresh = "Pages cache is fresh"
# Blog Messages
blog.not_found = "No blog files found."
blog.generating = "Generating blog"
blog.no_template = "Unable to find the blog template: %s"
blog.cache_updated = "Blog cache updated"
blog.cache_loading = "Loading blog cache"
blog.cache_stale = "Blog cache is stale, rebuilding..."
blog.cache_fresh = "Blog cache is fresh"
blog.post_updated = "Updated blog post: %s"
blog.post_skipped = "Skipped (no changes): %s"
blog.post_error = "Error processing blog post: %s"
# Blog Generation Messages
blog.hello_world_title = "Hello, World!"
blog.published_on = "Published on"
blog.welcome_message = "Welcome to your new blog! This is a sample blog post."
blog.getting_started = "Getting Started"
blog.edit_this_post = "You can edit this post at %s"
blog.features = "Features"
blog.feature_markdown = "Markdown support"
blog.feature_easy_customize = "Easy to customize"
blog.feature_fast_lightweight = "Fast and lightweight"
blog.next_steps = "Next Steps"
blog.step_edit_post = "Edit this post"
blog.step_add_posts = "Add more posts"
blog.step_customize_theme = "Customize your theme"
blog.step_publish_site = "Publish your site"
blog.happy_blogging = "Happy blogging!"
blog.latest_posts = "Latest Posts"
blog.sample_post = "Blog Post"
blog.categories = "Categories"
blog.sample_category = "Category"
blog.archives = "Archives"
blog.tags = "Tags"
blog.about = "About"
blog.about_text = "This is a sample blog index page. You can edit it at %s"
# Page Generation Messages
page.about_me_title = "About Me"
page.welcome_title = "Welcome to My Site"
page.welcome_message = "This is a sample about page. You can edit it at %s"
page.my_story_title = "My Story"
page.my_story_content = "I'm a passionate developer who loves creating amazing websites with qsgen2!"
page.skills_title = "Skills"
page.skill_webdev = "Web Development"
page.skill_design = "Design"
page.skill_opensource = "Open Source"
page.contact_title = "Contact"
page.contact_content = "You can reach me at: email@example.com"
page.about_site_title = "About This Site"
page.about_site_content = "This site was built with [qsgen2](https://github.com/kekePower/qsgen2)."
# Success Messages
success.config_loaded = "Configuration loaded successfully"
success.build_complete = "Build completed successfully"
success.blog_index_created = "Created blog index at: %s"
success.sample_post_created = "Created sample blog post at: %s"
success.sample_page_created = "Created sample page at: %s"
success.project_initialized = "Project initialized successfully!"
success.theme_initialized = "Theme initialized successfully!"
success.config_initialized = "Configuration file created successfully!"
# System Messages
system.created_by = "- Created by kekePower - 2018-%s"
system.see_help = "- See '%s help' for more information."
# List Messages
list.pages_not_found = "_list_pages: No Pages found with ext %s"
list.pages_adding = "_list_pages: Adding file to array: %s"
list.blogs_not_found = "_list_blogs: No blog files found."
list.blogs_adding = "_list_blogs: Adding file to array: %s"
# Blog Cache Messages
blog_cache.hash = "_blog_cache: HASH VALUE:"
blog_cache.current = "1. _blog_cache:"
blog_cache.cache_file = "2. _blog_cache: current_cache:"
blog_cache.new_cache = "3. _blog_cache: new_cache_file:"
blog_cache.new_current = "4. _blog_cache: new_current_cache:"
# Pages Cache Messages
page_cache.hash = "PAGES HASH VALUE:"
page_cache.current = "1. pages_cache:"
page_cache.cache_file = "2. _pages_cache: current_cache:"
page_cache.pages_file = "2. _pages_cache: pages_file:"
# Navigation
nav.home = "Home"
nav.blog = "Blog"
nav.about = "About"
# Footer
footer.all_rights_reserved = "All rights reserved."
# Configuration
config.site_config_title = "Site Configuration"
config.theme_config_title = "Theme Configuration"
config.site_name_default = "My Awesome Site"
config.site_tagline_default = "A static site generated with qsgen2"
config.site_description_default = "This is my awesome static site"
config.your_name = "Your Name"
config.theme_description = "A custom theme for qsgen2"
config.theme_files_title = "Theme files (relative to theme directory)"
# CSS and JavaScript
css.main_styles = "Main Styles"
js.main_javascript = "Main JavaScript"
js.console_message = "Hello from qsgen2!"
js.add_custom_javascript = "Add any custom JavaScript here"
js.your_code_here = "Your code here"
# Last Updated Messages
last_updated.setting = "_last_updated: Setting date and version in footer"
last_updated.file_not_found = "_f_last_updated: File %s not found."
# Pages Messages
pages.generating = "Generating Pages"
pages.none = "* You do not have any pages *"
pages.no_template = "Unable to find the Pages template: %s"
# Pandoc Messages
pandoc.install = "Please install Pandoc."
pandoc.download = "https://github.com/jgm/pandoc/releases"
# Generator Messages
generator.not_found = "No valid generator found. Are you sure you've selected the correct generator in 'config'?"
# Build Messages
build.forced = "- Forced Update: Generating Everything"
build.using_engine = "Using the %s -engine for files:"

View File

@ -1,217 +0,0 @@
# Quick Site Generator 2 - English Language File
# This file contains all user-facing strings for the application
# Error Messages
error.missing_dependencies = "Missing required dependencies: %s"
error.config_validation_failed = "Configuration validation failed. Please check your configuration files."
error.config_missing_key = "Missing required configuration: %s"
error.invalid_url = "site_url must start with http:// or https://"
error.directory_not_found = "Directory does not exist: %s"
error.theme_not_found = "Theme directory not found: %s"
error.theme_config_not_found = "Theme configuration not found: %s"
error.theme_config_creation_failed = "Failed to create theme configuration: %s"
error.config_parse = "Failed to parse config file: %s"
error.invalid_path = "Invalid path: %s"
error.write_failed = "Failed to write to temporary file: %s"
error.move_failed = "Failed to move temporary file to: %s"
error.config_load_failed = "Failed to load configuration file: %s"
error.config_not_found = "No valid configuration file found."
error.create_blog_index_failed = "Failed to create blog index at: %s"
error.create_sample_post_failed = "Failed to create sample blog post at: %s"
error.create_sample_page_failed = "Failed to create sample page at: %s"
error.engine_not_found = "Engine not found or not executable: %s"
error.unknown_generator = "Unknown generator: %s"
error.unknown_option = "Unknown option: %s"
error.directory_not_empty = "Directory '%s' already exists and is not empty."
error.theme_creation_failed = "Failed to create theme: %s"
error.config_creation_failed = "Failed to create configuration file: %s"
error.directory_creation_failed = "Failed to create directory: %s"
error.file_creation_failed = "Failed to create file: %s"
error.layout_creation_failed = "Failed to create layout file: %s"
error.stylesheet_creation_failed = "Failed to create stylesheet: %s"
error.script_creation_failed = "Failed to create script file: %s"
# Warning Messages
warning.optional_dependency = "Optional tool '%s' is required for %s but not found"
warning.dependency_version = "%s version %s is below the recommended version %s"
warning.legacy_config = "Using legacy config file. Consider renaming '%s' to 'site.conf'"
warning.git_repo = "Warning: Running in a git repository directory. Make sure this is intended."
warning.outdated_dependencies = "Some dependencies are outdated:"
# Info Messages
info.legacy_config = "Warning: Using legacy '%s' file. Consider renaming to 'site.conf'"
info.legacy_config_used = "Using legacy config file. Consider renaming 'config' to 'site.conf'"
info.config_help = "Please create 'site.conf' in your project directory."
info.config_template = "You can use 'config.example' as a template."
info.git_repo_help = "If you want to generate the site, run from the project root directory."
info.usage = "Usage: %s <command> [options]"
info.engine_usage = "Usage: _run_engine <input>"
info.creating_blog_index = "Creating blog index file..."
info.creating_sample_post = "Creating sample blog post..."
info.creating_sample_page = "Creating sample page..."
info.setting_up_project = "Setting up project structure..."
info.creating_directories = "Creating project directories..."
info.initializing_blog = "Initializing blog..."
info.initializing_pages = "Initializing pages..."
info.initializing_theme = "Initializing theme..."
info.initializing_config = "Initializing configuration..."
info.initializing_complete = "Initialization complete!"
info.initializing_aborted = "Initialization aborted."
info.use_force_option = "Use --force to overwrite the existing directory."
info.get_started_instructions = "To get started"
info.happy_coding = "Happy coding!"
info.initializing_project = "Initializing project..."
info.initializing_blog_cache = "Initializing blog cache..."
info.initializing_pages_cache = "Initializing pages cache..."
# Debug Messages
debug.loading_config = "Loading config file: %s"
debug.loaded_config = "=== Loaded Configuration ==="
debug.config_value = "%s: %s"
debug.config_end = "==========================="
debug.raw_config = "=== Raw Config File ==="
debug.raw_config_end = "======================"
debug.blog_cache_update = "Updating blog cache at %s"
debug.blog_cache_bytes = "Blog cache updated with %d bytes"
debug.blog_cache_loading = "Loading blog index from cache"
debug.blog_cache_stale_new = "Blog cache stale: New or updated blogs detected"
debug.blog_cache_stale_missing = "Blog cache stale: Cache file does not exist"
debug.blog_cache_stale_old = "Blog cache stale: Cache is older than 1 hour"
debug.blog_cache_fresh = "Blog cache is fresh"
debug.pages_cache_update = "Updating pages cache at %s"
debug.pages_cache_bytes = "Pages cache updated with %d bytes"
debug.pages_cache_loading = "Loading pages index from cache"
debug.pages_cache_stale_new = "Pages cache stale: New or updated pages detected"
debug.pages_cache_stale_missing = "Pages cache stale: Cache file does not exist"
debug.pages_cache_stale_old = "Pages cache stale: Cache is older than 1 hour"
debug.pages_cache_fresh = "Pages cache is fresh"
# Blog Messages
blog.not_found = "No blog files found."
blog.generating = "Generating blog"
blog.no_template = "Unable to find the blog template: %s"
blog.cache_updated = "Blog cache updated"
blog.cache_loading = "Loading blog cache"
blog.cache_stale = "Blog cache is stale, rebuilding..."
blog.cache_fresh = "Blog cache is fresh"
blog.post_updated = "Updated blog post: %s"
blog.post_skipped = "Skipped (no changes): %s"
blog.post_error = "Error processing blog post: %s"
# Blog Generation Messages
blog.hello_world_title = "Hello, World!"
blog.published_on = "Published on"
blog.welcome_message = "Welcome to your new blog! This is a sample blog post."
blog.getting_started = "Getting Started"
blog.edit_this_post = "You can edit this post at %s"
blog.features = "Features"
blog.feature_markdown = "Markdown support"
blog.feature_easy_customize = "Easy to customize"
blog.feature_fast_lightweight = "Fast and lightweight"
blog.next_steps = "Next Steps"
blog.step_edit_post = "Edit this post"
blog.step_add_posts = "Add more posts"
blog.step_customize_theme = "Customize your theme"
blog.step_publish_site = "Publish your site"
blog.happy_blogging = "Happy blogging!"
blog.latest_posts = "Latest Posts"
blog.sample_post = "Blog Post"
blog.categories = "Categories"
blog.sample_category = "Category"
blog.archives = "Archives"
blog.tags = "Tags"
blog.about = "About"
blog.about_text = "This is a sample blog index page. You can edit it at %s"
# Page Generation Messages
page.about_me_title = "About Me"
page.welcome_title = "Welcome to My Site"
page.welcome_message = "This is a sample about page. You can edit it at %s"
page.my_story_title = "My Story"
page.my_story_content = "I'm a passionate developer who loves creating amazing websites with qsgen2!"
page.skills_title = "Skills"
page.skill_webdev = "Web Development"
page.skill_design = "Design"
page.skill_opensource = "Open Source"
page.contact_title = "Contact"
page.contact_content = "You can reach me at: email@example.com"
page.about_site_title = "About This Site"
page.about_site_content = "This site was built with [qsgen2](https://github.com/kekePower/qsgen2)."
# Success Messages
success.config_loaded = "Configuration loaded successfully"
success.build_complete = "Build completed successfully"
success.blog_index_created = "Created blog index at: %s"
success.sample_post_created = "Created sample blog post at: %s"
success.sample_page_created = "Created sample page at: %s"
success.project_initialized = "Project initialized successfully!"
success.theme_initialized = "Theme initialized successfully!"
success.config_initialized = "Configuration file created successfully!"
# System Messages
system.created_by = "- Created by kekePower - 2018-%s"
system.see_help = "- See '%s help' for more information."
# List Messages
list.pages_not_found = "_list_pages: No Pages found with ext %s"
list.pages_adding = "_list_pages: Adding file to array: %s"
list.blogs_not_found = "_list_blogs: No blog files found."
list.blogs_adding = "_list_blogs: Adding file to array: %s"
# Blog Cache Messages
blog_cache.hash = "_blog_cache: HASH VALUE:"
blog_cache.current = "1. _blog_cache:"
blog_cache.cache_file = "2. _blog_cache: current_cache:"
blog_cache.new_cache = "3. _blog_cache: new_cache_file:"
blog_cache.new_current = "4. _blog_cache: new_current_cache:"
# Pages Cache Messages
page_cache.hash = "PAGES HASH VALUE:"
page_cache.current = "1. pages_cache:"
page_cache.cache_file = "2. _pages_cache: current_cache:"
page_cache.pages_file = "2. _pages_cache: pages_file:"
# Navigation
nav.home = "Home"
nav.blog = "Blog"
nav.about = "About"
# Footer
footer.all_rights_reserved = "All rights reserved."
# Configuration
config.site_config_title = "Site Configuration"
config.theme_config_title = "Theme Configuration"
config.site_name_default = "My Awesome Site"
config.site_tagline_default = "A static site generated with qsgen2"
config.site_description_default = "This is my awesome static site"
config.your_name = "Your Name"
config.theme_description = "A custom theme for qsgen2"
config.theme_files_title = "Theme files (relative to theme directory)"
# CSS and JavaScript
css.main_styles = "Main Styles"
js.main_javascript = "Main JavaScript"
js.console_message = "Hello from qsgen2!"
js.add_custom_javascript = "Add any custom JavaScript here"
js.your_code_here = "Your code here"
# Last Updated Messages
last_updated.setting = "_last_updated: Setting date and version in footer"
last_updated.file_not_found = "_f_last_updated: File %s not found."
# Pages Messages
pages.generating = "Generating Pages"
pages.none = "* You do not have any pages *"
pages.no_template = "Unable to find the Pages template: %s"
# Pandoc Messages
pandoc.install = "Please install Pandoc."
pandoc.download = "https://github.com/jgm/pandoc/releases"
# Generator Messages
generator.not_found = "No valid generator found. Are you sure you've selected the correct generator in 'config'?"
# Build Messages
build.forced = "- Forced Update: Generating Everything"
build.using_engine = "Using the %s -engine for files:"

View File

@ -1,207 +0,0 @@
# Generador Rápido de Sitios 2 - Archivo de idioma español
# Este archivo contiene todas las cadenas visibles para el usuario de la aplicación
# Mensajes de error
error.missing_dependencies = "Faltan dependencias requeridas: %s"
error.config_validation_failed = "Error en la validación de la configuración. Por favor, verifique sus archivos de configuración."
error.config_missing_key = "Falta la configuración requerida: %s"
error.invalid_url = "site_url debe comenzar con http:// o https://"
error.directory_not_found = "El directorio no existe: %s"
error.theme_not_found = "Directorio del tema no encontrado: %s"
error.theme_config_not_found = "Configuración del tema no encontrada: %s"
error.theme_config_creation_failed = "Error al crear la configuración del tema: %s"
error.config_parse = "Error al analizar el archivo de configuración: %s"
error.invalid_path = "Ruta no válida: %s"
error.write_failed = "Error al escribir en el archivo temporal: %s"
error.move_failed = "Error al mover el archivo temporal a: %s"
error.config_load_failed = "Error al cargar el archivo de configuración: %s"
error.config_not_found = "No se encontró ningún archivo de configuración válido."
error.create_blog_index_failed = "Error al crear el índice del blog en: %s"
error.create_sample_post_failed = "Error al crear la entrada de blog de ejemplo en: %s"
error.create_sample_page_failed = "Error al crear la página de ejemplo en: %s"
error.engine_not_found = "Motor no encontrado o no ejecutable: %s"
error.unknown_generator = "Generador desconocido: %s"
error.unknown_option = "Opción desconocida: %s"
error.directory_not_empty = "El directorio '%s' ya existe y no está vacío."
error.theme_creation_failed = "Error al crear el tema: %s"
error.config_creation_failed = "Error al crear el archivo de configuración: %s"
error.directory_creation_failed = "Error al crear el directorio: %s"
error.file_creation_failed = "Error al crear el archivo: %s"
error.layout_creation_failed = "Error al crear el archivo de diseño: %s"
error.stylesheet_creation_failed = "Error al crear la hoja de estilos: %s"
error.script_creation_failed = "Error al crear el archivo de script: %s"
# Mensajes de advertencia
warning.optional_dependency = "La herramienta opcional '%s' es necesaria para %s pero no se encontró"
warning.dependency_version = "La versión %s de %s es inferior a la versión recomendada %s"
warning.legacy_config = "Usando archivo de configuración heredado. Considere renombrar '%s' a 'site.conf'"
warning.git_repo = "Advertencia: Ejecutando en un directorio de repositorio git. Asegúrese de que es intencionado."
warning.outdated_dependencies = "Algunas dependencias están desactualizadas:"
# Mensajes informativos
info.legacy_config = "Advertencia: Usando archivo heredado '%s'. Considere renombrarlo a 'site.conf'"
info.legacy_config_used = "Usando archivo de configuración heredado. Considere renombrar 'config' a 'site.conf'"
info.config_help = "Por favor, cree un archivo 'site.conf' en el directorio de su proyecto."
info.config_template = "Puede usar 'config.example' como plantilla."
info.git_repo_help = "Si desea generar el sitio, ejecútelo desde el directorio raíz del proyecto."
info.usage = "Uso: %s <comando> [opciones]"
info.engine_usage = "Uso: _run_engine <entrada>"
info.creating_blog_index = "Creando archivo de índice del blog..."
info.creating_sample_post = "Creando entrada de blog de ejemplo..."
info.creating_sample_page = "Creando página de ejemplo..."
info.setting_up_project = "Configurando la estructura del proyecto..."
info.creating_directories = "Creando directorios del proyecto..."
info.initializing_blog = "Inicializando blog..."
info.initializing_pages = "Inicializando páginas..."
info.initializing_theme = "Inicializando tema..."
info.initializing_config = "Inicializando configuración..."
info.initializing_complete = "¡Inicialización completada!"
info.initializing_aborted = "Inicialización cancelada."
info.use_force_option = "Use --force para sobrescribir el directorio existente."
info.get_started_instructions = "Para comenzar"
info.happy_coding = "¡Feliz programación!"
info.initializing_project = "Inicializando proyecto..."
info.initializing_blog_cache = "Inicializando caché del blog..."
info.initializing_pages_cache = "Inicializando caché de páginas..."
# Mensajes de depuración
debug.loading_config = "Cargando archivo de configuración: %s"
debug.loaded_config = "=== Configuración Cargada ==="
debug.config_value = "%s: %s"
debug.config_end = "============================"
debug.raw_config = "=== Archivo de Configuración en Bruto ==="
debug.raw_config_end = "=================================="
debug.blog_cache_update = "Actualizando caché del blog en %s"
debug.blog_cache_bytes = "Caché del blog actualizado con %d bytes"
debug.blog_cache_loading = "Cargando índice del blog desde la caché"
debug.blog_cache_stale_new = "Caché del blog desactualizado: Se detectaron blogs nuevos o actualizados"
debug.blog_cache_stale_missing = "Caché del blog desactualizado: El archivo de caché no existe"
debug.blog_cache_stale_old = "Caché del blog desactualizado: La caché tiene más de 1 hora"
debug.blog_cache_fresh = "La caché del blog está actualizada"
debug.pages_cache_update = "Actualizando caché de páginas en %s"
debug.pages_cache_bytes = "Caché de páginas actualizado con %d bytes"
debug.pages_cache_loading = "Cargando índice de páginas desde la caché"
debug.pages_cache_stale_new = "Caché de páginas desactualizado: Se detectaron páginas nuevas o actualizadas"
debug.pages_cache_stale_missing = "Caché de páginas desactualizado: El archivo de caché no existe"
debug.pages_cache_stale_old = "Caché de páginas desactualizado: La caché tiene más de 1 hora"
debug.pages_cache_fresh = "La caché de páginas está actualizada"
# Mensajes del Blog
blog.not_found = "No se encontraron archivos de blog."
blog.generating = "Generando blog"
blog.no_template = "No se pudo encontrar la plantilla del blog: %s"
blog.cache_updated = "Caché del blog actualizado"
blog.cache_loading = "Cargando caché del blog"
blog.cache_stale = "La caché del blog está desactualizada, reconstruyendo..."
blog.cache_fresh = "La caché del blog está actualizada"
blog.post_updated = "Entrada de blog actualizada: %s"
blog.post_skipped = "Omitido (sin cambios): %s"
blog.post_error = "Error al procesar la entrada del blog: %s"
# Mensajes de Generación del Blog
blog.hello_world_title = "¡Hola, Mundo!"
blog.published_on = "Publicado el"
blog.welcome_message = "¡Bienvenido a tu nuevo blog! Esta es una entrada de blog de ejemplo."
blog.getting_started = "Comenzando"
blog.edit_this_post = "Puedes editar esta entrada en %s"
blog.features = "Características"
blog.feature_markdown = "Soporte para Markdown"
blog.feature_easy_customize = "Fácil de personalizar"
blog.feature_fast_lightweight = "Rápido y ligero"
blog.next_steps = "Próximos pasos"
blog.step_edit_post = "Editar esta entrada"
blog.step_add_posts = "Añadir más entradas"
blog.step_customize_theme = "Personalizar tu tema"
blog.step_publish_site = "Publicar tu sitio"
blog.happy_blogging = "¡Feliz blogueo!"
blog.latest_posts = "Últimas entradas"
blog.sample_post = "Entrada de blog"
blog.categories = "Categorías"
blog.sample_category = "Categoría"
blog.archives = "Archivos"
blog.tags = "Etiquetas"
blog.about = "Acerca de"
blog.about_text = "Esta es una página de índice de blog de ejemplo. Puedes editarla en %s"
# Mensajes de Generación de Páginas
page.about_me_title = "Sobre Mí"
page.welcome_title = "Bienvenido a Mi Sitio"
page.welcome_message = "Esta es una página de ejemplo. Puedes editarla en %s"
page.my_story_title = "Mi Historia"
page.my_story_content = "¡Soy un desarrollador apasionado que adora crear sitios web increíbles con qsgen2!"
page.skills_title = "Habilidades"
page.skill_webdev = "Desarrollo Web"
page.skill_design = "Diseño"
page.skill_opensource = "Código Abierto"
page.contact_title = "Contacto"
page.contact_content = "Puedes contactarme en: email@example.com"
page.about_site_title = "Acerca de Este Sitio"
page.about_site_content = "Este sitio fue construido con [qsgen2](https://github.com/kekePower/qsgen2)."
# Mensajes de Éxito
success.config_loaded = "Configuración cargada exitosamente"
success.build_complete = "Construcción completada exitosamente"
success.blog_index_created = "Índice del blog creado en: %s"
success.sample_post_created = "Entrada de blog de ejemplo creada en: %s"
success.sample_page_created = "Página de ejemplo creada en: %s"
success.project_initialized = "¡Proyecto inicializado exitosamente!"
success.theme_initialized = "¡Tema inicializado exitosamente!"
success.config_initialized = "¡Archivo de configuración creado exitosamente!"
# Mensajes del Sistema
system.created_by = "- Creado por kekePower - 2018-%s"
system.see_help = "- Ver '%s help' para más información."
# Mensajes de Lista
list.pages_not_found = "_list_pages: No se encontraron páginas con la extensión %s"
list.pages_adding = "_list_pages: Añadiendo archivo al array: %s"
list.blogs_not_found = "_list_blogs: No se encontraron archivos de blog."
list.blogs_adding = "_list_blogs: Añadiendo archivo al array: %s"
# Navegación
nav.home = "Inicio"
nav.blog = "Blog"
nav.about = "Acerca de"
# Pie de Página
footer.all_rights_reserved = "Todos los derechos reservados."
# Configuración
config.site_config_title = "Configuración del Sitio"
config.theme_config_title = "Configuración del Tema"
config.site_name_default = "Mi Sitio Increíble"
config.site_tagline_default = "Un sitio estático generado con qsgen2"
config.site_description_default = "Este es mi increíble sitio estático"
config.your_name = "Tu Nombre"
config.theme_description = "Un tema personalizado para qsgen2"
config.theme_files_title = "Archivos del tema (relativo al directorio del tema)"
# CSS y JavaScript
css.main_styles = "Estilos Principales"
js.main_javascript = "JavaScript Principal"
js.console_message = "¡Hola desde qsgen2!"
js.add_custom_javascript = "Añade cualquier JavaScript personalizado aquí"
js.your_code_here = "Tu código aquí"
# Mensajes de Última Actualización
last_updated.setting = "_last_updated: Estableciendo fecha y versión en el pie de página"
last_updated.file_not_found = "_f_last_updated: Archivo %s no encontrado."
# Mensajes de Páginas
pages.generating = "Generando Páginas"
pages.none = "* No tienes páginas *"
pages.no_template = "No se pudo encontrar la plantilla de páginas: %s"
# Mensajes de Pandoc
pandoc.install = "Por favor, instala Pandoc."
pandoc.download = "https://github.com/jgm/pandoc/releases"
# Mensajes del Generador
generator.not_found = "No se encontró un generador válido. ¿Estás seguro de que has seleccionado el generador correcto en 'config'?"
generator.using = "Usando generador: %s"
generator.execution_failed = "Error en la ejecución del generador: %s"
generator.execution_success = "Generador ejecutado exitosamente: %s"
# Mensajes de Construcción
build.forced = "- Actualización forzada: Generando todo"
build.using_engine = "Usando el motor %s para archivos:"

View File

@ -1,209 +0,0 @@
# Générateur de Site Rapide 2 - Fichier de langue française
# Ce fichier contient toutes les chaînes visibles par l'utilisateur pour l'application
# Messages d'erreur
error.missing_dependencies = "Dépendances requises manquantes : %s"
error.config_validation_failed = "Échec de la validation de la configuration. Veuillez vérifier vos fichiers de configuration."
error.config_missing_key = "Configuration requise manquante : %s"
error.invalid_url = "site_url doit commencer par http:// ou https://"
error.directory_not_found = "Le répertoire n'existe pas : %s"
error.theme_not_found = "Répertoire du thème introuvable : %s"
error.theme_config_not_found = "Configuration du thème introuvable : %s"
error.theme_config_creation_failed = "Échec de la création de la configuration du thème : %s"
error.config_parse = "Échec de l'analyse du fichier de configuration : %s"
error.invalid_path = "Chemin invalide : %s"
error.write_failed = "Échec de l'écriture dans le fichier temporaire : %s"
error.move_failed = "Échec du déplacement du fichier temporaire vers : %s"
error.config_load_failed = "Échec du chargement du fichier de configuration : %s"
error.config_not_found = "Aucun fichier de configuration valide trouvé."
error.create_blog_index_failed = "Échec de la création de l'index du blog à : %s"
error.create_sample_post_failed = "Échec de la création d'un exemple d'article de blog à : %s"
error.create_sample_page_failed = "Échec de la création d'une page exemple à : %s"
error.engine_not_found = "Moteur introuvable ou non exécutable : %s"
error.unknown_generator = "Générateur inconnu : %s"
error.unknown_option = "Option inconnue : %s"
error.directory_not_empty = "Le répertoire '%s' existe déjà et n'est pas vide."
error.theme_creation_failed = "Échec de la création du thème : %s"
error.config_creation_failed = "Échec de la création du fichier de configuration : %s"
error.directory_creation_failed = "Échec de la création du répertoire : %s"
error.file_creation_failed = "Échec de la création du fichier : %s"
error.layout_creation_failed = "Échec de la création du fichier de mise en page : %s"
error.stylesheet_creation_failed = "Échec de la création de la feuille de style : %s"
error.script_creation_failed = "Échec de la création du fichier de script : %s"
# Messages d'avertissement
warning.optional_dependency = "L'outil optionnel '%s' est requis pour %s mais n'a pas été trouvé"
warning.dependency_version = "La version %s de %s est inférieure à la version recommandée %s"
warning.legacy_config = "Utilisation d'un fichier de configuration hérité. Envisagez de renommer '%s' en 'site.conf'"
warning.git_repo = "Attention : Exécution dans un répertoire de dépôt git. Assurez-vous que c'est intentionnel."
warning.outdated_dependencies = "Certaines dépendances ne sont pas à jour :"
# Messages d'information
info.legacy_config = "Attention : Utilisation du fichier hérité '%s'. Envisagez de le renommer en 'site.conf'"
info.legacy_config_used = "Utilisation du fichier de configuration hérité. Envisagez de renommer 'config' en 'site.conf'"
info.config_help = "Veuillez créer un fichier 'site.conf' dans votre répertoire de projet."
info.config_template = "Vous pouvez utiliser 'config.example' comme modèle."
info.git_repo_help = "Si vous souhaitez générer le site, exécutez depuis le répertoire racine du projet."
info.usage = "Utilisation : %s <commande> [options]"
info.engine_usage = "Utilisation : _run_engine <entrée>"
info.creating_blog_index = "Création du fichier d'index du blog..."
info.creating_sample_post = "Création d'un exemple d'article de blog..."
info.creating_sample_page = "Création d'une page exemple..."
info.setting_up_project = "Configuration de la structure du projet..."
info.creating_directories = "Création des répertoires du projet..."
info.initializing_blog = "Initialisation du blog..."
info.initializing_pages = "Initialisation des pages..."
info.initializing_theme = "Initialisation du thème..."
# Messages de débogage
debug.loading_config = "Chargement du fichier de configuration : %s"
debug.loaded_config = "=== Configuration Chargée ==="
debug.config_value = "%s : %s"
debug.config_end = "=========================="
debug.raw_config = "=== Fichier de Configuration Brut ==="
debug.raw_config_end = "================================"
debug.blog_cache_update = "Mise à jour du cache du blog à %s"
debug.blog_cache_bytes = "Cache du blog mis à jour avec %d octets"
debug.blog_cache_loading = "Chargement de l'index du blog depuis le cache"
debug.blog_cache_stale_new = "Cache du blog obsolète : Nouveaux blogs ou mises à jour détectés"
debug.blog_cache_stale_deleted = "Cache du blog obsolète : Blogs supprimés détectés"
debug.blog_cache_fresh = "Le cache du blog est à jour, reconstruction ignorée"
debug.blog_cache_rebuilding = "Reconstruction du cache du blog..."
debug.blog_cache_rebuilt = "Cache du blog reconstruit avec %d entrées"
debug.pages_cache_update = "Mise à jour du cache des pages à %s"
debug.pages_cache_bytes = "Cache des pages mis à jour avec %d octets"
debug.pages_cache_loading = "Chargement de l'index des pages depuis le cache"
debug.pages_cache_stale_new = "Cache des pages obsolète : Nouvelles pages ou mises à jour détectées"
debug.pages_cache_stale_deleted = "Cache des pages obsolète : Pages supprimées détectées"
debug.pages_cache_fresh = "Le cache des pages est à jour, reconstruction ignorée"
debug.pages_cache_rebuilding = "Reconstruction du cache des pages..."
debug.pages_cache_rebuilt = "Cache des pages reconstruit avec %d entrées"
debug.cache_hit = "Cache trouvé pour %s"
debug.cache_miss = "Cache manquant pour %s"
debug.cache_updated = "Cache mis à jour pour %s"
debug.cache_skipped = "Mise à jour du cache ignorée pour %s (aucun changement détecté)"
blog.cache_loading = "Chargement de l'index du blog depuis le cache"
blog.cache_stale = "Cache du blog obsolète, reconstruction..."
blog.cache_fresh = "Le cache du blog est à jour"
blog.post_updated = "Article de blog mis à jour : %s"
blog.post_skipped = "Ignoré (aucun changement) : %s"
# Blog Messages
blog.not_found = "Aucun fichier de blog trouvé."
blog.generating = "Génération du blog"
blog.no_template = "Impossible de trouver le modèle de blog : %s"
blog.cache_updated = "Cache du blog mis à jour"
blog.cache_loading = "Chargement de l'index du blog depuis le cache"
blog.cache_stale = "Cache du blog obsolète, reconstruction..."
blog.cache_fresh = "Le cache du blog est à jour"
blog.post_updated = "Article de blog mis à jour : %s"
blog.post_skipped = "Ignoré (aucun changement) : %s"
blog.post_error = "Erreur lors du traitement de l'article de blog : %s"
# Messages de Génération de Blog
blog.hello_world_title = "Bonjour le monde !"
blog.published_on = "Publié le"
blog.welcome_message = "Bienvenue sur votre nouveau blog ! Ceci est un exemple d'article de blog."
blog.getting_started = "Pour commencer"
blog.edit_this_post = "Vous pouvez modifier cet article à l'emplacement %s"
blog.features = "Fonctionnalités"
blog.feature_markdown = "Prise en charge du Markdown"
blog.feature_easy_customize = "Facile à personnaliser"
blog.feature_fast_lightweight = "Rapide et léger"
blog.next_steps = "Prochaines étapes"
blog.step_edit_post = "Modifier cet article"
blog.step_add_posts = "Ajouter plus d'articles"
blog.step_customize_theme = "Personnaliser votre thème"
blog.step_publish_site = "Publier votre site"
blog.happy_blogging = "Bon blogage !"
blog.latest_posts = "Derniers articles"
blog.sample_post = "Article de blog"
blog.categories = "Catégories"
blog.sample_category = "Catégorie"
blog.archives = "Archives"
blog.tags = "Étiquettes"
blog.about = "À propos"
blog.about_text = "Ceci est une page d'index de blog exemple. Vous pouvez la modifier à l'emplacement %s"
# Messages de Génération de Pages
page.about_me_title = "À propos de moi"
page.welcome_title = "Bienvenue sur mon site"
page.welcome_message = "Ceci est une page À propos exemple. Vous pouvez la modifier à l'emplacement %s"
page.my_story_title = "Mon histoire"
page.my_story_content = "Je suis un développeur passionné qui adore créer des sites web incroyables avec qsgen2 !"
page.skills_title = "Compétences"
page.skill_webdev = "Développement Web"
page.skill_design = "Design"
page.skill_opensource = "Logiciel Libre"
page.contact_title = "Contact"
page.contact_content = "Vous pouvez me contacter à : email@exemple.com"
page.about_site_title = "À propos de ce site"
page.about_site_content = "Ce site a été construit avec [qsgen2](https://github.com/kekePower/qsgen2)."
# Messages de Succès
success.config_loaded = "Configuration chargée avec succès"
success.build_complete = "Construction terminée avec succès"
success.blog_index_created = "Index du blog créé à l'emplacement : %s"
success.sample_post_created = "Exemple d'article de blog créé à l'emplacement : %s"
success.sample_page_created = "Page exemple créée à l'emplacement : %s"
success.project_initialized = "Projet initialisé avec succès !"
success.theme_initialized = "Thème initialisé avec succès !"
success.config_initialized = "Fichier de configuration créé avec succès !"
# Messages Système
system.created_by = "- Créé par kekePower - 2018-%s"
system.see_help = "- Voir '%s help' pour plus d'informations."
# Messages de Liste
list.pages_not_found = "_list_pages : Aucune page trouvée avec l'extension %s"
list.pages_adding = "_list_pages : Ajout du fichier au tableau : %s"
list.blogs_not_found = "_list_blogs : Aucun fichier de blog trouvé."
list.blogs_adding = "_list_blogs : Ajout du fichier au tableau : %s"
# Navigation
nav.home = "Accueil"
nav.blog = "Blog"
nav.about = "À propos"
# Pied de page
footer.all_rights_reserved = "Tous droits réservés."
# Configuration
config.site_config_title = "Configuration du Site"
config.theme_config_title = "Configuration du Thème"
config.site_name_default = "Mon Super Site"
config.site_tagline_default = "Un site statique généré avec qsgen2"
config.site_description_default = "Voici mon super site statique"
config.your_name = "Votre Nom"
config.theme_description = "Un thème personnalisé pour qsgen2"
config.theme_files_title = "Fichiers du thème (relatif au répertoire du thème)"
# CSS et JavaScript
css.main_styles = "Styles Principaux"
js.main_javascript = "JavaScript Principal"
js.console_message = "Bonjour depuis qsgen2 !"
js.add_custom_javascript = "Ajoutez votre code JavaScript personnalisé ici"
js.your_code_here = "Votre code ici"
# Messages de Dernière Mise à Jour
last_updated.setting = "_last_updated : Définition de la date et de la version dans le pied de page"
last_updated.file_not_found = "_f_last_updated : Fichier %s non trouvé."
# Pages Messages
pages.generating = "Génération des Pages"
pages.none = "* Vous n'avez aucune page *"
pages.no_template = "Impossible de trouver le modèle de page : %s"
# Messages Pandoc
pandoc.install = "Veuillez installer Pandoc."
pandoc.download = "https://github.com/jgm/pandoc/releases"
# Messages du Générateur
generator.not_found = "Aucun générateur valide trouvé. Êtes-vous sûr d'avoir sélectionné le bon générateur dans 'config' ?"
generator.using = "Utilisation du générateur : %s"
generator.not_found = "Générateur introuvable : %s"
generator.execution_failed = "Échec de l'exécution du générateur : %s"
generator.execution_success = "Générateur exécuté avec succès : %s"
# Messages de Construction
build.forced = "- Mise à jour forcée : Génération complète"
build.using_engine = "Utilisation du moteur %s pour les fichiers :"

View File

@ -1,217 +0,0 @@
# Quick Site Generator 2 - Norsk språkfil
# Denne filen inneholder alle brukervendte strenger for applikasjonen
# Feilmeldinger
error.missing_dependencies = "Mangler påkrevde avhengigheter: %s"
error.config_validation_failed = "Validering av konfigurasjon feilet. Vennligst sjekk konfigurasjonsfilene dine."
error.config_missing_key = "Mangler påkrevd konfigurasjon: %s"
error.invalid_url = "site_url må starte med http:// eller https://"
error.directory_not_found = "Mappen finnes ikke: %s"
error.theme_not_found = "Temamappe ikke funnet: %s"
error.theme_config_not_found = "Temakonfigurasjon ikke funnet: %s"
error.theme_config_creation_failed = "Kunne ikke opprette temakonfigurasjon: %s"
error.config_parse = "Kunne ikke tolke konfigurasjonsfil: %s"
error.invalid_path = "Ugyldig sti: %s"
error.write_failed = "Kunne ikke skrive til midlertidig fil: %s"
error.move_failed = "Kunne ikke flytte midlertidig fil til: %s"
error.config_load_failed = "Kunne ikke laste konfigurasjonsfil: %s"
error.config_not_found = "Ingen gyldig konfigurasjonsfil funnet."
error.create_blog_index_failed = "Kunne ikke opprette bloggindeks på: %s"
error.create_sample_post_failed = "Kunne ikke opprette eksempelinnlegg på: %s"
error.create_sample_page_failed = "Kunne ikke opprette eksempelside på: %s"
error.engine_not_found = "Motor ikke funnet eller ikke kjørbar: %s"
error.unknown_generator = "Ukjent generator: %s"
error.unknown_option = "Ukjent alternativ: %s"
error.directory_not_empty = "Mappen '%s' finnes allerede og er ikke tom."
error.theme_creation_failed = "Kunne ikke opprette tema: %s"
error.config_creation_failed = "Kunne ikke opprette konfigurasjonsfil: %s"
error.directory_creation_failed = "Kunne ikke opprette mappe: %s"
error.file_creation_failed = "Kunne ikke opprette fil: %s"
error.layout_creation_failed = "Kunne ikke opprette layoutfil: %s"
error.stylesheet_creation_failed = "Kunne ikke opprette stilark: %s"
error.script_creation_failed = "Kunne ikke opprette scriptfil: %s"
# Advarselsmeldinger
warning.optional_dependency = "Valgfritt verktøy '%s' kreves for %s, men ble ikke funnet"
warning.dependency_version = "%s versjon %s er lavere enn anbefalt versjon %s"
warning.legacy_config = "Bruker gammel konfigurasjonsfil. Vurder å endre navn på '%s' til 'site.conf'"
warning.git_repo = "Advarsel: Kjører i en git-mappe. Forsikre deg om at dette er meningen."
warning.outdated_dependencies = "Noen avhengigheter er utdaterte:"
# Informasjonsmeldinger
info.legacy_config = "Advarsel: Bruker gammel '%s'-fil. Vurder å endre navn til 'site.conf'"
info.legacy_config_used = "Bruker gammel konfigurasjonsfil. Vurder å endre navn fra 'config' til 'site.conf'"
info.config_help = "Vennligst opprett 'site.conf' i prosjektmappen din."
info.config_template = "Du kan bruke 'config.example' som en mal."
info.git_repo_help = "Hvis du vil generere nettsiden, kjør fra prosjektets rotmappe."
info.usage = "Bruk: %s <kommando> [alternativer]"
info.engine_usage = "Bruk: _run_engine <inndata>"
info.creating_blog_index = "Oppretter bloggindeksfil..."
info.creating_sample_post = "Oppretter eksempelinnlegg..."
info.creating_sample_page = "Oppretter eksempelside..."
info.setting_up_project = "Setter opp prosjektstruktur..."
info.creating_directories = "Oppretter prosjektmapper..."
info.initializing_blog = "Initialiserer blogg..."
info.initializing_pages = "Initialiserer sider..."
info.initializing_theme = "Initialiserer tema..."
info.initializing_config = "Initialiserer konfigurasjon..."
info.initializing_complete = "Initialisering fullført!"
info.initializing_aborted = "Initialisering avbrutt."
info.use_force_option = "Bruk --force for å overskrive den eksisterende mappen."
info.get_started_instructions = "For å komme i gang"
info.happy_coding = "Lykke til med kodingen!"
info.initializing_project = "Initialiserer prosjekt..."
info.initializing_blog_cache = "Initialiserer blogg-mellomlager..."
info.initializing_pages_cache = "Initialiserer side-mellomlager..."
# Feilsøkingsmeldinger
debug.loading_config = "Laster konfigurasjonsfil: %s"
debug.loaded_config = "=== Lastet Konfigurasjon ==="
debug.config_value = "%s: %s"
debug.config_end = "=========================="
debug.raw_config = "=== Rå Konfigurasjonsfil ==="
debug.raw_config_end = "========================"
debug.blog_cache_update = "Oppdaterer blogg-mellomlager på %s"
debug.blog_cache_bytes = "Blogg-mellomlager oppdatert med %d byte"
debug.blog_cache_loading = "Laster bloggindeks fra mellomlager"
debug.blog_cache_stale_new = "Blogg-mellomlager utdatert: Nye eller oppdaterte blogger oppdaget"
debug.blog_cache_stale_missing = "Blogg-mellomlager utdatert: Mellomlagerfilen finnes ikke"
debug.blog_cache_stale_old = "Blogg-mellomlager utdatert: Mellomlager er eldre enn 1 time"
debug.blog_cache_fresh = "Blogg-mellomlager er oppdatert"
debug.pages_cache_update = "Oppdaterer side-mellomlager på %s"
debug.pages_cache_bytes = "Side-mellomlager oppdatert med %d byte"
debug.pages_cache_loading = "Laster sideindeks fra mellomlager"
debug.pages_cache_stale_new = "Side-mellomlager utdatert: Nye eller oppdaterte sider oppdaget"
debug.pages_cache_stale_missing = "Side-mellomlager utdatert: Mellomlagerfilen finnes ikke"
debug.pages_cache_stale_old = "Side-mellomlager utdatert: Mellomlager er eldre enn 1 time"
debug.pages_cache_fresh = "Side-mellomlager er oppdatert"
# Bloggmeldinger
blog.not_found = "Ingen bloggfiler funnet."
blog.generating = "Genererer blogg"
blog.no_template = "Kunne ikke finne bloggmalen: %s"
blog.cache_updated = "Blogg-mellomlager oppdatert"
blog.cache_loading = "Laster blogg-mellomlager"
blog.cache_stale = "Blogg-mellomlager er utdatert, bygger på nytt..."
blog.cache_fresh = "Blogg-mellomlager er oppdatert"
blog.post_updated = "Oppdatert blogginnlegg: %s"
blog.post_skipped = "Hoppet over (ingen endringer): %s"
blog.post_error = "Feil ved behandling av blogginnlegg: %s"
# Blogg-genereringsmeldinger
blog.hello_world_title = "Hallo, verden!"
blog.published_on = "Publisert den"
blog.welcome_message = "Velkommen til din nye blogg! Dette er et eksempel på et blogginnlegg."
blog.getting_started = "Kom i gang"
blog.edit_this_post = "Du kan redigere dette innlegget på %s"
blog.features = "Funksjoner"
blog.feature_markdown = "Støtte for Markdown"
blog.feature_easy_customize = "Lett å tilpasse"
blog.feature_fast_lightweight = "Rask og lettvektig"
blog.next_steps = "Neste steg"
blog.step_edit_post = "Rediger dette innlegget"
blog.step_add_posts = "Legg til flere innlegg"
blog.step_customize_theme = "Tilpass temaet ditt"
blog.step_publish_site = "Publiser nettstedet ditt"
blog.happy_blogging = "Lykke til med bloggingen!"
blog.latest_posts = "Siste innlegg"
blog.sample_post = "Blogginnlegg"
blog.categories = "Kategorier"
blog.sample_category = "Kategori"
blog.archives = "Arkiv"
blog.tags = "Emneknagger"
blog.about = "Om"
blog.about_text = "Dette er en eksempelindeksside for bloggen. Du kan redigere den på %s"
# Sidegenereringsmeldinger
page.about_me_title = "Om meg"
page.welcome_title = "Velkommen til nettstedet mitt"
page.welcome_message = "Dette er en eksempel 'om'-side. Du kan redigere den på %s"
page.my_story_title = "Min historie"
page.my_story_content = "Jeg er en lidenskapelig utvikler som elsker å lage fantastiske nettsteder med qsgen2!"
page.skills_title = "Ferdigheter"
page.skill_webdev = "Nettutvikling"
page.skill_design = "Design"
page.skill_opensource = "Åpen kildekode"
page.contact_title = "Kontakt"
page.contact_content = "Du kan nå meg på: epost@eksempel.no"
page.about_site_title = "Om dette nettstedet"
page.about_site_content = "Dette nettstedet er bygget med [qsgen2](https://github.com/kekePower/qsgen2)."
# Suksessmeldinger
success.config_loaded = "Konfigurasjon lastet inn vellykket"
success.build_complete = "Bygging fullført vellykket"
success.blog_index_created = "Opprettet bloggindeks på: %s"
success.sample_post_created = "Opprettet eksempelblogginnlegg på: %s"
success.sample_page_created = "Opprettet eksempelside på: %s"
success.project_initialized = "Prosjektet er initialisert!"
success.theme_initialized = "Temaet er initialisert!"
success.config_initialized = "Konfigurasjonsfil opprettet!"
# Blogg-mellomlager meldinger
blog_cache.hash = "_blog_cache: HASH VERDI:"
blog_cache.current = "1. _blog_cache:"
blog_cache.cache_file = "2. _blog_cache: current_cache:"
blog_cache.new_cache = "3. _blog_cache: new_cache_file:"
blog_cache.new_current = "4. _blog_cache: new_current_cache:"
# Sider-mellomlager meldinger
page_cache.hash = "SIDER HASH VERDI:"
page_cache.current = "1. pages_cache:"
page_cache.cache_file = "2. _pages_cache: current_cache:"
page_cache.pages_file = "2. _pages_cache: pages_file:"
# Systemmeldinger
system.created_by = "- Laget av kekePower - 2018-%s"
system.see_help = "- Se '%s help' for mer informasjon."
# Listemeldinger
list.pages_not_found = "_list_pages: Ingen sider funnet med filendelse %s"
list.pages_adding = "_list_pages: Legger til fil i tabell: %s"
list.blogs_not_found = "_list_blogs: Ingen bloggfiler funnet."
list.blogs_adding = "_list_blogs: Legger til fil i tabell: %s"
# Navigasjon
nav.home = "Hjem"
nav.blog = "Blogg"
nav.about = "Om"
# Bunntekst
footer.all_rights_reserved = "Alle rettigheter reservert."
# Konfigurasjon
config.site_config_title = "Nettstedsinnstillinger"
config.theme_config_title = "Temainnstillinger"
config.site_name_default = "Mitt fantastiske nettsted"
config.site_tagline_default = "Et statisk nettsted generert med qsgen2"
config.site_description_default = "Dette er mitt fantastiske statiske nettsted"
config.your_name = "Ditt navn"
config.theme_description = "Et egendefinert tema for qsgen2"
config.theme_files_title = "Temafiler (relativ til temamappe)"
# CSS og JavaScript
css.main_styles = "Hovedstiler"
js.main_javascript = "Hoved-JavaScript"
js.console_message = "Hallo fra qsgen2!"
js.add_custom_javascript = "Legg til egendefinert JavaScript her"
js.your_code_here = "Din kode her"
# Sist oppdatert-meldinger
last_updated.setting = "_last_updated: Setter dato og versjon i bunntekst"
last_updated.file_not_found = "_f_last_updated: Filen %s ble ikke funnet."
# Pages Messages
pages.generating = "Genererer sider"
pages.none = "* Du har ingen sider *"
pages.no_template = "Kunne ikke finne sidemalen: %s"
# Pandoc Messages
pandoc.install = "Please install Pandoc."
pandoc.download = "https://github.com/jgm/pandoc/releases"
# Generator Messages
generator.not_found = "No valid generator found. Are you sure you've selected the correct generator in 'config'?"
# Build Messages
build.forced = "- Forced Update: Generating Everything"
build.using_engine = "Using the %s -engine for files:"

47
layouts/index.html Normal file
View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$site_name$ - $site_tagline$</title>
$for(css)$
<link rel="stylesheet" href="$css$">
$endfor$
$if(site_rss_url)$
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="$site_rss_url$">
$endif$
</head>
<body>
<header>
<h1><a href="$site_url$">$site_name$</a></h1>
<p>$site_tagline$</p>
</header>
<main>
<section id="posts-list">
<h2>Latest Posts</h2>
$if(posts)$
<ul>
$for(posts)$
<li>
<h3><a href="$posts.url$">$posts.title$</a></h3>
$if(posts.date)$
<p class="date">$posts.date$</p>
$endif$
$if(posts.summary)$
<p>$posts.summary$</p>
$endif$
</li>
$endfor$
</ul>
$else$
<p>No posts found.</p>
$endif$
</section>
</main>
<footer>
<p>&copy; $current_year$ $site_name$. Generated by qsgen3.</p>
</footer>
</body>
</html>

32
layouts/page.html Normal file
View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$site_name$ - $title$</title>
<meta name="description" content="$description$"> <!-- Add description to frontmatter -->
<link rel="stylesheet" href="/static/css/style.css"> <!-- Assuming site served from root -->
$for(css)$
<link rel="stylesheet" href="$css$">
$endfor$
$if(math)$ $math$ $endif$
</head>
<body>
<header>
<h1><a href="/">$site_name$</a></h1>
<p>$site_tagline$</p>
</header>
<main>
<article>
<header>
<h1>$title$</h1>
</header>
$body$
</article>
</main>
<footer>
<p>&copy; $current_year$ $site_name$. Generated by qsgen3.</p>
<p><a href="$site_url$">$site_url$</a></p>
</footer>
</body>
</html>

39
layouts/post.html Normal file
View File

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$site_name$ - $title$</title>
<meta name="author" content="$author$">
<meta name="description" content="$description$"> <!-- Add description to frontmatter -->
$if(date)$<meta name="date" content="$date$">$endif$
$for(css)$
<link rel="stylesheet" href="$css$">
$endfor$
$if(math)$ $math$ $endif$
</head>
<body>
<header>
<h1><a href="/">$site_name$</a></h1>
<p>$site_tagline$</p>
</header>
<main>
<article>
<header>
<h1>$title$</h1>
$if(author)$
<p class="author">By: $author$</p>
$endif$
$if(date)$
<p class="date">Published: $date$</p>
$endif$
</header>
$body$
</article>
</main>
<footer>
<p>&copy; $current_year$ $site_name$. Generated by qsgen3. </p>
<p><a href="$site_url$">$site_url$</a></p>
</footer>
</body>
</html>

24
layouts/rss.xml Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>$site_name$</title>
<link>$site_url$</link>
<description>$site_tagline$</description>
<language>en-us</language>
<lastBuildDate>$rfc_2822_date$</lastBuildDate>
<atom:link href="$site_url$/rss.xml" rel="self" type="application/rss+xml" />
$if(posts)$
$for(posts)$
<item>
<title>$it.post_title$</title>
<link>$it.post_url$</link>
<pubDate>$it.post_rfc_2822_date$</pubDate>
<guid isPermaLink="true">$it.post_url$</guid>
<description><![CDATA[$it.post_summary$]]></description>
</item>
$endfor$
$endif$
</channel>
</rss>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 620 KiB

2275
qsgen3

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,288 @@
import re
import argparse
from pathlib import Path
# Tags that will be kept as HTML as they don't have direct Markdown equivalents
HTML_PASSTHROUGH_TAGS = {
"#DV": "<div>", "#EDV": "</div>",
"#SPN": "<span>", "#ESPN": "</span>",
"#TBL": "<table>", "#ETBL": "</table>",
"#TR": "<tr>", "#ETR": "</tr>",
"#TD": "<td>", "#ETD": "</td>",
"#TH": "<th>", "#ETH": "</th>",
"#ART": "<article>", "#EART": "</article>",
"#SEC": "<section>", "#ESEC": "</section>",
"#ASIDE": "<aside>", "#EASIDE": "</aside>",
"#NAV": "<nav>", "#ENAV": "</nav>",
"#BTN": "<button>", "#EBTN": "</button>",
"#SEL": "<select>", "#ESEL": "</select>",
"#OPT": "<option>", "#EOPT": "</option>",
}
def sanitize_filename(name):
"""Sanitizes a string to be a valid filename."""
name = name.lower()
name = re.sub(r'\s+', '-', name) # Replace spaces with hyphens
name = re.sub(r'[^a-z0-9\-_.]', '', name) # Remove unwanted characters
name = re.sub(r'-+', '-', name) # Replace multiple hyphens with single
name = name.strip('-_')
return name if name else "untitled"
def convert_qstags_to_markdown(content):
"""Converts qstags in content to Markdown syntax."""
# Start with a copy to modify
md_content = content
# Links: #link URL¤TEXT¤ -> [TEXT](URL)
md_content = re.sub(r'#link\s+([^¤]+)¤([^¤]+)¤', r'[\2](\1)', md_content)
# Headings: #H1...#EH1 -> # ..., etc.
for i in range(6, 0, -1):
# Regex to capture content between #Hi and #EHi, case insensitive, dotall for newlines
# Makes #EHi optional if it's at the end of a section or file.
md_content = re.sub(r"#H{i}(.*?)(?:#EH{i}|$)".format(i=i),
r"{} \1".format("#"*i),
md_content, flags=re.IGNORECASE | re.DOTALL)
# Clean up potential multiple newlines left by DOTALL capture if content was multi-line
md_content = re.sub(r"({} .*?)\n\n".format("#"*i), r"\1\n", md_content)
# Blockquotes: #Q...#EQ -> > ...
# This is a simplified approach. For multi-line blockquotes, each line needs '>' prefix.
# We'll capture the content and then process it line by line.
def replace_blockquote(match):
inner_content = match.group(1).strip()
lines = inner_content.split('\n')
return '\n'.join([f"> {line}" for line in lines]) + '\n'
md_content = re.sub(r"#Q(.*?)(?:#EQ|$)", replace_blockquote, md_content, flags=re.IGNORECASE | re.DOTALL)
# Ordered Lists: #OL ... #LI ... #ELI ... #EOL
def replace_ordered_list(match_ol):
ol_content = match_ol.group(1).strip()
list_item_texts = re.findall(r"^[ \t]*#LI[ \t]*(.*?)[ \t]*(?:#ELI)?\s*$", ol_content, flags=re.IGNORECASE | re.MULTILINE)
processed_items = []
for i, item_text in enumerate(list_item_texts):
processed_items.append(f"{i + 1}. {item_text.strip()}")
return "\n".join(processed_items) + ("\n" if processed_items else "")
md_content = re.sub(r"^[ \t]*#OL[ \t]*\n(.*?)\n^[ \t]*#EOL[ \t]*$", replace_ordered_list, md_content, flags=re.IGNORECASE | re.DOTALL | re.MULTILINE)
# Unordered Lists: #UL ... #LI ... #ELI ... #EUL
def replace_unordered_list(match_ul):
ul_content = match_ul.group(1).strip()
list_item_texts = re.findall(r"^[ \t]*#LI[ \t]*(.*?)[ \t]*(?:#ELI)?\s*$", ul_content, flags=re.IGNORECASE | re.MULTILINE)
processed_items = []
for item_text in list_item_texts:
processed_items.append(f"- {item_text.strip()}")
return "\n".join(processed_items) + ("\n" if processed_items else "")
md_content = re.sub(r"^[ \t]*#UL[ \t]*\n(.*?)\n^[ \t]*#EUL[ \t]*$", replace_unordered_list, md_content, flags=re.IGNORECASE | re.DOTALL | re.MULTILINE)
# Remove any stray #ELI tags if they weren't consumed by the #LI regex (unlikely but for cleanup)
md_content = re.sub(r"^[ \t]*#ELI[ \t]*$", "", md_content, flags=re.IGNORECASE | re.MULTILINE)
# Paragraphs: Remove #P, replace #EP with a newline to help separate blocks.
# Markdown relies on blank lines between paragraphs.
md_content = re.sub(r"#P\s*", "", md_content, flags=re.IGNORECASE)
md_content = re.sub(r"\s*#EP", "\n", md_content, flags=re.IGNORECASE)
# Inline elements
md_content = re.sub(r"#BD(.*?)#EBD", r"**\1**", md_content, flags=re.IGNORECASE)
md_content = re.sub(r"#STRONG(.*?)#ESTRONG", r"**\1**", md_content, flags=re.IGNORECASE)
md_content = re.sub(r"#I(.*?)#EI", r"*\1*", md_content, flags=re.IGNORECASE)
md_content = re.sub(r"#EM(.*?)#SEM", r"*\1*", md_content, flags=re.IGNORECASE) # Assuming #SEM is end tag for emphasis
md_content = re.sub(r"#C(.*?)#EC", r"`\1`", md_content, flags=re.IGNORECASE)
md_content = re.sub(r"#UD(.*?)#EUD", r"\1", md_content, flags=re.IGNORECASE) # Markdown has no underline, strip tags
# Images: #showimg IMAGE_PATH¤ALT_TEXT¤ -> ![ALT_TEXT](PROCESSED_IMAGE_PATH)
def process_image_path_for_markdown(raw_path):
if raw_path.startswith(('http://', 'https://', '/')):
return raw_path
else:
return f"/images/{raw_path}"
def replace_showimg_to_markdown(match):
raw_path = match.group(1)
alt_text = match.group(2)
processed_path = process_image_path_for_markdown(raw_path)
return f"![{alt_text}]({processed_path})"
md_content = re.sub(r'#showimg\s+([^¤]+)¤([^¤]+)¤', replace_showimg_to_markdown, md_content)
# Linked Images: #linkimg IMAGE_PATH¤ALT_TEXT¤ -> [![ALT_TEXT](PROCESSED_IMAGE_PATH)](PROCESSED_IMAGE_PATH)
def replace_linkimg_to_markdown(match):
raw_path = match.group(1)
alt_text = match.group(2)
processed_path = process_image_path_for_markdown(raw_path) # Reusing the same path processor
return f"[![{alt_text}]({processed_path})]({processed_path})"
md_content = re.sub(r'#linkimg\s+([^¤]+)¤([^¤]+)¤', replace_linkimg_to_markdown, md_content)
# YouTube Videos: #ytvideo YOUTUBE_ID -> HTML iframe
def replace_ytvideo_to_html(match):
video_id = match.group(1)
return f'<iframe width="560" height="315" src="https://www.youtube.com/embed/{video_id}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>'
md_content = re.sub(r'#ytvideo\s+([A-Za-z0-9_\-]+)', replace_ytvideo_to_html, md_content)
# Line break: #BR -> two spaces + newline
md_content = md_content.replace("#BR", " \n")
# HTML Entities (these are fine as is, Markdown supports them)
md_content = md_content.replace("#LT", "&lt;")
md_content = md_content.replace("#GT", "&gt;")
md_content = md_content.replace("#NUM", "&num;")
# Passthrough HTML for tags without direct Markdown equivalents
for qstag, html_tag in HTML_PASSTHROUGH_TAGS.items():
md_content = md_content.replace(qstag, html_tag)
# Final cleanup:
# Normalize multiple blank lines to a single blank line (Markdown standard for paragraph separation)
md_content = re.sub(r"\n\s*\n", "\n\n", md_content)
# Remove leading/trailing whitespace from the whole content
md_content = md_content.strip()
return md_content
def process_blog_file(file_path, output_dir_base):
"""Processes a .blog file and creates a new Markdown file."""
print(f"Processing blog file: {file_path}")
content_lines = file_path.read_text().splitlines()
metadata = {
"title": "Untitled Post",
"date": "",
"layout": "post",
"author": "Anonymous"
}
body_content = []
# Extract date from filename (e.g., 20250530-3.blog)
match_date_filename = re.match(r'(\d{8})-\d+\.blog', file_path.name)
if match_date_filename:
date_str = match_date_filename.group(1)
metadata['date'] = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}"
else:
print(f" [WARN] Could not parse date from filename: {file_path.name}. Skipping date.")
parsing_ingress = False
parsing_body = False
for line in content_lines:
if line.startswith("DATE "):
# DATE field in file is secondary to filename date for posts
pass
elif line.startswith("BLOG_TITLE "):
metadata['title'] = line.replace("BLOG_TITLE ", "", 1).strip()
elif line.strip() == "#INGRESS_START":
parsing_ingress = True
continue
elif line.strip() == "#INGRESS_STOP":
parsing_ingress = False
continue
elif line.strip() == "#BODY_START":
parsing_body = True
continue
elif line.strip() == "#BODY_STOP":
parsing_body = False
continue
if parsing_ingress or parsing_body:
body_content.append(line)
markdown_body = convert_qstags_to_markdown("\n".join(body_content))
escaped_title = metadata['title'].replace('"', '\\"') # Escape for YAML
frontmatter = [
"---",
f'title: "{escaped_title}"', # Use single quotes for f-string, double for YAML value
f"date: {metadata['date']}",
f"layout: {metadata['layout']}",
f"author: {metadata['author']}",
"---",
""
]
output_content = "\n".join(frontmatter) + markdown_body
sanitized_title = sanitize_filename(metadata['title'])
if not metadata['date']:
# Fallback if date couldn't be parsed, though unlikely for .blog files
output_subdir = Path(output_dir_base) / "blog"
else:
# Put all blog posts in a single directory instead of year/month/day structure
output_subdir = Path(output_dir_base) / "blog"
output_subdir.mkdir(parents=True, exist_ok=True)
output_file_path = output_subdir / f"{sanitized_title}.md"
output_file_path.write_text(output_content)
print(f" -> Created: {output_file_path}")
def process_qst_file(file_path, output_dir_base):
"""Processes a .qst file and creates a new Markdown file."""
print(f"Processing page file: {file_path}")
content_lines = file_path.read_text().splitlines()
metadata = {
"title": "Untitled Page",
"layout": "page",
"author": "Anonymous" # Added for consistency
}
body_content_lines = []
if content_lines and content_lines[0].startswith("#title="):
metadata['title'] = content_lines[0].replace("#title=", "", 1).strip()
body_content_lines = content_lines[1:]
else:
print(f" [WARN] No #title= found in {file_path.name}. Using filename as title.")
metadata['title'] = file_path.stem
body_content_lines = content_lines
markdown_body = convert_qstags_to_markdown("\n".join(body_content_lines))
escaped_title = metadata['title'].replace('"', '\\"') # Escape for YAML
frontmatter = [
"---",
f'title: "{escaped_title}"', # Use single quotes for f-string, double for YAML value
f"layout: {metadata['layout']}",
f"author: {metadata['author']}",
"---",
""
]
output_content = "\n".join(frontmatter) + markdown_body
sanitized_title = sanitize_filename(metadata['title'])
# Pages go into the root of the output_dir_base (e.g. content/)
output_file_path = Path(output_dir_base) / f"{sanitized_title}.md"
output_file_path.write_text(output_content)
print(f" -> Created: {output_file_path}")
def main():
parser = argparse.ArgumentParser(description="Migrate qsgen2 (.blog, .qst) files to qsgen3 Markdown format.")
parser.add_argument("--source-dir", required=True, help="Directory containing old .blog and .qst files.")
parser.add_argument("--output-dir", required=True, help="Directory to save new Markdown files (e.g., your qsgen3 'content' directory).")
args = parser.parse_args()
source_path = Path(args.source_dir)
output_path = Path(args.output_dir)
if not source_path.is_dir():
print(f"Error: Source directory '{source_path}' not found or not a directory.")
return
output_path.mkdir(parents=True, exist_ok=True)
print(f"Source directory: {source_path.resolve()}")
print(f"Output directory: {output_path.resolve()}")
for item in source_path.rglob('*'): # rglob to find in subdirectories too, if any
if item.is_file():
if item.name.endswith(".blog"):
process_blog_file(item, output_path)
elif item.name.endswith(".qst"):
process_qst_file(item, output_path)
print("\nMigration complete.")
if __name__ == "__main__":
main()

22
site.conf Normal file
View File

@ -0,0 +1,22 @@
# Site Configuration for qsgen3
# --- Site Metadata ---
site_name="My Awesome Site"
site_tagline="A brief description of my site"
site_url="http://localhost:8000"
site_theme="minimal"
site_theme_css_file="css/style.css"
# --- Paths ---
paths_content_dir="content"
paths_output_dir="output"
paths_layouts_dir="layouts"
paths_static_dir="static"
# --- Build Options ---
build_options_generate_rss=true
build_options_generate_sitemap=true
build_options_process_drafts=false
build_options_minify_html=true
build_options_minify_css=true
build_options_minify_xml=true

View File

@ -1,26 +1,44 @@
; Place this file in your project directory
# Example Site Configuration for qsgen3
# Copy this file to 'site.conf' in your project root and customize it.
[site]
; This is the name of your site
name = "The Site Name"
; This is the tagline
tagline = "The Site Tagline"
; This is the URL of your site
url = "https://www.example.com"
; This is where your HTML files go
root = /path/to/www/dir
; The theme of your site
theme = theme_name
; sitemap or not: true or false
sitemap = true
; Do you want the blog to appear on the front page
; true = yes and false = no
blog = true
# --- Site Metadata ---
# These settings define general information about your site.
site_name="My Example Site" # The main title of your website, used in page titles, headers, and RSS feed.
site_tagline="An example site generated by qsgen3" # A short description or subtitle for your site, often used in meta tags or headers.
site_url="http://localhost:8000" # Full base URL of your site (e.g., https://www.example.com). Essential for generating correct absolute links in RSS feeds, sitemaps, etc.
site_theme="minimal" # Name of the theme directory located under your project's 'themes/' folder (e.g., "minimal", "custom-theme").
site_theme_css_file="css/minimaltemplate-v1.css" # Path to the theme's main CSS file, relative to the THEME'S 'static/' directory (e.g., "css/style.css", "main.css").
[project]
; This is where you work before you generate the output
root = /path/to/working/project
; Languages: en_US, en_UK, es_ES, nb_NO, fr_FR
lang = en_US
; Use QStags (native) or Markdown (markdown)
generator = native
# --- Paths ---
# Define the directory structure for your project.
# Paths are relative to your project's root directory (where site.conf is) unless an absolute path (starting with '/') is provided.
paths_content_dir="content" # Directory containing your Markdown content files (posts, pages).
paths_output_dir="output" # Directory where the generated static website will be written.
paths_layouts_dir="layouts" # Directory containing global HTML layout templates (e.g., post.html, page.html, index.html) used by Pandoc.
paths_static_dir="static" # Project's root directory for global static assets (images, CSS, JS) that are not theme-specific.
# These are copied to the output's static folder. Theme static files take precedence in case of name conflicts.
# --- Build Options ---
# Control various aspects of the site generation process.
build_options_generate_rss=true # Generate an RSS feed for your posts. Set to 'true' to enable, 'false' to disable.
# The feed will be available at /rss.xml.
build_options_generate_sitemap=true # Generate a sitemap.xml. Set to 'true' to enable, 'false' to disable.
# Note: Sitemap generation is a basic implementation. The sitemap will be at /sitemap.xml.
build_options_process_drafts=false # Process draft posts/pages. Set to 'true' to include content marked as 'draft: true' in its frontmatter,
# 'false' to exclude them from the build.
# --- Minification Options ---
# Control file minification to reduce file sizes and improve site loading performance.
build_options_minify_html=false # Minify HTML files by removing comments, extra whitespace, and empty lines.
# Set to 'true' to enable HTML minification, 'false' to disable.
# Typical size reduction: 25-35%.
build_options_minify_css=false # Minify CSS files by removing comments, whitespace, and optimizing syntax.
# Set to 'true' to enable CSS minification, 'false' to disable.
# Typical size reduction: 5-15%.
build_options_minify_xml=false # Minify XML files (RSS feeds, sitemaps) by removing comments and extra whitespace.
# Set to 'true' to enable XML minification, 'false' to disable.
# Typical size reduction: 5-10%.

View File

@ -1,70 +0,0 @@
<!-- This is the beginning of the HEADER -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>#sitename - Blog</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="/css/dark.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/css/cal-icon.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/css/blog.css" media="screen" />
<link rel="shortcut icon" href="/images/favicon-kekepower-transparent.png" type="image/png" />
</head>
<body>
<div id="wrap">
<div id="header">
<table border=0>
<tr>
<td id="logo">
<a href="/"><img src="/images/favicon-kekepower-transparent.png" height="75"></a>
</td>
<td id="sitetitle">
<h1><a href="/">#sitename</a></h1>
<h2>#tagline</h2>
</td>
</tr>
</table>
</div>
<div id="topmenu">
<a href="https://mageia.org/">Mageia</a> |
<a href="https://kernel.org/">Linux Kernel</a> |
<a href="https://kodi.tv/">Kodi Mediacenter</a> |
<a href="https://slashdot.org/">Slashdot</a> |
<a href="https://distrowatch.com/">Distrowatch</a> |
<a href="https://github.com/">Github</a>
</div>
<div id="right">
<!-- This is the end of the HEADER -->
<!-- Body Start -->
BODY
<!-- Body End -->
<!-- This is the beginning of the FOOTER -->
</div> <!-- End of div right -->
<div id="bottomleft">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/kekePower.html">About Me</a></li>
<li><a href="/hardware.html">My Hardware</a></li>
<li><a href="/mageia.html">Mageia Info</a></li>
<li><a href="/linux.html">Linux</a></li>
<!-- <li><a href="/blog/index.html">My Blog</a></li> -->
</ul>
<div id="generated">
#updated
</div>
</div>
</body>
</html>
<!-- This is the end of the FOOTER -->

View File

@ -1,26 +0,0 @@
<!-- Blog List Start -->
<br />
<div class="blog">
<div class="blogtitle"><a class="blogtitle" href="BLOGURL">BLOGTITLE</a></div>
<div class="blogcontent">
<div class="cal-icon">
<div class="datetime">
<div class="caltop"><p>CALADAY</p></div>
<p class="day">CALNDAY</p>
<p class="mon">CALMONTH</p>
<p class="yr">CALYEAR</p>
</div>
</div>
</div>
<div class="blogingress" id="ingress">
<br />
INGRESS
</div>
</div>
<!-- Blog List End -->

View File

@ -1,88 +0,0 @@
<!-- This is the beginning of the HEADER -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>#sitename - BLOGTITLE</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="/css/dark.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/css/cal-icon.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/css/blog.css" media="screen" />
<link rel="shortcut icon" href="/images/favicon-kekepower-transparent.png" type="image/png" />
</head>
<body>
<div id="wrap">
<div id="header">
<table border=0>
<tr>
<td id="logo">
<a href="/"><img src="/images/favicon-kekepower-transparent.png" height="75"></a>
</td>
<td id="sitetitle">
<h1><a href="/">#sitename</a></h1>
<h2>#tagline</h2>
</td>
</tr>
</table>
</div>
<div id="topmenu">
<a href="https://mageia.org/">Mageia</a> |
<a href="https://kernel.org/">Linux Kernel</a> |
<a href="https://kodi.tv/">Kodi Mediacenter</a> |
<a href="https://slashdot.org/">Slashdot</a> |
<a href="https://distrowatch.com/">Distrowatch</a> |
<a href="https://github.com/">Github</a>
</div>
<div id="right">
<!-- This is the end of the HEADER -->
<!-- Blog Content Start -->
<div class="blog">
<div class="blogtitle">BLOGTITLE</div>
<div class="blogcontent">
<div class="cal-icon">
<div class="datetime">
<div class="caltop"><p>CALADAY</p></div>
<p class="day">CALNDAY</p>
<p class="mon">CALMONTH</p>
<p class="yr">CALYEAR</p>
</div>
</div>
</div>
<div class="blogingress">
<br />
INGRESS
</div>
<div class="blogbody">
BODY
</div>
</div> <!-- End blog content -->
<!-- This is the beginning of the FOOTER -->
</div> <!-- End of div right -->
<div id="bottomleft">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/kekePower.html">About Me</a></li>
<li><a href="/hardware.html">My Hardware</a></li>
<li><a href="/mageia.html">Mageia Info</a></li>
<li><a href="/linux.html">Linux</a></li>
<!-- <li><a href="/blog/index.html">My Blog</a></li> -->
</ul>
<div id="generated">
#updated
</div>
</div>
</body>
</html>
<!-- This is the end of the FOOTER -->

View File

@ -1,93 +0,0 @@
div.blog {
border-left: 1px groove #ccc;
padding-left: 1px;
width: 100%;
float: right;
color: white;
font-size: 14px;
/* margin-left: 50px; */
}
div.blogtitle {
/* background: url(/images/round_corner.png) top right no-repeat;
background-size: 37px; */
border-top-right-radius: 10px;
border-bottom-left-radius: 10px;
padding: 3px;
margin-left: 2.1em;
background-color: #444;
font-size: 20px;
}
div.blogtitle a {
text-decoration: none !important;
}
div.blogcontent{
padding: 3px;
float: left;
width: 45px;
color: white;
height: 5em;
}
div.cal-icon {
text-align: center;
width: 40px;
float: left;
}
div.blogcontent div.blogingress {
/* font-size: 14px; */
color: white !important;
float: left;
width: 94%;
padding-left: 5px;
padding-top: 5px;
margin-left: 5px;
height: 5em;
}
div.blogbody {
border-top-right-radius: 20px;
border-bottom-left-radius: 20px;
background-color: #222;
font-size: 14px;
float: left;
padding-bottom: 10px;
padding-top: 10px;
margin-left: 3.5em;
padding-left: 5px;
/* color: white !important; */
width: 94%;
}
div.blogbody, img {
float:left;
}
img.exticon {
float: none !important;
}
div.blogingress img {
width: 100px !important;
float: left;
padding-right: 5px;
padding-bottom: 5px;
}
div.right h2 {
font-size: 26px;
}
#logo td {
align: center;
height: 75px;
}
#sitetitle td {
align: left;
height: 75px;
text-align: left;
vertical-align: middle;
padding-left: 15px;
}
#libody td {
padding-left: 35px;
}

View File

@ -1,26 +0,0 @@
div.datetime .caltop p {
font:bold x-small/100% Georgia, "New Century Schoolbook", "Book Antiqua", "Times New Roman", serif;
letter-spacing:0.12em;
text-transform:uppercase;
color:#fefefe !important;
background-color: #222; /* #2f4765; */
}
/* day of the month (NUMBER) */
div.datetime p.day {
font:bold 1.5em/98% Georgia, "New Century Schoolbook", "Book Antiqua", "Times New Roman", serif !important;
letter-spacing:0.13em;
}
/* month */
div.datetime p.mon {
font:x-small/135% Verdana,Geneva,Arial,Helvetica,sans-serif !important;
letter-spacing:normal;
text-transform:uppercase;
}
/* year */
div.datetime p.yr {
font:x-small/110% Verdana,Geneva,Arial,Helvetica,sans-serif;
letter-spacing:0.05em;
}

View File

@ -1,175 +0,0 @@
* {
padding: 0;
margin: 0;
}
body {
font: 1em Arial, Helvetica, sans-serif;
background: #111;
}
h2 {
font-size: 1em;
}
a {
color: #FF9621;
}
#wrap {
margin: 20px auto;
width: 90%;
background: #111;
}
#header {
/* background: url(/images/dark_header_bg.png) top right no-repeat;
background-size: 100px; */
height: 70px;
margin: 0;
padding: 0;
}
#header h1 {
margin: 0;
padding-left: 1px;
padding-top: 12px;
font-size: 1.1em;
color: #FF9621;
}
#header h1 a {
font-size: 1.1em;
color: #FF9621;
text-decoration: none;
}
#header h2 {
margin: 0;
padding-left: 1px;
padding-top: 0px;
font-size: .8em;
color: #fff;
}
#right h2 {
margin: 0;
padding-left: 1px;
padding-top: 0px;
font-size: 26px;
color: #fff;
}
#topmenu a {
color: #FFF;
text-decoration: none;
line-height: 22px;
}
#topmenu a:hover {
color: #aaa;
}
#topmenu a:visited {
color: #ddd;
}
#topmenu {
border-top-right-radius: 10px;
background-color: #222;
font: .8em "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
text-align: center;
background: #444;
margin-bottom: 5px;
color: #fff;
height: 22px;
}
#right {
font: .8em "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
float: right;
width: 82%;
margin-top: 5px;
margin-left: 10px;
color: #f4f4f4;
/* border: 1px solid white; */
height: auto;
}
#left {
font: .8em "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
width: 14%;
padding: 1px;
line-height: 1.4em;
}
#bottomleft {
font: .8em "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
width: 16%;
padding: 1px;
line-height: 1.4em;
}
#left li {
list-style-type: none;
border-bottom: 1px dotted #fff;
}
#left li a {
text-decoration: none;
}
#left li a:hover {
color : #FFEB31;
}
#bottomleft li {
list-style-type: none;
border-bottom: 1px dotted #fff;
}
#bottomleft li a {
text-decoration: none;
}
#bottomleft li a:hover {
color : #FFEB31;
}
#generated {
background: #222;
text-align: center;
margin-top: 15px;
color: #eee;
height: auto;
line-height: 20px;
padding: 3px;
font-size: 10px;
font-style: italic;
}
blockquote {
background-color: #222;
color: #EEE;
font-size: 14px;
border-left: 1px solid white;
padding-left: 0.5em;
display: block;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 40px;
margin-right: 40px;
}
blockquote img {
float: none !important;
}
blockquote ol {
font-family: "Times New Roman";
font-size: 16px;
line-height: 1.1em;
padding-bottom: 10px;
padding-top: 10px;
padding-left: 35px;
}
blockquote ul {
padding-bottom: 10px;
padding-top: 10px;
padding-left: 25px;
}
img.exturl {
position: absolute !important;
bottom: 0 !important;
}

View File

@ -1,70 +0,0 @@
<!-- This is the beginning of the HEADER -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>#sitename - #pagetitle</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="/css/dark.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/css/cal-icon.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/css/blog.css" media="screen" />
<link rel="shortcut icon" href="/images/favicon-kekepower-transparent.png" type="image/png" />
</head>
<body>
<div id="wrap">
<div id="header">
<table border=0>
<tr>
<td id="logo">
<a href="/"><img src="/images/favicon-kekepower-transparent.png" height="75"></a>
</td>
<td id="sitetitle">
<h1><a href="/">#sitename</a></h1>
<h2>#tagline</h2>
</td>
</tr>
</table>
</div>
<div id="topmenu">
<a href="https://mageia.org/">Mageia</a> |
<a href="https://kernel.org/">Linux Kernel</a> |
<a href="https://kodi.tv/">Kodi Mediacenter</a> |
<a href="https://slashdot.org/">Slashdot</a> |
<a href="https://distrowatch.com/">Distrowatch</a> |
<a href="https://github.com/">Github</a>
</div>
<div id="right">
<!-- This is the end of the HEADER -->
<!-- Body Start -->
BODY
<!-- Body End -->
<!-- This is the beginning of the FOOTER -->
</div> <!-- End of div right -->
<div id="bottomleft">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/kekePower.html">About Me</a></li>
<li><a href="/hardware.html">My Hardware</a></li>
<li><a href="/mageia.html">Mageia Info</a></li>
<li><a href="/linux.html">Linux</a></li>
<!-- <li><a href="/blog/index.html">My Blog</a></li> -->
</ul>
<div id="generated">
#updated
</div>
</div>
</body>
</html>
<!-- This is the end of the FOOTER -->

49
themes/minimal/README.md Normal file
View File

@ -0,0 +1,49 @@
# Minimal Theme for qsgen3
A clean, minimal theme that demonstrates the proper qsgen3 theme structure.
## Features
- Clean, modern design
- Responsive layout
- Semantic HTML structure
- Accessible typography
- Fast loading
## Structure
```
themes/minimal/
├── layouts/ # Complete set of Pandoc 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 # Main theme stylesheet
```
## Usage
1. Set in your `site.conf`:
```
site_theme="minimal"
site_theme_css_file="css/style.css"
```
2. Run qsgen3:
```bash
./bin/qsgen3
```
## Customization
- Edit `static/css/style.css` to modify the visual appearance
- Modify layout templates in `layouts/` to change HTML structure
- Add JavaScript files to `static/js/` and reference them in templates
## Browser Support
- Modern browsers (Chrome 90+, Firefox 88+, Safari 14+)
- Graceful degradation for older browsers

View File

@ -1,131 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>#sitename - Blog</title>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<meta content="Webflow" name="generator"/>
<link href="/css/minimaltemplate-v1.css" rel="stylesheet" type="text/css"/>
<script src="/css/webfont.js" type="text/javascript">
</script>
<script type="text/javascript">WebFont.load({ google: { families: ["Vollkorn:400,400italic,700,700italic","Montserrat:100,100italic,200,200italic,300,300italic,400,400italic,500,500italic,600,600italic,700,700italic,800,800italic,900,900italic","Oswald:200,300,400,500,600,700"] }});</script>
<script type="text/javascript">
!function(o,c){var n=c.documentElement,t=" w-mod-";n.className+=t+"js",("ontouchstart"in o||o.DocumentTouch&&c instanceof DocumentTouch)&&(n.className+=t+"touch")}(window,document);
</script>
<link href="/images/el-vikingo-ti.png" rel="shortcut icon" type="image/png"/>
<link href="/images/el-vikingo-ti.png" rel="apple-touch-icon"/>
</head>
<body>
<div data-collapse="medium" data-animation="default" data-duration="400" role="banner" class="navbar w-nav">
<div class="w-container">
<a href="/" class="brand-block w-clearfix w-nav-brand">
<img src="/images/el-vikingo-ti.png" width="65" alt="" class="logo-img"/>
<h1 class="logo-title">#sitename</h1>
</a>
<nav role="navigation" class="nav-menu w-nav-menu">
<a href="/" class="nav-link w-nav-link">Inicio</a>
<a href="/sobre.html" class="nav-link w-nav-link">Sobre El Vikingo TI</a>
<a href="/servicios.html" class="nav-link w-nav-link">Que Hago</a>
<a href="/contacto.html" class="nav-link w-nav-link">Contáctame</a>
<a href="/blog/" class="nav-link w-nav-link">Blog</a>
</nav>
<div class="menu-button w-nav-button">
<div class="w-icon-nav-menu">
</div>
</div>
</div>
</div>
<div class="header">
<div class="w-container">
<h1 class="main-heading">Blog</h1>
<div class="divider">
</div>
<div class="main-subtitle">#tagline</div>
</div>
</div>
<div class="about-section">
<div class="w-container">
<p>&nbsp;</p>
<!-- Header End -->
<!-- Body Start -->
BODY
<!-- Body End -->
<!-- Begin Footer Template -->
</div>
</div>
</div>
<div id="contact" class="section contact">
<div class="w-container">
<h2>Ponte en contacto conmigo</h2>
<div class="divider grey">
</div>
<div class="w-row">
<div class="w-col w-col-4">
<div class="icon-wrapper">
<img src="/images/map-icon.png" width="44" alt=""/>
</div>
<h3>Lo que hago</h3>
<p class="contact-text">
Elegir a El Vikingo TI significa<br/>
optar por la tranquilidad, la profesionalidad<br/>
y una calidad de transmisión inigualable.
</p>
</div>
<div class="w-col w-col-4">
<div class="icon-wrapper _2">
<img src="/images/mail-icon.png" width="70" alt=""/>
</div>
<h3>La manera tradicional</h3>
<p class="contact-text">Correo Electronico<br/>
<a href="/contacto.html" class="link">Envíeme un mensaje</a>
</p>
</div>
<div class="w-col w-col-4">
<div class="icon-wrapper _2">
<img src="/images/heart-icon.png" width="68" alt=""/>
</div>
<h3>Redes Sociales</h3>
<a href="#" class="social-wrapper contact-text w-inline-block w-clearfix">
<img src="/images/facebook-icon_black.svg" width="14" alt="" class="social-icon"/>
<div class="social-link-text">Facebook</div></a>
<a href="#" class="social-wrapper contact-text w-inline-block">
<img src="/images/twitter-icon_black.svg" width="14" alt="" class="social-icon"/>
<div class="social-link-text">Twitter</div></a>
<a href="#" class="social-wrapper contact-text w-inline-block">
<img src="/images/linkdin-icon-black.svg" width="14" alt="" class="social-icon"/>
<div class="social-link-text">LinkedIn</div></a>
</div>
</div>
</div>
</div>
<footer id="footer" class="newsection footer">
<img src="/images/el-vikingo-ti.png" width="43" alt="El Vikingo TI Logo" class="footer-logo"/>
<p class="footer-text">
#updated
</p>
</div>
</footer>
<script src="/css/jquery-3.5.1.js" type="text/javascript" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="/css/webflow.js" type="text/javascript"></script>
</body>
</html>

View File

@ -1,17 +0,0 @@
<!-- Blog Post for Index Start -->
<!-- <div id="process" class="section"> -->
<div class="w-container">
<h3><a class="link" href="BLOGURL">BLOGTITLE</a></h3>
<div class="grow-row w-row">
INGRESS
</div>
<div class="grow-row w-row">
<strong style="font-size: 10px; padding-top: 3px;">BLOGDATE</strong>
</div>
<div class="divider grey"></div>
</div>
<!-- </div> -->
<!-- Blog Post for Index End -->

View File

@ -1,125 +0,0 @@
<html>
<head>
<meta charset="utf-8"/>
<title>#sitename - BLOGTITLE</title>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<link href="/css/minimaltemplate-v1.css" rel="stylesheet" type="text/css"/>
<script src="/css/webfont.js" type="text/javascript">
</script>
<script type="text/javascript">
WebFont.load({ google: { families: ["Vollkorn:400,400italic,700,700italic","Montserrat:100,100italic,200,200italic,300,300italic,400,400italic,500,500italic,600,600italic,700,700italic,800,800italic,900,900italic","Oswald:200,300,400,500,600,700"] }});</script>
<script type="text/javascript">
!function(o,c){var n=c.documentElement,t=" w-mod-";n.className+=t+"js",("ontouchstart"in o||o.DocumentTouch&&c instanceof DocumentTouch)&&(n.className+=t+"touch")}(window,document);</script>
<link href="/images/el-vikingo-ti.png" rel="shortcut icon" type="image/png"/>
<link href="/images/el-vikingo-ti.png" rel="apple-touch-icon"/>
</head>
<body>
<div data-collapse="medium" data-animation="default" data-duration="400" role="banner" class="navbar w-nav">
<div class="w-container">
<a href="/" class="brand-block w-clearfix w-nav-brand">
<img src="/images/el-vikingo-ti.png" width="65" alt="" class="logo-img"/>
<h1 class="logo-title">#sitename</h1>
</a>
<nav role="navigation" class="nav-menu w-nav-menu">
<a href="/blog/" class="nav-link w-nav-link">← Al Blog</a>
</nav>
<div class="menu-button w-nav-button">
<div class="w-icon-nav-menu">
</div>
</div>
</div>
</div>
<div class="header project-page">
<div class="w-container">
<h1 class="main-heading">BLOGTITLE</h1>
<div class="divider">
</div>
<div class="main-subtitle">
CALADAY - CALNDAY - CALMONTH - CALYEAR
</div>
</div>
</div>
<!-- Blog Post Start -->
<div class="about-section">
<div class="w-container">
<div id="process" class="section ingress">
<div class="w-container">
INGRESS
<div class="divider grey"></div>
<div class="grow-row w-row">
BODY
</div>
</div>
</div>
</div>
<!-- Blog Post End -->
</div>
<div id="contact" class="section contact">
<div class="w-container">
<h2>Ponte en contacto conmigo</h2>
<div class="divider grey">
</div>
<div class="w-row">
<div class="w-col w-col-4">
<div class="icon-wrapper">
<img src="/images/map-icon.png" width="44" alt=""/>
</div>
<h3>Lo que hago</h3>
<p class="contact-text">
Elegir a El Vikingo TI significa<br/>
optar por la tranquilidad, la profesionalidad<br/>
y una calidad de transmisión inigualable.
</p>
</div>
<div class="w-col w-col-4">
<div class="icon-wrapper _2">
<img src="/images/mail-icon.png" width="70" alt=""/>
</div>
<h3>La manera tradicional</h3>
<p class="contact-text">Correo Electronico<br/>
<a href="/contacto.html" class="link">Envíeme un mensaje</a>
</p>
</div>
<div class="w-col w-col-4">
<div class="icon-wrapper _2">
<img src="/images/heart-icon.png" width="68" alt=""/>
</div>
<h3>Redes Sociales</h3>
<a href="#" class="social-wrapper contact-text w-inline-block w-clearfix">
<img src="/images/facebook-icon_black.svg" width="14" alt="" class="social-icon"/>
<div class="social-link-text">Facebook</div></a>
<a href="#" class="social-wrapper contact-text w-inline-block">
<img src="/images/twitter-icon_black.svg" width="14" alt="" class="social-icon"/>
<div class="social-link-text">Twitter</div></a>
<a href="#" class="social-wrapper contact-text w-inline-block">
<img src="/images/linkdin-icon-black.svg" width="14" alt="" class="social-icon"/>
<div class="social-link-text">LinkedIn</div></a>
</div>
</div>
</div>
</div>
<footer id="footer" class="newsection footer">
<img src="/images/el-vikingo-ti.png" width="43" alt="El Vikingo TI Logo" class="footer-logo"/>
<p class="footer-text">
#updated
</p>
</div>
</footer>
<script src="/css/jquery-3.5.1.js" type="text/javascript" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="/css/webflow.js" type="text/javascript"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,33 +0,0 @@
/*
* Copyright 2016 Small Batch, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
/* Web Font Loader v1.6.26 - (c) Adobe Systems, Google. License: Apache 2.0 */(function(){function aa(a,b,c){return a.call.apply(a.bind,arguments)}function ba(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}}function p(a,b,c){p=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?aa:ba;return p.apply(null,arguments)}var q=Date.now||function(){return+new Date};function ca(a,b){this.a=a;this.m=b||a;this.c=this.m.document}var da=!!window.FontFace;function t(a,b,c,d){b=a.c.createElement(b);if(c)for(var e in c)c.hasOwnProperty(e)&&("style"==e?b.style.cssText=c[e]:b.setAttribute(e,c[e]));d&&b.appendChild(a.c.createTextNode(d));return b}function u(a,b,c){a=a.c.getElementsByTagName(b)[0];a||(a=document.documentElement);a.insertBefore(c,a.lastChild)}function v(a){a.parentNode&&a.parentNode.removeChild(a)}
function w(a,b,c){b=b||[];c=c||[];for(var d=a.className.split(/\s+/),e=0;e<b.length;e+=1){for(var f=!1,g=0;g<d.length;g+=1)if(b[e]===d[g]){f=!0;break}f||d.push(b[e])}b=[];for(e=0;e<d.length;e+=1){f=!1;for(g=0;g<c.length;g+=1)if(d[e]===c[g]){f=!0;break}f||b.push(d[e])}a.className=b.join(" ").replace(/\s+/g," ").replace(/^\s+|\s+$/,"")}function y(a,b){for(var c=a.className.split(/\s+/),d=0,e=c.length;d<e;d++)if(c[d]==b)return!0;return!1}
function z(a){if("string"===typeof a.f)return a.f;var b=a.m.location.protocol;"about:"==b&&(b=a.a.location.protocol);return"https:"==b?"https:":"http:"}function ea(a){return a.m.location.hostname||a.a.location.hostname}
function A(a,b,c){function d(){k&&e&&f&&(k(g),k=null)}b=t(a,"link",{rel:"stylesheet",href:b,media:"all"});var e=!1,f=!0,g=null,k=c||null;da?(b.onload=function(){e=!0;d()},b.onerror=function(){e=!0;g=Error("Stylesheet failed to load");d()}):setTimeout(function(){e=!0;d()},0);u(a,"head",b)}
function B(a,b,c,d){var e=a.c.getElementsByTagName("head")[0];if(e){var f=t(a,"script",{src:b}),g=!1;f.onload=f.onreadystatechange=function(){g||this.readyState&&"loaded"!=this.readyState&&"complete"!=this.readyState||(g=!0,c&&c(null),f.onload=f.onreadystatechange=null,"HEAD"==f.parentNode.tagName&&e.removeChild(f))};e.appendChild(f);setTimeout(function(){g||(g=!0,c&&c(Error("Script load timeout")))},d||5E3);return f}return null};function C(){this.a=0;this.c=null}function D(a){a.a++;return function(){a.a--;E(a)}}function F(a,b){a.c=b;E(a)}function E(a){0==a.a&&a.c&&(a.c(),a.c=null)};function G(a){this.a=a||"-"}G.prototype.c=function(a){for(var b=[],c=0;c<arguments.length;c++)b.push(arguments[c].replace(/[\W_]+/g,"").toLowerCase());return b.join(this.a)};function H(a,b){this.c=a;this.f=4;this.a="n";var c=(b||"n4").match(/^([nio])([1-9])$/i);c&&(this.a=c[1],this.f=parseInt(c[2],10))}function fa(a){return I(a)+" "+(a.f+"00")+" 300px "+J(a.c)}function J(a){var b=[];a=a.split(/,\s*/);for(var c=0;c<a.length;c++){var d=a[c].replace(/['"]/g,"");-1!=d.indexOf(" ")||/^\d/.test(d)?b.push("'"+d+"'"):b.push(d)}return b.join(",")}function K(a){return a.a+a.f}function I(a){var b="normal";"o"===a.a?b="oblique":"i"===a.a&&(b="italic");return b}
function ga(a){var b=4,c="n",d=null;a&&((d=a.match(/(normal|oblique|italic)/i))&&d[1]&&(c=d[1].substr(0,1).toLowerCase()),(d=a.match(/([1-9]00|normal|bold)/i))&&d[1]&&(/bold/i.test(d[1])?b=7:/[1-9]00/.test(d[1])&&(b=parseInt(d[1].substr(0,1),10))));return c+b};function ha(a,b){this.c=a;this.f=a.m.document.documentElement;this.h=b;this.a=new G("-");this.j=!1!==b.events;this.g=!1!==b.classes}function ia(a){a.g&&w(a.f,[a.a.c("wf","loading")]);L(a,"loading")}function M(a){if(a.g){var b=y(a.f,a.a.c("wf","active")),c=[],d=[a.a.c("wf","loading")];b||c.push(a.a.c("wf","inactive"));w(a.f,c,d)}L(a,"inactive")}function L(a,b,c){if(a.j&&a.h[b])if(c)a.h[b](c.c,K(c));else a.h[b]()};function ja(){this.c={}}function ka(a,b,c){var d=[],e;for(e in b)if(b.hasOwnProperty(e)){var f=a.c[e];f&&d.push(f(b[e],c))}return d};function N(a,b){this.c=a;this.f=b;this.a=t(this.c,"span",{"aria-hidden":"true"},this.f)}function O(a){u(a.c,"body",a.a)}function P(a){return"display:block;position:absolute;top:-9999px;left:-9999px;font-size:300px;width:auto;height:auto;line-height:normal;margin:0;padding:0;font-variant:normal;white-space:nowrap;font-family:"+J(a.c)+";"+("font-style:"+I(a)+";font-weight:"+(a.f+"00")+";")};function Q(a,b,c,d,e,f){this.g=a;this.j=b;this.a=d;this.c=c;this.f=e||3E3;this.h=f||void 0}Q.prototype.start=function(){var a=this.c.m.document,b=this,c=q(),d=new Promise(function(d,e){function k(){q()-c>=b.f?e():a.fonts.load(fa(b.a),b.h).then(function(a){1<=a.length?d():setTimeout(k,25)},function(){e()})}k()}),e=new Promise(function(a,d){setTimeout(d,b.f)});Promise.race([e,d]).then(function(){b.g(b.a)},function(){b.j(b.a)})};function R(a,b,c,d,e,f,g){this.v=a;this.B=b;this.c=c;this.a=d;this.s=g||"BESbswy";this.f={};this.w=e||3E3;this.u=f||null;this.o=this.j=this.h=this.g=null;this.g=new N(this.c,this.s);this.h=new N(this.c,this.s);this.j=new N(this.c,this.s);this.o=new N(this.c,this.s);a=new H(this.a.c+",serif",K(this.a));a=P(a);this.g.a.style.cssText=a;a=new H(this.a.c+",sans-serif",K(this.a));a=P(a);this.h.a.style.cssText=a;a=new H("serif",K(this.a));a=P(a);this.j.a.style.cssText=a;a=new H("sans-serif",K(this.a));a=
P(a);this.o.a.style.cssText=a;O(this.g);O(this.h);O(this.j);O(this.o)}var S={D:"serif",C:"sans-serif"},T=null;function U(){if(null===T){var a=/AppleWebKit\/([0-9]+)(?:\.([0-9]+))/.exec(window.navigator.userAgent);T=!!a&&(536>parseInt(a[1],10)||536===parseInt(a[1],10)&&11>=parseInt(a[2],10))}return T}R.prototype.start=function(){this.f.serif=this.j.a.offsetWidth;this.f["sans-serif"]=this.o.a.offsetWidth;this.A=q();la(this)};
function ma(a,b,c){for(var d in S)if(S.hasOwnProperty(d)&&b===a.f[S[d]]&&c===a.f[S[d]])return!0;return!1}function la(a){var b=a.g.a.offsetWidth,c=a.h.a.offsetWidth,d;(d=b===a.f.serif&&c===a.f["sans-serif"])||(d=U()&&ma(a,b,c));d?q()-a.A>=a.w?U()&&ma(a,b,c)&&(null===a.u||a.u.hasOwnProperty(a.a.c))?V(a,a.v):V(a,a.B):na(a):V(a,a.v)}function na(a){setTimeout(p(function(){la(this)},a),50)}function V(a,b){setTimeout(p(function(){v(this.g.a);v(this.h.a);v(this.j.a);v(this.o.a);b(this.a)},a),0)};function W(a,b,c){this.c=a;this.a=b;this.f=0;this.o=this.j=!1;this.s=c}var X=null;W.prototype.g=function(a){var b=this.a;b.g&&w(b.f,[b.a.c("wf",a.c,K(a).toString(),"active")],[b.a.c("wf",a.c,K(a).toString(),"loading"),b.a.c("wf",a.c,K(a).toString(),"inactive")]);L(b,"fontactive",a);this.o=!0;oa(this)};
W.prototype.h=function(a){var b=this.a;if(b.g){var c=y(b.f,b.a.c("wf",a.c,K(a).toString(),"active")),d=[],e=[b.a.c("wf",a.c,K(a).toString(),"loading")];c||d.push(b.a.c("wf",a.c,K(a).toString(),"inactive"));w(b.f,d,e)}L(b,"fontinactive",a);oa(this)};function oa(a){0==--a.f&&a.j&&(a.o?(a=a.a,a.g&&w(a.f,[a.a.c("wf","active")],[a.a.c("wf","loading"),a.a.c("wf","inactive")]),L(a,"active")):M(a.a))};function pa(a){this.j=a;this.a=new ja;this.h=0;this.f=this.g=!0}pa.prototype.load=function(a){this.c=new ca(this.j,a.context||this.j);this.g=!1!==a.events;this.f=!1!==a.classes;qa(this,new ha(this.c,a),a)};
function ra(a,b,c,d,e){var f=0==--a.h;(a.f||a.g)&&setTimeout(function(){var a=e||null,k=d||null||{};if(0===c.length&&f)M(b.a);else{b.f+=c.length;f&&(b.j=f);var h,m=[];for(h=0;h<c.length;h++){var l=c[h],n=k[l.c],r=b.a,x=l;r.g&&w(r.f,[r.a.c("wf",x.c,K(x).toString(),"loading")]);L(r,"fontloading",x);r=null;null===X&&(X=window.FontFace?(x=/Gecko.*Firefox\/(\d+)/.exec(window.navigator.userAgent))?42<parseInt(x[1],10):!0:!1);X?r=new Q(p(b.g,b),p(b.h,b),b.c,l,b.s,n):r=new R(p(b.g,b),p(b.h,b),b.c,l,b.s,a,
n);m.push(r)}for(h=0;h<m.length;h++)m[h].start()}},0)}function qa(a,b,c){var d=[],e=c.timeout;ia(b);var d=ka(a.a,c,a.c),f=new W(a.c,b,e);a.h=d.length;b=0;for(c=d.length;b<c;b++)d[b].load(function(b,d,c){ra(a,f,b,d,c)})};function sa(a,b){this.c=a;this.a=b}function ta(a,b,c){var d=z(a.c);a=(a.a.api||"fast.fonts.net/jsapi").replace(/^.*http(s?):(\/\/)?/,"");return d+"//"+a+"/"+b+".js"+(c?"?v="+c:"")}
sa.prototype.load=function(a){function b(){if(f["__mti_fntLst"+d]){var c=f["__mti_fntLst"+d](),e=[],h;if(c)for(var m=0;m<c.length;m++){var l=c[m].fontfamily;void 0!=c[m].fontStyle&&void 0!=c[m].fontWeight?(h=c[m].fontStyle+c[m].fontWeight,e.push(new H(l,h))):e.push(new H(l))}a(e)}else setTimeout(function(){b()},50)}var c=this,d=c.a.projectId,e=c.a.version;if(d){var f=c.c.m;B(this.c,ta(c,d,e),function(e){e?a([]):(f["__MonotypeConfiguration__"+d]=function(){return c.a},b())}).id="__MonotypeAPIScript__"+
d}else a([])};function ua(a,b){this.c=a;this.a=b}ua.prototype.load=function(a){var b,c,d=this.a.urls||[],e=this.a.families||[],f=this.a.testStrings||{},g=new C;b=0;for(c=d.length;b<c;b++)A(this.c,d[b],D(g));var k=[];b=0;for(c=e.length;b<c;b++)if(d=e[b].split(":"),d[1])for(var h=d[1].split(","),m=0;m<h.length;m+=1)k.push(new H(d[0],h[m]));else k.push(new H(d[0]));F(g,function(){a(k,f)})};function va(a,b,c){a?this.c=a:this.c=b+wa;this.a=[];this.f=[];this.g=c||""}var wa="//fonts.googleapis.com/css";function xa(a,b){for(var c=b.length,d=0;d<c;d++){var e=b[d].split(":");3==e.length&&a.f.push(e.pop());var f="";2==e.length&&""!=e[1]&&(f=":");a.a.push(e.join(f))}}
function ya(a){if(0==a.a.length)throw Error("No fonts to load!");if(-1!=a.c.indexOf("kit="))return a.c;for(var b=a.a.length,c=[],d=0;d<b;d++)c.push(a.a[d].replace(/ /g,"+"));b=a.c+"?family="+c.join("%7C");0<a.f.length&&(b+="&subset="+a.f.join(","));0<a.g.length&&(b+="&text="+encodeURIComponent(a.g));return b};function za(a){this.f=a;this.a=[];this.c={}}
var Aa={latin:"BESbswy","latin-ext":"\u00e7\u00f6\u00fc\u011f\u015f",cyrillic:"\u0439\u044f\u0416",greek:"\u03b1\u03b2\u03a3",khmer:"\u1780\u1781\u1782",Hanuman:"\u1780\u1781\u1782"},Ba={thin:"1",extralight:"2","extra-light":"2",ultralight:"2","ultra-light":"2",light:"3",regular:"4",book:"4",medium:"5","semi-bold":"6",semibold:"6","demi-bold":"6",demibold:"6",bold:"7","extra-bold":"8",extrabold:"8","ultra-bold":"8",ultrabold:"8",black:"9",heavy:"9",l:"3",r:"4",b:"7"},Ca={i:"i",italic:"i",n:"n",normal:"n"},
Da=/^(thin|(?:(?:extra|ultra)-?)?light|regular|book|medium|(?:(?:semi|demi|extra|ultra)-?)?bold|black|heavy|l|r|b|[1-9]00)?(n|i|normal|italic)?$/;
function Ea(a){for(var b=a.f.length,c=0;c<b;c++){var d=a.f[c].split(":"),e=d[0].replace(/\+/g," "),f=["n4"];if(2<=d.length){var g;var k=d[1];g=[];if(k)for(var k=k.split(","),h=k.length,m=0;m<h;m++){var l;l=k[m];if(l.match(/^[\w-]+$/)){var n=Da.exec(l.toLowerCase());if(null==n)l="";else{l=n[2];l=null==l||""==l?"n":Ca[l];n=n[1];if(null==n||""==n)n="4";else var r=Ba[n],n=r?r:isNaN(n)?"4":n.substr(0,1);l=[l,n].join("")}}else l="";l&&g.push(l)}0<g.length&&(f=g);3==d.length&&(d=d[2],g=[],d=d?d.split(","):
g,0<d.length&&(d=Aa[d[0]])&&(a.c[e]=d))}a.c[e]||(d=Aa[e])&&(a.c[e]=d);for(d=0;d<f.length;d+=1)a.a.push(new H(e,f[d]))}};function Fa(a,b){this.c=a;this.a=b}var Ga={Arimo:!0,Cousine:!0,Tinos:!0};Fa.prototype.load=function(a){var b=new C,c=this.c,d=new va(this.a.api,z(c),this.a.text),e=this.a.families;xa(d,e);var f=new za(e);Ea(f);A(c,ya(d),D(b));F(b,function(){a(f.a,f.c,Ga)})};function Ha(a,b){this.c=a;this.a=b}Ha.prototype.load=function(a){var b=this.a.id,c=this.c.m;b?B(this.c,(this.a.api||"https://use.typekit.net")+"/"+b+".js",function(b){if(b)a([]);else if(c.Typekit&&c.Typekit.config&&c.Typekit.config.fn){b=c.Typekit.config.fn;for(var e=[],f=0;f<b.length;f+=2)for(var g=b[f],k=b[f+1],h=0;h<k.length;h++)e.push(new H(g,k[h]));try{c.Typekit.load({events:!1,classes:!1,async:!0})}catch(m){}a(e)}},2E3):a([])};function Ia(a,b){this.c=a;this.f=b;this.a=[]}Ia.prototype.load=function(a){var b=this.f.id,c=this.c.m,d=this;b?(c.__webfontfontdeckmodule__||(c.__webfontfontdeckmodule__={}),c.__webfontfontdeckmodule__[b]=function(b,c){for(var g=0,k=c.fonts.length;g<k;++g){var h=c.fonts[g];d.a.push(new H(h.name,ga("font-weight:"+h.weight+";font-style:"+h.style)))}a(d.a)},B(this.c,z(this.c)+(this.f.api||"//f.fontdeck.com/s/css/js/")+ea(this.c)+"/"+b+".js",function(b){b&&a([])})):a([])};var Y=new pa(window);Y.a.c.custom=function(a,b){return new ua(b,a)};Y.a.c.fontdeck=function(a,b){return new Ia(b,a)};Y.a.c.monotype=function(a,b){return new sa(b,a)};Y.a.c.typekit=function(a,b){return new Ha(b,a)};Y.a.c.google=function(a,b){return new Fa(b,a)};var Z={load:p(Y.load,Y)};"function"===typeof define&&define.amd?define(function(){return Z}):"undefined"!==typeof module&&module.exports?module.exports=Z:(window.WebFont=Z,window.WebFontConfig&&Y.load(window.WebFontConfig));}());

View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$site_name$ - $site_tagline$</title>
$for(css)$
<link rel="stylesheet" href="$css$">
$endfor$
$if(site_rss_url)$
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="$site_rss_url$">
$endif$
</head>
<body class="minimal-theme">
<header class="site-header">
<div class="container">
<h1 class="site-title"><a href="$site_url$">$site_name$</a></h1>
<p class="site-tagline">$site_tagline$</p>
</div>
</header>
<main class="main-content">
<div class="container">
<section id="posts-list">
<h2>Latest Posts</h2>
$if(posts)$
<div class="posts-grid">
$for(posts)$
<article class="post-card">
<h3><a href="$posts.url$">$posts.title$</a></h3>
$if(posts.date)$
<p class="post-date">$posts.date$</p>
$endif$
$if(posts.summary)$
<p class="post-summary">$posts.summary$</p>
$endif$
</article>
$endfor$
</div>
$else$
<p class="no-posts">No posts found.</p>
$endif$
</section>
</div>
</main>
<footer class="site-footer">
<div class="container">
<p>&copy; $current_year$ $site_name$. Generated by qsgen3.</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$title$ - $site_name$</title>
<meta name="description" content="$description$">
$for(css)$
<link rel="stylesheet" href="$css$">
$endfor$
$if(math)$ $math$ $endif$
</head>
<body class="minimal-theme">
<header class="site-header">
<div class="container">
<h1 class="site-title"><a href="/">$site_name$</a></h1>
<p class="site-tagline">$site_tagline$</p>
</div>
</header>
<main class="main-content">
<div class="container">
<article class="page">
<header class="page-header">
<h1 class="page-title">$title$</h1>
</header>
<div class="page-content">
$body$
</div>
</article>
<nav class="page-nav">
<a href="/" class="back-link">&larr; Back to Home</a>
</nav>
</div>
</main>
<footer class="site-footer">
<div class="container">
<p>&copy; $current_year$ $site_name$. Generated by qsgen3.</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$title$ - $site_name$</title>
<meta name="author" content="$author$">
<meta name="description" content="$description$">
$if(date)$<meta name="date" content="$date$">$endif$
$for(css)$
<link rel="stylesheet" href="$css$">
$endfor$
$if(math)$ $math$ $endif$
</head>
<body class="minimal-theme">
<header class="site-header">
<div class="container">
<h1 class="site-title"><a href="/">$site_name$</a></h1>
<p class="site-tagline">$site_tagline$</p>
</div>
</header>
<main class="main-content">
<div class="container">
<article class="post">
<header class="post-header">
<h1 class="post-title">$title$</h1>
<div class="post-meta">
$if(author)$
<span class="post-author">By: $author$</span>
$endif$
$if(date)$
<span class="post-date">Published: $date$</span>
$endif$
</div>
</header>
<div class="post-content">
$body$
</div>
</article>
<nav class="post-nav">
<a href="/" class="back-link">&larr; Back to Home</a>
</nav>
</div>
</main>
<footer class="site-footer">
<div class="container">
<p>&copy; $current_year$ $site_name$. Generated by qsgen3.</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>$site_name$</title>
<link>$site_url$</link>
<description>$site_tagline$</description>
<language>en-us</language>
<lastBuildDate>$rfc_2822_date$</lastBuildDate>
<atom:link href="$site_url$/rss.xml" rel="self" type="application/rss+xml" />
$if(posts)$
$for(posts)$
<item>
<title>$it.post_title$</title>
<link>$it.post_url$</link>
<pubDate>$it.post_rfc_2822_date$</pubDate>
<guid isPermaLink="true">$it.post_url$</guid>
<description><![CDATA[$it.post_summary$]]></description>
</item>
$endfor$
$endif$
</channel>
</rss>

View File

@ -1,127 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>#sitename - #pagetitle</title>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<meta content="Webflow" name="generator"/>
<link href="/css/minimaltemplate-v1.css" rel="stylesheet" type="text/css"/>
<script src="/css/webfont.js" type="text/javascript">
</script>
<script type="text/javascript">WebFont.load({ google: { families: ["Vollkorn:400,400italic,700,700italic","Montserrat:100,100italic,200,200italic,300,300italic,400,400italic,500,500italic,600,600italic,700,700italic,800,800italic,900,900italic","Oswald:200,300,400,500,600,700"] }});</script>
<script type="text/javascript">
!function(o,c){var n=c.documentElement,t=" w-mod-";n.className+=t+"js",("ontouchstart"in o||o.DocumentTouch&&c instanceof DocumentTouch)&&(n.className+=t+"touch")}(window,document);
</script>
<link href="/images/el-vikingo-ti.png" rel="shortcut icon" type="image/png"/>
<link href="/images/el-vikingo-ti.png" rel="apple-touch-icon"/>
</head>
<body>
<div data-collapse="medium" data-animation="default" data-duration="400" role="banner" class="navbar w-nav">
<div class="w-container">
<a href="/" class="brand-block w-clearfix w-nav-brand">
<img src="/images/el-vikingo-ti.png" width="65" alt="" class="logo-img"/>
<h1 class="logo-title">#sitename</h1>
</a>
<nav role="navigation" class="nav-menu w-nav-menu">
<a href="/" class="nav-link w-nav-link">Inicio</a>
<a href="/sobre.html" class="nav-link w-nav-link">Sobre #sitename</a>
<a href="/servicios.html" class="nav-link w-nav-link">Que Hago</a>
<a href="/contacto.html" class="nav-link w-nav-link">Contáctame</a>
<a href="/blog/" class="nav-link w-nav-link">Blog</a>
</nav>
<div class="menu-button w-nav-button">
<div class="w-icon-nav-menu">
</div>
</div>
</div>
</div>
<div class="header">
<div class="w-container">
<h1 class="main-heading">#pagetitle</h1>
<div class="divider">
</div>
<div class="main-subtitle">#tagline</div>
</div>
</div>
<div class="about-section">
<div class="w-container">
<!-- Header End -->
<!-- Body Start -->
BODY
<!-- Body End -->
<!-- Begin Footer Template -->
</div>
<div id="contact" class="section contact">
<div class="w-container">
<h2>Ponte en contacto conmigo</h2>
<div class="divider grey">
</div>
<div class="w-row">
<div class="w-col w-col-4">
<div class="icon-wrapper">
<img src="/images/map-icon.png" width="44" alt=""/>
</div>
<h3>Lo que hago</h3>
<p class="contact-text">
Elegir a El Vikingo TI significa<br/>
optar por la tranquilidad, la profesionalidad<br/>
y una calidad de transmisión inigualable.
</p>
</div>
<div class="w-col w-col-4">
<div class="icon-wrapper _2">
<img src="/images/mail-icon.png" width="70" alt=""/>
</div>
<h3>La manera tradicional</h3>
<p class="contact-text">Correo Electronico<br/>
<a href="/contacto.html" class="link">Envíeme un mensaje</a>
</p>
</div>
<div class="w-col w-col-4">
<div class="icon-wrapper _2">
<img src="/images/heart-icon.png" width="68" alt=""/>
</div>
<h3>Redes Sociales</h3>
<a href="#" class="social-wrapper contact-text w-inline-block w-clearfix">
<img src="/images/facebook-icon_black.svg" width="14" alt="" class="social-icon"/>
<div class="social-link-text">Facebook</div></a>
<a href="#" class="social-wrapper contact-text w-inline-block">
<img src="/images/twitter-icon_black.svg" width="14" alt="" class="social-icon"/>
<div class="social-link-text">Twitter</div></a>
<a href="#" class="social-wrapper contact-text w-inline-block">
<img src="/images/linkdin-icon-black.svg" width="14" alt="" class="social-icon"/>
<div class="social-link-text">LinkedIn</div></a>
</div>
</div>
</div>
</div>
<footer id="footer" class="newsection footer">
<img src="/images/el-vikingo-ti.png" width="43" alt="El Vikingo TI Logo" class="footer-logo"/>
<p class="footer-text">
#updated
</p>
</div>
</footer>
<script src="/css/jquery-3.5.1.js" type="text/javascript" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="/css/webflow.js" type="text/javascript"></script>
</body>
</html>

View File

@ -0,0 +1,267 @@
/* Minimal Theme for qsgen3 */
/* Reset and base styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #333;
background-color: #fff;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 0 1rem;
}
/* Header */
.site-header {
background: #f8f9fa;
border-bottom: 1px solid #e9ecef;
padding: 2rem 0;
margin-bottom: 2rem;
}
.site-title {
font-size: 2rem;
font-weight: 700;
margin-bottom: 0.5rem;
}
.site-title a {
color: #333;
text-decoration: none;
}
.site-title a:hover {
color: #007bff;
}
.site-tagline {
color: #6c757d;
font-size: 1.1rem;
}
/* Main content */
.main-content {
min-height: calc(100vh - 200px);
margin-bottom: 3rem;
}
/* Posts grid */
.posts-grid {
display: grid;
gap: 2rem;
margin-top: 1rem;
}
.post-card {
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 1.5rem;
background: #fff;
transition: box-shadow 0.2s ease;
}
.post-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.post-card h3 {
margin-bottom: 0.5rem;
}
.post-card h3 a {
color: #333;
text-decoration: none;
}
.post-card h3 a:hover {
color: #007bff;
}
.post-date {
color: #6c757d;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.post-summary {
color: #555;
line-height: 1.5;
}
.no-posts {
text-align: center;
color: #6c757d;
font-style: italic;
padding: 2rem;
}
/* Post page */
.post {
max-width: none;
}
.post-header {
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid #e9ecef;
}
.post-title {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 1rem;
line-height: 1.2;
}
.post-meta {
color: #6c757d;
font-size: 0.9rem;
}
.post-meta span {
margin-right: 1rem;
}
.post-content {
font-size: 1.1rem;
line-height: 1.7;
}
.post-content h1,
.post-content h2,
.post-content h3,
.post-content h4,
.post-content h5,
.post-content h6 {
margin-top: 2rem;
margin-bottom: 1rem;
font-weight: 600;
}
.post-content p {
margin-bottom: 1rem;
}
.post-content ul,
.post-content ol {
margin-bottom: 1rem;
padding-left: 2rem;
}
.post-content li {
margin-bottom: 0.5rem;
}
.post-content blockquote {
border-left: 4px solid #007bff;
padding-left: 1rem;
margin: 1.5rem 0;
font-style: italic;
color: #555;
}
.post-content code {
background: #f8f9fa;
padding: 0.2rem 0.4rem;
border-radius: 3px;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 0.9em;
}
.post-content pre {
background: #f8f9fa;
padding: 1rem;
border-radius: 6px;
overflow-x: auto;
margin: 1.5rem 0;
}
.post-content pre code {
background: none;
padding: 0;
}
/* Page content */
.page {
max-width: none;
}
.page-header {
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid #e9ecef;
}
.page-title {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 1rem;
line-height: 1.2;
}
.page-content {
font-size: 1.1rem;
line-height: 1.7;
}
/* Navigation */
.post-nav,
.page-nav {
margin-top: 3rem;
padding-top: 2rem;
border-top: 1px solid #e9ecef;
}
.back-link {
color: #007bff;
text-decoration: none;
font-weight: 500;
}
.back-link:hover {
text-decoration: underline;
}
/* Footer */
.site-footer {
background: #f8f9fa;
border-top: 1px solid #e9ecef;
padding: 2rem 0;
margin-top: auto;
color: #6c757d;
text-align: center;
}
/* Responsive design */
@media (max-width: 768px) {
.container {
padding: 0 0.75rem;
}
.site-header {
padding: 1.5rem 0;
}
.site-title {
font-size: 1.5rem;
}
.post-title,
.page-title {
font-size: 2rem;
}
.post-content,
.page-content {
font-size: 1rem;
}
}

View File

@ -1,29 +0,0 @@
<div id="process" class="section">
<div class="w-container">
<h2>How we make brands thrive</h2>
<div class="divider grey"></div>
<div class="w-row">
<div class="w-col w-col-4">
<div class="grey-icon-wrapper">
<img src="https://assets.website-files.com/530ab3ac7b5bc4ca19000b96/530b7763b9b97cdf3e0008b9_icon-target.png" width="127" alt="" class="big-icon"/>
</div>
<h3>SET a target</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique.</p>
</div>
<div class="w-col w-col-4">
<div class="grey-icon-wrapper push-top">
<img src="https://assets.website-files.com/530ab3ac7b5bc4ca19000b96/530b7772b9b97cdf3e0008bc_icon-design.png" width="127" alt="" class="big-icon"/>
</div>
<h3>design a solution</h3>
<p>Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat.</p>
</div>
<div class="w-col w-col-4">
<div class="grey-icon-wrapper push-top">
<img src="https://assets.website-files.com/530ab3ac7b5bc4ca19000b96/530b7778b9b97cdf3e0008be_icon-chart.png" width="127" alt="" class="big-icon"/>
</div>
<h3>track the progress</h3>
<p>Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.</p>
</div>
</div>
</div>
</div>