mirror of
https://github.com/tiennm99/HugoBlox-kit.git
synced 2026-10-15 00:16:48 +00:00
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).
170 lines
9.2 KiB
HTML
170 lines
9.2 KiB
HTML
{{/*
|
|
Award badge — single source of truth for rendering an award entry.
|
|
|
|
Args (dict):
|
|
award Award entry (dict with name, level, issuer, date, note, url).
|
|
Bare-string entries are coerced to {name: <string>}.
|
|
page Owning page (used to fall back issuer to publication, date to page date).
|
|
variant Visual style — one of:
|
|
"pill" horizontal pill (default; used in skim rows)
|
|
"card-corner" absolute-positioned corner pill (for card/grid views)
|
|
"row" full row with name + note (for metadata grid)
|
|
"inline" compact inline marker for citations
|
|
|
|
Falls back gracefully when fields are missing.
|
|
*/}}
|
|
{{- $award := .award -}}
|
|
{{- $page := .page -}}
|
|
{{- $variant := .variant | default "pill" -}}
|
|
|
|
{{/* Coerce bare-string entries to {name: ...} */}}
|
|
{{- if not (reflect.IsMap $award) -}}
|
|
{{- $award = dict "name" $award -}}
|
|
{{- end -}}
|
|
|
|
{{- $name := $award.name | default "" -}}
|
|
{{- $level := $award.level | default "winner" -}}
|
|
{{- $note := $award.note | default "" -}}
|
|
{{- $url := $award.url | default "" -}}
|
|
|
|
{{/* Issuer fallback: explicit → publication short_name → publication name → empty */}}
|
|
{{- $issuer := $award.issuer | default "" -}}
|
|
{{- if not $issuer -}}
|
|
{{- with $page -}}
|
|
{{- $pub := partial "functions/resolve_publication.html" . -}}
|
|
{{- $issuer = $pub.short_name | default $pub.name | default "" -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Date fallback: explicit → page date year */}}
|
|
{{- $date := $award.date | default "" -}}
|
|
{{- if not $date -}}
|
|
{{- with $page -}}
|
|
{{- with .Date -}}{{- $date = .Format "2006" -}}{{- end -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Icon + colour token per level */}}
|
|
{{- $icon := "trophy" -}}
|
|
{{- $tone := "amber" -}}
|
|
{{- if eq $level "winner" -}}{{- $icon = "trophy" -}}{{- $tone = "amber" -}}
|
|
{{- else if eq $level "runner_up" -}}{{- $icon = "medal" -}}{{- $tone = "slate" -}}
|
|
{{- else if eq $level "honorable_mention" -}}{{- $icon = "ribbon" -}}{{- $tone = "rose" -}}
|
|
{{- else if eq $level "nominee" -}}{{- $icon = "star" -}}{{- $tone = "sky" -}}
|
|
{{- else if eq $level "selected" -}}{{- $icon = "sparkles" -}}{{- $tone = "violet" -}}
|
|
{{- else if eq $level "featured" -}}{{- $icon = "bookmark-star" -}}{{- $tone = "emerald" -}}
|
|
{{- end -}}
|
|
|
|
{{/* Tailwind class shards keyed by tone (full classes for the extractor) */}}
|
|
{{- $bg := "" -}}{{- $text := "" -}}{{- $ring := "" -}}
|
|
{{- if eq $tone "amber" -}}
|
|
{{- $bg = "bg-amber-100 dark:bg-amber-900/40" -}}
|
|
{{- $text = "text-amber-900 dark:text-amber-200" -}}
|
|
{{- $ring = "ring-amber-500/30 dark:ring-amber-400/30" -}}
|
|
{{- else if eq $tone "slate" -}}
|
|
{{- $bg = "bg-slate-100 dark:bg-slate-800/60" -}}
|
|
{{- $text = "text-slate-900 dark:text-slate-200" -}}
|
|
{{- $ring = "ring-slate-500/30 dark:ring-slate-400/30" -}}
|
|
{{- else if eq $tone "rose" -}}
|
|
{{- $bg = "bg-rose-100 dark:bg-rose-900/40" -}}
|
|
{{- $text = "text-rose-900 dark:text-rose-200" -}}
|
|
{{- $ring = "ring-rose-500/30 dark:ring-rose-400/30" -}}
|
|
{{- else if eq $tone "sky" -}}
|
|
{{- $bg = "bg-sky-100 dark:bg-sky-900/40" -}}
|
|
{{- $text = "text-sky-900 dark:text-sky-200" -}}
|
|
{{- $ring = "ring-sky-500/30 dark:ring-sky-400/30" -}}
|
|
{{- else if eq $tone "violet" -}}
|
|
{{- $bg = "bg-violet-100 dark:bg-violet-900/40" -}}
|
|
{{- $text = "text-violet-900 dark:text-violet-200" -}}
|
|
{{- $ring = "ring-violet-500/30 dark:ring-violet-400/30" -}}
|
|
{{- else if eq $tone "emerald" -}}
|
|
{{- $bg = "bg-emerald-100 dark:bg-emerald-900/40" -}}
|
|
{{- $text = "text-emerald-900 dark:text-emerald-200" -}}
|
|
{{- $ring = "ring-emerald-500/30 dark:ring-emerald-400/30" -}}
|
|
{{- end -}}
|
|
|
|
{{/* Inline SVG icons (small, self-contained — no dependency on external icon system at render time) */}}
|
|
{{- $svg := "" -}}
|
|
{{- if eq $icon "trophy" -}}
|
|
{{- $svg = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 21h8M12 17v4M7 4h10v5a5 5 0 0 1-10 0V4ZM5 4H3v2a3 3 0 0 0 3 3M19 4h2v2a3 3 0 0 1-3 3"/></svg>` -}}
|
|
{{- else if eq $icon "medal" -}}
|
|
{{- $svg = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="15" r="6"/><path d="M8.5 9L6 2h12l-2.5 7M9 15l1 2.5L12 14l2 3.5L15 15"/></svg>` -}}
|
|
{{- else if eq $icon "ribbon" -}}
|
|
{{- $svg = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2l3 7 7 1-5 5 1 7-6-3-6 3 1-7-5-5 7-1z"/></svg>` -}}
|
|
{{- else if eq $icon "star" -}}
|
|
{{- $svg = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26"/></svg>` -}}
|
|
{{- else if eq $icon "sparkles" -}}
|
|
{{- $svg = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/></svg>` -}}
|
|
{{- else if eq $icon "bookmark-star" -}}
|
|
{{- $svg = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/><polygon points="12 7 13 9 15 9.3 13.5 11 14 13 12 12 10 13 10.5 11 9 9.3 11 9"/></svg>` -}}
|
|
{{- end -}}
|
|
|
|
{{/* Build subtitle: "Issuer · Year" or just whichever is present */}}
|
|
{{- $subtitle := "" -}}
|
|
{{- if and $issuer $date -}}
|
|
{{- $subtitle = printf "%s · %s" $issuer $date -}}
|
|
{{- else if $issuer -}}
|
|
{{- $subtitle = $issuer -}}
|
|
{{- else if $date -}}
|
|
{{- $subtitle = $date -}}
|
|
{{- end -}}
|
|
|
|
{{- $tooltip := $name -}}
|
|
{{- with $subtitle -}}{{- $tooltip = printf "%s — %s" $name . -}}{{- end -}}
|
|
|
|
{{- if $name -}}
|
|
{{- if eq $variant "pill" -}}
|
|
{{- if $url -}}
|
|
<a href="{{ $url }}" target="_blank" rel="noopener" class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold ring-1 {{ $bg }} {{ $text }} {{ $ring }} max-w-full" title="{{ $tooltip }}" data-pagefind-filter="award:{{ $level }}">
|
|
<span class="w-3.5 h-3.5 flex-shrink-0">{{ $svg | safeHTML }}</span>
|
|
<span class="truncate">{{ $name }}</span>
|
|
{{- with $subtitle }}<span class="opacity-70 font-normal hidden sm:inline">· {{ . }}</span>{{ end -}}
|
|
</a>
|
|
{{- else -}}
|
|
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold ring-1 {{ $bg }} {{ $text }} {{ $ring }} max-w-full" title="{{ $tooltip }}" data-pagefind-filter="award:{{ $level }}">
|
|
<span class="w-3.5 h-3.5 flex-shrink-0">{{ $svg | safeHTML }}</span>
|
|
<span class="truncate">{{ $name }}</span>
|
|
{{- with $subtitle }}<span class="opacity-70 font-normal hidden sm:inline">· {{ . }}</span>{{ end -}}
|
|
</span>
|
|
{{- end -}}
|
|
{{- else if eq $variant "card-corner" -}}
|
|
{{- if $url -}}
|
|
<a href="{{ $url }}" target="_blank" rel="noopener" class="absolute top-3 right-3 z-10 inline-flex items-center gap-1 px-2 py-1 rounded-full text-[11px] font-semibold shadow-sm backdrop-blur-sm ring-1 {{ $bg }} {{ $text }} {{ $ring }}" title="{{ $tooltip }}">
|
|
<span class="w-3 h-3 flex-shrink-0">{{ $svg | safeHTML }}</span>
|
|
<span class="truncate max-w-[140px]">{{ $name }}</span>
|
|
</a>
|
|
{{- else -}}
|
|
<span class="absolute top-3 right-3 z-10 inline-flex items-center gap-1 px-2 py-1 rounded-full text-[11px] font-semibold shadow-sm backdrop-blur-sm ring-1 {{ $bg }} {{ $text }} {{ $ring }}" title="{{ $tooltip }}">
|
|
<span class="w-3 h-3 flex-shrink-0">{{ $svg | safeHTML }}</span>
|
|
<span class="truncate max-w-[140px]">{{ $name }}</span>
|
|
</span>
|
|
{{- end -}}
|
|
{{- else if eq $variant "inline" -}}
|
|
{{- if $url -}}
|
|
<a href="{{ $url }}" target="_blank" rel="noopener" class="inline-flex items-center gap-1 text-xs font-medium {{ $text }}" title="{{ $tooltip }}">
|
|
<span class="w-3 h-3 flex-shrink-0">{{ $svg | safeHTML }}</span>
|
|
<span>{{ $name }}</span>
|
|
</a>
|
|
{{- else -}}
|
|
<span class="inline-flex items-center gap-1 text-xs font-medium {{ $text }}" title="{{ $tooltip }}">
|
|
<span class="w-3 h-3 flex-shrink-0">{{ $svg | safeHTML }}</span>
|
|
<span>{{ $name }}</span>
|
|
</span>
|
|
{{- end -}}
|
|
{{- else if eq $variant "row" -}}
|
|
<div class="flex items-start gap-3" data-pagefind-filter="award:{{ $level }}">
|
|
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full {{ $bg }} {{ $text }} flex-shrink-0">
|
|
<span class="w-4 h-4">{{ $svg | safeHTML }}</span>
|
|
</span>
|
|
<div class="min-w-0">
|
|
<div class="font-semibold {{ $text }}">
|
|
{{- if $url -}}<a href="{{ $url }}" target="_blank" rel="noopener" class="hover:underline">{{ $name }}</a>
|
|
{{- else -}}{{ $name }}{{- end -}}
|
|
</div>
|
|
{{- with $subtitle -}}<div class="text-sm text-gray-600 dark:text-gray-400">{{ . }}</div>{{- end -}}
|
|
{{- with $note -}}<div class="text-sm text-gray-700 dark:text-gray-300 mt-1">{{ . | markdownify }}</div>{{- end -}}
|
|
</div>
|
|
</div>
|
|
{{- end -}}
|
|
{{- end -}}
|