diff --git a/modules/blox/blox/collection/block.html b/modules/blox/blox/collection/block.html index 79fa5e2d..08b6d8df 100644 --- a/modules/blox/blox/collection/block.html +++ b/modules/blox/blox/collection/block.html @@ -5,14 +5,21 @@ {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} -{{ $view := $block.design.view | default "card" }} +{{ $content := $block.content }} +{{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} +{{ $design := $block.design }} +{{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} -{{ $items_offset := $block.content.offset | default 0 }} -{{ $items_count := $block.content.count }} +{{ $view := "card" }} +{{ $view_raw := index $design "view" }} +{{ if eq (printf "%T" $view_raw) "string" }} + {{ $view = lower (strings.TrimSpace $view_raw) }} +{{ end }} + +{{ $items_offset := partial "functions/coerce_int" (dict "value" (index $content "offset") "default" 0 "min" 0) }} +{{ $items_count := partial "functions/coerce_int" (dict "value" (index $content "count") "default" 5 "min" 0) }} {{ if eq $items_count 0 }} {{ $items_count = 65535 }} -{{ else }} - {{ $items_count = $items_count | default 5 }} {{ end }} {{/* Query */}} @@ -20,22 +27,78 @@ {{ $archive_page := "" }} {{/* Filters */}} -{{ $kinds := $block.content.filters.kinds | default (slice "page") }} +{{ $filters := index $content "filters" }} +{{ if not (reflect.IsMap $filters) }}{{ $filters = dict }}{{ end }} + +{{ $kinds := slice }} +{{ $kinds_raw := index $filters "kinds" }} +{{ if reflect.IsSlice $kinds_raw }} + {{ range $kinds_raw }} + {{ $kind := strings.TrimSpace (printf "%v" .) }} + {{ if $kind }} + {{ $kinds = $kinds | append $kind }} + {{ end }} + {{ end }} +{{ else if eq (printf "%T" $kinds_raw) "string" }} + {{ $kind := strings.TrimSpace $kinds_raw }} + {{ if $kind }} + {{ $kinds = slice $kind }} + {{ end }} +{{ end }} +{{ if eq (len $kinds) 0 }} + {{ $kinds = slice "page" }} +{{ end }} {{ $query = where $query "Kind" "in" $kinds }} -{{ if $block.content.page_type }} - {{ $query = where $query "Type" $block.content.page_type }} - {{ $archive_page = site.GetPage "Section" $block.content.page_type }} +{{ $page_type := "" }} +{{ $page_type_raw := index $content "page_type" }} +{{ if eq (printf "%T" $page_type_raw) "string" }} + {{ $page_type = strings.TrimSpace $page_type_raw }} {{ end }} -{{ if $block.content.filters.folders }} - {{ $folders := $block.content.filters.folders }} +{{ if $page_type }} + {{ $query = where $query "Type" $page_type }} + {{ $archive_page = site.GetPage "Section" $page_type }} +{{ end }} + +{{ $folders_raw := index $filters "folders" }} +{{ $folders := slice }} +{{ if reflect.IsSlice $folders_raw }} + {{ range $folders_raw }} + {{ $folder := strings.TrimSpace (printf "%v" .) }} + {{ if $folder }} + {{ $folders = $folders | append $folder }} + {{ end }} + {{ end }} +{{ else if eq (printf "%T" $folders_raw) "string" }} + {{ $folder := strings.TrimSpace $folders_raw }} + {{ if $folder }} + {{ $folders = slice $folder }} + {{ end }} +{{ end }} +{{ if gt (len $folders) 0 }} {{ $query = where $query "Section" "in" $folders }} - {{/* Init archive page to main folder */}} - {{ $main_folder := index $folders 0 }} - {{ $archive_page = site.GetPage "Section" $main_folder }} + {{ $main_folder := strings.TrimSpace (printf "%v" (index $folders 0)) }} + {{ if $main_folder }} + {{ $archive_page = site.GetPage "Section" $main_folder }} + {{ end }} {{ end }} -{{ if $block.content.filters.tags }} - {{ $tags := $block.content.filters.tags }} + +{{ $tags_raw := index $filters "tags" }} +{{ $tags := slice }} +{{ if reflect.IsSlice $tags_raw }} + {{ range $tags_raw }} + {{ $tag := strings.TrimSpace (printf "%v" .) }} + {{ if $tag }} + {{ $tags = $tags | append $tag }} + {{ end }} + {{ end }} +{{ else if eq (printf "%T" $tags_raw) "string" }} + {{ $tag := strings.TrimSpace $tags_raw }} + {{ if $tag }} + {{ $tags = slice $tag }} + {{ end }} +{{ end }} +{{ if gt (len $tags) 0 }} {{ $selected := slice }} {{ range $tags }} {{ $tag_page := site.GetPage (printf "tags/%s" (urlize .)) }} @@ -45,47 +108,110 @@ {{ end }} {{ if gt (len $selected) 0 }} {{ $query = $query | intersect $selected }} - {{ $archive_page = site.GetPage (printf "tags/%s" (urlize (index $tags 0))) }} + {{ $first_tag := index $tags 0 }} + {{ $archive_page = site.GetPage (printf "tags/%s" (urlize $first_tag)) }} {{ end }} {{ end }} -{{ if $block.content.filters.tag }} - {{ $archive_page = site.GetPage (printf "tags/%s" (urlize $block.content.filters.tag)) }} - {{ $query = $query | intersect $archive_page.Pages }} + +{{ $tag := "" }} +{{ $tag_raw := index $filters "tag" }} +{{ if eq (printf "%T" $tag_raw) "string" }} + {{ $tag = strings.TrimSpace $tag_raw }} {{ end }} -{{ if $block.content.filters.category }} - {{ $archive_page = site.GetPage (printf "categories/%s" (urlize $block.content.filters.category)) }} - {{ $query = $query | intersect $archive_page.Pages }} +{{ if $tag }} + {{ with site.GetPage (printf "tags/%s" (urlize $tag)) }} + {{ $archive_page = . }} + {{ $query = $query | intersect .Pages }} + {{ end }} {{ end }} -{{ if $block.content.filters.publication_type }} - {{ $archive_page = site.GetPage (printf "publication_types/%s" $block.content.filters.publication_type) }} - {{ $query = $query | intersect $archive_page.Pages }} + +{{ $category := "" }} +{{ $category_raw := index $filters "category" }} +{{ if eq (printf "%T" $category_raw) "string" }} + {{ $category = strings.TrimSpace $category_raw }} {{ end }} -{{ if $block.content.filters.exclude_publication_type }} - {{ $query = $query | complement (site.GetPage (printf "publication_types/%s" $block.content.filters.exclude_publication_type)).Pages }} +{{ if $category }} + {{ with site.GetPage (printf "categories/%s" (urlize $category)) }} + {{ $archive_page = . }} + {{ $query = $query | intersect .Pages }} + {{ end }} {{ end }} -{{ if $block.content.filters.author }} - {{ $archive_page = site.GetPage (printf "authors/%s" (urlize $block.content.filters.author)) }} - {{ $query = $query | intersect $archive_page.Pages }} + +{{ $publication_type := "" }} +{{ $publication_type_raw := index $filters "publication_type" }} +{{ if eq (printf "%T" $publication_type_raw) "string" }} + {{ $publication_type = strings.TrimSpace $publication_type_raw }} {{ end }} -{{ if $block.content.filters.featured_only }} +{{ if $publication_type }} + {{ with site.GetPage (printf "publication_types/%s" $publication_type) }} + {{ $archive_page = . }} + {{ $query = $query | intersect .Pages }} + {{ end }} +{{ end }} + +{{ $exclude_publication_type := "" }} +{{ $exclude_publication_type_raw := index $filters "exclude_publication_type" }} +{{ if eq (printf "%T" $exclude_publication_type_raw) "string" }} + {{ $exclude_publication_type = strings.TrimSpace $exclude_publication_type_raw }} +{{ end }} +{{ if $exclude_publication_type }} + {{ with site.GetPage (printf "publication_types/%s" $exclude_publication_type) }} + {{ $query = $query | complement .Pages }} + {{ end }} +{{ end }} + +{{ $author_filter := "" }} +{{ $author_filter_raw := index $filters "author" }} +{{ if eq (printf "%T" $author_filter_raw) "string" }} + {{ $author_filter = strings.TrimSpace $author_filter_raw }} +{{ end }} +{{ if $author_filter }} + {{ with site.GetPage (printf "authors/%s" (urlize $author_filter)) }} + {{ $archive_page = . }} + {{ $query = $query | intersect .Pages }} + {{ end }} +{{ end }} + +{{ $featured_only := partial "functions/coerce_bool" (dict "value" (index $filters "featured_only") "default" false) }} +{{ if $featured_only }} {{ $query = where $query "Params.featured" "==" true }} {{ end }} -{{ if $block.content.filters.exclude_featured }} +{{ $exclude_featured := partial "functions/coerce_bool" (dict "value" (index $filters "exclude_featured") "default" false) }} +{{ if $exclude_featured }} {{ $query = where $query "Params.featured" "!=" true }} {{ end }} -{{ if $block.content.filters.exclude_past }} +{{ $exclude_past := partial "functions/coerce_bool" (dict "value" (index $filters "exclude_past") "default" false) }} +{{ if $exclude_past }} {{ $query = where $query "Date" ">=" now }} {{ end }} -{{ if $block.content.filters.exclude_future }} +{{ $exclude_future := partial "functions/coerce_bool" (dict "value" (index $filters "exclude_future") "default" false) }} +{{ if $exclude_future }} {{ $query = where $query "Date" "<" now }} {{ end }} {{ $count := len $query }} {{/* Sort */}} -{{ $sort_by := $block.content.sort_by | default "Date" }} +{{ $sort_by := "Date" }} +{{ $sort_by_raw := index $content "sort_by" }} +{{ if eq (printf "%T" $sort_by_raw) "string" }} + {{ $sort_by_raw = strings.TrimSpace $sort_by_raw }} + {{ if ne $sort_by_raw "" }} + {{ $sort_by = $sort_by_raw }} + {{ end }} +{{ end }} {{ $sort_by = partial "functions/get_sort_by_parameter" $sort_by }} -{{ $sort_ascending := $block.content.sort_ascending | default (eq $block.content.order "asc") | default false }} +{{ $sort_ascending := false }} +{{ if isset $content "sort_ascending" }} + {{ $sort_ascending = partial "functions/coerce_bool" (dict "value" (index $content "sort_ascending") "default" false) }} +{{ else }} + {{ $order_raw := index $content "order" }} + {{ if eq (printf "%T" $order_raw) "string" }} + {{ if eq (lower (strings.TrimSpace $order_raw)) "asc" }} + {{ $sort_ascending = true }} + {{ end }} + {{ end }} +{{ end }} {{ $sort_order := cond $sort_ascending "asc" "desc" }} {{ $query = sort $query $sort_by $sort_order }} @@ -104,28 +230,32 @@ {{ end }} {{ end }} -{{ $columns := $block.design.columns | default "2" }} +{{ $columns := partial "functions/coerce_int" (dict "value" (index $design "columns") "default" 2 "min" 1 "max" 4) }} +{{ $title := "" }} +{{ with index $content "title" }}{{ $title = printf "%v" . | emojify | $page.RenderString }}{{ end }} +{{ $text := "" }} +{{ with index $content "text" }}{{ $text = printf "%v" . | emojify | $page.RenderString }}{{ end }} -{{ if $block.content.title }} +{{ if $title }}
- {{ $block.content.title | emojify | $page.RenderString }} + {{ $title }}
- {{ with $block.content.text }}

{{ . | emojify | $page.RenderString }}

{{ end }} + {{ with $text }}

{{ . }}

{{ end }}
{{ end }}
{{ $config := dict - "columns" ($block.design.columns | default 2) + "columns" $columns "len" (len $query) - "fill_image" ($block.design.fill_image | default true) - "show_date" ($block.design.show_date | default true) - "show_read_time" ($block.design.show_read_time | default true) - "show_read_more" ($block.design.show_read_more | default true) + "fill_image" (partial "functions/coerce_bool" (dict "value" (index $design "fill_image") "default" true)) + "show_date" (partial "functions/coerce_bool" (dict "value" (index $design "show_date") "default" true)) + "show_read_time" (partial "functions/coerce_bool" (dict "value" (index $design "show_read_time") "default" true)) + "show_read_more" (partial "functions/coerce_bool" (dict "value" (index $design "show_read_more") "default" true)) }} {{ partial "functions/render_view" (dict "fragment" "start" "page" $block "item" . "view" $view "config" $config) }} @@ -138,15 +268,30 @@
{{/* Archive link */}} -{{ $show_archive_link := $block.content.archive.enable | default (gt $count $items_count) }} +{{ $archive := index $content "archive" }} +{{ if not (reflect.IsMap $archive) }}{{ $archive = dict }}{{ end }} +{{ $show_archive_link := gt $count $items_count }} +{{ if isset $archive "enable" }} + {{ $show_archive_link = partial "functions/coerce_bool" (dict "value" (index $archive "enable") "default" false) }} +{{ end }} {{ if $show_archive_link | and $archive_page }} {{ $archive_link := "" }} - {{ if $block.content.archive.link }} - {{ $archive_link = $block.content.archive.link | relLangURL }} - {{ else }} + {{ $archive_link_raw := index $archive "link" }} + {{ if eq (printf "%T" $archive_link_raw) "string" }} + {{ $archive_link = strings.TrimSpace $archive_link_raw }} + {{ end }} + {{ if not $archive_link }} {{ $archive_link = $archive_page.RelPermalink }} {{ end }} + {{ if $archive_link }} + {{ $scheme := (urls.Parse $archive_link).Scheme }} + {{ if not $scheme }} + {{ if not (hasPrefix $archive_link "#") }} + {{ $archive_link = $archive_link | relLangURL }} + {{ end }} + {{ end }} + {{ end }} {{/* Localisation */}} {{ $items_type := $archive_page.Type }} @@ -161,13 +306,20 @@ {{ $i18n = "more_pages" }} {{ end }} - {{ $archive_text := $block.content.archive.text | default (i18n $i18n) | default "See all" }} + {{ $archive_text := "" }} + {{ $archive_text_raw := index $archive "text" }} + {{ if eq (printf "%T" $archive_text_raw) "string" }} + {{ $archive_text = strings.TrimSpace $archive_text_raw }} + {{ end }} + {{ if not $archive_text }} + {{ $archive_text = i18n $i18n | default "See all" }} + {{ end }}
+ href="{{ $archive_link | safeURL }}"> {{ $archive_text | emojify }}
diff --git a/modules/blox/blox/collection/schema.json b/modules/blox/blox/collection/schema.json index d1126f16..2e607fe8 100644 --- a/modules/blox/blox/collection/schema.json +++ b/modules/blox/blox/collection/schema.json @@ -154,7 +154,7 @@ "properties": { "view": { "type": "string", - "enum": ["card", "compact", "showcase", "citation", "list", "masonry"], + "enum": ["card", "compact", "showcase", "citation", "list", "masonry", "article-grid", "date-title-summary", "slides-gallery"], "description": "Display view type", "default": "card" }, diff --git a/modules/blox/blox/cta-card/block.html b/modules/blox/blox/cta-card/block.html index 60f8fcd0..a0ce680c 100644 --- a/modules/blox/blox/cta-card/block.html +++ b/modules/blox/blox/cta-card/block.html @@ -6,14 +6,52 @@ {{ $page := .wcPage }} {{ $block := .wcBlock }} -{{ $title := $block.content.title | emojify | $page.RenderString }} -{{ $text := $block.content.text | emojify | $page.RenderString | safeHTML }} -{{ $card_class := $block.design.card.css_class }} -{{ $card_style := $block.design.card.css_style }} +{{ $content := $block.content }} +{{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} +{{ $design := $block.design }} +{{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} +{{ $card := index $design "card" }} +{{ if not (reflect.IsMap $card) }}{{ $card = dict }}{{ end }} + +{{ $title := "" }} +{{ with index $content "title" }}{{ $title = printf "%v" . | emojify | $page.RenderString }}{{ end }} +{{ $text := "" }} +{{ with index $content "text" }}{{ $text = printf "%v" . | emojify | $page.RenderString | safeHTML }}{{ end }} +{{ $card_class := "" }} +{{ $card_class_raw := index $card "css_class" }} +{{ if eq (printf "%T" $card_class_raw) "string" }} + {{ $card_class = $card_class_raw }} +{{ end }} +{{ $card_style := "" }} +{{ $card_style_raw := index $card "css_style" }} +{{ if eq (printf "%T" $card_style_raw) "string" }} + {{ $card_style = $card_style_raw }} +{{ end }} {{/* Contrast and accessibility controls */}} -{{ $text_color_mode := $block.design.card.text_color | default "auto" }} -{{ $overlay_opacity := $block.design.card.overlay_opacity | default 0.15 }} +{{ $text_color_mode := "auto" }} +{{ $text_color_raw := index $card "text_color" }} +{{ if eq (printf "%T" $text_color_raw) "string" }} + {{ $text_color_candidate := lower (strings.TrimSpace $text_color_raw) }} + {{ if in (slice "auto" "light" "dark") $text_color_candidate }} + {{ $text_color_mode = $text_color_candidate }} + {{ end }} +{{ end }} +{{ $overlay_opacity := 0.15 }} +{{ $overlay_raw := index $card "overlay_opacity" }} +{{ if ne $overlay_raw nil }} + {{ $overlay_type := printf "%T" $overlay_raw }} + {{ if or (eq $overlay_type "int") (eq $overlay_type "int8") (eq $overlay_type "int16") (eq $overlay_type "int32") (eq $overlay_type "int64") (eq $overlay_type "uint") (eq $overlay_type "uint8") (eq $overlay_type "uint16") (eq $overlay_type "uint32") (eq $overlay_type "uint64") (eq $overlay_type "float32") (eq $overlay_type "float64") }} + {{ $overlay_opacity = float $overlay_raw }} + {{ else if eq $overlay_type "string" }} + {{ $overlay_trimmed := strings.TrimSpace $overlay_raw }} + {{ if gt (len (findRE "^-?[0-9]*\\.?[0-9]+$" $overlay_trimmed)) 0 }} + {{ $overlay_opacity = float $overlay_trimmed }} + {{ end }} + {{ end }} +{{ end }} +{{ if lt $overlay_opacity 0 }}{{ $overlay_opacity = 0 }}{{ end }} +{{ if gt $overlay_opacity 1 }}{{ $overlay_opacity = 1 }}{{ end }} {{/* Auto-detect text color based on background */}} {{ $text_classes := "" }} @@ -27,8 +65,19 @@ {{ else }} {{/* Auto mode - detect based on gradient colors */}} {{ $is_dark_bg := false }} - {{ with $block.design.background.gradient.start }} - {{ if or (hasPrefix . "primary-7") (hasPrefix . "primary-8") (hasPrefix . "primary-9") (hasPrefix . "secondary-7") (hasPrefix . "secondary-8") (hasPrefix . "secondary-9") }} + {{ $gradient_start := "" }} + {{ $bg := index $design "background" }} + {{ if and $bg (reflect.IsMap $bg) }} + {{ $gradient := index $bg "gradient" }} + {{ if and $gradient (reflect.IsMap $gradient) }} + {{ $start_raw := index $gradient "start" }} + {{ if eq (printf "%T" $start_raw) "string" }} + {{ $gradient_start = $start_raw }} + {{ end }} + {{ end }} + {{ end }} + {{ if $gradient_start }} + {{ if or (hasPrefix $gradient_start "primary-7") (hasPrefix $gradient_start "primary-8") (hasPrefix $gradient_start "primary-9") (hasPrefix $gradient_start "secondary-7") (hasPrefix $gradient_start "secondary-8") (hasPrefix $gradient_start "secondary-9") }} {{ $is_dark_bg = true }} {{ end }} {{ end }} @@ -52,59 +101,78 @@ style="{{ $custom_style | safeCSS }}"> {{/* Modern Typography Hierarchy - Responsive text colors */}} + {{ with $title }}

- {{ $title }} + {{ . }}

+ {{ end }} {{/* Enhanced Text with Better Spacing - Responsive colors */}} + {{ with $text }}
- {{ $text }} -
- - {{ with $block.content.button }} - {{/* Modern 2025 Button Container */}} -
- {{ $button_link := .url }} - {{ $button_scheme := (urls.Parse $button_link).Scheme }} - {{ $button_target := "" }} - {{ $new_tab := .new_tab | default false }} - {{ if not $button_scheme }} - {{/* Check if it's a hash fragment (page anchor) */}} - {{ if hasPrefix $button_link "#" }} - {{/* Keep hash fragments as-is */}} - {{ $button_link = $button_link }} - {{ else }} - {{/* Apply relLangURL for relative paths */}} - {{ $button_link = $button_link | relLangURL }} - {{ end }} - {{ else if in (slice "http" "https") $button_scheme }} - {{ $new_tab = true }} - {{ end }} - {{/* Apply new tab if requested or external link */}} - {{ if $new_tab }} - {{ $button_target = "target=\"_blank\" rel=\"noopener\"" }} - {{ end }} - - {{/* 2025 Glassmorphism Button */}} - - - {{/* Button Background with Glassmorphism */}} -
- - {{/* Button Content */}} - {{ .text }} - {{ with .icon }} - - {{ partial "functions/get_icon" (dict "name" . "attributes" "style=\"height: 1.25em\" class='inline-block'") }} - - {{ end }} - - {{/* Subtle glow effect */}} -
-
+ {{ . }}
{{ end }} + {{ $button_raw := index $content "button" }} + {{ if and $button_raw (reflect.IsMap $button_raw) }} + {{ $button_text := "" }} + {{ $button_url := "" }} + {{ $button_icon := "" }} + {{ $button_new_tab := partial "functions/coerce_bool" (dict "value" (index $button_raw "new_tab") "default" false) }} + {{ with index $button_raw "text" }}{{ $button_text = printf "%v" . }}{{ end }} + {{ with index $button_raw "url" }}{{ $button_url = printf "%v" . }}{{ end }} + {{ with index $button_raw "icon" }} + {{ if eq (printf "%T" .) "string" }} + {{ $button_icon = . }} + {{ end }} + {{ end }} + {{ $button_text = strings.TrimSpace $button_text }} + {{ $button_url = strings.TrimSpace $button_url }} + {{ if and $button_text $button_url }} + {{/* Modern 2025 Button Container */}} +
+ {{ $button_link := $button_url }} + {{ $button_scheme := (urls.Parse $button_link).Scheme }} + {{ $button_target := "" }} + {{ if not $button_scheme }} + {{/* Check if it's a hash fragment (page anchor) */}} + {{ if not (hasPrefix $button_link "#") }} + {{/* Apply relLangURL for relative paths */}} + {{ $button_link = $button_link | relLangURL }} + {{ end }} + {{ if eq (path.Ext $button_link) ".pdf" }} + {{ $button_new_tab = true }} + {{ end }} + {{ else if in (slice "http" "https") $button_scheme }} + {{ $button_new_tab = true }} + {{ end }} + {{/* Apply new tab if requested or external link */}} + {{ if $button_new_tab }} + {{ $button_target = "target=\"_blank\" rel=\"noopener\"" }} + {{ end }} + + {{/* 2025 Glassmorphism Button */}} + + + {{/* Button Background with Glassmorphism */}} +
+ + {{/* Button Content */}} + {{ $button_text }} + {{ if $button_icon }} + + {{ partial "functions/get_icon" (dict "name" $button_icon "attributes" "style=\"height: 1.25em\" class='inline-block'") }} + + {{ end }} + + {{/* Subtle glow effect */}} +
+
+
+ {{ end }} + {{ end }} +
diff --git a/modules/blox/blox/cta-card/schema.json b/modules/blox/blox/cta-card/schema.json index 29e83b04..ee2b8ed6 100644 --- a/modules/blox/blox/cta-card/schema.json +++ b/modules/blox/blox/cta-card/schema.json @@ -41,6 +41,11 @@ "icon": { "type": "string", "description": "Optional button icon (icon pack format: pack/icon-name)" + }, + "new_tab": { + "type": "boolean", + "description": "Open the button link in a new tab", + "default": false } }, "required": ["url", "text"], diff --git a/modules/blox/blox/markdown/block.html b/modules/blox/blox/markdown/block.html index 32288cdb..5a7db822 100644 --- a/modules/blox/blox/markdown/block.html +++ b/modules/blox/blox/markdown/block.html @@ -5,14 +5,20 @@ {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} -{{ $title := $block.content.title | emojify | $page.RenderString }} -{{ $text := $block.content.text | emojify | $page.RenderString | safeHTML }} +{{ $content := $block.content }} +{{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} +{{ $title := "" }} +{{ with index $content "title" }}{{ $title = printf "%v" . | emojify | $page.RenderString }}{{ end }} +{{ $text := "" }} +{{ with index $content "text" }}{{ $text = printf "%v" . | emojify | $page.RenderString | safeHTML }}{{ end }}
+ {{ with $title }}
- {{ $title }} + {{ . }}
+ {{ end }} {{/* We use DIV rather than P to support `prose` class and multiple paragraphs */}} {{ with $text }}
{{ . }}
{{ end }} diff --git a/modules/blox/blox/resume-biography-3/block.html b/modules/blox/blox/resume-biography-3/block.html index 619a5cac..e615b4f4 100644 --- a/modules/blox/blox/resume-biography-3/block.html +++ b/modules/blox/blox/resume-biography-3/block.html @@ -6,16 +6,45 @@ {{ $page := .wcPage }} {{ $block := .wcBlock }} -{{ $author := $block.content.username | default "me" }} +{{ $content := $block.content }} +{{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} +{{ $design := $block.design }} +{{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} + +{{ $author := "me" }} +{{ $authorRaw := index $content "username" }} +{{ if eq (printf "%T" $authorRaw) "string" }} + {{ $author = $authorRaw }} +{{ end }} {{ $profile := partial "functions/get_author_profile" $author }} {{ $avatar := $profile.avatar }} +{{ $headings := index $content "headings" }} +{{ if not (reflect.IsMap $headings) }}{{ $headings = dict }}{{ end }} {{/* Avatar customization parameters */}} -{{ $avatar_size := $block.design.avatar.size | default "large" }} -{{ $avatar_shape := $block.design.avatar.shape | default "circle" }} +{{ $avatar_size := "large" }} +{{ $avatar_shape := "circle" }} +{{ $avatar_config := index $design "avatar" }} +{{ if and $avatar_config (reflect.IsMap $avatar_config) }} + {{ $avatar_size_raw := index $avatar_config "size" }} + {{ if eq (printf "%T" $avatar_size_raw) "string" }} + {{ $avatar_size = $avatar_size_raw }} + {{ end }} + {{ $avatar_shape_raw := index $avatar_config "shape" }} + {{ if eq (printf "%T" $avatar_shape_raw) "string" }} + {{ $avatar_shape = $avatar_shape_raw }} + {{ end }} +{{ end }} {{/* Profile name typography */}} -{{ $name_size := $block.design.name.size | default "lg" }} +{{ $name_size := "lg" }} +{{ $name_config := index $design "name" }} +{{ if and $name_config (reflect.IsMap $name_config) }} + {{ $name_size_raw := index $name_config "size" }} + {{ if eq (printf "%T" $name_size_raw) "string" }} + {{ $name_size = $name_size_raw }} + {{ end }} +{{ end }} {{ $name_class_map := dict "xs" "text-xl sm:text-2xl lg:text-3xl" "sm" "text-2xl sm:text-3xl lg:text-4xl" @@ -35,6 +64,24 @@ {{ $shape_classes := dict "circle" "rounded-full" "square" "rounded-none" "rounded" "rounded-lg" }} {{ $shape_class := index $shape_classes $avatar_shape | default "rounded-full" }} +{{ $banner_filename := "" }} +{{ $banner_config := index $design "banner" }} +{{ if and $banner_config (reflect.IsMap $banner_config) }} + {{ $banner_raw := index $banner_config "filename" }} + {{ if eq (printf "%T" $banner_raw) "string" }} + {{ $banner_filename = $banner_raw }} + {{ end }} +{{ end }} + +{{ $bio_style := "" }} +{{ $bio_config := index $design "biography" }} +{{ if and $bio_config (reflect.IsMap $bio_config) }} + {{ $bio_style_raw := index $bio_config "style" }} + {{ if eq (printf "%T" $bio_style_raw) "string" }} + {{ $bio_style = $bio_style_raw }} + {{ end }} +{{ end }} +
{{/* Add subtle top gradient for navbar transition */}}
@@ -45,33 +92,42 @@ {{/* Banner Image */}} {{ $img := "" }} - {{with $block.design.banner.filename}} - {{- $img = resources.Get (path.Join "media" .) -}} - {{ if $img }} -
- {{ if ne $img.MediaType.SubType "gif" }} - {{ $responsive := partial "functions/process_responsive_image.html" (dict - "image" $img - "mode" "fill" - "aspect_ratio" "16:9" - "sizes" (slice 768 1024 1366 1920 2560) - ) }} - - {{ else }} - {{- $img = $img.Process "webp" -}} - - {{ end }} -
- {{ end }} + {{ if $banner_filename }} + {{- $img = resources.Get (path.Join "media" $banner_filename) -}} + {{ if $img }} +
+ {{ if ne $img.MediaType.SubType "gif" }} + {{ $responsive := partial "functions/process_responsive_image.html" (dict + "image" $img + "mode" "fill" + "aspect_ratio" "16:9" + "sizes" (slice 768 1024 1366 1920 2560) + ) }} + + {{ else }} + {{- $img = $img.Process "webp" -}} + + {{ end }} +
+ {{ end }} {{ end }} {{/* Avatar */}} + {{ $status_icon := "" }} + {{ $status := $profile.status }} + {{ if and $status (reflect.IsMap $status) }} + {{ $status_icon_raw := index $status "icon" }} + {{ if eq (printf "%T" $status_icon_raw) "string" }} + {{ $status_icon = $status_icon_raw }} + {{ end }} + {{ end }} + {{ if $avatar }}
{{ $avatar_image := $avatar.Fill (printf "%sx%s Center" $generation_size $generation_size) }} @@ -81,7 +137,7 @@ width="{{$display_size}}" height="{{$display_size}}" style="width: {{$display_size}}px; height: {{$display_size}}px; object-fit: cover;"> - {{with $profile.status.icon}}{{.|emojify}}{{end}} + {{ with $status_icon }}{{ . | emojify }}{{ end }}
{{ end }} @@ -91,52 +147,141 @@ {{ $profile.title }} - {{- with $profile.pronouns -}} + {{ $pronouns := "" }} + {{ with $profile.pronouns }} + {{ if eq (printf "%T" .) "string" }} + {{ $pronouns = . }} + {{ end }} + {{ end }} + {{ with $pronouns }}

({{ . }})

- {{- end -}} + {{ end }} + {{ $role_text := "" }} {{ with $profile.role }} + {{ if eq (printf "%T" .) "string" }} + {{ $role_text = . }} + {{ end }} + {{ end }} + {{ with $role_text }}

{{ . | markdownify | emojify }}

{{ end }} - {{ range $profile.affiliations }} -

- {{ with .url }}{{ end }} - {{ .name }} - {{ if .url }}{{ end }} -

+ {{ $affiliations_raw := $profile.affiliations }} + {{ $affiliations := slice }} + {{ if reflect.IsSlice $affiliations_raw }} + {{ $affiliations = $affiliations_raw }} + {{ else if eq (printf "%T" $affiliations_raw) "string" }} + {{ $affiliations = slice $affiliations_raw }} + {{ end }} + {{ range $affiliations }} + {{ $aff_name := "" }} + {{ $aff_url := "" }} + {{ if reflect.IsMap . }} + {{ $nameRaw := index . "name" | default (index . "title") }} + {{ if ne $nameRaw nil }} + {{ $aff_name = printf "%v" $nameRaw }} + {{ end }} + {{ $urlRaw := index . "url" }} + {{ if eq (printf "%T" $urlRaw) "string" }} + {{ $aff_url = $urlRaw }} + {{ end }} + {{ else if eq (printf "%T" .) "string" }} + {{ $aff_name = . }} + {{ end }} + {{ $aff_name = strings.TrimSpace $aff_name }} + {{ $aff_url = strings.TrimSpace $aff_url }} + {{ if $aff_name }} +

+ {{ if $aff_url }} + {{ $link := $aff_url }} + {{ $scheme := (urls.Parse $link).Scheme }} + {{ $target := "" }} + {{ if not $scheme }} + {{ if not (hasPrefix $link "#") }} + {{ $link = $link | relLangURL }} + {{ end }} + {{ if eq (path.Ext $link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} + {{ else if in (slice "http" "https") $scheme }} + {{ $target = "target=\"_blank\" rel=\"noopener\"" }} + {{ end }} + {{ $aff_name }} + {{ else }} + {{ $aff_name }} + {{ end }} +

+ {{ end }} {{ end }}
{{/* Social Icons */}} + {{ $links_raw := $profile.links }} + {{ $links := slice }} + {{ if reflect.IsSlice $links_raw }} + {{ $links = $links_raw }} + {{ else if eq (printf "%T" $links_raw) "string" }} + {{ $links = slice $links_raw }} + {{ end }} + {{ if gt (len $links) 0 }}
- {{ range $profile.links }} - {{ $link := .url | default .link }} - {{ $scheme := (urls.Parse $link).Scheme }} - {{ $target := "" }} - {{ if not $scheme }} - {{ $link = (.url | default .link) | relLangURL }} - {{ if eq (path.Ext $link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} - {{ else if in (slice "http" "https") $scheme }} - {{ $target = "target=\"_blank\" rel=\"noopener\"" }} + {{ range $links }} + {{ $linkUrl := "" }} + {{ $iconName := "hero/link" }} + {{ $linkLabel := "" }} + {{ if reflect.IsMap . }} + {{ $urlRaw := index . "url" | default (index . "link") }} + {{ if eq (printf "%T" $urlRaw) "string" }} + {{ $linkUrl = $urlRaw }} + {{ end }} + {{ $iconRaw := index . "icon" }} + {{ if eq (printf "%T" $iconRaw) "string" }} + {{ $iconName = $iconRaw }} + {{ end }} + {{ $labelRaw := index . "label" }} + {{ if eq (printf "%T" $labelRaw) "string" }} + {{ $linkLabel = $labelRaw }} + {{ end }} + {{ else if eq (printf "%T" .) "string" }} + {{ $linkUrl = . }} + {{ end }} + {{ $linkUrl = strings.TrimSpace $linkUrl }} + {{ if $linkUrl }} + {{ $scheme := (urls.Parse $linkUrl).Scheme }} + {{ $target := "" }} + {{ if not $scheme }} + {{ if not (hasPrefix $linkUrl "#") }} + {{ $linkUrl = $linkUrl | relLangURL }} + {{ end }} + {{ if eq (path.Ext $linkUrl) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} + {{ else if in (slice "http" "https") $scheme }} + {{ $target = "target=\"_blank\" rel=\"noopener\"" }} + {{ end }} + + {{ partial "functions/get_icon" (dict "name" $iconName "attributes" "class=\"w-6 h-6\"") }} + {{ end }} - - {{ partial "functions/get_icon" (dict "name" .icon "attributes" "class=\"w-6 h-6\"") }} - {{ end }}
+ {{ end }}
{{/* Right Column: Flexible span */}}
{{/* Bio Section */}} - {{ $bio_content := ($block.content.text | emojify | $page.RenderString) | default $profile.bio }} + {{ $bio_content := "" }} + {{ $bio_override_raw := index $content "text" }} + {{ if ne $bio_override_raw nil }} + {{ $bio_content = printf "%v" $bio_override_raw | emojify | $page.RenderString }} + {{ end }} + {{ if not $bio_content }} + {{ with $profile.bio }}{{ $bio_content = printf "%v" . }}{{ end }} + {{ end }} {{ with $bio_content }}
@@ -145,11 +290,18 @@
{{ $i18n_about := i18n "about_me" }} {{ $about_default := cond (eq $i18n_about "about_me") "Professional Summary" $i18n_about }} - {{ $about_heading := $block.content.headings.about | default $about_default }} + {{ $about_heading := $about_default }} + {{ $about_heading_raw := index $headings "about" }} + {{ if eq (printf "%T" $about_heading_raw) "string" }} + {{ $about_heading_raw = strings.TrimSpace $about_heading_raw }} + {{ if ne $about_heading_raw "" }} + {{ $about_heading = $about_heading_raw }} + {{ end }} + {{ end }}

{{ $about_heading }}

-
+
{{ . }}
@@ -157,78 +309,148 @@ {{ end }} {{/* CV Download Button */}} - {{ with $block.content.button }} - + {{ $button_raw := index $content "button" }} + {{ if and $button_raw (reflect.IsMap $button_raw) }} + {{ $button_text := "" }} + {{ $button_url := "" }} + {{ with index $button_raw "text" }}{{ $button_text = printf "%v" . }}{{ end }} + {{ with index $button_raw "url" }}{{ $button_url = printf "%v" . }}{{ end }} + {{ $button_text = strings.TrimSpace $button_text }} + {{ $button_url = strings.TrimSpace $button_url }} + {{ if and $button_text $button_url }} + {{ $button_link := $button_url }} + {{ $scheme := (urls.Parse $button_link).Scheme }} + {{ $target := "" }} + {{ if not $scheme }} + {{ if not (hasPrefix $button_link "#") }} + {{ $button_link = $button_link | relLangURL }} + {{ end }} + {{ if eq (path.Ext $button_link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} + {{ else if in (slice "http" "https") $scheme }} + {{ $target = "target=\"_blank\" rel=\"noopener\"" }} + {{ end }} + + {{ end }} {{ end }} {{/* Education Section */}} - {{ with $profile.education }} + {{ $education_raw := $profile.education }} + {{ $education := slice }} + {{ if reflect.IsSlice $education_raw }} + {{ $education = $education_raw }} + {{ end }} + {{ if gt (len $education) 0 }}
{{ partial "functions/get_icon" (dict "name" "academic-cap" "attributes" "class='w-6 h-6 text-primary-600 dark:text-primary-400'") }}
- {{ $education_heading := $block.content.headings.education | default (i18n "education") }} + {{ $education_heading := i18n "education" }} + {{ $education_heading_raw := index $headings "education" }} + {{ if eq (printf "%T" $education_heading_raw) "string" }} + {{ $education_heading_raw = strings.TrimSpace $education_heading_raw }} + {{ if ne $education_heading_raw "" }} + {{ $education_heading = $education_heading_raw }} + {{ end }} + {{ end }}

{{ $education_heading | markdownify }}

- {{ range . }} + {{ range $education }} + {{ if reflect.IsMap . }} + {{ $degree := "" }} + {{ $degreeRaw := index . "degree" | default (index . "area") }} + {{ if ne $degreeRaw nil }}{{ $degree = printf "%v" $degreeRaw }}{{ end }} + {{ $year := "" }} + {{ with index . "year" }}{{ $year = printf "%v" . }}{{ end }} + {{ $start := "" }} + {{ with index . "start" }}{{ $start = printf "%v" . }}{{ end }} + {{ $end := "" }} + {{ with index . "end" }}{{ $end = printf "%v" . }}{{ end }} + {{ $institution := "" }} + {{ with index . "institution" }}{{ $institution = printf "%v" . }}{{ end }} + {{ $icon := "" }} + {{ $iconRaw := index . "icon" }} + {{ if eq (printf "%T" $iconRaw) "string" }} + {{ $icon = $iconRaw }} + {{ end }}
- {{ if .icon }} - {{ partial "functions/get_icon" (dict "name" .icon "attributes" "class='w-6 h-6 text-primary-600 dark:text-primary-400'") }} - {{else}} + {{ if $icon }} + {{ partial "functions/get_icon" (dict "name" $icon "attributes" "class='w-6 h-6 text-primary-600 dark:text-primary-400'") }} + {{ else }} {{ partial "functions/get_icon" (dict "name" "academic-cap" "attributes" "class='w-6 h-6 text-primary-600 dark:text-primary-400'") }} - {{end}} + {{ end }}
- {{ $degree := .degree | default .area }} + {{ if $degree }}

{{ $degree }}

- {{ if .year }} -

{{ .year }}

- {{ else if .start }} + {{ end }} + {{ if $year }} +

{{ $year }}

+ {{ else if $start }}

- {{ .start }} - {{ if .end }}
{{ .end }}{{ end }} + {{ $start }} + {{ if $end }}
{{ $end }}{{ end }}

{{ end }} -

{{ .institution }}

+ {{ if $institution }} +

{{ $institution }}

+ {{ end }}
{{ end }} + {{ end }}
{{ end }} {{/* Interests Section */}} - {{ with $profile.interests }} + {{ $interests_raw := $profile.interests }} + {{ $interests := slice }} + {{ if reflect.IsSlice $interests_raw }} + {{ $interests = $interests_raw }} + {{ else if eq (printf "%T" $interests_raw) "string" }} + {{ $interests = slice $interests_raw }} + {{ end }} + {{ if gt (len $interests) 0 }}
{{ partial "functions/get_icon" (dict "name" "sparkles" "attributes" "class='w-6 h-6 text-primary-600 dark:text-primary-400'") }}
- {{ $interests_heading := $block.content.headings.interests | default (i18n "interests") }} + {{ $interests_heading := i18n "interests" }} + {{ $interests_heading_raw := index $headings "interests" }} + {{ if eq (printf "%T" $interests_heading_raw) "string" }} + {{ $interests_heading_raw = strings.TrimSpace $interests_heading_raw }} + {{ if ne $interests_heading_raw "" }} + {{ $interests_heading = $interests_heading_raw }} + {{ end }} + {{ end }}

{{ $interests_heading | markdownify }}

- {{ range . }} + {{ range $interests }} + {{ $interest := strings.TrimSpace (printf "%v" .) }} + {{ if $interest }} - {{ . | markdownify | emojify }} + {{ $interest | markdownify | emojify }} {{ end }} + {{ end }}
{{ end }} diff --git a/modules/blox/blox/team-showcase/block.html b/modules/blox/blox/team-showcase/block.html index f4d402f3..fbaf22bf 100644 --- a/modules/blox/blox/team-showcase/block.html +++ b/modules/blox/blox/team-showcase/block.html @@ -5,16 +5,38 @@ {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} -{{ $show_social := $block.design.show_social | default true }} -{{ $show_interests := $block.design.show_interests | default false }} -{{ $show_role := $block.design.show_role | default true }} -{{ $show_organizations := $block.design.show_organizations | default true }} -{{ $max_interests := $block.design.max_interests | default 3 }} -{{ $align := $block.design.align | default "center" }} -{{ $max_columns := $block.design.max_columns | default 4 }} -{{ $show_empty_groups := $block.design.show_empty_groups | default false }} -{{ $sort_field := $block.content.sort_by | default "name_family" }} -{{ $sort_asc := $block.content.sort_ascending | default true }} + +{{ $content := $block.content }} +{{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} +{{ $design := $block.design }} +{{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} + +{{ $show_social := partial "functions/coerce_bool" (dict "value" (index $design "show_social") "default" true) }} +{{ $show_interests := partial "functions/coerce_bool" (dict "value" (index $design "show_interests") "default" false) }} +{{ $show_role := partial "functions/coerce_bool" (dict "value" (index $design "show_role") "default" true) }} +{{ $show_organizations := partial "functions/coerce_bool" (dict "value" (index $design "show_organizations") "default" true) }} +{{ $show_empty_groups := partial "functions/coerce_bool" (dict "value" (index $design "show_empty_groups") "default" false) }} +{{ $max_interests_int := partial "functions/coerce_int" (dict "value" (index $design "max_interests") "default" 3 "min" 0) }} +{{ $max_columns_int := partial "functions/coerce_int" (dict "value" (index $design "max_columns") "default" 4 "min" 2 "max" 4) }} + +{{ $align := "center" }} +{{ $align_raw := index $design "align" }} +{{ if eq (printf "%T" $align_raw) "string" }} + {{ $align_candidate := lower (strings.TrimSpace $align_raw) }} + {{ if in (slice "center" "left") $align_candidate }} + {{ $align = $align_candidate }} + {{ end }} +{{ end }} + +{{ $sort_field := "name_family" }} +{{ $sort_field_raw := index $content "sort_by" }} +{{ if eq (printf "%T" $sort_field_raw) "string" }} + {{ $sort_field_raw = strings.TrimSpace $sort_field_raw }} + {{ if ne $sort_field_raw "" }} + {{ $sort_field = $sort_field_raw }} + {{ end }} +{{ end }} +{{ $sort_asc := partial "functions/coerce_bool" (dict "value" (index $content "sort_ascending") "default" true) }} {{ $sort_field_lc := lower $sort_field }} {{ if hasPrefix $sort_field_lc "params." }} {{/* Backwards compatibility with Params.* used when authors were pages */}} @@ -22,36 +44,15 @@ {{ $sort_field_lc = lower $sort_field }} {{ end }} -{{ $title := $block.content.title | emojify | $page.RenderString }} -{{ $subtitle := $block.content.subtitle | emojify | $page.RenderString }} -{{ $text := $block.content.text | emojify | $page.RenderString }} +{{ $title := "" }} +{{ with index $content "title" }}{{ $title = printf "%v" . | emojify | $page.RenderString }}{{ end }} +{{ $subtitle := "" }} +{{ with index $content "subtitle" }}{{ $subtitle = printf "%v" . | emojify | $page.RenderString }}{{ end }} +{{ $text := "" }} +{{ with index $content "text" }}{{ $text = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ $alignClass := cond (eq $align "left") "items-start text-left" "items-center text-center" }} {{ $ctaAlignClass := cond (eq $align "left") "text-left" "text-center" }} -{{/* Safe numeric handling with clamping using type checks */}} -{{ $max_columns_int := 4 }} -{{ $max_columns_type := printf "%T" $max_columns }} -{{ if or (eq $max_columns_type "int") (eq $max_columns_type "int64") (eq $max_columns_type "float64") (eq $max_columns_type "float32") (eq $max_columns_type "uint") (eq $max_columns_type "uint64") }} - {{ $max_columns_int = int $max_columns }} -{{ else if eq $max_columns_type "string" }} - {{ if gt (len (findRE "^[0-9]+$" $max_columns)) 0 }} - {{ $max_columns_int = int $max_columns }} - {{ end }} -{{ end }} -{{ if lt $max_columns_int 2 }}{{ $max_columns_int = 2 }}{{ end }} -{{ if gt $max_columns_int 4 }}{{ $max_columns_int = 4 }}{{ end }} - -{{ $max_interests_int := 3 }} -{{ $max_interests_type := printf "%T" $max_interests }} -{{ if or (eq $max_interests_type "int") (eq $max_interests_type "int64") (eq $max_interests_type "float64") (eq $max_interests_type "float32") (eq $max_interests_type "uint") (eq $max_interests_type "uint64") }} - {{ $max_interests_int = int $max_interests }} -{{ else if eq $max_interests_type "string" }} - {{ if gt (len (findRE "^[0-9]+$" $max_interests)) 0 }} - {{ $max_interests_int = int $max_interests }} - {{ end }} -{{ end }} -{{ if lt $max_interests_int 0 }}{{ $max_interests_int = 0 }}{{ end }} - {{ $columnsClasses := dict "2" "grid grid-cols-1 gap-8 sm:grid-cols-2" "3" "grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3" @@ -91,9 +92,17 @@ {{ $allProfiles = $allProfiles | append (dict "profile" $profile "profileData" $profileData) }} {{ end }} - {{ $groups := $block.content.user_groups }} + {{ $groups_raw := index $content "user_groups" }} + {{ $groups := slice }} + {{ if reflect.IsSlice $groups_raw }} + {{ $groups = $groups_raw }} + {{ else if eq (printf "%T" $groups_raw) "string" }} + {{ $groups = slice $groups_raw }} + {{ else if and $groups_raw (reflect.IsMap $groups_raw) }} + {{ $groups = slice $groups_raw }} + {{ end }} - {{ if $groups }} + {{ if gt (len $groups) 0 }} {{ range $i, $groupItem := $groups }} {{ $groupName := "" }} {{ $groupSortField := $sort_field }} @@ -101,12 +110,22 @@ {{ $groupSortFieldLc := "" }} {{ $itemIsMap := reflect.IsMap $groupItem }} {{ if $itemIsMap }} - {{ $groupName = index $groupItem "name" | default (index $groupItem "title") | default "" }} - {{ $groupSortField = index $groupItem "sort_by" | default $groupSortField }} - {{ $groupSortAsc = index $groupItem "sort_ascending" | default $groupSortAsc }} + {{ $groupNameRaw := index $groupItem "name" | default (index $groupItem "title") }} + {{ if ne $groupNameRaw nil }} + {{ $groupName = printf "%v" $groupNameRaw }} + {{ end }} + {{ $groupSortFieldRaw := index $groupItem "sort_by" }} + {{ if eq (printf "%T" $groupSortFieldRaw) "string" }} + {{ $groupSortFieldRaw = strings.TrimSpace $groupSortFieldRaw }} + {{ if ne $groupSortFieldRaw "" }} + {{ $groupSortField = $groupSortFieldRaw }} + {{ end }} + {{ end }} + {{ $groupSortAsc = partial "functions/coerce_bool" (dict "value" (index $groupItem "sort_ascending") "default" $groupSortAsc) }} {{ else }} - {{ $groupName = $groupItem }} + {{ $groupName = printf "%v" $groupItem }} {{ end }} + {{ $groupName = strings.TrimSpace $groupName }} {{ if eq (trim $groupName " ") "" }} {{/* Skip groups with empty names to avoid matching everything */}} {{ continue }} @@ -122,10 +141,17 @@ {{ $groupProfiles := slice }} {{ range $allProfiles }} {{ $profile := .profile }} - {{ $uRaw := $profile.user_groups | default (slice) }} {{ $u := slice }} - {{ range $uRaw }} - {{ $u = $u | append (printf "%v" .) }} + {{ $uRaw := $profile.user_groups }} + {{ if reflect.IsSlice $uRaw }} + {{ range $uRaw }} + {{ $u = $u | append (printf "%v" .) }} + {{ end }} + {{ else if eq (printf "%T" $uRaw) "string" }} + {{ $trimmedGroup := strings.TrimSpace $uRaw }} + {{ if ne $trimmedGroup "" }} + {{ $u = slice $trimmedGroup }} + {{ end }} {{ end }} {{ if gt (len (intersect $u (slice (printf "%v" $groupName)))) 0 }} {{ $profileData := .profileData }} @@ -212,37 +238,67 @@ + {{ $affiliations_raw := $profile.affiliations }} + {{ $affiliations := slice }} + {{ if reflect.IsSlice $affiliations_raw }} + {{ $affiliations = $affiliations_raw }} + {{ else if eq (printf "%T" $affiliations_raw) "string" }} + {{ $affiliations = slice $affiliations_raw }} + {{ end }} + {{ $first_affiliation := "" }} + {{ if gt (len $affiliations) 0 }} + {{ $aff := index $affiliations 0 }} + {{ if reflect.IsMap $aff }} + {{ $affNameRaw := index $aff "name" | default (index $aff "title") }} + {{ if ne $affNameRaw nil }} + {{ $first_affiliation = printf "%v" $affNameRaw }} + {{ end }} + {{ else if eq (printf "%T" $aff) "string" }} + {{ $first_affiliation = $aff }} + {{ end }} + {{ $first_affiliation = strings.TrimSpace $first_affiliation }} + {{ end }} + {{ if $show_role }}
{{ $roleText := "" }} - {{ with $profile.role }}{{ $roleText = . }}{{ end }} - {{ if and (not $roleText) $profile.affiliations }} - {{ range first 1 $profile.affiliations }} - {{ $roleText = .name }} + {{ with $profile.role }} + {{ if eq (printf "%T" .) "string" }} + {{ $roleText = . }} {{ end }} {{ end }} + {{ if and (not $roleText) $first_affiliation }} + {{ $roleText = $first_affiliation }} + {{ end }} {{ with $roleText }}

{{ . }}

{{ end }} - {{ if and $show_organizations $profile.affiliations }} - {{ range first 1 $profile.affiliations }} -

{{ .name }}

- {{ end }} + {{ if and $show_organizations $first_affiliation }} +

{{ $first_affiliation }}

{{ end }}
{{ end }} - {{ with $profile.bio }} + {{ $bio := "" }} + {{ with $profile.bio }}{{ $bio = printf "%v" . }}{{ end }} + {{ with $bio }}

{{ . }}

{{ end }} - {{ if and $show_interests $profile.interests }} + {{ $interests_raw := $profile.interests }} + {{ $interests := slice }} + {{ if reflect.IsSlice $interests_raw }} + {{ $interests = $interests_raw }} + {{ else if eq (printf "%T" $interests_raw) "string" }} + {{ $interests = slice $interests_raw }} + {{ end }} + {{ if and $show_interests (gt (len $interests) 0) }}
{{ if gt $max_interests_int 0 }} - {{ range first $max_interests_int $profile.interests }} + {{ range first $max_interests_int $interests }} - {{ . }} + {{ printf "%v" . }} {{ end }} {{ end }} @@ -250,26 +306,55 @@
{{ end }} - {{ if and $show_social $profile.links }} + {{ $links_raw := $profile.links }} + {{ $links := slice }} + {{ if reflect.IsSlice $links_raw }} + {{ $links = $links_raw }} + {{ else if eq (printf "%T" $links_raw) "string" }} + {{ $links = slice $links_raw }} + {{ end }} + {{ if and $show_social (gt (len $links) 0) }}
- {{ range $profile.links }} - {{ $l := .url | default .link }} - {{ $scheme := (urls.Parse $l).Scheme }} - {{ $target := "" }} - {{ if not $scheme }} - {{ $l = (.url | default .link) | relLangURL }} - {{ if eq (path.Ext $l) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} - {{ else if in (slice "http" "https") $scheme }} - {{ $target = "target=\"_blank\" rel=\"noopener\"" }} - {{ end }} - - - {{ partial "functions/get_icon" (dict "name" .icon "attributes" "class=\"w-5 h-5\"") }} - + {{ range $links }} + {{ $linkUrl := "" }} + {{ $iconName := "hero/link" }} + {{ $linkLabel := "" }} + {{ if reflect.IsMap . }} + {{ $urlRaw := index . "url" | default (index . "link") }} + {{ if eq (printf "%T" $urlRaw) "string" }} + {{ $linkUrl = $urlRaw }} + {{ end }} + {{ $iconRaw := index . "icon" }} + {{ if eq (printf "%T" $iconRaw) "string" }} + {{ $iconName = $iconRaw }} + {{ end }} + {{ $labelRaw := index . "label" }} + {{ if eq (printf "%T" $labelRaw) "string" }} + {{ $linkLabel = $labelRaw }} + {{ end }} + {{ else if eq (printf "%T" .) "string" }} + {{ $linkUrl = . }} + {{ end }} + {{ $linkUrl = strings.TrimSpace $linkUrl }} + {{ if $linkUrl }} + {{ $scheme := (urls.Parse $linkUrl).Scheme }} + {{ $target := "" }} + {{ if not $scheme }} + {{ if not (hasPrefix $linkUrl "#") }} + {{ $linkUrl = $linkUrl | relLangURL }} + {{ end }} + {{ if eq (path.Ext $linkUrl) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} + {{ else if in (slice "http" "https") $scheme }} + {{ $target = "target=\"_blank\" rel=\"noopener\"" }} + {{ end }} + + {{ partial "functions/get_icon" (dict "name" $iconName "attributes" "class=\"w-5 h-5\"") }} + + {{ end }} {{ end }}
{{ end }} @@ -347,45 +432,115 @@ {{ $profile.title }} + + {{ $affiliations_raw := $profile.affiliations }} + {{ $affiliations := slice }} + {{ if reflect.IsSlice $affiliations_raw }} + {{ $affiliations = $affiliations_raw }} + {{ else if eq (printf "%T" $affiliations_raw) "string" }} + {{ $affiliations = slice $affiliations_raw }} + {{ end }} + {{ $first_affiliation := "" }} + {{ if gt (len $affiliations) 0 }} + {{ $aff := index $affiliations 0 }} + {{ if reflect.IsMap $aff }} + {{ $affNameRaw := index $aff "name" | default (index $aff "title") }} + {{ if ne $affNameRaw nil }} + {{ $first_affiliation = printf "%v" $affNameRaw }} + {{ end }} + {{ else if eq (printf "%T" $aff) "string" }} + {{ $first_affiliation = $aff }} + {{ end }} + {{ $first_affiliation = strings.TrimSpace $first_affiliation }} + {{ end }} + {{ if $show_role }}
- {{ with $profile.role }}

{{ . }}

{{ end }} - {{ if and $show_organizations $profile.affiliations }} - {{ range first 1 $profile.affiliations }} -

{{ .name }}

+ {{ $roleText := "" }} + {{ with $profile.role }} + {{ if eq (printf "%T" .) "string" }} + {{ $roleText = . }} {{ end }} {{ end }} + {{ if and (not $roleText) $first_affiliation }} + {{ $roleText = $first_affiliation }} + {{ end }} + {{ with $roleText }}

{{ . }}

{{ end }} + {{ if and $show_organizations $first_affiliation }} +

{{ $first_affiliation }}

+ {{ end }}
{{ end }} - {{ with $profile.bio }} + {{ $bio := "" }} + {{ with $profile.bio }}{{ $bio = printf "%v" . }}{{ end }} + {{ with $bio }}

{{ . }}

{{ end }} - {{ if and $show_interests $profile.interests }} + + {{ $interests_raw := $profile.interests }} + {{ $interests := slice }} + {{ if reflect.IsSlice $interests_raw }} + {{ $interests = $interests_raw }} + {{ else if eq (printf "%T" $interests_raw) "string" }} + {{ $interests = slice $interests_raw }} + {{ end }} + {{ if and $show_interests (gt (len $interests) 0) }}
{{ if gt $max_interests_int 0 }} - {{ range first $max_interests_int $profile.interests }} - {{ . }} + {{ range first $max_interests_int $interests }} + {{ printf "%v" . }} {{ end }} {{ end }}
{{ end }} - {{ if and $show_social $profile.links }} + + {{ $links_raw := $profile.links }} + {{ $links := slice }} + {{ if reflect.IsSlice $links_raw }} + {{ $links = $links_raw }} + {{ else if eq (printf "%T" $links_raw) "string" }} + {{ $links = slice $links_raw }} + {{ end }} + {{ if and $show_social (gt (len $links) 0) }}
- {{ range $profile.links }} - {{ $l := .url | default .link }} - {{ $scheme := (urls.Parse $l).Scheme }} - {{ $target := "" }} - {{ if not $scheme }} - {{ $l = (.url | default .link) | relLangURL }} - {{ if eq (path.Ext $l) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} - {{ else if in (slice "http" "https") $scheme }} - {{ $target = "target=\"_blank\" rel=\"noopener\"" }} - {{ end }} - - {{ partial "functions/get_icon" (dict "name" .icon "attributes" "class=\"w-5 h-5\"") }} - + {{ range $links }} + {{ $linkUrl := "" }} + {{ $iconName := "hero/link" }} + {{ $linkLabel := "" }} + {{ if reflect.IsMap . }} + {{ $urlRaw := index . "url" | default (index . "link") }} + {{ if eq (printf "%T" $urlRaw) "string" }} + {{ $linkUrl = $urlRaw }} + {{ end }} + {{ $iconRaw := index . "icon" }} + {{ if eq (printf "%T" $iconRaw) "string" }} + {{ $iconName = $iconRaw }} + {{ end }} + {{ $labelRaw := index . "label" }} + {{ if eq (printf "%T" $labelRaw) "string" }} + {{ $linkLabel = $labelRaw }} + {{ end }} + {{ else if eq (printf "%T" .) "string" }} + {{ $linkUrl = . }} + {{ end }} + {{ $linkUrl = strings.TrimSpace $linkUrl }} + {{ if $linkUrl }} + {{ $scheme := (urls.Parse $linkUrl).Scheme }} + {{ $target := "" }} + {{ if not $scheme }} + {{ if not (hasPrefix $linkUrl "#") }} + {{ $linkUrl = $linkUrl | relLangURL }} + {{ end }} + {{ if eq (path.Ext $linkUrl) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} + {{ else if in (slice "http" "https") $scheme }} + {{ $target = "target=\"_blank\" rel=\"noopener\"" }} + {{ end }} + + {{ partial "functions/get_icon" (dict "name" $iconName "attributes" "class=\"w-5 h-5\"") }} + + {{ end }} {{ end }}
{{ end }} @@ -397,15 +552,41 @@ {{ end }} {{/* Call to Action */}} - {{ with $block.content.cta }} - + {{ end }} + {{ $cta_text = strings.TrimSpace $cta_text }} + {{ $cta_url = strings.TrimSpace $cta_url }} + {{ if and $cta_text $cta_url }} + {{ $cta_link := $cta_url }} + {{ $scheme := (urls.Parse $cta_link).Scheme }} + {{ $target := "" }} + {{ if not $scheme }} + {{ if not (hasPrefix $cta_link "#") }} + {{ $cta_link = $cta_link | relLangURL }} + {{ end }} + {{ if eq (path.Ext $cta_link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} + {{ else if in (slice "http" "https") $scheme }} + {{ $target = "target=\"_blank\" rel=\"noopener\"" }} + {{ end }} + + {{ end }} {{ end }}
diff --git a/modules/blox/blox/team-showcase/schema.json b/modules/blox/blox/team-showcase/schema.json index 45d78476..991efdf0 100644 --- a/modules/blox/blox/team-showcase/schema.json +++ b/modules/blox/blox/team-showcase/schema.json @@ -108,7 +108,7 @@ }, "show_interests": { "type": "boolean", - "description": "Display up to three interests per profile", + "description": "Display interests per profile (capped by max_interests)", "default": false }, "show_social": { @@ -152,7 +152,13 @@ "title": "Meet the team", "subtitle": "Research + Engineering", "text": "We combine safety research with high-velocity engineering.", - "user_groups": ["Principal Investigators", "PhD Students"], + "user_groups": [ + "Principal Investigators", + "Research Engineers", + { "name": "Alumni", "sort_by": "graduation_year", "sort_ascending": false } + ], + "sort_by": "name_family", + "sort_ascending": true, "cta": { "text": "Join us", "url": "/apply", @@ -162,8 +168,12 @@ "design": { "show_role": true, "show_organizations": true, - "show_interests": false, - "show_social": true + "show_interests": true, + "max_interests": 3, + "show_social": true, + "align": "left", + "max_columns": 3, + "show_empty_groups": false } } ] diff --git a/modules/blox/layouts/_partials/functions/coerce_bool.html b/modules/blox/layouts/_partials/functions/coerce_bool.html new file mode 100644 index 00000000..1de91656 --- /dev/null +++ b/modules/blox/layouts/_partials/functions/coerce_bool.html @@ -0,0 +1,20 @@ +{{ $value := .value }} +{{ $result := .default }} +{{ if ne $value nil }} + {{ $valueType := printf "%T" $value }} + {{ if eq $valueType "bool" }} + {{ $result = $value }} + {{ else if or (eq $valueType "int") (eq $valueType "int8") (eq $valueType "int16") (eq $valueType "int32") (eq $valueType "int64") (eq $valueType "uint") (eq $valueType "uint8") (eq $valueType "uint16") (eq $valueType "uint32") (eq $valueType "uint64") }} + {{ $result = ne (int $value) 0 }} + {{ else if or (eq $valueType "float32") (eq $valueType "float64") }} + {{ $result = ne (float $value) 0 }} + {{ else if eq $valueType "string" }} + {{ $trimmed := lower (strings.TrimSpace $value) }} + {{ if in (slice "1" "true" "yes" "y" "on") $trimmed }} + {{ $result = true }} + {{ else if in (slice "0" "false" "no" "n" "off") $trimmed }} + {{ $result = false }} + {{ end }} + {{ end }} +{{ end }} +{{ return $result }} diff --git a/modules/blox/layouts/_partials/functions/coerce_int.html b/modules/blox/layouts/_partials/functions/coerce_int.html new file mode 100644 index 00000000..5581c904 --- /dev/null +++ b/modules/blox/layouts/_partials/functions/coerce_int.html @@ -0,0 +1,26 @@ +{{ $value := .value }} +{{ $result := .default }} +{{ if ne $value nil }} + {{ $valueType := printf "%T" $value }} + {{ if or (eq $valueType "int") (eq $valueType "int8") (eq $valueType "int16") (eq $valueType "int32") (eq $valueType "int64") (eq $valueType "uint") (eq $valueType "uint8") (eq $valueType "uint16") (eq $valueType "uint32") (eq $valueType "uint64") (eq $valueType "float32") (eq $valueType "float64") }} + {{ $result = int $value }} + {{ else if eq $valueType "string" }} + {{ $trimmed := strings.TrimSpace $value }} + {{ if gt (len (findRE "^-?[0-9]+$" $trimmed)) 0 }} + {{ $result = int $trimmed }} + {{ else if gt (len (findRE "^-?[0-9]*\\.[0-9]+$" $trimmed)) 0 }} + {{ $result = int (float $trimmed) }} + {{ end }} + {{ end }} +{{ end }} +{{ if isset . "min" }} + {{ if lt $result .min }} + {{ $result = .min }} + {{ end }} +{{ end }} +{{ if isset . "max" }} + {{ if gt $result .max }} + {{ $result = .max }} + {{ end }} +{{ end }} +{{ return $result }}