From 512f1ce9b2829e587f4228dfb4f360d5c47fc265 Mon Sep 17 00:00:00 2001 From: Mischa Date: Sat, 20 Jun 2026 23:25:16 +0200 Subject: [PATCH] feat(story-blocks): add full-bleed and image-caption shortcodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two new shortcodes for immersive storytelling: - [full-bleed image="" caption="" credit=""] — viewport-wide image, max 80vh - [image-caption image="" caption="" credit="" width="column|full|bleed"] — photo at configurable width with caption Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01WPJztrVGbwic2xTG7G9fjM --- .../shortcodes/FullBleedShortcode.php | 34 +++++++++++ .../shortcodes/ImageCaptionShortcode.php | 37 ++++++++++++ themes/intotheeast/css/style.css | 59 +++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 plugins/story-blocks/shortcodes/FullBleedShortcode.php create mode 100644 plugins/story-blocks/shortcodes/ImageCaptionShortcode.php diff --git a/plugins/story-blocks/shortcodes/FullBleedShortcode.php b/plugins/story-blocks/shortcodes/FullBleedShortcode.php new file mode 100644 index 0000000..6664685 --- /dev/null +++ b/plugins/story-blocks/shortcodes/FullBleedShortcode.php @@ -0,0 +1,34 @@ +shortcode->getHandlers()->add('full-bleed', function (ShortcodeInterface $sc) { + $plugin = $this->grav['plugins']->getPlugin('story-blocks'); + $page = $plugin ? $plugin->getCurrentPage() : null; + + $imageName = htmlspecialchars($sc->getParameter('image', ''), ENT_QUOTES); + $alt = htmlspecialchars($sc->getParameter('alt', ''), ENT_QUOTES); + $caption = htmlspecialchars($sc->getParameter('caption', ''), ENT_QUOTES); + $credit = htmlspecialchars($sc->getParameter('credit', ''), ENT_QUOTES); + $imageUrl = ($page && $imageName) ? $page->url() . '/' . $imageName : $imageName; + + $captionHtml = ''; + if ($caption || $credit) { + $creditHtml = $credit ? ' · ' . $credit . '' : ''; + $captionHtml = '
' . $caption . $creditHtml . '
'; + } + + return << + {$alt} + {$captionHtml} + +HTML; + }); + } +} diff --git a/plugins/story-blocks/shortcodes/ImageCaptionShortcode.php b/plugins/story-blocks/shortcodes/ImageCaptionShortcode.php new file mode 100644 index 0000000..9848312 --- /dev/null +++ b/plugins/story-blocks/shortcodes/ImageCaptionShortcode.php @@ -0,0 +1,37 @@ +shortcode->getHandlers()->add('image-caption', function (ShortcodeInterface $sc) { + $plugin = $this->grav['plugins']->getPlugin('story-blocks'); + $page = $plugin ? $plugin->getCurrentPage() : null; + + $imageName = htmlspecialchars($sc->getParameter('image', ''), ENT_QUOTES); + $alt = htmlspecialchars($sc->getParameter('alt', ''), ENT_QUOTES); + $caption = htmlspecialchars($sc->getParameter('caption', ''), ENT_QUOTES); + $credit = htmlspecialchars($sc->getParameter('credit', ''), ENT_QUOTES); + $width = $sc->getParameter('width', 'column'); + if (!in_array($width, ['column', 'full', 'bleed'])) $width = 'column'; + $imageUrl = ($page && $imageName) ? $page->url() . '/' . $imageName : $imageName; + + $widthClass = $width !== 'column' ? ' img-caption--' . $width : ''; + $captionHtml = ''; + if ($caption || $credit) { + $creditHtml = $credit ? ' · ' . $credit . '' : ''; + $captionHtml = '
' . $caption . $creditHtml . '
'; + } + + return << + {$alt} + {$captionHtml} + +HTML; + }); + } +} diff --git a/themes/intotheeast/css/style.css b/themes/intotheeast/css/style.css index 1b08180..732c2ec 100644 --- a/themes/intotheeast/css/style.css +++ b/themes/intotheeast/css/style.css @@ -1647,6 +1647,65 @@ body::after { } .pgallery__dot.is-active { background: var(--color-accent); } +/* ── FullBleed shortcode ──────────────────────────────────── */ +.full-bleed { + width: 100vw; + left: 50%; + margin-left: -50vw; + position: relative; + margin-top: var(--space-16); + margin-bottom: var(--space-16); +} +.full-bleed__img { + width: 100%; + display: block; + max-height: 80vh; + object-fit: cover; +} +.full-bleed__caption { + text-align: center; + font-family: var(--font-ui); + font-size: var(--text-sm); + color: var(--color-ink-muted); + margin-top: var(--space-3); + padding: 0 var(--space-8); +} +.full-bleed__credit { font-style: italic; } + +/* ── ImageCaption shortcode ───────────────────────────────── */ +.img-caption { + margin-top: var(--space-12); + margin-bottom: var(--space-12); +} +.img-caption__img { + width: 100%; + display: block; + border-radius: var(--radius-sm); +} +.img-caption__text { + font-family: var(--font-ui); + font-size: var(--text-sm); + color: var(--color-ink-muted); + margin-top: var(--space-3); +} +.img-caption__credit { font-style: italic; } +.img-caption--full { + width: calc(100% + var(--space-16)); + margin-left: calc(var(--space-8) * -1); +} +.img-caption--full .img-caption__img { border-radius: 0; } +.img-caption--bleed { + width: 100vw; + left: 50%; + margin-left: -50vw; + position: relative; +} +.img-caption--bleed .img-caption__img { + border-radius: 0; + max-height: 80vh; + object-fit: cover; +} + /* ── Stories listing ──────────────────────────────────────── */ .stories-listing { padding: var(--space-10) 0; } .stories-listing__heading {