29 Commits
Author SHA1 Message Date
George Cushen 26c336eb6d feat(publications): improve structure + awards/funding/license metadata
Restructure `publication` frontmatter from a flat Markdown string into a
structured object (name, short_name, volume, issue, pages, publisher),
resolved through a new `functions/resolve_publication.html` partial that
also emits a per-page warning pointing legacy sites at `hugoblox migrate
publications`. APA/MLA citation rendering and the publication metadata
row both consume the resolver - no parsing of conventional Markdown
strings at render time.

Add work-level metadata fields surfaced via a new reusable
`components/award_badge.html` partial (variants: pill, card-corner,
inline, row; level-driven icon + colour tokens; pagefind filter):

- `awards[]` - name, level (winner/runner_up/honorable_mention/nominee/
  selected/featured), issuer, date, note, url; skim-row pills above the
  featured image, full row in the metadata grid, corner badges on card
  and slides-gallery views, inline marker on citation views, pill on
  date-title-summary
- `funding[]` - funder + grant + url, rendered as a metadata grid row
- `license` - SPDX-friendly string, metadata grid row
- `peer_reviewed`, `open_access` - status pills, decoupled from
  the publication block so preprints can surface them

Demo content updated in academic-cv (and the same shape in research-lab).
2026-05-27 03:53:21 +01:00
George Cushen 64cdb4a81a refactor(image): centralize page image params and warn on bad shape
Route all .Params.image access through a single normalizer partial that
returns the params as a map and emits a warnf with the expected shape
when frontmatter is set but not an object.
2026-05-27 03:53:21 +01:00
George Cushen bdd3820f27 feat(gallery): sidecar files, EXIF/IPTC, and page-bundle auto-discovery
Adds the metadata pipeline that makes the gallery block self-curating.
Per-image metadata now resolves through a four-tier waterfall, first
non-empty source wins:

  1. Frontmatter (items[].caption etc.)
  2. Sidecar file next to the image - tries six patterns:
     <name>.yaml / .yml / .json and <basename>.yaml / .yml / .json,
     looked up in both site assets and the page bundle (covers album
     mode and page-resource mode alike).
  3. Embedded IPTC/EXIF via Hugo's .Exif.Tags - caption from
     Caption-Abstract / ImageDescription / XPSubject / Description,
     credit from By-line / Artist / Creator. Wrapped in `try` so
     non-EXIF formats and bad metadata never break the build.
  4. Humanised filename - alt fallback only; captions stay empty
     rather than fabricated from filenames.

Also adds a third source mode - content.page_resources: true -
auto-discovers image resources attached to the current page bundle.
Drop-in for blog posts and project pages where photos live next to
index.md; sidecar lookup works inside the bundle too.

Fixes a leading-slash quirk: Resource.Name returns "/media/..." for
site assets but a bare path for page-bundle resources; the path is
now normalised so sidecar lookups land in either layout.

Test site adds two sidecar YAML files (04-cabin.jpg.yaml and
06-mountain.jpg.yaml) - the masonry album demo now picks up titles,
markdown captions, and links from those sidecars without listing any
items[].
2026-05-17 23:45:27 +01:00
George Cushen b67f09b8fd feat(gallery): add gallery block with grid/masonry layouts and lightbox
First-class image gallery block. Two layouts ship today - grid (uniform
tiles, configurable columns 1-6, aspect-ratio presets) and masonry
(CSS-columns Pinterest packing). Click-to-zoom lightbox built in Preact,
portalled to <body> so it escapes the section's `isolation: isolate`
stacking context; keyboard navigation (← → Esc), touch swipe, and body
scroll-lock included.

Two source modes: explicit items[] for curated galleries with per-image
captions/credits/links, or album: <folder> for drop-in folder loading
sorted by filename. Remote URLs (Unsplash/Pexels/CDNs) are passed
through unprocessed; local images get the full responsive variants +
inline base64 LQIP placeholder for instant first-paint over the eventual
sharp image.

Captions, titles, and credits are rendered through Hugo's RenderString
at build time (display: inline) - users get full Markdown (bold/italic/
code/links) in any of those fields with zero JS markdown parser. Alt
text falls back to plainified caption → humanised filename so screen
readers always have something useful.

Caption positions: below (default - accessibility-first), overlay
(magazine gradient), hover (clean grid reveal), none (lightbox-only).
Block-scoped CSS in the co-located style.css is picked up by the
existing block-CSS auto-discovery.

Test site: two demos under home.yaml (curated grid + auto-loaded
masonry) with 9 sample Picsum images stored under
test/assets/media/albums/gallery/ at varied aspect ratios.
2026-05-17 23:32:49 +01:00
George Cushen d7a8fbb415 fix(parse_block_v3): force stacking context on section element
The previous section_break implementation used CSS mask-image, which
incidentally established a stacking context on the section. Replacing
it with a gradient overlay div removed that side-effect — and broke
the visual depth on every section with a gradient mesh or radial
background.

Without a stacking context, the section's negative-z-index descendants
(home-section-bg at z:-1 carrying the radial gradient, and the
gradient_mesh wrapper at z:-10 carrying the orbs) escaped the section
and painted behind the page root, where they were occluded by the
page body — flat dark hero, no glow, no orbs.

Add `isolate` (isolation: isolate) to the section element. This is
the no-visual-side-effect way to force a stacking context, restoring
containment of the negative-z layers without affecting siblings or
content.
2026-05-02 19:08:32 +01:00
George Cushen f584ad1610 fix(parse_block_v3): replace section_break mask-image with gradient overlay
The mask-image approach for section_break was wrong: making pixels
transparent reveals the body background, not the next sibling section
(which sits below in document flow, not behind in z-order). When the
body bg didn't match the adjacent section, this produced a visible
white/light strip between sections — exactly what the fade was
supposed to prevent.

Replace mask-image with absolutely-positioned gradient overlay divs at
the section's top/bottom edges. The overlay fades from transparent to
a user-specified colour matching the adjacent sibling's background.
Explicit colour declaration is required because Hugo can't reliably
auto-detect the next sibling's bg at parse time.

API change (no backward-compat — feature was added this session, no
sites depend on the legacy string form):

  # before
  section_break: fade-bottom

  # after
  section_break:
    fade_bottom: "#101828"   # CSS colour matching next section's bg
    fade_top:    "#0a0e27"   # optional, independent
    size:        "6rem"      # optional, default 6rem

Update the landing page hero (fade-bottom into dark logos band) and
cta-card (fade-top from white FAQ section above) to the new form.
2026-05-02 18:25:18 +01:00
George Cushen 80913c028a feat(hero): Phase 3 — media slot and split-layout variants
- New `content.media` field accepts image (Hugo-pipeline-processed for
  responsive srcset) or video (passes through as <video>). Optional
  `dark_src` provides a dark-mode image variant.
- New `design.layout` enum: centered (default) | split-left |
  split-right | stacked. Split layouts auto-set alignment to 'left'
  unless explicitly overridden.
- Bump trust-strip star size from w-4 to w-5 for visual presence.
- Two new shared partials in layouts/_partials/functions/:
  - resolve_image_resource: path → {resource | fallback_url}
  - process_image_for_props: path → {src, srcset, width, height}
  These factor out the resource-resolution + responsive-processing
  pipeline so media-bearing blocks don't have to inline it.
- Capabilities registry: media-image, media-video, split-layouts.
- Landing page _index.md: keeps the centered hero (no behavioural
  change) but documents the opt-in pattern for split layouts inline.
2026-05-02 17:52:57 +01:00
George Cushen a2bc56bd14 feat(blox): 2026 visual polish and new layout options across blocks
- features: add bento layout (asymmetric first-card-featured grid with
  grid-flow-dense), subtitle field, per-item image support
- stats: add numbers_gradient option (bg-clip-text gradient numbers)
- pricing: gradient border wrapper on highlighted tier replacing ring,
  gradient CTA button on primary style; extracted TierCardContent
- testimonials: single item → featured card with decorative quote mark
  and gradient avatar fallback; multiple → responsive card grid
- cta-image-paragraph: rounded-2xl image wrapper with shadow, pill CTA
  button, circle-icon feature list
- cta-card: fix auto text-color detection on colored gradient cards;
  use full literal class strings (Tailwind scanner safety)
- parse_block_v3: radial gradient support, section_break mask-image
  fade, bg-color migration to section element when gradient_mesh active
  to fix stacking context (orbs at z:-10 no longer occluded)
2026-05-02 17:03:52 +01:00
George Cushen dc14b48b42 feat(faq): migrate FAQ block from Go HTML to Preact
Replaces block.html with a Preact component featuring smooth CSS grid
0fr→1fr height animation, icon rotation, and multi-paragraph answer
support via renderRich(). Single-open accordion with question/title and
answer/text field aliases for backward compatibility.
2026-05-02 17:03:36 +01:00
George Cushen ca9888609e fix(sections): update stale singular section path references to plural
- Fix build_links.html project/ → projects/ GetPage lookup (breaking bug)
- Fix collection block.html event/publication → events/publications type checks
- Update academic-cv publication archetypes, import workflow (publication/ → publications/)
- Update data-science-blog import workflow, notebook, author RSS URL (post/ → blog/)
- Update documentation and startup-landing-page author RSS URLs (post/ → blog/)
2026-04-16 02:16:23 +01:00
George Cushen a955161dbb fix(spacing): connect section spacing to design token system
Wire .hbb-section to var(--hb-spacing-section) instead of hardcoded 6rem,
enabling hugoblox.layout.spacing (compact/comfortable/spacious) to take effect.

- Default to "spacious" (6rem) to preserve existing visual layouts
- Per-section override via design.spacing.padding still works (inline > class)
- Remove dead design.spacing frontmatter field from all templates
- Set correct layout.spacing token in each template's params.yaml

Closes #3314
2026-04-08 18:19:15 +01:00
George Cushen 76023f9461 refactor(images): adopt Hugo reflect.IsImageResource* API for type-safe image processing
Replace manual format detection (printf "%T", MediaType.SubType whitelists,
duck-typing) with Hugo's new reflect.IsResource, reflect.IsImageResource, and
reflect.IsImageResourceProcessable functions across 19 template files.

Key changes:
- process_responsive_image: collapse 15-line format whitelist into single
  reflect.IsImageResourceProcessable call
- Unify three-way SVG/processable/GIF branches into two-way $canProcess guard
- Remove duplicate GIF passthrough branches in single.html, events/page.html
- Add missing SVG guard in research-areas block (was calling .Fill unprotected)
- Replace nil checks with reflect.IsResource in get_cover_image/get_featured_image

Design decision: GIFs are intentionally excluded from processing despite Hugo
supporting it — processing strips animation frames, so we preserve user-optimized
animated GIFs by checking (IsImageResourceProcessable AND not GIF).
2026-03-27 04:35:53 +00:00
George Cushen 13dde12ae0 refactor(hugo): use strings.ReplacePairs for chained replacements
Adopt Hugo v0.158's strings.ReplacePairs in rss.xml and
parse_block_v3.html to replace nested replace calls.
2026-03-27 03:33:15 +00:00
George Cushen ef8ed449c7 feat(hugo): replace deprecated APIs for Hugo v0.156+ compatibility
Migrate site.Data → hugo.Data (42 occurrences), site.IsMultiLingual →
hugo.IsMultilingual, and site.AllPages → hugo.Sites nested range.
Simplify Netlify redirects template to use pre-processed aliases
instead of relLangURL per gohugoio/hugo#14408.
2026-03-27 03:25:42 +00:00
George Cushen 5733b053bb feat(icons): expand brands icon pack and update all packs
Also, refactor icon resolution to avoid duplicated logic:

get_icon_svg.html	New shared core — alias resolution, pack lookup, hb fallback, user assets, hugo fallback. Returns raw SVG string.

get_icon.html	Thin wrapper — emoji handling, calls get_icon_svg, Unicode emoji fallback for bare names, attribute injection, safeHTML return.

get_icon_data.html	Thin wrapper — one-liner delegating to get_icon_svg.
2026-03-27 00:19:41 +00:00
George Cushen e02d32190a refactor(theme): prefix font/theme pack CSS vars with --hb- namespace 2026-03-13 15:46:35 +00:00
George Cushen 71b5a1b844 feat(typography): auto-detect bundled fonts and skip Google Fonts CDN
Add a second resolution tier to the typography system: before falling
back to Google Fonts, check assets/dist/font/ for a matching local
file. When found, emit @font-face with local() fallback instead of a
CDN <link>. Variable fonts detected from ".var." filename convention.

Bundle JetBrains Mono alongside Inter so the default "modern" pack
loads entirely from local files — zero external font requests.
2026-03-13 15:29:32 +00:00
George Cushen 2c3a2491f1 fix: handle SVG images in responsive image processing
SVG resources don't support .Width, .Height, or .Process in Hugo,
causing crashes in process_responsive_image.html and all callers
that pass SVGs without guards.

Add SVG checks to process_responsive_image.html, preact-wrapper.html,
resume-biography, resume-biography-3, authors/term, and
page_author_card.

Fixes #3305
2026-03-13 13:39:56 +00:00
George Cushen 4d38c40f9f feat(i18n): add multilingual support for author data files
Hugo doesn't natively merge language-specific data directories with the default data. Add a `get_authors_data` partial that manually
looks up `data/<lang>/authors/` and deep-merges translated fields
on top of the default data/authors/ profiles.

Centralizes all `site.Data.authors` access through this new partial
so author names, bios, roles, and other fields can be translated
per language while inheriting non-translated fields from the default.
2026-03-03 00:30:27 +00:00
George Cushen dbe0c86df7 fix(blocks): restore missing background design features in v3 parser
- Fix background image brightness filter not applying (closes issue URL below)
- Add CSS filters: blur, contrast, saturate, grayscale
- Add background image size, position, and repeat controls
- Add background.css_class for custom classes on bg layer
- Add design.clip_path for shaped section edges
- Add errorf for missing background images
- Remove dead v2 parser (no longer referenced)

Fixes https://discord.com/channels/722225264733716590/1477717661981999114/1477717661981999114
2026-03-03 00:30:27 +00:00
George Cushen 24dc36f6d7 feat(typography): extend typography system with Google Fonts and font packs 2026-03-03 00:30:27 +00:00
George Cushen ef8a34e33a feat: convert remaining Landing Page blocks from Go HTML to React 2026-02-18 19:21:54 +00:00
George Cushen 98f0d201c1 feat: harden block inputs (batch 1)
Hardened 1st batch of five homepage blocks by normalizing config types, clamping unsafe values, and guarding bad inputs so user‑supplied params fail safe without template errors.

Changes

coerce_bool.html and coerce_int.html: added shared coercion helpers for consistent, safe defaults across blocks.

block.html: sanitized content/design inputs, robust user_groups parsing, safer role/affiliation/interest/link handling, and CTA URL validation.

block.html: guarded avatar/banner/name/headings/bio, safe
button/link resolution, and resilient parsing for affiliations, education, interests, and social links.

block.html: hardened filters (kinds/folders/tags), safer sort/order handling, clamped numeric params, and archive link safety/fallbacks.

block.html and block.html: defensive content rendering, clamped overlay opacity, and safe button link handling.

schema.json, schema.json, schema.json: added view enum entries, added new_tab, and Biome formatting applied.
2026-01-07 18:23:51 +00:00
George Cushen 8ca8e40a8f feat(team-showcase): polish sorting, layout, and docs for labs/startups
- default to last-name sort with numeric-friendly keys for weight/graduation_year
- support per-group sorting, optional empty-state, and role fallback to affiliation
- add grid/interest caps, alignment controls, and avatar initial placeholders
- expose graduation_year/weight/name_family_pref in profiles; update schema/README
2026-01-07 16:04:26 +00:00
George Cushen 85307a8097 feat(authors): preserve author casing when profiles are missing
- retain raw front-matter author strings as display names when no profile data is present
- title-case humanized slug only as last-resort fallback to avoid lowercase surnames
- reduce need for author profile files while keeping names correctly capitalized

Fixes https://discord.com/channels/722225264733716590/1457522006462435541
2026-01-06 20:13:34 +00:00
George Cushen bfdcb6603c feat: port Markdown Slides template from Wowchemy/Bootstrap 2026-01-06 20:12:26 +00:00
George Cushen ad2af1f352 refactor: repo rename 2026-01-02 22:07:38 +00:00
George Cushen 43530f4a92 refactor: module versions 2026-01-02 21:13:36 +00:00
George Cushen f4280ddb1c refactor: rename modules and update migration docs
BREAKING CHANGE
Module paths moved to `github.com/HugoBlox/kit` with new names:
- core `blox-tailwind` → `blox`
- analytics → `analytics`
- netlify → `integrations/netlify`
- slides (reveal) → `slides`
Update go.mod, module.yaml/params, scripts, tests, and v0.11 migration guide accordingly.
2026-01-02 20:59:48 +00:00