From 1675dd45f046d210c24c1183ce67b09617be5311 Mon Sep 17 00:00:00 2001 From: George Cushen Date: Sun, 7 Sep 2025 23:04:43 +0100 Subject: [PATCH] feat: add `embed` shortcode Embed GitHub repos, HuggingFace, and custom providers See Academic CV demo blog for examples --- modules/blox-tailwind/data/icons/brands.yaml | 7 +- modules/blox-tailwind/data/icons/hb.yaml | 11 +- .../_partials/functions/embed/github.html | 97 ++++++++ .../functions/embed/hbx_content_section.html | 107 +++++++++ .../functions/embed/hbx_platform_icon.html | 28 +++ .../functions/embed/hbx_title_section.html | 162 ++++++++++++++ .../functions/embed/huggingface.html | 67 ++++++ .../_partials/functions/hbx_verify.html | 70 ++++++ .../layouts/_partials/functions/uid.html | 19 ++ .../layouts/_shortcodes/embed.html | 208 ++++++++++++++++++ .../content/post/data-visualization/index.md | 82 ++++++- .../content/post/get-started/index.md | 3 - .../academic-cv/content/teaching/js/index.md | 6 +- .../content/teaching/python/index.md | 6 +- .../content/docs/guide/shortcodes/_index.md | 1 + .../content/docs/guide/shortcodes/button.md | 202 +++++++++++++++++ 16 files changed, 1065 insertions(+), 11 deletions(-) create mode 100644 modules/blox-tailwind/layouts/_partials/functions/embed/github.html create mode 100644 modules/blox-tailwind/layouts/_partials/functions/embed/hbx_content_section.html create mode 100644 modules/blox-tailwind/layouts/_partials/functions/embed/hbx_platform_icon.html create mode 100644 modules/blox-tailwind/layouts/_partials/functions/embed/hbx_title_section.html create mode 100644 modules/blox-tailwind/layouts/_partials/functions/embed/huggingface.html create mode 100644 modules/blox-tailwind/layouts/_partials/functions/hbx_verify.html create mode 100644 modules/blox-tailwind/layouts/_partials/functions/uid.html create mode 100644 modules/blox-tailwind/layouts/_shortcodes/embed.html create mode 100644 starters/documentation/content/docs/guide/shortcodes/button.md diff --git a/modules/blox-tailwind/data/icons/brands.yaml b/modules/blox-tailwind/data/icons/brands.yaml index 7852ee9f..61739aa1 100644 --- a/modules/blox-tailwind/data/icons/brands.yaml +++ b/modules/blox-tailwind/data/icons/brands.yaml @@ -17,6 +17,9 @@ icons: google-scholar: orcid: reddit: - - # Hugo + + # AI/ML Platforms + huggingface: + + # Development hugo: diff --git a/modules/blox-tailwind/data/icons/hb.yaml b/modules/blox-tailwind/data/icons/hb.yaml index 69a4b182..f845f1ee 100644 --- a/modules/blox-tailwind/data/icons/hb.yaml +++ b/modules/blox-tailwind/data/icons/hb.yaml @@ -13,14 +13,19 @@ icons: card: folder-tree: one: - code-bracket: + code-bracket: + - circle-stack: + circle-stack: + magnifying-glass: # Phosphor icons cat: - person-simple-walk: + person-simple-walk: + + # Git icons + git-fork: diff --git a/modules/blox-tailwind/layouts/_partials/functions/embed/github.html b/modules/blox-tailwind/layouts/_partials/functions/embed/github.html new file mode 100644 index 00000000..e78676f5 --- /dev/null +++ b/modules/blox-tailwind/layouts/_partials/functions/embed/github.html @@ -0,0 +1,97 @@ +{{/* + Hugo Blox GitHub Platform Configuration + Part of Hugo Blox embed system + + Parameters: + - resource: repository identifier (e.g., "owner/repo") + - type: "repo", "gist", etc. + - user: username/organization + - customUrl: optional override URL +*/}} + +{{- $resource := .resource -}} +{{- $type := .type | default "repo" -}} +{{- $user := .user -}} +{{- $customUrl := .customUrl -}} +{{- $showThumbnail := .showThumbnail | default false -}} +{{- $width := .width | default 600 -}} +{{- $height := .height | default 315 -}} +{{- $quality := .quality | default 85 -}} +{{- $formats := .formats | default (slice "avif" "webp" "jpg") -}} + +{{- $config := dict -}} + +{{- if $resource -}} + {{- if eq $type "repo" -}} + {{- if $showThumbnail -}} + {{- $config = dict + "apiUrl" (print "https://api.github.com/repos/" $resource) + "repoLink" (print "https://github.com/" $resource) + "imageUrl" (print "https://opengraph.githubassets.com/0/" $resource) + "icon" "code-bracket" + "brandColors" (slice "slate-800" "slate-900") + "typeColor" "primary-500" + "isImageEmbed" true + "imageProcessing" (dict + "width" $width + "height" $height + "quality" $quality + "formats" $formats + "sizes" (slice 400 600 800) + ) + "statsConfig" (dict + "stars" (dict "icon" "star" "color" "yellow-500" "field" "stargazers_count") + "forks" (dict "icon" "git-fork" "color" "primary-500" "field" "forks_count") + "issues" (dict "icon" "exclamation-circle" "color" "red-500" "field" "open_issues_count") + ) + "titleField" "name" + "descriptionField" "description" + "subtypeField" "language" + "ownerField" "owner.login" + -}} + {{- else -}} + {{- $config = dict + "apiUrl" (print "https://api.github.com/repos/" $resource) + "repoLink" (print "https://github.com/" $resource) + "icon" "code-bracket" + "brandColors" (slice "slate-800" "slate-900") + "typeColor" "primary-500" + "statsConfig" (dict + "stars" (dict "icon" "star" "color" "yellow-500" "field" "stargazers_count") + "forks" (dict "icon" "git-fork" "color" "primary-500" "field" "forks_count") + "issues" (dict "icon" "exclamation-circle" "color" "red-500" "field" "open_issues_count") + ) + "titleField" "name" + "descriptionField" "description" + "subtypeField" "language" + "ownerField" "owner.login" + -}} + {{- end -}} + {{- else if eq $type "gist" -}} + {{- $config = dict + "apiUrl" (print "https://api.github.com/gists/" $resource) + "repoLink" (print "https://gist.github.com/" $resource) + "icon" "document-text" + "brandColors" (slice "slate-800" "slate-900") + "typeColor" "secondary-500" + "titleField" "description" + "descriptionField" "description" + -}} + {{- else -}} + {{- $config = dict + "repoLink" (print "https://github.com/" $resource) + "icon" "link" + "brandColors" (slice "slate-800" "slate-900") + "typeColor" "zinc-500" + -}} + {{- end -}} +{{- else if $customUrl -}} + {{- $config = dict + "repoLink" $customUrl + "icon" "link" + "brandColors" (slice "slate-800" "slate-900") + "typeColor" "zinc-500" + -}} +{{- end -}} + +{{ return $config }} diff --git a/modules/blox-tailwind/layouts/_partials/functions/embed/hbx_content_section.html b/modules/blox-tailwind/layouts/_partials/functions/embed/hbx_content_section.html new file mode 100644 index 00000000..efe6b205 --- /dev/null +++ b/modules/blox-tailwind/layouts/_partials/functions/embed/hbx_content_section.html @@ -0,0 +1,107 @@ +{{/* + Content section rendering for embed cards + + Parameters: + - customDescription: user-provided description override + - embedData: data fetched from API + - platform: platform name + - hb_id: Hugo Blox unique identifier + - config: platform configuration + - processedImage: processed image data (for image embeds) +*/}} + +{{- $customDescription := .customDescription -}} +{{- $embedData := .embedData -}} +{{- $platform := .platform -}} +{{- $hb_id := .hb_id -}} +{{- $config := .config -}} +{{- $processedImage := .processedImage -}} + +{{/* Display processed image if available */}} +{{- if $processedImage -}} +
+ {{ if $customDescription }}{{ $customDescription }}{{ else if and $embedData $config.titleField }}{{ index $embedData $config.titleField }}{{ else }}Embedded image{{ end }} +
+{{- end -}} + +{{/* Description handling */}} +{{- $description := $customDescription -}} +{{- if and (not $description) $embedData $config.descriptionField -}} + {{- $description = index $embedData $config.descriptionField -}} + {{/* Apply platform-specific cleanup */}} + {{- if $config.descriptionCleanup -}} + {{- $description = $description | replaceRE $config.descriptionCleanup "" -}} + {{- end -}} +{{- end -}} + +{{- if $description -}} +

+ {{ $description | plainify | htmlUnescape | truncate 200 | emojify }} +

+{{- end -}} + +{{/* Platform-specific stats section */}} +{{- if and $embedData $config.statsConfig -}} +
+ {{- range $statKey, $statConfig := $config.statsConfig -}} + {{- $statValue := index $embedData $statConfig.field -}} + {{- if $statValue -}} +
+ {{ partial "functions/get_icon" (dict "name" $statConfig.icon "attributes" (printf "class=\"w-4 h-4 text-%s\"" $statConfig.color)) }} + {{- if and (eq $platform "github") (eq $statKey "issues") -}} + {{/* Make issues count clickable for GitHub */}} + + {{- if gt $statValue 999 -}} + {{- if gt $statValue 999999 -}} + {{ div $statValue 1000000 }}M + {{- else -}} + {{ div $statValue 1000 }}k + {{- end -}} + {{- else -}} + {{ $statValue }} + {{- end -}} + + {{- else -}} + + {{- if gt $statValue 999 -}} + {{- if gt $statValue 999999 -}} + {{ div $statValue 1000000 }}M + {{- else -}} + {{ div $statValue 1000 }}k + {{- end -}} + {{- else -}} + {{ $statValue }} + {{- end -}} + + {{- end -}} +
+ {{- end -}} + {{- end -}} +
+{{- end -}} + +{{/* Additional platform-specific content */}} +{{- if eq $platform "github" -}} + {{/* Show additional GitHub-specific info if available */}} + {{- if and $embedData $embedData.topics -}} +
+ {{- range first 3 $embedData.topics -}} + + {{ . | emojify }} + + {{- end -}} + {{- if gt (len $embedData.topics) 3 -}} + +{{ sub (len $embedData.topics) 3 }} + {{- end -}} +
+ {{- end -}} +{{- end -}} diff --git a/modules/blox-tailwind/layouts/_partials/functions/embed/hbx_platform_icon.html b/modules/blox-tailwind/layouts/_partials/functions/embed/hbx_platform_icon.html new file mode 100644 index 00000000..838b0834 --- /dev/null +++ b/modules/blox-tailwind/layouts/_partials/functions/embed/hbx_platform_icon.html @@ -0,0 +1,28 @@ +{{/* + Platform icon rendering + + Parameters: + - platform: platform name (huggingface, github, etc.) + - config: platform configuration dict + - hb_id: Hugo Blox unique identifier for the embed +*/}} + +{{- $platform := .platform -}} +{{- $config := .config -}} +{{- $hb_id := .hb_id -}} + +{{- if eq $platform "huggingface" -}} +
+ {{ partial "functions/get_icon" (dict "name" "brands/huggingface" "attributes" "class=\"w-6 h-6 text-white\"") }} +
+{{- else if eq $platform "github" -}} +
+ {{ partial "functions/get_icon" (dict "name" "brands/github" "attributes" "class=\"w-6 h-6 text-white\"") }} +
+{{- else -}} + {{/* Custom/generic embeds use neutral styling */}} +
+ {{ partial "functions/get_icon" (dict "name" ($config.icon | default "globe-alt") "attributes" "class=\"w-5 h-5 text-white\"") }} +
+{{- end -}} + diff --git a/modules/blox-tailwind/layouts/_partials/functions/embed/hbx_title_section.html b/modules/blox-tailwind/layouts/_partials/functions/embed/hbx_title_section.html new file mode 100644 index 00000000..3655747a --- /dev/null +++ b/modules/blox-tailwind/layouts/_partials/functions/embed/hbx_title_section.html @@ -0,0 +1,162 @@ +{{/* + Title section rendering for embed cards + + Parameters: + - hb_id: Hugo Blox unique identifier + - customTitle: user-provided title override + - embedData: data fetched from API + - customUrl: custom URL if provided + - resource: platform resource identifier + - type: resource type + - platform: platform name + - config: platform configuration +*/}} + +{{- $hb_id := .hb_id -}} +{{- $customTitle := .customTitle -}} +{{- $embedData := .embedData -}} +{{- $customUrl := .customUrl -}} +{{- $resource := .resource -}} +{{- $type := .type -}} +{{- $platform := .platform -}} +{{- $config := .config -}} + +

+ + {{- if $customTitle -}} + {{ $customTitle | emojify }} + {{- else if and $embedData $config.titleField -}} + {{ index $embedData $config.titleField | emojify }} + {{- else if and $embedData $embedData.name -}} + {{ $embedData.name | emojify }} + {{- else if and $embedData $embedData.id -}} + {{ $embedData.id | emojify }} + {{- else if $customUrl -}} + {{- $parsed := urls.Parse $customUrl -}} + {{ $parsed.Host | emojify }} + {{- else if $resource -}} + {{- if eq $platform "github" -}} + {{/* For GitHub, show just the repo name, not the full "owner/repo" */}} + {{- $parts := split $resource "/" -}} + {{- if gt (len $parts) 1 -}} + {{ index $parts 1 | emojify }} + {{- else -}} + {{ $resource | emojify }} + {{- end -}} + {{- else -}} + {{ $resource | emojify }} + {{- end -}} + {{- else -}} + Embedded Resource + {{- end -}} + +

+ +{{/* Resource type and subtype indicator */}} +{{- $showTypeIndicator := false -}} +{{- $typeText := "" -}} +{{- $typeColor := $config.typeColor | default "zinc-500" -}} + +{{/* Always show type indicator for GitHub repos with data */}} +{{- if and (eq $platform "github") $embedData $config.ownerField -}} + {{- $showTypeIndicator = true -}} +{{- end -}} + +{{/* Force metadata line for custom embeds to ensure proper alignment */}} +{{- if eq $platform "custom" -}} + {{- $showTypeIndicator = true -}} +{{- end -}} + +{{- if $type -}} + {{- $showTypeIndicator = true -}} + {{- if and $embedData $config.subtypeField -}} + {{- if $config.subtypeIndex -}} + {{- $subtypes := index $embedData $config.subtypeField -}} + {{- if $subtypes -}} + {{- $typeText = index $subtypes $config.subtypeIndex -}} + {{- else -}} + {{- $typeText = $type -}} + {{- end -}} + {{- else -}} + {{- $typeText = index $embedData $config.subtypeField | default $type -}} + {{- end -}} + {{- else -}} + {{- $typeText = $type -}} + {{- end -}} +{{- else if and $embedData $config.subtypeField -}} + {{- $showTypeIndicator = true -}} + {{- if $config.subtypeIndex -}} + {{- $subtypes := index $embedData $config.subtypeField -}} + {{- if $subtypes -}} + {{- $typeText = index $subtypes $config.subtypeIndex -}} + {{- end -}} + {{- else -}} + {{- $typeText = index $embedData $config.subtypeField -}} + {{- end -}} +{{- end -}} + +{{- if $showTypeIndicator -}} +
+ {{/* GitHub repos: Show owner prominently, then language */}} + {{- if eq $platform "github" -}} + {{- $owner := "" -}} + {{/* Get owner from API data if available */}} + {{- if $embedData -}} + {{- if eq $config.ownerField "owner.login" -}} + {{/* Handle nested GitHub API structure: embedData.owner.login */}} + {{- $ownerObj := index $embedData "owner" -}} + {{- if $ownerObj -}} + {{- $owner = index $ownerObj "login" -}} + {{- end -}} + {{- else if $config.ownerField -}} + {{/* Handle simple field access */}} + {{- $owner = index $embedData $config.ownerField -}} + {{- end -}} + {{- end -}} + + {{/* Fallback: extract owner from resource string (e.g., "HugoBlox/hugo-blox-builder" -> "HugoBlox") */}} + {{- if and (not $owner) $resource -}} + {{- $parts := split $resource "/" -}} + {{- if gt (len $parts) 0 -}} + {{- $owner = index $parts 0 -}} + {{- end -}} + {{- end -}} + + {{- if $owner -}} + by + {{ $owner | emojify }} + + {{- if $typeText -}} + • + + {{ $typeText | emojify }} + {{- end -}} + {{- else if $typeText -}} + {{/* No owner, just show type */}} + + {{ $typeText | emojify }} + {{- end -}} + {{- else if eq $platform "custom" -}} + {{/* Custom embeds: Show domain or minimal placeholder for consistent alignment */}} + {{- if $customUrl -}} + {{- $parsed := urls.Parse $customUrl -}} + {{- $domain := $parsed.Host -}} + {{ $domain | emojify }} + {{- else -}} + {{/* Minimal placeholder to maintain visual spacing */}} + external resource + {{- end -}} + {{- else -}} + {{/* Other platforms: Show type with indicator */}} + {{- if $typeText -}} + + + {{ $typeText | emojify }} + + {{- else -}} + {{/* Minimal placeholder for consistent spacing */}} + platform resource + {{- end -}} + {{- end -}} +
+{{- end -}} diff --git a/modules/blox-tailwind/layouts/_partials/functions/embed/huggingface.html b/modules/blox-tailwind/layouts/_partials/functions/embed/huggingface.html new file mode 100644 index 00000000..9920beab --- /dev/null +++ b/modules/blox-tailwind/layouts/_partials/functions/embed/huggingface.html @@ -0,0 +1,67 @@ +{{/* + HuggingFace platform configuration + + Parameters: + - resource: model or dataset identifier + - type: "model" or "dataset" + - customUrl: optional override URL +*/}} + +{{- $resource := .resource -}} +{{- $type := .type -}} +{{- $customUrl := .customUrl -}} + +{{- $config := dict -}} + +{{- if $resource -}} + {{- if eq $type "model" -}} + {{- $config = dict + "apiUrl" (print "https://huggingface.co/api/models/" $resource) + "repoLink" (print "https://huggingface.co/" $resource) + "icon" "cpu-chip" + "brandColors" (slice "yellow-400" "orange-500") + "typeColor" "secondary-500" + "statsConfig" (dict + "likes" (dict "icon" "heart" "color" "secondary-500" "field" "likes") + "downloads" (dict "icon" "arrow-down-tray" "color" "primary-500" "field" "downloads") + ) + "titleField" "id" + "descriptionField" "description" + "descriptionCleanup" `Dataset Card for .+\s+Dataset Summary\s+` + "subtypeField" "pipeline_tag" + -}} + {{- else if eq $type "dataset" -}} + {{- $config = dict + "apiUrl" (print "https://huggingface.co/api/datasets/" $resource) + "repoLink" (print "https://huggingface.co/datasets/" $resource) + "icon" "circle-stack" + "brandColors" (slice "yellow-400" "orange-500") + "typeColor" "primary-500" + "statsConfig" (dict + "likes" (dict "icon" "heart" "color" "secondary-500" "field" "likes") + "downloads" (dict "icon" "arrow-down-tray" "color" "primary-500" "field" "downloads") + ) + "titleField" "id" + "descriptionField" "description" + "descriptionCleanup" `Dataset Card for .+\s+Dataset Summary\s+` + "subtypeField" "task_categories" + "subtypeIndex" 0 + -}} + {{- else -}} + {{- $config = dict + "repoLink" (print "https://huggingface.co/" $resource) + "icon" "link" + "brandColors" (slice "yellow-400" "orange-500") + "typeColor" "zinc-500" + -}} + {{- end -}} +{{- else if $customUrl -}} + {{- $config = dict + "repoLink" $customUrl + "icon" "link" + "brandColors" (slice "yellow-400" "orange-500") + "typeColor" "zinc-500" + -}} +{{- end -}} + +{{ return $config }} diff --git a/modules/blox-tailwind/layouts/_partials/functions/hbx_verify.html b/modules/blox-tailwind/layouts/_partials/functions/hbx_verify.html new file mode 100644 index 00000000..feaed417 --- /dev/null +++ b/modules/blox-tailwind/layouts/_partials/functions/hbx_verify.html @@ -0,0 +1,70 @@ +{{/* + Hugo Blox Builder Ecosystem Verification + + Reusable verification function for Hugo Blox components. + Ensures all required Hugo Blox Builder dependencies are present. + + Usage: {{ partial "functions/hbx_verify.html" . }} + Returns: "verified" or "failed" + + Used by: shortcodes, blocks, advanced components +*/}} + +{{/* Check for Hugo Blox specific icon system */}} +{{- $hb_icon_check := partial "functions/get_icon" (dict "name" "academic-cap" "attributes" "style=\"display: none;\"") -}} + +{{/* Verify Hugo Blox data structures */}} +{{- $hb_data_check := site.Data.icons.hero -}} + +{{/* Verify Hugo Blox UID generation */}} +{{- $hb_uid_check := partial "functions/uid.html" . -}} + +{{/* DEBUG: Print hugo.Deps output for analysis (dev only) */}} +{{- if getenv "HUGO_BLOX_DEBUG" -}} + {{- warnf "=== DEBUG hugo.Deps output ===" -}} + {{- range $index, $dep := hugo.Deps -}} + {{- warnf "DEP %d: Path=%s, Version=%s, Vendor=%t" $index $dep.Path $dep.Version $dep.Vendor -}} + {{- end -}} + {{- warnf "=== END hugo.Deps ===" -}} +{{- end -}} + +{{/* Check for required Hugo Blox module dependencies */}} +{{- $hb_module_check := false -}} +{{- $required_modules := slice "blox-tailwind" -}} +{{- range $required := $required_modules -}} + {{- range $dep := hugo.Deps -}} + {{- if strings.Contains $dep.Path $required -}} + {{/* Accept both official GitHub org paths AND local development paths */}} + {{- if or (strings.Contains $dep.Path "github.com/HugoBlox/") (strings.Contains $dep.Path "../../../modules") -}} + {{- $hb_module_check = true -}} + {{- if getenv "HUGO_BLOX_DEBUG" -}} + {{- warnf "Found Hugo Blox module: %s" $dep.Path -}} + {{- end -}} + {{- break -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* Verify Hugo Blox brands icon pack */}} +{{- $hb_brands_check := site.Data.icons.brands -}} + +{{/* Debug output to identify failing check (dev only) */}} +{{- if getenv "HUGO_BLOX_DEBUG" -}} + {{- warnf "=== VERIFICATION RESULTS ===" -}} + {{- warnf "Icon check: %t" (and $hb_icon_check true) -}} + {{- warnf "Data check: %t" (and $hb_data_check true) -}} + {{- warnf "UID check: %t" (and $hb_uid_check true) -}} + {{- warnf "Module check: %t" $hb_module_check -}} + {{- warnf "Brands check: %t" (and $hb_brands_check true) -}} + {{- warnf "=== END VERIFICATION ===" -}} +{{- end -}} + +{{/* Set return value based on verification results */}} +{{- $return := "failed" -}} +{{- if and $hb_icon_check $hb_data_check $hb_uid_check $hb_module_check $hb_brands_check -}} + {{- $return = "verified" -}} +{{- end -}} + +{{/* Return result using proper Hugo function pattern */}} +{{ return $return }} diff --git a/modules/blox-tailwind/layouts/_partials/functions/uid.html b/modules/blox-tailwind/layouts/_partials/functions/uid.html new file mode 100644 index 00000000..f1a86cb9 --- /dev/null +++ b/modules/blox-tailwind/layouts/_partials/functions/uid.html @@ -0,0 +1,19 @@ +{{/* + Hugo Blox UID Generator + Generate a unique ID for shortcodes and components. + Uses the page's unique ID combined with ordinal for uniqueness. +*/}} + +{{ $uid := .Page.File.UniqueID }} +{{ $ctx := . }} + +{{ range seq 16 }} + {{ with $ctx }} + {{ $uid = printf "%s-%d" $uid .Ordinal }} + {{ $ctx = .Parent }} + {{ else }} + {{ break }} + {{ end }} +{{ end }} + +{{ return (crypto.MD5 $uid) }} diff --git a/modules/blox-tailwind/layouts/_shortcodes/embed.html b/modules/blox-tailwind/layouts/_shortcodes/embed.html new file mode 100644 index 00000000..d727852f --- /dev/null +++ b/modules/blox-tailwind/layouts/_shortcodes/embed.html @@ -0,0 +1,208 @@ +{{/* + Hugo Blox Embed Shortcode + Copyright (c) George Cushen + + Licensed under MIT with Attribution Required: + - Copyright notice and this license must be retained + - "Powered by Hugo Blox" attribution must be maintained + - See: https://github.com/HugoBlox/hugo-blox-builder/blob/main/LICENSE.md + + Docs: https://docs.hugoblox.com/content/writing-markdown-latex/ + + Parameters + ---------- + platform : default auto-detected + Platform type (huggingface, github, etc.) + resource : optional + Platform-specific resource identifier (model/dataset for HF, repo for GitHub) + type : optional + Resource type (model, dataset, repo, etc.) + title : optional + Override the default title + description : optional + Override the default description + url : optional + Direct URL to the resource + user : optional + Username/organization (for GitHub: "owner/repo") + thumbnail : default false + Show platform thumbnail (e.g., GitHub OpenGraph image) + image : optional + Remote image URL to process and display (works with any URL including Unsplash) + + Image Processing Parameters (when using image parameter) + -------------------------------------------------------- + width : default 800 + Image width in pixels + height : default 600 + Image height in pixels + quality : default 80 + Image quality 1-100 + formats : default ["avif", "webp", "jpg"] + Image formats to generate + + Examples + -------- + {{< embed platform="huggingface" resource="microsoft/DialoGPT-medium" type="model" >}} + {{< embed platform="github" resource="hugo-blox/hugo-blox-builder" type="repo" >}} + {{< embed platform="github" resource="hugo-blox/hugo-blox-builder" type="repo" thumbnail="true" >}} + {{< embed url="https://example.com" title="Custom Title" description="Description" image="https://images.unsplash.com/photo-123" >}} + {{< embed platform="github" resource="owner/repo" image="https://custom-image.jpg" width="600" height="400" >}} +*/}} + +{{/* Hugo Blox Builder ecosystem verification - Required for functionality */}} +{{- $hbx_verification_result := partial "functions/hbx_verify.html" . -}} +{{- if ne $hbx_verification_result "verified" -}} + {{ errorf "Hugo Blox Embed requires complete Hugo Blox Builder theme ecosystem at %s" .Position }} +{{- end -}} + +{{ $hbx_embed_id := delimit (slice "hb-embed" (partial "functions/uid.html" .)) "-" }} + +{{/* New flexible parameters */}} +{{- $platform := .Get "platform" -}} +{{- $resource := .Get "resource" -}} +{{- $type := .Get "type" -}} +{{- $user := .Get "user" -}} +{{- $customTitle := .Get "title" -}} +{{- $customDescription := .Get "description" -}} +{{- $customUrl := .Get "url" -}} +{{- $imageUrl := .Get "image" -}} + +{{/* Image processing parameters */}} +{{- $width := .Get "width" | default "800" | int -}} +{{- $height := .Get "height" | default "600" | int -}} +{{- $quality := .Get "quality" | default "80" | int -}} +{{- $formats := .Get "formats" | default (slice "avif" "webp" "jpg") -}} +{{- $showThumbnail := .Get "thumbnail" | default false -}} + +{{/* Set default platform based on available parameters */}} +{{- if not $platform -}} + {{- if $customUrl -}} + {{- $platform = "custom" -}} + {{- else -}} + {{- $platform = "custom" -}} + {{- end -}} +{{- end -}} + +{{/* Platform configuration - extensible for future platforms */}} +{{- $config := dict -}} +{{- if eq $platform "huggingface" -}} + {{- $config = partial "functions/embed/huggingface.html" (dict "resource" $resource "type" $type "customUrl" $customUrl) -}} +{{- else if eq $platform "github" -}} + {{- $config = partial "functions/embed/github.html" (dict "resource" $resource "type" $type "user" $user "customUrl" $customUrl "showThumbnail" $showThumbnail "width" $width "height" $height "quality" $quality "formats" $formats) -}} +{{- else -}} + {{/* Custom/generic embed configuration */}} + {{- $config = dict + "repoLink" $customUrl + "icon" "globe-alt" + "brandColors" (slice "zinc-700" "zinc-800") + "typeColor" "zinc-500" + -}} +{{- end -}} + +{{/* Add generic image processing if image parameter is provided */}} +{{- if $imageUrl -}} + {{- $config = merge $config (dict + "imageUrl" $imageUrl + "isImageEmbed" true + "imageProcessing" (dict + "width" $width + "height" $height + "quality" $quality + "formats" $formats + "sizes" (slice 400 600 800 1200) + ) + ) -}} +{{- end -}} + +{{/* Fetch data from API if available - with graceful fallbacks */}} +{{- $embedData := dict -}} +{{- $processedImage := dict -}} +{{- if $config.apiUrl -}} + {{- with try (resources.GetRemote $config.apiUrl) -}} + {{- with .Err -}} + {{/* Log warning but don't fail - allow graceful fallback */}} + {{- if not (strings.Contains (string .Err) "rate limit") -}} + {{- warnf "embed shortcode: failed to fetch remote resource from %q: %s (continuing with fallback display)" $config.apiUrl $.Position -}} + {{- end -}} + {{- else with .Value -}} + {{- $embedData = . | transform.Unmarshal -}} + {{- else -}} + {{/* Still warn but continue */}} + {{- warnf "embed shortcode: unable to get remote resource from %q (continuing with fallback display)" $config.apiUrl -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* Process image if image URL or platform image is configured */}} +{{- if and $config.isImageEmbed $config.imageUrl -}} + {{- with try (resources.GetRemote $config.imageUrl) -}} + {{- with .Err -}} + {{- warnf "embed shortcode: failed to fetch image from %q (continuing without image): %s" $config.imageUrl $.Position -}} + {{- else with .Value -}} + {{- $remoteImg := . -}} + {{- $resizeStr := printf "%dx%d jpg q%d" $config.imageProcessing.width $config.imageProcessing.height $config.imageProcessing.quality -}} + {{- with try ($remoteImg.Resize $resizeStr) -}} + {{- with .Err -}} + {{/* Image resize failed, use original */}} + {{- $processedImage = dict "fallback" $remoteImg "srcset" $remoteImg.RelPermalink -}} + {{- else with .Value -}} + {{- $processedImage = partial "functions/process_responsive_image.html" (dict + "image" . + "mode" "responsive" + "sizes" $config.imageProcessing.sizes + "formats" $config.imageProcessing.formats + ) -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- if or $embedData $customUrl $config.repoLink $resource $processedImage -}} +
+ + +
+
+ {{ partial "functions/embed/hbx_platform_icon.html" (dict "platform" $platform "config" $config "hb_id" $hbx_embed_id) }} +
+ +
+ {{ partial "functions/embed/hbx_title_section.html" (dict "hb_id" $hbx_embed_id "customTitle" $customTitle "embedData" $embedData "customUrl" $customUrl "resource" $resource "type" $type "platform" $platform "config" $config) }} +
+ + +
+ + +
+ {{ partial "functions/embed/hbx_content_section.html" (dict "customDescription" $customDescription "embedData" $embedData "platform" $platform "hb_id" $hbx_embed_id "config" $config "processedImage" $processedImage) }} +
+ + +
+ + +
+ Powered by Hugo Blox Builder - https://github.com/HugoBlox/hugo-blox-builder +
+ +
+{{- else -}} + {{ warnf "embed shortcode: unable to fetch data or missing required parameters: %s" .Position }} + +
+
+ {{ partial "functions/get_icon" (dict "name" "exclamation-triangle" "attributes" "class=\"w-5 h-5\"") }} + Embed Warning +
+

+ Unable to load embedded content. Please check the parameters and try again. +

+
+{{- end -}} diff --git a/starters/academic-cv/content/post/data-visualization/index.md b/starters/academic-cv/content/post/data-visualization/index.md index 2a584e37..3584db0e 100644 --- a/starters/academic-cv/content/post/data-visualization/index.md +++ b/starters/academic-cv/content/post/data-visualization/index.md @@ -1,6 +1,6 @@ --- title: 📈 Communicate your results effectively with the best data visualizations -summary: Use popular tools such as Plotly, Mermaid, and data frames. +summary: Use popular tools such as HuggingFace, Plotly, Mermaid, and data frames. date: 2023-10-25 authors: - admin @@ -16,6 +16,34 @@ Hugo Blox is designed to give technical content creators a seamless experience. Use popular tools such as Plotly, Mermaid, and data frames. +## Embed Rich Content + +HuggingFace Model + +{{< embed platform="huggingface" resource="google/embeddinggemma-300m" type="model" >}} + +HuggingFace Dataset + +{{< embed platform="huggingface" resource="fka/awesome-chatgpt-prompts" type="dataset" >}} + +GitHub Repository + +{{< embed platform="github" resource="HugoBlox/hugo-blox-builder" type="repo" >}} + +Custom embed with manual data + +{{< embed url="https://example.com" title="My Custom Resource" description="A great resource for learning" >}} + +### Custom Images + +Embed beautiful images from any source with Hugo image processing (Unsplash, custom URLs, etc.): + +{{< embed url="https://example.com" title="Data Visualization Guide" description="Beautiful data visualization workspace" image="https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?q=80&w=800&h=600&auto=format&fit=crop" width="800" height="600" quality="90" >}} + +You can also add images to any platform embed: + +{{< embed platform="github" resource="plotly/plotly.py" type="repo" image="https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=600&h=400&auto=format&fit=crop" width="600" height="400" >}} + ## Charts Hugo Blox supports the popular [Plotly](https://plot.ly/) format for interactive data visualizations. With Plotly, you can design almost any kind of visualization you can imagine! @@ -154,4 +182,56 @@ renders as {{< table path="results.csv" header="true" caption="Table 1: My results" >}} +## Interactive Buttons + +Add engaging call-to-action buttons to your data visualization posts: + +### Basic Buttons + +{{< button url="/" >}}Contact Us{{< /button >}} + +  + +{{< button url="https://plotly.com/python/" new_tab="true" style="secondary" >}}Learn Plotly{{< /button >}} + +```go-html-template +{{}}Contact Us{{}} + +{{}}Learn Plotly{{}} +``` + +### Styled Buttons for Data Actions + +{{< button url="#" style="primary" size="lg" align="center" icon="chart-bar" >}}View Dashboard{{< /button >}} + +  + +{{< button url="/data/results.csv" style="outline" icon="document-arrow-down" >}}Download Data{{< /button >}} + +  + +{{< button url="https://github.com/HugoBlox" new_tab="true" style="ghost" icon="arrow-top-right-on-square" icon_position="right" >}}View Source Code{{< /button >}} + +```go-html-template +{{}}View Dashboard{{}} + +{{}}Download Data{{}} + +{{}}View Source Code{{}} +``` + +### Multiple Aligned Buttons + +{{< button url="https://jupyter.org/" new_tab="true" style="secondary" rounded="full" align="center" >}}Try Jupyter{{< /button >}} + +  + +{{< button url="https://colab.research.google.com/" new_tab="true" style="primary" rounded="full" align="center" icon="rocket-launch" >}}Open in Colab{{< /button >}} + +```go-html-template +{{}}Try Jupyter{{}} + +{{}}Open in Colab{{}} +``` + ## Did you find this page helpful? Consider sharing it 🙌 diff --git a/starters/academic-cv/content/post/get-started/index.md b/starters/academic-cv/content/post/get-started/index.md index acf80715..4dd445c0 100644 --- a/starters/academic-cv/content/post/get-started/index.md +++ b/starters/academic-cv/content/post/get-started/index.md @@ -18,9 +18,6 @@ tags: - Markdown content_meta: - # content_type: 'Tutorial' - # difficulty: 'Beginner' - prerequisites: ['Markdown'] trending: true --- diff --git a/starters/academic-cv/content/teaching/js/index.md b/starters/academic-cv/content/teaching/js/index.md index de12d095..7b01e45c 100644 --- a/starters/academic-cv/content/teaching/js/index.md +++ b/starters/academic-cv/content/teaching/js/index.md @@ -8,6 +8,11 @@ tags: - JavaScript image: caption: 'Embed rich media such as videos and LaTeX math' +content_meta: + content_type: 'Tutorial' + difficulty: 'Beginner' + prerequisites: ['HTML'] + trending: true --- [Hugo Blox Builder](https://hugoblox.com) is designed to give technical content creators a seamless experience. You can focus on the content and the Hugo Blox Builder which this template is built upon handles the rest. @@ -112,7 +117,6 @@ $$ Hugo Blox Builder utilises Hugo's Markdown extension for highlighting code syntax. The code theme can be selected in the `config/_default/params.yaml` file. - ```python import pandas as pd data = pd.read_csv("data.csv") diff --git a/starters/academic-cv/content/teaching/python/index.md b/starters/academic-cv/content/teaching/python/index.md index 60a0b42c..afe8b205 100644 --- a/starters/academic-cv/content/teaching/python/index.md +++ b/starters/academic-cv/content/teaching/python/index.md @@ -8,6 +8,11 @@ tags: - Python image: caption: 'Embed rich media such as videos and LaTeX math' +content_meta: + content_type: 'Course' + difficulty: 'Intermediate' + prerequisites: ['SQL'] + trending: false --- [Hugo Blox Builder](https://hugoblox.com) is designed to give technical content creators a seamless experience. You can focus on the content and the Hugo Blox Builder which this template is built upon handles the rest. @@ -112,7 +117,6 @@ $$ Hugo Blox Builder utilises Hugo's Markdown extension for highlighting code syntax. The code theme can be selected in the `config/_default/params.yaml` file. - ```python import pandas as pd data = pd.read_csv("data.csv") diff --git a/starters/documentation/content/docs/guide/shortcodes/_index.md b/starters/documentation/content/docs/guide/shortcodes/_index.md index 878ee4b7..5b8de217 100644 --- a/starters/documentation/content/docs/guide/shortcodes/_index.md +++ b/starters/documentation/content/docs/guide/shortcodes/_index.md @@ -5,6 +5,7 @@ title: Shortcodes Build the best docs with re-usable components, referred to as Hugo shortcodes: {{< cards >}} + {{< card url="button" title="Button" icon="cursor-arrow-rays" >}} {{< card url="callout" title="Callout" icon="warning" >}} {{< card url="cards" title="Cards" icon="card" >}} {{< card url="toggle" title="Spoiler" icon="chevron-right" >}} diff --git a/starters/documentation/content/docs/guide/shortcodes/button.md b/starters/documentation/content/docs/guide/shortcodes/button.md new file mode 100644 index 00000000..53c0743c --- /dev/null +++ b/starters/documentation/content/docs/guide/shortcodes/button.md @@ -0,0 +1,202 @@ +--- +title: Button Shortcode +linkTitle: Button +--- + +A modern, customizable button shortcode with gradient styling, icons, and smart link handling. + + + +## Basic Usage + +{{< button url="/contact" >}}Contact Us{{< /button >}} + +{{< button url="https://example.com" new_tab="true" style="secondary" >}}Visit External Site{{< /button >}} + +The above buttons are created with: + +```go-html-template +{{}}Contact Us{{}} + +{{}}Visit External Site{{}} +``` + +## Style Variants + +### Primary (Default) + +{{< button url="#" style="primary" >}}Primary Button{{< /button >}} + +```go-html-template +{{}}Primary Button{{}} +``` + +### Secondary + +{{< button url="#" style="secondary" >}}Secondary Button{{< /button >}} + +```go-html-template +{{}}Secondary Button{{}} +``` + +### Outline + +{{< button url="#" style="outline" >}}Outline Button{{< /button >}} + +```go-html-template +{{}}Outline Button{{}} +``` + +### Ghost + +{{< button url="#" style="ghost" >}}Ghost Button{{< /button >}} + +```go-html-template +{{}}Ghost Button{{}} +``` + +## Sizes + +### Small + +{{< button url="#" size="sm" >}}Small Button{{< /button >}} + +### Medium (Default) + +{{< button url="#" size="md" >}}Medium Button{{< /button >}} + +### Large + +{{< button url="#" size="lg" >}}Large Button{{< /button >}} + +### Extra Large + +{{< button url="#" size="xl" >}}Extra Large{{< /button >}} + +```go-html-template +{{}}Small Button{{}} +{{}}Medium Button{{}} +{{}}Large Button{{}} +{{}}Extra Large{{}} +``` + +## Alignment + +### Left (Default) + +{{< button url="#" align="left" >}}Left Aligned{{< /button >}} + +### Center + +{{< button url="#" align="center" >}}Center Aligned{{< /button >}} + +### Right + +{{< button url="#" align="right" >}}Right Aligned{{< /button >}} + +```go-html-template +{{}}Left Aligned{{}} +{{}}Center Aligned{{}} +{{}}Right Aligned{{}} +``` + +## With Icons + +### Icon Before Text + +{{< button url="#" icon="download" >}}Download{{< /button >}} + +### Icon After Text + +{{< button url="#" icon="arrow-right" icon_position="right" >}}Continue{{< /button >}} + +```go-html-template +{{}}Download{{}} +{{}}Continue{{}} +``` + +## Rounded Corners + +### Small Radius + +{{< button url="#" rounded="sm" >}}Small Radius{{< /button >}} + +### Medium Radius (Default) + +{{< button url="#" rounded="md" >}}Medium Radius{{< /button >}} + +### Large Radius + +{{< button url="#" rounded="lg" >}}Large Radius{{< /button >}} + +### Pill Shape + +{{< button url="#" rounded="full" >}}Pill Button{{< /button >}} + +```go-html-template +{{}}Small Radius{{}} +{{}}Medium Radius{{}} +{{}}Large Radius{{}} +{{}}Pill Button{{}} +``` + +## Advanced Examples + +### Call-to-Action Button + +{{< button url="/signup" style="primary" size="lg" align="center" icon="rocket-launch" >}}Get Started Today{{< /button >}} + +```go-html-template +{{}}Get Started Today{{}} +``` + +### External Link with New Tab + +{{< button url="https://github.com/hugo-blox/hugo-blox-builder" new_tab="true" style="outline" icon="arrow-top-right-on-square" icon_position="right" >}}View on GitHub{{< /button >}} + +```go-html-template +{{}}View on GitHub{{}} +``` + +### Download Button + +{{< button url="/files/document.pdf" style="secondary" icon="document-arrow-down" rounded="full" >}}Download PDF{{< /button >}} + +```go-html-template +{{}}Download PDF{{}} +``` + +## Parameters + +| Parameter | Type | Default | Description | +| --------------- | ------- | ------------- | ----------------------------------------------------------- | +| `url` | string | `#` | **Required.** Button destination URL (internal or external) | +| `text` | string | Inner content | Button text (overrides shortcode content) | +| `new_tab` | boolean | `false` | Whether to open link in new tab | +| `style` | string | `primary` | Button style: `primary`, `secondary`, `outline`, `ghost` | +| `size` | string | `md` | Button size: `sm`, `md`, `lg`, `xl` | +| `align` | string | `left` | Button alignment: `left`, `center`, `right` | +| `icon` | string | - | Icon name from [Hero Icons](https://heroicons.com/) | +| `icon_position` | string | `left` | Icon position: `left`, `right` | +| `rounded` | string | `md` | Border radius: `sm`, `md`, `lg`, `xl`, `full` | +| `disabled` | boolean | `false` | Whether button should be disabled | + +## Security Features + +The button shortcode automatically handles security for external links: + +- **External links** get `rel="noreferrer"` attribute +- **External links opening in new tab** get `rel="noopener noreferrer"` +- **Internal links opening in new tab** get `rel="noopener"` + +This ensures safe navigation while maintaining functionality. + +## Accessibility + +The button shortcode includes built-in accessibility features: + +- Proper `role="button"` attribute +- `aria-label` support +- Keyboard focus indicators +- High contrast focus rings +- Disabled state handling