Compare commits
14 Commits
c14e943f2b
...
main
Author | SHA1 | Date | |
---|---|---|---|
7521c744bd | |||
81ffa53d70 | |||
f72fe18873 | |||
ed7ed0ee18 | |||
5266559f26 | |||
4b95426256 | |||
1283eb30cb | |||
f5d6d0eb49 | |||
1b8898ae2e | |||
681857225b | |||
47a4c04d96 | |||
8ffd19a0c4 | |||
3dad33a939 | |||
c470ac40c0 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -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
40
.qsgen3_preserve.example
Normal 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
220
HOWTO.md
@ -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*
|
156
README.md
156
README.md
@ -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)
|
||||
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.
|
||||
|
||||
1. **Installation**
|
||||
```bash
|
||||
git clone https://github.com/kekePower/qsgen2.git
|
||||
cd qsgen2
|
||||
chmod +x qsgen2
|
||||
```
|
||||
We asked ourselves: *What if a static site generator just... generated static sites?*
|
||||
|
||||
2. **Create a new site**
|
||||
```bash
|
||||
./qsgen2 new my-site
|
||||
cd my-site
|
||||
```
|
||||
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?
|
||||
|
||||
3. **Build and serve**
|
||||
```bash
|
||||
./qsgen2 build
|
||||
./qsgen2 serve
|
||||
```
|
||||
That's qsgen3.
|
||||
|
||||
For detailed documentation, see the [HOWTO.md](HOWTO.md) guide.
|
||||
## How qsgen3 is Different
|
||||
|
||||
## Recent Changes
|
||||
### 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.
|
||||
|
||||
- Added Norwegian (nb_NO) language support
|
||||
- Improved internationalization (i18n) system
|
||||
- Cleaned up temporary and backup files
|
||||
- Updated documentation
|
||||
- Added comprehensive HOWTO guide
|
||||
### 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.
|
||||
|
||||
## Requirements
|
||||
### 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.
|
||||
|
||||
- Zsh 5.8 or later
|
||||
- Pandoc (for Markdown support)
|
||||
- Basic Unix tools (sed, grep, etc.)
|
||||
### 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.
|
||||
|
||||
## License
|
||||
## What You Actually Get
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
When you use qsgen3, you get a tool that handles the boring stuff so you can focus on what matters—your content.
|
||||
|
||||
## Contributing
|
||||
**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
|
||||
|
||||
Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) before submitting pull requests.
|
||||
**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
|
||||
|
||||
## Support
|
||||
**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
|
||||
|
||||
For support, please [open an issue](https://github.com/kekePower/qsgen2/issues) on GitHub.
|
||||
## 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:
|
||||
|
||||
```bash
|
||||
# Get qsgen3
|
||||
git clone https://git.kekepower.com/kekePower/qsgen3.git
|
||||
cd qsgen3
|
||||
|
||||
# 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.
|
||||
|
194
THEME-HOWTO.md
194
THEME-HOWTO.md
@ -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>© #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
865
THEMES-HOWTO.md
Normal 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>© $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>© $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>© $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
1542
bin/qsgen3
Executable file
File diff suppressed because it is too large
Load Diff
30
content/posts/hello-world.md
Normal file
30
content/posts/hello-world.md
Normal 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
528
how-it-works.md
Normal 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 `#`
|
||||
|
||||
---
|
@ -1,3 +0,0 @@
|
||||
Copy this directory to your **www_root**
|
||||
|
||||
**$www_root/images/**
|
@ -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 |
@ -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"
|
@ -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
|
||||
|
||||
}
|
@ -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
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
# Function: LOGGER
|
||||
# Usage: loggy <message>
|
||||
function loggy () {
|
||||
|
||||
echo "$$ - $(date +%T) - ${KODIVERSION} - ${@}" >> ${LOGGYLOGFILE}
|
||||
|
||||
}
|
@ -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}
|
||||
|
||||
}
|
@ -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."
|
||||
}
|
@ -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:"
|
@ -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:"
|
@ -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:"
|
@ -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 :"
|
@ -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
47
layouts/index.html
Normal 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>© $current_year$ $site_name$. Generated by qsgen3.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
32
layouts/page.html
Normal file
32
layouts/page.html
Normal 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>© $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
39
layouts/post.html
Normal 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>© $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
24
layouts/rss.xml
Normal 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>
|
BIN
qsg2-square.png
BIN
qsg2-square.png
Binary file not shown.
Before Width: | Height: | Size: 620 KiB |
288
scripts/migrate_qs2_to_qs3.py
Normal file
288
scripts/migrate_qs2_to_qs3.py
Normal 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¤ -> 
|
||||
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""
|
||||
md_content = re.sub(r'#showimg\s+([^¤]+)¤([^¤]+)¤', replace_showimg_to_markdown, md_content)
|
||||
|
||||
# Linked Images: #linkimg IMAGE_PATH¤ALT_TEXT¤ -> [](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"[]({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", "<")
|
||||
md_content = md_content.replace("#GT", ">")
|
||||
md_content = md_content.replace("#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
22
site.conf
Normal 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
|
@ -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%.
|
||||
|
@ -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 -->
|
||||
|
@ -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 -->
|
@ -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 -->
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
49
themes/minimal/README.md
Normal 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
|
@ -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> </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>
|
@ -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 -->
|
@ -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>
|
2
themes/minimal/css/jquery-3.5.1.js
vendored
2
themes/minimal/css/jquery-3.5.1.js
vendored
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
@ -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));}());
|
53
themes/minimal/layouts/index.html
Normal file
53
themes/minimal/layouts/index.html
Normal 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>© $current_year$ $site_name$. Generated by qsgen3.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
44
themes/minimal/layouts/page.html
Normal file
44
themes/minimal/layouts/page.html
Normal 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">← Back to Home</a>
|
||||
</nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<p>© $current_year$ $site_name$. Generated by qsgen3.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
54
themes/minimal/layouts/post.html
Normal file
54
themes/minimal/layouts/post.html
Normal 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">← Back to Home</a>
|
||||
</nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<p>© $current_year$ $site_name$. Generated by qsgen3.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
24
themes/minimal/layouts/rss.xml
Normal file
24
themes/minimal/layouts/rss.xml
Normal 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>
|
@ -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>
|
267
themes/minimal/static/css/style.css
Normal file
267
themes/minimal/static/css/style.css
Normal 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;
|
||||
}
|
||||
}
|
@ -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>
|
Reference in New Issue
Block a user