Compare commits
3 Commits
9c566bcc3c
...
2b8f30ef82
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b8f30ef82 | |||
| 882eed90f9 | |||
| d374df6b0b |
16
CHANGELOG.md
16
CHANGELOG.md
@@ -14,6 +14,19 @@ and this project uses date-based versioning (YYYY.MM.DD).
|
|||||||
### Fixed
|
### Fixed
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
|
## [2025.11.18] - 2025-11-18
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- HTML embed support for comics (`html_embed` field in YAML allows custom HTML instead of images)
|
||||||
|
- Configurable social links in footer (`SOCIAL_LINKS` in `comics_data.py`)
|
||||||
|
- Customizable newsletter section (`NEWSLETTER_ENABLED` and `NEWSLETTER_HTML` in `comics_data.py`)
|
||||||
|
- CDN option for serving static assets
|
||||||
|
- Upstream update workflow (`UPSTREAM.md`) for fork-friendly development
|
||||||
|
- Automatic cache building, RSS feed, and sitemap generation in Docker container
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Footer social links now fully customizable with any platform (Instagram, YouTube, Patreon, etc.)
|
||||||
|
|
||||||
## [2025.11.15] - 2025-11-15
|
## [2025.11.15] - 2025-11-15
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -25,5 +38,6 @@ and this project uses date-based versioning (YYYY.MM.DD).
|
|||||||
- This CHANGELOG.md file to track version history
|
- This CHANGELOG.md file to track version history
|
||||||
- Version bump script (`scripts/bump_version.py`) to automate releases
|
- Version bump script (`scripts/bump_version.py`) to automate releases
|
||||||
|
|
||||||
[Unreleased]: https://git.puercito.net/mi/sunday/compare/v2025.11.15...HEAD
|
[Unreleased]: https://git.puercito.net/mi/sunday/compare/v2025.11.18...HEAD
|
||||||
|
[2025.11.18]: https://git.puercito.net/mi/sunday/compare/v2025.11.15...v2025.11.18
|
||||||
[2025.11.15]: https://git.puercito.net/mi/sunday/releases/tag/v2025.11.15
|
[2025.11.15]: https://git.puercito.net/mi/sunday/releases/tag/v2025.11.15
|
||||||
|
|||||||
26
CLAUDE.md
26
CLAUDE.md
@@ -214,7 +214,8 @@ Performance with caching (1000 comics):
|
|||||||
|
|
||||||
Each comic YAML file contains:
|
Each comic YAML file contains:
|
||||||
- `number` (required): Sequential comic number
|
- `number` (required): Sequential comic number
|
||||||
- `filename` (required): Image filename in `static/images/comics/` OR list of filenames for multi-image comics (webtoon style)
|
- `filename` (required unless using html_embed): Image filename in `static/images/comics/` OR list of filenames for multi-image comics (webtoon style)
|
||||||
|
- `html_embed` (optional): Custom HTML to embed instead of an image (e.g., video player, widget). Takes precedence over `filename`.
|
||||||
- `date` (required): Publication date in YYYY-MM-DD format
|
- `date` (required): Publication date in YYYY-MM-DD format
|
||||||
- `alt_text` (required): Accessibility text OR list of alt texts (one per image for multi-image comics)
|
- `alt_text` (required): Accessibility text OR list of alt texts (one per image for multi-image comics)
|
||||||
- `title` (optional): Comic title (defaults to "#X" if absent)
|
- `title` (optional): Comic title (defaults to "#X" if absent)
|
||||||
@@ -224,6 +225,18 @@ Each comic YAML file contains:
|
|||||||
- `plain` (optional): Override global PLAIN_DEFAULT setting (hides header/border)
|
- `plain` (optional): Override global PLAIN_DEFAULT setting (hides header/border)
|
||||||
- `section` (optional): Section/chapter title (e.g., "Chapter 1: Origins"). Add to first comic of a new section.
|
- `section` (optional): Section/chapter title (e.g., "Chapter 1: Origins"). Add to first comic of a new section.
|
||||||
|
|
||||||
|
**HTML embeds in YAML:**
|
||||||
|
```yaml
|
||||||
|
html_embed: '<iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" width="560" height="315" frameborder="0" allowfullscreen></iframe>'
|
||||||
|
alt_text: "Video description for accessibility"
|
||||||
|
```
|
||||||
|
- Use `html_embed` to display custom HTML content instead of an image
|
||||||
|
- Useful for embedding videos, interactive widgets, or special content
|
||||||
|
- When `html_embed` is present, it takes precedence over `filename` and `mobile_filename`
|
||||||
|
- The HTML is rendered as-is using the `| safe` filter in templates
|
||||||
|
- No click-through navigation on HTML embeds (use navigation buttons instead)
|
||||||
|
- Still provide `alt_text` for accessibility context
|
||||||
|
|
||||||
**Multi-image comics (webtoon style) in YAML:**
|
**Multi-image comics (webtoon style) in YAML:**
|
||||||
```yaml
|
```yaml
|
||||||
filename:
|
filename:
|
||||||
@@ -258,9 +271,7 @@ Global configuration in `comics_data.py`:
|
|||||||
- `USE_FOOTER_SOCIAL_ICONS`: Set to True to use icons instead of text for footer social links (uses instagram.png, youtube.png, mail.png, alert.png)
|
- `USE_FOOTER_SOCIAL_ICONS`: Set to True to use icons instead of text for footer social links (uses instagram.png, youtube.png, mail.png, alert.png)
|
||||||
- `NEWSLETTER_ENABLED`: Set to True to show newsletter section in footer
|
- `NEWSLETTER_ENABLED`: Set to True to show newsletter section in footer
|
||||||
- `NEWSLETTER_HTML`: Custom HTML for newsletter form (user pastes their service's form code here)
|
- `NEWSLETTER_HTML`: Custom HTML for newsletter form (user pastes their service's form code here)
|
||||||
- `SOCIAL_INSTAGRAM`: Instagram URL (set to None to hide)
|
- `SOCIAL_LINKS`: List of dicts for social media links. Each dict has 'label', 'url', and optional 'icon' (filename in static/images/icons/). Users can add any platform (Instagram, YouTube, Bluesky, Patreon, etc.)
|
||||||
- `SOCIAL_YOUTUBE`: YouTube URL (set to None to hide)
|
|
||||||
- `SOCIAL_EMAIL`: Email mailto link (set to None to hide)
|
|
||||||
|
|
||||||
### Markdown Support
|
### Markdown Support
|
||||||
|
|
||||||
@@ -291,7 +302,8 @@ Global configuration in `comics_data.py`:
|
|||||||
Provides SPA-like navigation without page reloads:
|
Provides SPA-like navigation without page reloads:
|
||||||
- Fetches comics from `/api/comics/<id>`
|
- Fetches comics from `/api/comics/<id>`
|
||||||
- Updates DOM with `displayComic(comic)` function
|
- Updates DOM with `displayComic(comic)` function
|
||||||
- Handles navigation buttons and image click-through
|
- Handles navigation buttons and image click-through (disabled for HTML embeds and multi-image comics)
|
||||||
|
- Renders HTML embeds, multi-image comics, and single-image comics dynamically
|
||||||
- Uses History API to maintain proper URLs and browser back/forward
|
- Uses History API to maintain proper URLs and browser back/forward
|
||||||
- Shows/hides header based on plain mode
|
- Shows/hides header based on plain mode
|
||||||
- Adjusts container for full_width mode
|
- Adjusts container for full_width mode
|
||||||
@@ -320,9 +332,7 @@ Global context variables injected into all templates:
|
|||||||
- `use_footer_social_icons`: Boolean for footer social link icons from `comics_data.py`
|
- `use_footer_social_icons`: Boolean for footer social link icons from `comics_data.py`
|
||||||
- `newsletter_enabled`: Boolean to show/hide newsletter section from `comics_data.py`
|
- `newsletter_enabled`: Boolean to show/hide newsletter section from `comics_data.py`
|
||||||
- `newsletter_html`: Custom HTML for newsletter form from `comics_data.py` (rendered with `| safe` filter)
|
- `newsletter_html`: Custom HTML for newsletter form from `comics_data.py` (rendered with `| safe` filter)
|
||||||
- `social_instagram`: Instagram URL from `comics_data.py`
|
- `social_links`: List of social media link dicts from `comics_data.py` (each with 'label', 'url', 'icon')
|
||||||
- `social_youtube`: YouTube URL from `comics_data.py`
|
|
||||||
- `social_email`: Email link from `comics_data.py`
|
|
||||||
|
|
||||||
## Static Assets
|
## Static Assets
|
||||||
|
|
||||||
|
|||||||
6
app.py
6
app.py
@@ -11,7 +11,7 @@ from comics_data import (
|
|||||||
HEADER_IMAGE, FOOTER_IMAGE, BANNER_IMAGE, COMPACT_FOOTER, ARCHIVE_FULL_WIDTH, SECTIONS_ENABLED,
|
HEADER_IMAGE, FOOTER_IMAGE, BANNER_IMAGE, COMPACT_FOOTER, ARCHIVE_FULL_WIDTH, SECTIONS_ENABLED,
|
||||||
USE_COMIC_NAV_ICONS, USE_HEADER_NAV_ICONS, USE_FOOTER_SOCIAL_ICONS, USE_SHARE_ICONS,
|
USE_COMIC_NAV_ICONS, USE_HEADER_NAV_ICONS, USE_FOOTER_SOCIAL_ICONS, USE_SHARE_ICONS,
|
||||||
NEWSLETTER_ENABLED, NEWSLETTER_HTML,
|
NEWSLETTER_ENABLED, NEWSLETTER_HTML,
|
||||||
SOCIAL_INSTAGRAM, SOCIAL_YOUTUBE, SOCIAL_EMAIL, API_SPEC_LINK, EMBED_ENABLED, PERMALINK_ENABLED
|
SOCIAL_LINKS, API_SPEC_LINK, EMBED_ENABLED, PERMALINK_ENABLED
|
||||||
)
|
)
|
||||||
import markdown
|
import markdown
|
||||||
from version import __version__
|
from version import __version__
|
||||||
@@ -74,9 +74,7 @@ def inject_global_settings():
|
|||||||
'use_share_icons': USE_SHARE_ICONS,
|
'use_share_icons': USE_SHARE_ICONS,
|
||||||
'newsletter_enabled': NEWSLETTER_ENABLED,
|
'newsletter_enabled': NEWSLETTER_ENABLED,
|
||||||
'newsletter_html': NEWSLETTER_HTML,
|
'newsletter_html': NEWSLETTER_HTML,
|
||||||
'social_instagram': SOCIAL_INSTAGRAM,
|
'social_links': SOCIAL_LINKS,
|
||||||
'social_youtube': SOCIAL_YOUTUBE,
|
|
||||||
'social_email': SOCIAL_EMAIL,
|
|
||||||
'api_spec_link': API_SPEC_LINK,
|
'api_spec_link': API_SPEC_LINK,
|
||||||
'embed_enabled': EMBED_ENABLED,
|
'embed_enabled': EMBED_ENABLED,
|
||||||
'permalink_enabled': PERMALINK_ENABLED,
|
'permalink_enabled': PERMALINK_ENABLED,
|
||||||
|
|||||||
@@ -97,10 +97,19 @@ NEWSLETTER_ENABLED = False
|
|||||||
# '''
|
# '''
|
||||||
NEWSLETTER_HTML = '<p class="newsletter-placeholder">Newsletter coming soon!</p>'
|
NEWSLETTER_HTML = '<p class="newsletter-placeholder">Newsletter coming soon!</p>'
|
||||||
|
|
||||||
# Social media links - set to None to hide the link
|
# Social media links - add/remove/reorder as needed
|
||||||
SOCIAL_INSTAGRAM = None # e.g., 'https://instagram.com/yourhandle'
|
# Each link should have 'label', 'url', and optionally 'icon' (filename in static/images/icons/)
|
||||||
SOCIAL_YOUTUBE = None # e.g., 'https://youtube.com/@yourchannel'
|
# Set to empty list [] to show no social links
|
||||||
SOCIAL_EMAIL = None # e.g., 'mailto:your@email.com'
|
SOCIAL_LINKS = [
|
||||||
|
# Example links (uncomment and customize):
|
||||||
|
# {'label': 'Instagram', 'url': 'https://instagram.com/yourhandle', 'icon': 'instagram.png'},
|
||||||
|
# {'label': 'YouTube', 'url': 'https://youtube.com/@yourchannel', 'icon': 'youtube.png'},
|
||||||
|
# {'label': 'Email', 'url': 'mailto:your@email.com', 'icon': 'mail.png'},
|
||||||
|
# {'label': 'Bluesky', 'url': 'https://bsky.app/profile/yourhandle', 'icon': 'bluesky.png'},
|
||||||
|
# {'label': 'Patreon', 'url': 'https://patreon.com/yourname', 'icon': 'patreon.png'},
|
||||||
|
# {'label': 'Ko-fi', 'url': 'https://ko-fi.com/yourname', 'icon': 'kofi.png'},
|
||||||
|
# {'label': 'Mastodon', 'url': 'https://mastodon.social/@yourhandle', 'icon': 'mastodon.png'},
|
||||||
|
]
|
||||||
|
|
||||||
# API documentation link - set to None to hide the link
|
# API documentation link - set to None to hide the link
|
||||||
# Path is relative to static/ directory
|
# Path is relative to static/ directory
|
||||||
|
|||||||
@@ -97,10 +97,19 @@ NEWSLETTER_ENABLED = False
|
|||||||
# '''
|
# '''
|
||||||
NEWSLETTER_HTML = '<p class="newsletter-placeholder">Newsletter coming soon!</p>'
|
NEWSLETTER_HTML = '<p class="newsletter-placeholder">Newsletter coming soon!</p>'
|
||||||
|
|
||||||
# Social media links - set to None to hide the link
|
# Social media links - add/remove/reorder as needed
|
||||||
SOCIAL_INSTAGRAM = None # e.g., 'https://instagram.com/yourhandle'
|
# Each link should have 'label', 'url', and optionally 'icon' (filename in static/images/icons/)
|
||||||
SOCIAL_YOUTUBE = None # e.g., 'https://youtube.com/@yourchannel'
|
# Set to empty list [] to show no social links
|
||||||
SOCIAL_EMAIL = None # e.g., 'mailto:your@email.com'
|
SOCIAL_LINKS = [
|
||||||
|
# Example links (uncomment and customize):
|
||||||
|
# {'label': 'Instagram', 'url': 'https://instagram.com/yourhandle', 'icon': 'instagram.png'},
|
||||||
|
# {'label': 'YouTube', 'url': 'https://youtube.com/@yourchannel', 'icon': 'youtube.png'},
|
||||||
|
# {'label': 'Email', 'url': 'mailto:your@email.com', 'icon': 'mail.png'},
|
||||||
|
# {'label': 'Bluesky', 'url': 'https://bsky.app/profile/yourhandle', 'icon': 'bluesky.png'},
|
||||||
|
# {'label': 'Patreon', 'url': 'https://patreon.com/yourname', 'icon': 'patreon.png'},
|
||||||
|
# {'label': 'Ko-fi', 'url': 'https://ko-fi.com/yourname', 'icon': 'kofi.png'},
|
||||||
|
# {'label': 'Mastodon', 'url': 'https://mastodon.social/@yourhandle', 'icon': 'mastodon.png'},
|
||||||
|
]
|
||||||
|
|
||||||
# API documentation link - set to None to hide the link
|
# API documentation link - set to None to hide the link
|
||||||
# Path is relative to static/ directory
|
# Path is relative to static/ directory
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# REQUIRED: Sequential comic number
|
# REQUIRED: Sequential comic number
|
||||||
number: 999
|
number: 999
|
||||||
|
|
||||||
# REQUIRED: Image filename(s) in static/images/comics/
|
# REQUIRED (unless using html_embed): Image filename(s) in static/images/comics/
|
||||||
# Single image:
|
# Single image:
|
||||||
filename: comic-999.jpg
|
filename: comic-999.jpg
|
||||||
# OR multi-image (webtoon style):
|
# OR multi-image (webtoon style):
|
||||||
@@ -18,6 +18,12 @@ filename: comic-999.jpg
|
|||||||
# Optional: Mobile-optimized version of the comic
|
# Optional: Mobile-optimized version of the comic
|
||||||
# mobile_filename: comic-999-mobile.jpg
|
# mobile_filename: comic-999-mobile.jpg
|
||||||
|
|
||||||
|
# Optional: HTML embed instead of image
|
||||||
|
# Use this to embed videos, widgets, or other HTML content
|
||||||
|
# When set, this takes precedence over filename/mobile_filename
|
||||||
|
# Example: '<iframe src="https://www.youtube.com/embed/..." width="560" height="315"></iframe>'
|
||||||
|
# html_embed: '<div>Your custom HTML here</div>'
|
||||||
|
|
||||||
# REQUIRED: Publication date (YYYY-MM-DD format)
|
# REQUIRED: Publication date (YYYY-MM-DD format)
|
||||||
date: "2025-01-01"
|
date: "2025-01-01"
|
||||||
|
|
||||||
|
|||||||
@@ -80,8 +80,8 @@
|
|||||||
const comicImageDiv = document.querySelector('.comic-image');
|
const comicImageDiv = document.querySelector('.comic-image');
|
||||||
updateComicImage(comicImageDiv, comic, title);
|
updateComicImage(comicImageDiv, comic, title);
|
||||||
|
|
||||||
// Update or create/remove the link wrapper (only for single-image comics)
|
// Update or create/remove the link wrapper (only for single-image comics, not HTML embeds)
|
||||||
if (!comic.is_multi_image) {
|
if (!comic.is_multi_image && !comic.html_embed) {
|
||||||
updateComicImageLink(comic.number);
|
updateComicImageLink(comic.number);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,15 +181,26 @@
|
|||||||
// Clear all existing content
|
// Clear all existing content
|
||||||
comicImageDiv.innerHTML = '';
|
comicImageDiv.innerHTML = '';
|
||||||
|
|
||||||
// Update container class for multi-image
|
// Update container classes
|
||||||
if (comic.is_multi_image) {
|
if (comic.html_embed) {
|
||||||
|
comicImageDiv.classList.add('comic-image-embed');
|
||||||
|
comicImageDiv.classList.remove('comic-image-multi');
|
||||||
|
} else if (comic.is_multi_image) {
|
||||||
comicImageDiv.classList.add('comic-image-multi');
|
comicImageDiv.classList.add('comic-image-multi');
|
||||||
|
comicImageDiv.classList.remove('comic-image-embed');
|
||||||
} else {
|
} else {
|
||||||
comicImageDiv.classList.remove('comic-image-multi');
|
comicImageDiv.classList.remove('comic-image-multi');
|
||||||
|
comicImageDiv.classList.remove('comic-image-embed');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new image element(s)
|
// Create new content
|
||||||
if (comic.is_multi_image) {
|
if (comic.html_embed) {
|
||||||
|
// HTML embed (video, widget, etc.)
|
||||||
|
const embedWrapper = document.createElement('div');
|
||||||
|
embedWrapper.className = 'comic-embed-wrapper';
|
||||||
|
embedWrapper.innerHTML = comic.html_embed;
|
||||||
|
comicImageDiv.appendChild(embedWrapper);
|
||||||
|
} else if (comic.is_multi_image) {
|
||||||
// Multi-image comic (webtoon style)
|
// Multi-image comic (webtoon style)
|
||||||
comic.filenames.forEach((filename, index) => {
|
comic.filenames.forEach((filename, index) => {
|
||||||
const img = document.createElement('img');
|
const img = document.createElement('img');
|
||||||
@@ -447,13 +458,14 @@
|
|||||||
const formattedDate = dateDisplay ? dateDisplay.textContent : null;
|
const formattedDate = dateDisplay ? dateDisplay.textContent : null;
|
||||||
updateNavButtons(currentNumber, formattedDate);
|
updateNavButtons(currentNumber, formattedDate);
|
||||||
|
|
||||||
// Check if current comic is multi-image
|
// Check if current comic is multi-image or HTML embed
|
||||||
const comicImageDiv = document.querySelector('.comic-image');
|
const comicImageDiv = document.querySelector('.comic-image');
|
||||||
const isMultiImage = comicImageDiv && comicImageDiv.classList.contains('comic-image-multi');
|
const isMultiImage = comicImageDiv && comicImageDiv.classList.contains('comic-image-multi');
|
||||||
|
const isHtmlEmbed = comicImageDiv && comicImageDiv.classList.contains('comic-image-embed');
|
||||||
|
|
||||||
if (!isMultiImage) {
|
if (!isMultiImage && !isHtmlEmbed) {
|
||||||
updateComicImageLink(currentNumber);
|
updateComicImageLink(currentNumber);
|
||||||
} else {
|
} else if (isMultiImage) {
|
||||||
// Initialize lazy loading for multi-image comics on page load
|
// Initialize lazy loading for multi-image comics on page load
|
||||||
initLazyLoad();
|
initLazyLoad();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,33 +103,15 @@
|
|||||||
<div class="footer-section">
|
<div class="footer-section">
|
||||||
<h3>Follow</h3>
|
<h3>Follow</h3>
|
||||||
<div class="social-links{% if use_footer_social_icons %} social-links-icons{% endif %}">
|
<div class="social-links{% if use_footer_social_icons %} social-links-icons{% endif %}">
|
||||||
{% if social_instagram %}
|
{% for link in social_links %}
|
||||||
<a href="{{ social_instagram }}" target="_blank" rel="noopener noreferrer" aria-label="Instagram">
|
<a href="{{ link.url }}" {% if link.url.startswith('http') %}target="_blank" rel="noopener noreferrer"{% endif %} aria-label="{{ link.label }}">
|
||||||
{% if use_footer_social_icons %}
|
{% if use_footer_social_icons and link.icon %}
|
||||||
<img src="{{ 'images/icons/instagram.png' | cdn_static }}" alt="" class="social-icon">
|
<img src="{{ ('images/icons/' + link.icon) | cdn_static }}" alt="" class="social-icon">
|
||||||
{% else %}
|
{% else %}
|
||||||
Instagram
|
{{ link.label }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endfor %}
|
||||||
{% if social_youtube %}
|
|
||||||
<a href="{{ social_youtube }}" target="_blank" rel="noopener noreferrer" aria-label="YouTube">
|
|
||||||
{% if use_footer_social_icons %}
|
|
||||||
<img src="{{ 'images/icons/youtube.png' | cdn_static }}" alt="" class="social-icon">
|
|
||||||
{% else %}
|
|
||||||
YouTube
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if social_email %}
|
|
||||||
<a href="{{ social_email }}" aria-label="Email">
|
|
||||||
{% if use_footer_social_icons %}
|
|
||||||
<img src="{{ 'images/icons/mail .png' | cdn_static }}" alt="" class="social-icon">
|
|
||||||
{% else %}
|
|
||||||
Email
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
<a href="{{ 'feed.rss' | cdn_static }}" aria-label="RSS Feed">
|
<a href="{{ 'feed.rss' | cdn_static }}" aria-label="RSS Feed">
|
||||||
{% if use_footer_social_icons %}
|
{% if use_footer_social_icons %}
|
||||||
<img src="{{ 'images/icons/rss.png' | cdn_static }}" alt="" class="social-icon">
|
<img src="{{ 'images/icons/rss.png' | cdn_static }}" alt="" class="social-icon">
|
||||||
|
|||||||
@@ -37,8 +37,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="comic-image{% if comic.is_multi_image %} comic-image-multi{% endif %}" id="comic-image-focus" tabindex="-1">
|
<div class="comic-image{% if comic.is_multi_image %} comic-image-multi{% endif %}{% if comic.html_embed %} comic-image-embed{% endif %}" id="comic-image-focus" tabindex="-1">
|
||||||
{% if comic.is_multi_image %}
|
{% if comic.html_embed %}
|
||||||
|
{# HTML embed (video, widget, etc.) #}
|
||||||
|
<div class="comic-embed-wrapper">
|
||||||
|
{{ comic.html_embed | safe }}
|
||||||
|
</div>
|
||||||
|
{% elif comic.is_multi_image %}
|
||||||
{# Multi-image layout (webtoon style) - no click-through on individual images #}
|
{# Multi-image layout (webtoon style) - no click-through on individual images #}
|
||||||
{% for i in range(comic.filenames|length) %}
|
{% for i in range(comic.filenames|length) %}
|
||||||
<img src="{% if loop.first %}{{ ('images/comics/' + comic.filenames[i]) | cdn_static }}{% endif %}"
|
<img src="{% if loop.first %}{{ ('images/comics/' + comic.filenames[i]) | cdn_static }}{% endif %}"
|
||||||
|
|||||||
@@ -16,8 +16,13 @@
|
|||||||
<p class="comic-date">{{ comic.date }}</p>
|
<p class="comic-date">{{ comic.date }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="comic-image{% if comic.is_multi_image %} comic-image-multi{% endif %}" id="comic-image-focus" tabindex="-1">
|
<div class="comic-image{% if comic.is_multi_image %} comic-image-multi{% endif %}{% if comic.html_embed %} comic-image-embed{% endif %}" id="comic-image-focus" tabindex="-1">
|
||||||
{% if comic.is_multi_image %}
|
{% if comic.html_embed %}
|
||||||
|
{# HTML embed (video, widget, etc.) #}
|
||||||
|
<div class="comic-embed-wrapper">
|
||||||
|
{{ comic.html_embed | safe }}
|
||||||
|
</div>
|
||||||
|
{% elif comic.is_multi_image %}
|
||||||
{# Multi-image layout (webtoon style) - no click-through on individual images #}
|
{# Multi-image layout (webtoon style) - no click-through on individual images #}
|
||||||
{% for i in range(comic.filenames|length) %}
|
{% for i in range(comic.filenames|length) %}
|
||||||
<img src="{% if loop.first %}{{ ('images/comics/' + comic.filenames[i]) | cdn_static }}{% endif %}"
|
<img src="{% if loop.first %}{{ ('images/comics/' + comic.filenames[i]) | cdn_static }}{% endif %}"
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
# This file contains the version number for the project
|
# This file contains the version number for the project
|
||||||
# Format: YYYY.MM.DD (date-based versioning)
|
# Format: YYYY.MM.DD (date-based versioning)
|
||||||
|
|
||||||
__version__ = "2025.11.15"
|
__version__ = "2025.11.18"
|
||||||
|
|||||||
Reference in New Issue
Block a user