Files

175 lines
8.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Story Editing Research
Brainstorming session — 2026-06-20. Notes on options for improving the story editing
experience in Admin2. Not a plan — a reference to revisit once real story writing reveals
what actually matters.
---
## The core problem
Stories use shortcode syntax (`[scrolly-section image="x.jpg"]…[/scrolly-section]`) authored
in a single big markdown textarea in Admin2. Three pain points, roughly equal weight:
1. **Fragile syntax** — easy to typo a shortcode and get no useful error
2. **Writing blind** — no preview while editing; you don't see the result until you view the page
3. **Mobile unusable** — Admin2 is desktop-focused; the markdown textarea on a phone is painful
---
## What Keystatic / Sanity / Shorthand taught us
All three tools represent content as a **typed, ordered list of blocks** — not a text string.
In Keystatic the editing flow is: write prose normally → click "+" → pick a block type from a
list → fill in a form with labelled fields → the block appears as an opaque card in the editor.
Authors never see markup. Each block type (hero, gallery, scrolly section) has a typed schema
(image picker, text fields, selects). Sanity's Portable Text uses the same model. Shorthand
(used by BBC, Reuters, National Geographic) is a purpose-built CMS for exactly this kind of
immersive storytelling — their section vocabulary is the best reference for what block types
matter in practice.
**Key insight:** the gap between Grav and these tools is entirely on the authoring side.
Grav's rendering (Twig templates, shortcodes, parallax effects) is perfectly capable.
The problem is that Admin2 was not designed for structured block content authoring.
---
## Snow Fall block vocabulary
The canonical block types that appear across all immersive storytelling platforms:
| Block | What it does | Fields |
|---|---|---|
| **Hero** | Full-bleed opening image/video + title. Chapter opener. | image, headline, subtitle, text position, animation (static / ken-burns) |
| **Narrative text** | Prose reading column. The writing block. | body (markdown) |
| **Full-bleed media** | Single image/video edge-to-edge, no text. Visual pause. | image, caption, credit |
| **Image + caption** | Photo at configurable width with caption below. | image, caption, credit, width (column / full / bleed) |
| **Scrollytelling** | Text panels scroll over a fixed or animated background. | background image, panels (each: headline + body) |
| **Photo gallery** | Multi-image carousel/grid → lightbox. | images (each: file + caption + credit) |
| **Pull quote** | Typographically large extracted quote. | quote text, attribution, optional background |
| **Chapter break** | Major section transition with background image. | image, title, chapter number |
| **Grid / side-by-side** | 23 column photo+text pairs. | columns array |
| **Embed** | YouTube, Vimeo, audio, map. | URL, caption |
Current Grav shortcodes cover: hero (ken-burns), scrollytelling (scrolly-section), gallery
(snap-gallery), pull-quote, chapter-break. Missing from the vocabulary: narrative text as an
explicit block, full-bleed media, image+caption, grid, embed.
---
## The two fundamental approaches
### A — Blueprint-as-blocks (no shortcodes)
Replace the markdown body with a `list` field in the story blueprint. Each list item is a
block with a `type` selector + type-specific sub-fields. Content lives in frontmatter YAML;
the Twig template loops over blocks and renders each one with the right partial. No shortcode
syntax at all.
**Solves all three pain points.** Admin2 form fields are mobile-reasonable. Structure is
explicit and impossible to mis-type.
**One limitation:** Grav's native `list` field doesn't hide/show fields based on the selected
type. Every block card shows ALL fields for ALL block types; the template ignores the unused
ones. It's visually cluttered but functionally correct. This is a solvable UX problem (Grav
roadmap, or a future Admin2 extension) — the data model stays the same when it improves.
### B — Enhanced markdown (keep shortcodes, improve authoring UX)
Keep the markdown textarea; add tooling on top to reduce friction. Multiple options here
(see section below), but all hit an architectural constraint: Admin2 serves its SPA via
`echo $html; exit` which bypasses Grav's entire output pipeline. Standard plugin hooks
for injecting assets don't fire in Admin2. Any JS-based editor enhancement requires either
a fragile output-buffering hack or patching Admin2's pre-built `app/index.html` directly.
---
## 15 options researched
### Options that work natively (no Admin2 hacking required)
**1. Blueprint-as-blocks** — structured YAML fields per block, native Admin2 form rendering.
Best long-term solution for non-technical story editing and mobile. Medium effort (blueprint
YAML + Twig template rework). The field-clutter limitation is real but acceptable.
**2. page-inject sub-pages** — each story block is a standalone Grav sub-page; the parent
story injects them in sequence via `[plugin:page-inject]`. Editing = opening sub-pages
individually. More flexible than blueprint-as-blocks for reusable content but creates
more pages to manage and Admin2 navigation friction.
**3. New shortcodes via YAML + Twig** — shortcode-core supports YAML-configured Twig
shortcodes out of the box (`shortcode-core.yaml` + a Twig file in the theme). No plugin
needed. Used to add `full-bleed` and `image-caption` to the story-blocks plugin.
**4. Obsidian + Gitea git sync** — write stories in Obsidian on desktop or mobile with
snippet templates for shortcodes. Push to Gitea; webhook deploys to production. Zero dev
work. Good mobile writing experience. No image upload from mobile; requires comfort with git.
**5. `/story-editor` custom page** — a purpose-built page (like `/gpx-manager`) that presents
story blocks as drag-reorderable cards with typed forms, talks to the Grav API, designed
mobile-first. Highest effort; best mobile result. Would use the "one custom plugin" slot.
### Options blocked by Admin2's architecture
All of these require injecting JavaScript or CSS into Admin2 pages, which is architecturally
blocked (Admin2 bypasses Grav's output pipeline with `echo $html; exit`):
- EasyMDE / SimpleMDE drop-in (split-pane markdown preview)
- CodeMirror 6 autocomplete + syntax highlighting for shortcodes
- Toast UI Editor (WYSIWYG ↔ markdown toggle)
- Tiptap custom shortcode nodes
- Milkdown
- Slash-command / shortcode palette
- Toolbar-at-bottom CSS (mobile improvement)
- Web Speech API dictation button
**Workaround:** patch Admin2's pre-built `app/index.html` directly. Survives until the next
Admin2 update; a `make patch-admin2` command would re-apply it. Viable for a personal blog
but adds a maintenance step.
### Paid option
**Grav Editor Pro ($75)** — TipTap/ProseMirror-based WYSIWYM editor, confirmed Admin2-
compatible (listed as an optional dependency in the Admin2 README ≥ v2.0.1). When paired
with shortcode-core, shortcodes appear as visual green blocks with a modal form per type.
This is the cleanest story editing experience available without building it yourself. Ruled
out based on preference to avoid paid tools.
---
## Honest CMS comparison: Grav vs Keystatic for storytelling
**Wrong conclusion:** Grav can't do Snow Fall storytelling.
**Right conclusion:** Grav's rendering side (parallax, scrollytelling, ken-burns, galleries)
is fully capable. The authoring experience for structured block content is the genuine weak
point — and the options to improve it cleanly within Admin2 are limited.
Keystatic + a modern frontend (Astro, Next.js) would give a better editorial experience for
story authoring, but at the cost of migrating away from Grav and building a separate frontend.
For a solo travel blogger who is the only author, Grav with an improved shortcode setup or
blueprint-as-blocks is good enough. Keystatic's advantage is significant for publications with
multiple non-technical editors writing daily.
---
## What was actually done (2026-06-20)
- Added `full-bleed` shortcode to `story-blocks` plugin (PHP class + CSS)
- Added `image-caption` shortcode to `story-blocks` plugin (PHP class + CSS), with
`width` parameter: `column` (default) / `full` / `bleed`
- Next step when ready to revisit: write some actual stories, then decide whether
blueprint-as-blocks or the app/index.html patch route is worth pursuing
---
## References
- [Keystatic content components](https://keystatic.com/docs/content-components)
- [Sanity Portable Text](https://www.sanity.io/docs/portable-text)
- [Shorthand storytelling sections](https://shorthand.com/features/sections/)
- [Grav Editor Pro](https://getgrav.org/premium/editor-pro)
- [Admin2 GitHub](https://github.com/getgrav/grav-plugin-admin2)
- [shortcode-core](https://github.com/getgrav/grav-plugin-shortcode-core)