diff --git a/CLAUDE.md b/CLAUDE.md index 47d347d..8596ade 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -214,7 +214,8 @@ Performance with caching (1000 comics): Each comic YAML file contains: - `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 - `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) @@ -224,6 +225,18 @@ Each comic YAML file contains: - `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. +**HTML embeds in YAML:** +```yaml +html_embed: '' +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:** ```yaml filename: @@ -289,7 +302,8 @@ Global configuration in `comics_data.py`: Provides SPA-like navigation without page reloads: - Fetches comics from `/api/comics/` - 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 - Shows/hides header based on plain mode - Adjusts container for full_width mode diff --git a/data/comics/TEMPLATE.yaml b/data/comics/TEMPLATE.yaml index 4078c80..911e572 100644 --- a/data/comics/TEMPLATE.yaml +++ b/data/comics/TEMPLATE.yaml @@ -6,7 +6,7 @@ # REQUIRED: Sequential comic number number: 999 -# REQUIRED: Image filename(s) in static/images/comics/ +# REQUIRED (unless using html_embed): Image filename(s) in static/images/comics/ # Single image: filename: comic-999.jpg # OR multi-image (webtoon style): @@ -18,6 +18,12 @@ filename: comic-999.jpg # Optional: Mobile-optimized version of the comic # 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: '' +# html_embed: '
Your custom HTML here
' + # REQUIRED: Publication date (YYYY-MM-DD format) date: "2025-01-01" diff --git a/static/js/comic-nav.js b/static/js/comic-nav.js index 59a1985..3818816 100644 --- a/static/js/comic-nav.js +++ b/static/js/comic-nav.js @@ -80,8 +80,8 @@ const comicImageDiv = document.querySelector('.comic-image'); updateComicImage(comicImageDiv, comic, title); - // Update or create/remove the link wrapper (only for single-image comics) - if (!comic.is_multi_image) { + // Update or create/remove the link wrapper (only for single-image comics, not HTML embeds) + if (!comic.is_multi_image && !comic.html_embed) { updateComicImageLink(comic.number); } @@ -181,15 +181,26 @@ // Clear all existing content comicImageDiv.innerHTML = ''; - // Update container class for multi-image - if (comic.is_multi_image) { + // Update container classes + 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.remove('comic-image-embed'); } else { comicImageDiv.classList.remove('comic-image-multi'); + comicImageDiv.classList.remove('comic-image-embed'); } - // Create new image element(s) - if (comic.is_multi_image) { + // Create new content + 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) comic.filenames.forEach((filename, index) => { const img = document.createElement('img'); @@ -447,13 +458,14 @@ const formattedDate = dateDisplay ? dateDisplay.textContent : null; 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 isMultiImage = comicImageDiv && comicImageDiv.classList.contains('comic-image-multi'); + const isHtmlEmbed = comicImageDiv && comicImageDiv.classList.contains('comic-image-embed'); - if (!isMultiImage) { + if (!isMultiImage && !isHtmlEmbed) { updateComicImageLink(currentNumber); - } else { + } else if (isMultiImage) { // Initialize lazy loading for multi-image comics on page load initLazyLoad(); } diff --git a/templates/comic.html b/templates/comic.html index 9bfd1be..3f2bbd4 100644 --- a/templates/comic.html +++ b/templates/comic.html @@ -37,8 +37,13 @@ {% endif %} -
- {% if comic.is_multi_image %} +
+ {% if comic.html_embed %} + {# HTML embed (video, widget, etc.) #} +
+ {{ comic.html_embed | safe }} +
+ {% elif comic.is_multi_image %} {# Multi-image layout (webtoon style) - no click-through on individual images #} {% for i in range(comic.filenames|length) %} {{ comic.date }}

-
- {% if comic.is_multi_image %} +
+ {% if comic.html_embed %} + {# HTML embed (video, widget, etc.) #} +
+ {{ comic.html_embed | safe }} +
+ {% elif comic.is_multi_image %} {# Multi-image layout (webtoon style) - no click-through on individual images #} {% for i in range(comic.filenames|length) %}