📝 catch the docs up
This commit is contained in:
260
README.md
260
README.md
@@ -72,7 +72,7 @@ A Flask-based webcomic website with server-side rendering using Jinja2 templates
|
||||
- An archive page where readers can browse all your comics
|
||||
- RSS feed so readers can subscribe to updates
|
||||
- Mobile-friendly design that works on phones and tablets
|
||||
- No database required - just upload images and edit a simple text file
|
||||
- No database required - just upload images and edit simple YAML files
|
||||
|
||||
**Perfect for:**
|
||||
- Independent comic artists starting their first webcomic
|
||||
@@ -81,7 +81,7 @@ A Flask-based webcomic website with server-side rendering using Jinja2 templates
|
||||
- Anyone looking for a lightweight, customizable comic platform
|
||||
|
||||
**How it works:**
|
||||
You add your comics by uploading image files and adding basic information (title, date, description) to a configuration file. The website handles everything else - displaying comics with navigation, creating an archive, generating an RSS feed, and making your comics shareable on social media.
|
||||
You add your comics by uploading image files and creating individual YAML files with basic information (title, date, description). The website handles everything else - displaying comics with navigation, creating an archive, generating an RSS feed, and making your comics shareable on social media.
|
||||
|
||||
No coding knowledge required for basic use - just follow the instructions below to add comics and customize your site's appearance.
|
||||
|
||||
@@ -91,7 +91,7 @@ No coding knowledge required for basic use - just follow the instructions below
|
||||
|
||||
**Sunday Comics:**
|
||||
- Server-side application (Flask/Python) that runs on a web server
|
||||
- Comics stored in a Python file - edit text to add comics
|
||||
- Comics stored as individual YAML files - easy version control and management
|
||||
- Includes an RSS feed generator and helper scripts
|
||||
- API endpoints for programmatic access
|
||||
- Markdown support for rich-formatted content
|
||||
@@ -100,7 +100,7 @@ No coding knowledge required for basic use - just follow the instructions below
|
||||
|
||||
**Rarebit:**
|
||||
- Purely static HTML/CSS/JavaScript files
|
||||
- Comics are inferred from static images upload - edit a JS to customize
|
||||
- Comics are inferred from static images upload - edit a JS file to customize
|
||||
- Can be hosted for free on GitHub Pages, Neocities, etc.
|
||||
- No server or programming language required
|
||||
- Simpler deployment - just upload files
|
||||
@@ -233,13 +233,11 @@ To test keyboard navigation on your site:
|
||||
When adding comics to your site, follow these guidelines to maintain accessibility:
|
||||
|
||||
1. **Always provide alt text**
|
||||
```python
|
||||
{
|
||||
'number': 1,
|
||||
'filename': 'comic-001.png',
|
||||
'alt_text': 'A descriptive summary of what happens in the comic', # Required!
|
||||
# ...
|
||||
}
|
||||
```yaml
|
||||
number: 1
|
||||
filename: comic-001.png
|
||||
alt_text: A descriptive summary of what happens in the comic # Required!
|
||||
date: '2025-01-01'
|
||||
```
|
||||
|
||||
2. **Write meaningful alt text**
|
||||
@@ -632,16 +630,27 @@ Resources:
|
||||
```
|
||||
sunday/
|
||||
├── app.py # Main Flask application
|
||||
├── comics_data.py # Comic data and configuration
|
||||
├── comics_data.py # Global configuration (not comic data)
|
||||
├── data_loader.py # YAML comic loader with caching
|
||||
├── requirements.txt # Python dependencies
|
||||
├── Dockerfile # Production Docker image
|
||||
├── docker-compose.yml # Docker Compose configuration
|
||||
├── .dockerignore # Docker build exclusions
|
||||
├── data/ # Comic data directory
|
||||
│ └── comics/ # Individual comic YAML files
|
||||
│ ├── 001.yaml # Comic #1
|
||||
│ ├── 002.yaml # Comic #2
|
||||
│ ├── TEMPLATE.yaml # Template for new comics
|
||||
│ └── .comics_cache.pkl # Auto-generated cache file
|
||||
├── scripts/ # Utility scripts
|
||||
│ ├── add_comic.py # Script to add new comic entries
|
||||
│ └── generate_rss.py # Script to generate RSS feed
|
||||
│ ├── add_comic.py # Create new comic YAML files
|
||||
│ ├── generate_rss.py # Generate RSS feed
|
||||
│ ├── generate_sitemap.py # Generate sitemap.xml
|
||||
│ ├── rebuild_cache.py # Force rebuild comics cache
|
||||
│ └── publish_comic.py # Rebuild cache + RSS + sitemap
|
||||
├── content/ # Markdown content
|
||||
│ ├── about.md # About page content
|
||||
│ ├── terms.md # Terms of Service
|
||||
│ └── author_notes/ # Author notes for comics (by date)
|
||||
├── templates/ # Jinja2 templates
|
||||
│ ├── base.html # Base template with navigation
|
||||
@@ -659,7 +668,8 @@ sunday/
|
||||
│ ├── comics/ # Comic images
|
||||
│ ├── thumbs/ # Thumbnail images for archive
|
||||
│ └── icons/ # Navigation and social icons (optional)
|
||||
└── feed.rss # RSS feed (generated)
|
||||
├── feed.rss # RSS feed (generated)
|
||||
└── sitemap.xml # Sitemap (generated)
|
||||
```
|
||||
|
||||
## Setup
|
||||
@@ -683,6 +693,7 @@ The app can be configured via environment variables:
|
||||
- `SECRET_KEY` - Flask secret key (defaults to 'your-secret-key')
|
||||
- `PORT` - Port to run on (defaults to 3000)
|
||||
- `DEBUG` - Enable debug mode (defaults to False)
|
||||
- `DISABLE_COMIC_CACHE` - Set to 'true' to disable comic caching (useful for debugging)
|
||||
|
||||
**Development:**
|
||||
```bash
|
||||
@@ -697,9 +708,15 @@ export PORT=3000
|
||||
python app.py
|
||||
```
|
||||
|
||||
**Disable caching (debugging):**
|
||||
```bash
|
||||
export DISABLE_COMIC_CACHE=true
|
||||
python app.py
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The `comics_data.py` file contains both comic data and global configuration options:
|
||||
The `comics_data.py` file contains global configuration options for your comic site. Comic data itself is stored in individual YAML files in the `data/comics/` directory.
|
||||
|
||||
### Global Settings
|
||||
|
||||
@@ -716,10 +733,14 @@ FOOTER_IMAGE = None # Optional footer image path
|
||||
BANNER_IMAGE = 'banner.jpg' # Shareable banner for "Link to Me" section
|
||||
COMPACT_FOOTER = False # Display footer in compact mode
|
||||
ARCHIVE_FULL_WIDTH = True # Full-width archive with 4 columns
|
||||
SECTIONS_ENABLED = True # Enable section headers on archive page
|
||||
USE_COMIC_NAV_ICONS = True # Use icons for comic navigation buttons
|
||||
USE_HEADER_NAV_ICONS = True # Show icons in main header navigation
|
||||
USE_FOOTER_SOCIAL_ICONS = True # Use icons for social links
|
||||
USE_SHARE_ICONS = True # Use icons in share buttons (permalink/embed)
|
||||
NEWSLETTER_ENABLED = False # Show newsletter section in footer
|
||||
EMBED_ENABLED = True # Enable comic embed functionality
|
||||
PERMALINK_ENABLED = True # Enable permalink copy button
|
||||
SOCIAL_INSTAGRAM = None # Instagram URL (or None)
|
||||
SOCIAL_YOUTUBE = None # YouTube URL (or None)
|
||||
SOCIAL_EMAIL = None # Email mailto link (or None)
|
||||
@@ -728,78 +749,107 @@ API_SPEC_LINK = None # API documentation link (or None)
|
||||
|
||||
## Adding Comics
|
||||
|
||||
Comics are stored in the `COMICS` list in `comics_data.py`. Each comic entry:
|
||||
Comics are stored as individual YAML files in the `data/comics/` directory. Each comic file contains:
|
||||
|
||||
```python
|
||||
{
|
||||
'number': 1, # Comic number (required, sequential)
|
||||
'filename': 'comic-001.png', # Image filename (required) OR list for multi-image
|
||||
'mobile_filename': 'comic-001-mobile.png', # Optional mobile version (single-image only)
|
||||
'date': '2025-01-01', # Publication date (required)
|
||||
'alt_text': 'Alt text for comic', # Accessibility text (required) OR list for multi-image
|
||||
'title': 'Comic Title', # Title (optional, shows #X if absent)
|
||||
'author_note': 'Optional note', # Author note (optional, plain text)
|
||||
'author_note_md': '2025-01-01.md', # Optional markdown file for author note
|
||||
'full_width': True, # Optional: override FULL_WIDTH_DEFAULT
|
||||
'plain': True # Optional: override PLAIN_DEFAULT
|
||||
}
|
||||
```yaml
|
||||
number: 1 # Comic number (required, sequential)
|
||||
filename: comic-001.png # Image filename (required) OR list for multi-image
|
||||
date: '2025-01-01' # Publication date (required)
|
||||
alt_text: Alt text for comic # Accessibility text (required) OR list for multi-image
|
||||
title: Comic Title # Title (optional, shows #X if absent)
|
||||
author_note: Optional note # Author note (optional, plain text)
|
||||
author_note_md: 2025-01-01.md # Optional markdown file for author note
|
||||
full_width: true # Optional: override FULL_WIDTH_DEFAULT
|
||||
plain: true # Optional: override PLAIN_DEFAULT
|
||||
```
|
||||
|
||||
**For multi-image comics (webtoon style):**
|
||||
```python
|
||||
{
|
||||
'number': 2,
|
||||
'filename': ['page1.png', 'page2.png', 'page3.png'], # List of images
|
||||
'alt_text': ['Panel 1 description', 'Panel 2', 'Panel 3'], # Individual alt texts
|
||||
'date': '2025-01-08',
|
||||
'full_width': True # Recommended for webtoons
|
||||
}
|
||||
```yaml
|
||||
number: 2
|
||||
filename:
|
||||
- page1.png
|
||||
- page2.png
|
||||
- page3.png
|
||||
alt_text:
|
||||
- Panel 1 description
|
||||
- Panel 2 description
|
||||
- Panel 3 description
|
||||
date: '2025-01-08'
|
||||
full_width: true # Recommended for webtoons
|
||||
```
|
||||
|
||||
### Adding a New Comic
|
||||
|
||||
**Option 1: Use the script (recommended)**
|
||||
```bash
|
||||
# Add comic entry only
|
||||
# Add comic YAML file with defaults
|
||||
python scripts/add_comic.py
|
||||
|
||||
# Add comic entry AND create markdown file for author notes
|
||||
# Add comic YAML file AND create markdown file for author notes
|
||||
python scripts/add_comic.py -m
|
||||
```
|
||||
This will automatically add a new entry with defaults. The `-m` flag creates a markdown file in `content/author_notes/{date}.md` with a template and adds the `author_note_md` field to the comic entry. Then edit `comics_data.py` to customize.
|
||||
This will create a new YAML file in `data/comics/` with the next comic number and reasonable defaults. The `-m` flag also creates a markdown file in `content/author_notes/{date}.md` with a template. Then:
|
||||
1. Edit the generated YAML file to customize title, alt_text, author_note, etc.
|
||||
2. Upload your comic image to `static/images/comics/`
|
||||
3. Optionally create a thumbnail in `static/images/thumbs/` with the same filename
|
||||
|
||||
**Option 2: Manual**
|
||||
1. Save your comic image in `static/images/comics/` (e.g., `comic-001.png`)
|
||||
2. Optionally, create a thumbnail in `static/images/thumbs/` with the same filename
|
||||
3. Add the comic entry to the `COMICS` list in `comics_data.py`
|
||||
1. Copy `data/comics/TEMPLATE.yaml` and rename it (e.g., `003.yaml`)
|
||||
2. Edit the YAML file to set comic properties
|
||||
3. Save your comic image in `static/images/comics/`
|
||||
4. Optionally, create a thumbnail in `static/images/thumbs/` with the same filename
|
||||
|
||||
### Generating RSS Feed
|
||||
### Publishing Comics
|
||||
|
||||
After adding comics, regenerate the RSS feed:
|
||||
After adding or updating comics, use the publish script to update all generated files:
|
||||
```bash
|
||||
python scripts/generate_rss.py
|
||||
python scripts/publish_comic.py
|
||||
```
|
||||
This creates/updates `static/feed.rss`
|
||||
This convenience script rebuilds the cache and regenerates both RSS feed and sitemap in one command.
|
||||
|
||||
### Comic Caching System
|
||||
|
||||
Sunday Comics uses an automatic caching system to speed up comic loading:
|
||||
|
||||
**How it works:**
|
||||
- **First load**: Parses all YAML files, saves to `data/comics/.comics_cache.pkl`
|
||||
- **Subsequent loads**: Reads from cache (~100x faster)
|
||||
- **Auto-invalidation**: Cache rebuilds automatically when any YAML file is modified
|
||||
|
||||
**Performance (1000 comics):**
|
||||
- Initial load: ~2-3 seconds (builds cache)
|
||||
- Subsequent loads: ~0.01 seconds (uses cache)
|
||||
- Scripts share the same cache file on disk
|
||||
|
||||
**Manual cache management:**
|
||||
```bash
|
||||
# Force rebuild the cache (normally not needed)
|
||||
python scripts/rebuild_cache.py
|
||||
|
||||
# Disable caching (for debugging)
|
||||
export DISABLE_COMIC_CACHE=true
|
||||
python app.py
|
||||
```
|
||||
|
||||
The cache file is automatically excluded from git (listed in `.gitignore`).
|
||||
|
||||
### Markdown Support
|
||||
|
||||
**Author Notes:**
|
||||
Add the `author_note_md` field to your comic entry in `comics_data.py` to use markdown-formatted author notes. The field can be:
|
||||
- Just a filename (e.g., `"2025-01-01.md"`) - looked up in `content/author_notes/`
|
||||
- A path relative to `content/` (e.g., `"special/intro.md"`)
|
||||
Add the `author_note_md` field to your comic YAML file to use markdown-formatted author notes. The field can be:
|
||||
- Just a filename (e.g., `2025-01-01.md`) - looked up in `content/author_notes/`
|
||||
- A path relative to `content/` (e.g., `special/intro.md`)
|
||||
|
||||
Markdown author notes take precedence over the plain text `author_note` field and render as HTML.
|
||||
|
||||
Example:
|
||||
```python
|
||||
# In comics_data.py
|
||||
{
|
||||
'number': 1,
|
||||
'filename': 'comic-001.png',
|
||||
'date': '2025-01-01',
|
||||
'alt_text': 'First comic',
|
||||
'author_note_md': '2025-01-01.md' # References content/author_notes/2025-01-01.md
|
||||
}
|
||||
```yaml
|
||||
# In data/comics/001.yaml
|
||||
number: 1
|
||||
filename: comic-001.png
|
||||
date: '2025-01-01'
|
||||
alt_text: First comic
|
||||
author_note_md: 2025-01-01.md # References content/author_notes/2025-01-01.md
|
||||
```
|
||||
|
||||
```bash
|
||||
@@ -823,31 +873,34 @@ Sunday Comics supports vertical scrolling comics with multiple images stacked se
|
||||
- No click-through navigation on multi-image comics (use navigation buttons instead)
|
||||
|
||||
**Basic Example:**
|
||||
```python
|
||||
# In comics_data.py
|
||||
{
|
||||
'number': 4,
|
||||
'title': 'Webtoon Episode 1',
|
||||
'filename': ['page1.jpg', 'page2.jpg', 'page3.jpg'], # List of images
|
||||
'alt_text': 'A three-part vertical story', # Single alt text for all images
|
||||
'date': '2025-01-22',
|
||||
}
|
||||
```yaml
|
||||
# In data/comics/004.yaml
|
||||
number: 4
|
||||
title: Webtoon Episode 1
|
||||
filename:
|
||||
- page1.jpg
|
||||
- page2.jpg
|
||||
- page3.jpg
|
||||
alt_text: A three-part vertical story # Single alt text for all images
|
||||
date: '2025-01-22'
|
||||
```
|
||||
|
||||
**Individual Alt Text (Recommended for Accessibility):**
|
||||
```python
|
||||
{
|
||||
'number': 5,
|
||||
'title': 'Long Scroll Episode',
|
||||
'filename': ['scene1.png', 'scene2.png', 'scene3.png', 'scene4.png'],
|
||||
'alt_text': [
|
||||
'Opening scene showing the city at dawn',
|
||||
'Character walking through the marketplace',
|
||||
'Close-up of the mysterious artifact',
|
||||
'Dramatic reveal of the antagonist'
|
||||
], # List must match number of images (or use single string for all)
|
||||
'date': '2025-01-29',
|
||||
}
|
||||
```yaml
|
||||
# In data/comics/005.yaml
|
||||
number: 5
|
||||
title: Long Scroll Episode
|
||||
filename:
|
||||
- scene1.png
|
||||
- scene2.png
|
||||
- scene3.png
|
||||
- scene4.png
|
||||
alt_text:
|
||||
- Opening scene showing the city at dawn
|
||||
- Character walking through the marketplace
|
||||
- Close-up of the mysterious artifact
|
||||
- Dramatic reveal of the antagonist
|
||||
date: '2025-01-29'
|
||||
```
|
||||
|
||||
**Important:** If you provide `alt_text` as a list, it should match the number of images in `filename`. If the counts don't match, you'll see a warning in the logs. To use the same alt text for all images, just provide a single string instead of a list.
|
||||
@@ -866,29 +919,26 @@ Sunday Comics supports vertical scrolling comics with multiple images stacked se
|
||||
4. **Image optimization** - Compress images appropriately since readers will load multiple images per comic
|
||||
|
||||
**Example with all options:**
|
||||
```python
|
||||
{
|
||||
'number': 6,
|
||||
'title': 'Chapter 2: The Journey Begins',
|
||||
'filename': [
|
||||
'ch2-001.png',
|
||||
'ch2-002.png',
|
||||
'ch2-003.png',
|
||||
'ch2-004.png',
|
||||
'ch2-005.png'
|
||||
],
|
||||
'alt_text': [
|
||||
'Panel 1: Hero packs their bag at sunrise',
|
||||
'Panel 2: Saying goodbye to the village elder',
|
||||
'Panel 3: Walking along the forest path',
|
||||
'Panel 4: Encountering a mysterious stranger',
|
||||
'Panel 5: Accepting a map to the ancient ruins'
|
||||
],
|
||||
'date': '2025-02-05',
|
||||
'author_note': 'This was so much fun to draw! The journey arc begins.',
|
||||
'full_width': True, # Recommended for webtoon-style comics
|
||||
'section': 'Chapter 2', # Optional: mark the start of a new chapter
|
||||
}
|
||||
```yaml
|
||||
# In data/comics/006.yaml
|
||||
number: 6
|
||||
title: 'Chapter 2: The Journey Begins'
|
||||
filename:
|
||||
- ch2-001.png
|
||||
- ch2-002.png
|
||||
- ch2-003.png
|
||||
- ch2-004.png
|
||||
- ch2-005.png
|
||||
alt_text:
|
||||
- 'Panel 1: Hero packs their bag at sunrise'
|
||||
- 'Panel 2: Saying goodbye to the village elder'
|
||||
- 'Panel 3: Walking along the forest path'
|
||||
- 'Panel 4: Encountering a mysterious stranger'
|
||||
- 'Panel 5: Accepting a map to the ancient ruins'
|
||||
date: '2025-02-05'
|
||||
author_note: This was so much fun to draw! The journey arc begins.
|
||||
full_width: true # Recommended for webtoon-style comics
|
||||
section: Chapter 2 # Optional: mark the start of a new chapter
|
||||
```
|
||||
|
||||
**Technical Details:**
|
||||
|
||||
Reference in New Issue
Block a user