From cde369188e1e0cc1541026a7928dba8272aa0e72 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Fri, 15 May 2026 19:50:54 +0700 Subject: [PATCH] feat(theme): share button + QR + vCard + manifest + WebSite schema Adds share button, QR code block, and Schema.org WebSite markup for enhanced link sharing. Introduces vCard contact export and PWA manifest generation for mobile compatibility. Expands profile distribution and integration capabilities. --- .../layouts/_default/manifest.webmanifest | 31 +++++++++++++++++++ themes/bonsai/layouts/_default/vcard.vcf | 22 +++++++++++++ themes/bonsai/layouts/partials/qr-block.html | 15 +++++++++ .../layouts/partials/schema-website.html | 14 +++++++++ .../bonsai/layouts/partials/share-button.html | 19 ++++++++++++ 5 files changed, 101 insertions(+) create mode 100644 themes/bonsai/layouts/_default/manifest.webmanifest create mode 100644 themes/bonsai/layouts/_default/vcard.vcf create mode 100644 themes/bonsai/layouts/partials/qr-block.html create mode 100644 themes/bonsai/layouts/partials/schema-website.html create mode 100644 themes/bonsai/layouts/partials/share-button.html diff --git a/themes/bonsai/layouts/_default/manifest.webmanifest b/themes/bonsai/layouts/_default/manifest.webmanifest new file mode 100644 index 0000000..25156ad --- /dev/null +++ b/themes/bonsai/layouts/_default/manifest.webmanifest @@ -0,0 +1,31 @@ +{{- $name := site.Params.name | default site.Title -}} +{{- $shortName := site.Params.shortName | default (substr $name 0 12) -}} +{{- $themeColor := site.Params.themeColor | default "#8b3a2b" -}} +{{- $bgColor := site.Params.themeBackground | default "#f4efe6" -}} +{{- /* start_url and scope use relURL so subpath deployments (e.g. GitHub Pages + project sites at /repo/) install correctly. */ -}} +{{- $root := "/" | relURL -}} +{{- $hasIcons := or site.Params.appleTouchIcon site.Params.faviconSvg -}} +{ + "name": "{{ $name }}", + "short_name": "{{ $shortName }}", + "start_url": "{{ $root }}", + "scope": "{{ $root }}", + "display": "minimal-ui", + "background_color": "{{ $bgColor }}", + "theme_color": "{{ $themeColor }}" + {{- if $hasIcons -}} + , + "icons": [ + {{- $first := true -}} + {{- with site.Params.appleTouchIcon -}} + {{- if $first }}{{ $first = false }}{{ else }},{{ end }} + { "src": "{{ . | relURL }}", "sizes": "180x180", "type": "image/png" } + {{- end -}} + {{- with site.Params.faviconSvg -}} + {{- if $first }}{{ $first = false }}{{ else }},{{ end }} + { "src": "{{ . | relURL }}", "sizes": "any", "type": "image/svg+xml" } + {{- end -}} + ] + {{- end }} +} diff --git a/themes/bonsai/layouts/_default/vcard.vcf b/themes/bonsai/layouts/_default/vcard.vcf new file mode 100644 index 0000000..bfe888e --- /dev/null +++ b/themes/bonsai/layouts/_default/vcard.vcf @@ -0,0 +1,22 @@ +{{- $name := site.Params.name | default site.Title -}} +{{- /* Flatten links + sections for URL lines. */ -}} +{{- $allLinks := slice -}} +{{- if site.Params.sections -}} + {{- range site.Params.sections -}}{{- range .links -}}{{- $allLinks = $allLinks | append . -}}{{- end -}}{{- end -}} +{{- else -}}{{- $allLinks = site.Params.links -}}{{- end -}} +BEGIN:VCARD +VERSION:3.0 +FN:{{ $name }} +{{ with site.Params.jobTitle }}TITLE:{{ . }} +{{ end -}} +{{ with site.Params.email }}EMAIL:{{ . }} +{{ end -}} +{{ with site.Params.location }}ADR:;;{{ . }};;;; +{{ end -}} +URL:{{ site.BaseURL }} +{{ range $allLinks -}} +{{- if and .url (not (or (strings.HasPrefix .url "mailto:") (strings.HasPrefix .url "tel:"))) -}} +URL;TYPE={{ .title | upper }}:{{ .url }} +{{ end -}} +{{- end -}} +END:VCARD diff --git a/themes/bonsai/layouts/partials/qr-block.html b/themes/bonsai/layouts/partials/qr-block.html new file mode 100644 index 0000000..deec835 --- /dev/null +++ b/themes/bonsai/layouts/partials/qr-block.html @@ -0,0 +1,15 @@ +{{- /* Render a QR code of the current page Permalink inside a collapsible
. + Gated by site.Params.qr = true. Uses Hugo's built-in images.QR (≥ 0.140). + The PNG is generated at build time and cached under resources/_gen/. */ -}} +{{- if site.Params.qr -}} +{{- $url := .Permalink -}} +{{- $qr := images.QR $url (dict "level" "medium" "scale" 4) -}} +{{- $showLabel := i18n "show_qr" | default "Show QR code" -}} +{{- $alt := i18n "qr_alt" | default "QR code linking to this page" -}} +
+ {{ $showLabel }} + {{ $alt }} +
+{{- end -}} diff --git a/themes/bonsai/layouts/partials/schema-website.html b/themes/bonsai/layouts/partials/schema-website.html new file mode 100644 index 0000000..ee203d1 --- /dev/null +++ b/themes/bonsai/layouts/partials/schema-website.html @@ -0,0 +1,14 @@ +{{- /* Optional WebSite JSON-LD for rich-snippet eligibility. + Off by default — opt in via params.schemaWebSite = true. */ -}} +{{- if site.Params.schemaWebSite -}} +{{- $name := site.Params.name | default site.Title -}} +{{- $payload := dict + "@context" "https://schema.org" + "@type" "WebSite" + "name" $name + "url" site.BaseURL + "inLanguage" (site.Language.LanguageCode | default site.LanguageCode | default "en") +-}} +{{- with site.Params.bio -}}{{- $payload = merge $payload (dict "description" .) -}}{{- end -}} + +{{- end -}} diff --git a/themes/bonsai/layouts/partials/share-button.html b/themes/bonsai/layouts/partials/share-button.html new file mode 100644 index 0000000..22e7f7a --- /dev/null +++ b/themes/bonsai/layouts/partials/share-button.html @@ -0,0 +1,19 @@ +{{- /* Render a share button. Uses navigator.share (Web Share API) when available; + falls back to clipboard.writeText with a small toast. + Loaded only when site.Params.share = true (gated by caller). */ -}} +{{- $name := site.Params.name | default site.Title -}} +{{- $shareLabel := i18n "share_label" | default "Share this page" -}} +{{- $copied := i18n "share_copied" | default "Link copied" -}} +{{- $failed := i18n "share_failed" | default "Could not share" -}} + +