Add optional Alternative.image and Feature.color/icon for richer layouts
Deploy / deploy (push) Successful in 1m6s

image: a banner url rendered as <img>, client-fetched directly (never
server-side, so none of ResourceSource::Url's SSRF concern applies).
color: any CSS color, set as the feature's own --feature-accent custom
property (never interpolated into a stylesheet) - draws a left-border
accent; unset means no border, not a fallback to the global --accent.
icon: an Iconify name (lucide:star etc.), rendered via Iconify's public
SVG API - no icon library bundled, matching this app's zero-JS-
dependency content otherwise keeps to.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Bendik Aagaard Lynghaug
2026-08-12 17:34:07 +02:00
co-authored by Claude Sonnet 5
parent a29c025a85
commit 3ccc50248f
3 changed files with 62 additions and 1 deletions
+24
View File
@@ -62,6 +62,13 @@ pub struct Alternative {
pub consequence: Vec<String>,
#[serde(default)]
pub encouragements: Vec<String>,
/// A banner image url, rendered above the description - purely
/// decorative, no upload/hosting mechanism of its own, just an
/// already-hosted url the browser fetches directly (unlike
/// `ResourceSource::Url`, this is never fetched server-side, so it
/// carries none of that variant's SSRF concern).
#[serde(default)]
pub image: Option<String>,
#[serde(default)]
pub features: Vec<Feature>,
/// Names a NATS KV bucket to also durably store this submission
@@ -99,6 +106,23 @@ pub struct Feature {
pub name: String,
#[serde(default)]
pub description: String,
/// Any valid CSS color (hex, named, rgb()/oklch()/...) - set as this
/// feature's own `--feature-accent` custom property rather than
/// interpolated into a stylesheet, so a bad value just fails to
/// apply instead of being live CSS content could inject arbitrary
/// rules into. Unset means no accent border at all (see
/// style/main.css's `.feature`), not a silent fallback to the
/// global `--accent` - a feature that never asked for a color
/// shouldn't suddenly gain a visible border.
#[serde(default)]
pub color: Option<String>,
/// An Iconify icon name (`{prefix}:{name}`, e.g. `lucide:star`),
/// rendered via Iconify's public SVG API
/// (`https://api.iconify.design/{icon}.svg`) - no icon library
/// bundled here, matching this app's zero-JS-dependency content
/// otherwise keeps to.
#[serde(default)]
pub icon: Option<String>,
#[serde(default)]
pub requirements: Vec<Requirement>,
/// Live data this feature pulls in. Read-only unless `transitions`