From 73ae3cace67a7dc04587cc7b87e1b1eb22555f30 Mon Sep 17 00:00:00 2001 From: Stephan Heunis Date: Thu, 28 May 2026 12:20:03 +0200 Subject: [PATCH] Layout template generalization The goal of this change is to deduplicate all custom templates that are in use for taxonomy pages. This commit defines the entrypoint for any taxonomy list page to be the 'layouts/taxonomy.html' template, and removes all taxonomy-specific templates (e.g. 'layouts/publications/taxonomy.html'). Per-taxonomy page customization are now handled via new partials and with front matter configuration via 'params'. Any given taxonomy list page can now be customized to do the following: - show all terms vs only terms that have a metadata-generated '_index.md' page (via '.Params.title') - list items in a grid vs list items vertically - include vs exclude filtering functionality (inclusion assumes the vertical list layout) - specify which filter fields to use (e.g. 'kind', 'topic', 'year'), if filtering functionality is active - specify which fields to include in the text search functionality, if filtering functionality is active Customization happens in the '_index.md' page of any given taxonomy content directory. For example 'content/publications/_index.md': --- title: Publications params: list_variant: vertical # grid (default) | vertical (if filter == true, list_variant is set to vertical) items: generated # generated (default) | all filter: true # false (default) | true filter_fields: # no default - kind - topic - year search_fields: # default: kind, topic, year, author, title - kind - topic - year - author - title --- And partials are then rendered based on this configuration. Main configuration introduced with this commit: - persons: grid view (default) - objectives: grid view (default) - projects: grid view (default) - publications: filter view - datasets: filter view - instruments: filter view The main repo README is updated with a description of this configuration and template pattern TODO: - add some partials for the parts that are displayed on a list item (e.g. the list of authors, the topics, the icon-links, etc); and perhaps also configuration variables for their inclusion/exclusion - Improved logic for selecting depictions; the current depiction registration workflow registers files with names derived from the depiction kind, e.g. 'logo.png' or 'portrait.webp'. These are generally for different purposes, and the logic might want to prefer a specific kind for a specific taxonomy, e.g. 'portrait' for 'persons', or 'logo' for 'instrument'. - Update filtering-related code to make better use of hugo templating functionality; some aspects are still hardcoded, e.g. 'data-*' for setting the list-item data values. - Apply similar improvements to the 'term.html' template as done above for 'taxonomy.html' --- README.md | 37 ++++++ content/datasets/_index.md | 4 + content/instruments/_index.md | 8 ++ content/persons/_index.md | 2 + content/publications/_index.md | 17 +++ layouts/_partials/dataset-item.html | 95 --------------- layouts/_partials/instrument-item.html | 95 --------------- layouts/_partials/publication-item.html | 67 ----------- layouts/_partials/taxonomy-list-filter.html | 47 ++++++++ layouts/_partials/taxonomy-list-grid.html | 29 +++++ .../taxonomy-list-vertical-item.html | 111 ++++++++++++++++++ layouts/_partials/taxonomy-list-vertical.html | 13 ++ layouts/datasets/taxonomy.html | 67 ----------- layouts/instruments/taxonomy.html | 67 ----------- layouts/publications/taxonomy.html | 73 ------------ layouts/taxonomy.html | 30 ++--- static/filter-list.css | 4 + static/grid-list.css | 86 ++++++++++++++ 18 files changed, 368 insertions(+), 484 deletions(-) create mode 100644 content/instruments/_index.md create mode 100644 content/publications/_index.md delete mode 100644 layouts/_partials/dataset-item.html delete mode 100644 layouts/_partials/instrument-item.html delete mode 100644 layouts/_partials/publication-item.html create mode 100644 layouts/_partials/taxonomy-list-filter.html create mode 100644 layouts/_partials/taxonomy-list-grid.html create mode 100644 layouts/_partials/taxonomy-list-vertical-item.html create mode 100644 layouts/_partials/taxonomy-list-vertical.html delete mode 100644 layouts/datasets/taxonomy.html delete mode 100644 layouts/instruments/taxonomy.html delete mode 100644 layouts/publications/taxonomy.html create mode 100644 static/grid-list.css diff --git a/README.md b/README.md index 2d04ae27..69e40ca7 100644 --- a/README.md +++ b/README.md @@ -31,3 +31,40 @@ Making node/edge styling changes currently need to be done in the JS sources. The JS code reads the graph from `static/graph.json`. This file is generated by `code/pool2graph.py`. Choice of node and edge types to consider for the navigation graph is done at the top of this file. + +### Layout templates + +Taxonomy list pages can be customized to present terms in different formats by specifying +configuration properties in the taxonomy-specific `_index.md` page front matter. Technically, +this is done by using the `layouts/taxonomy.html` template as the main entrypoint for a taxonomy +list page rendering, which in turn renders specific partials driven by configuration. + +Any given taxonomy list page can be customized to do the following: +- show all terms vs only terms that have a metadata-generated `_index.md` page +- list items in a grid (with a depiction if available) vs list items vertically +- include vs exclude filtering functionality (inclusion assumes the vertical list layout) +- specify which filter fields to use (e.g. `kind`, `topic`, `year`), if filtering functionality is active +- specify which fields to include in the text search functionality, if filtering functionality is active + +An example configuration for the `publications` taxonomy list (including defaults), +specified in `content/publications/_index.md`, is: + +```yaml +--- +title: Publications +params: + list_variant: vertical # grid (default) | vertical (if filter == true, list_variant is set to vertical) + items: generated # generated (default) | all + filter: true # false (default) | true + filter_fields: # no default + - kind + - topic + - year + search_fields: # default: kind, topic, year, author, title + - kind + - topic + - year + - author + - title +--- +``` diff --git a/content/datasets/_index.md b/content/datasets/_index.md index 521e20af..e4ab4186 100644 --- a/content/datasets/_index.md +++ b/content/datasets/_index.md @@ -1,5 +1,9 @@ --- title: Dataset +params: + filter: true + filter_fields: + - topic --- Browse datasets that originate in activities of the Psychoinformatics project, or those that have seen contributions by such activities. diff --git a/content/instruments/_index.md b/content/instruments/_index.md new file mode 100644 index 00000000..015f1e7f --- /dev/null +++ b/content/instruments/_index.md @@ -0,0 +1,8 @@ +--- +title: Instruments +params: + filter: true + filter_fields: + - kind + - topic +--- diff --git a/content/persons/_index.md b/content/persons/_index.md index f0da7481..15006fae 100644 --- a/content/persons/_index.md +++ b/content/persons/_index.md @@ -1,5 +1,7 @@ --- title: People +params: + items: generated --- The following persons currently have or previously had a relationship with the Psychoniformatics project. diff --git a/content/publications/_index.md b/content/publications/_index.md new file mode 100644 index 00000000..de930ec1 --- /dev/null +++ b/content/publications/_index.md @@ -0,0 +1,17 @@ +--- +title: Publications +params: + list_variant: vertical + items: all + filter: true + filter_fields: + - kind + - topic + - year + search_fields: + - kind + - topic + - year + - author + - title +--- diff --git a/layouts/_partials/dataset-item.html b/layouts/_partials/dataset-item.html deleted file mode 100644 index e55e8aaf..00000000 --- a/layouts/_partials/dataset-item.html +++ /dev/null @@ -1,95 +0,0 @@ -
- - -

- - {{ .Title }} - - {{ if .Params.date_created }} - {{ $year := substr .Params.date_created 0 4 }} - - ({{ $year }}) - - {{ end }} - {{ with .Params.doi }} - - - DOI: {{ . }} - - - {{ end }} - {{ with .Params.kind }} - - {{ . | replaceRE "^.*:" "" }} - - {{ end }} - - {{ if or .Params.source_code_url .Params.documentation_url}} - - {{ with .Params.source_code_url }} - {{ partial "icon.html" "mdi-code-not-equal-variant"}} - {{ end }} - {{ with .Params.documentation_url }} - {{ partial "icon.html" "mdi-file-document"}} - {{ end }} - {{ end }} -

- - - {{ with .Params.author }} -
- {{ range $i, $a := . }} - - {{ $a.given_name }} {{ $a.family_name }} - - {{ end }} -
- {{ end }} - - - - {{ with .Params.topic }} -
- - Topics: - - {{ range . }} - - {{ .display_label }} - - {{ end }} -
- {{ end }} - - - {{ with .Params.license }} -
- - License: - - {{ range . }} - - {{ .label }} - - {{ end }} -
- {{ end }} - -
diff --git a/layouts/_partials/instrument-item.html b/layouts/_partials/instrument-item.html deleted file mode 100644 index 31993b3d..00000000 --- a/layouts/_partials/instrument-item.html +++ /dev/null @@ -1,95 +0,0 @@ -
- - -

- - {{ .Title }} - - {{ if .Params.date_created }} - {{ $year := substr .Params.date_created 0 4 }} - - ({{ $year }}) - - {{ end }} - {{ with .Params.doi }} - - - DOI: {{ . }} - - - {{ end }} - {{ with .Params.kind }} - - {{ . | replaceRE "^.*:" "" }} - - {{ end }} - - {{ if or .Params.source_code_url .Params.documentation_url}} - - {{ with .Params.source_code_url }} - {{ partial "icon.html" "mdi-code-not-equal-variant"}} - {{ end }} - {{ with .Params.documentation_url }} - {{ partial "icon.html" "mdi-file-document"}} - {{ end }} - {{ end }} -

- - - {{ with .Params.author }} -
- {{ range $i, $a := . }} - - {{ $a.given_name }} {{ $a.family_name }} - - {{ end }} -
- {{ end }} - - - - {{ with .Params.topic }} -
- - Topics: - - {{ range . }} - - {{ .display_label }} - - {{ end }} -
- {{ end }} - - - {{ with .Params.license }} -
- - License: - - {{ range . }} - - {{ .label }} - - {{ end }} -
- {{ end }} - -
\ No newline at end of file diff --git a/layouts/_partials/publication-item.html b/layouts/_partials/publication-item.html deleted file mode 100644 index 67be6ef7..00000000 --- a/layouts/_partials/publication-item.html +++ /dev/null @@ -1,67 +0,0 @@ -
- - -

- - {{ .Title }} - - {{ if .Params.date }} - {{ $year := substr .Params.date 0 4 }} - - ({{ $year }}) - - {{ end }} - {{ with .Params.doi }} - - - DOI: {{ . }} - - - {{ end }} - {{ with .Params.kind }} - - {{ . | replaceRE "^.*:" "" }} - - {{ end }} -

- - - {{ with .Params.author }} -
- {{ range $i, $a := . }} - - {{ $a.given_name }} {{ $a.family_name }} - - {{ end }} -
- {{ end }} - - - {{ with .Params.topic }} -
- {{ range . }} - - {{ .display_label }} -   - {{ end }} -
- {{ end }} - -
\ No newline at end of file diff --git a/layouts/_partials/taxonomy-list-filter.html b/layouts/_partials/taxonomy-list-filter.html new file mode 100644 index 00000000..027a7c41 --- /dev/null +++ b/layouts/_partials/taxonomy-list-filter.html @@ -0,0 +1,47 @@ +{{ $currentTaxonomy := .Data.Plural }} +{{ $singleTerm := .Data.Singular }} +{{ $filterFieldsDefault := (slice "kind" "year" "topic")}} +{{ $searchFieldsDefault := (slice "title" "kind" "year" "topic" "author")}} +{{ $filterFields := .Params.filter_fields | default $filterFieldsDefault }} +{{ $searchFields := .Params.search_fields | default $searchFieldsDefault }} + +
+ + + +
+ + +
+ {{ range .Pages }} + {{ $includeItems := .Params.items | default "generated" }} + {{ if or (ne $includeItems "generated") .Params.title }} + {{ partial "taxonomy-list-vertical-item.html" . }} + {{ end }} + {{ end }} +
+
+
+ + + + \ No newline at end of file diff --git a/layouts/_partials/taxonomy-list-grid.html b/layouts/_partials/taxonomy-list-grid.html new file mode 100644 index 00000000..d9c581e7 --- /dev/null +++ b/layouts/_partials/taxonomy-list-grid.html @@ -0,0 +1,29 @@ +{{ $includeItems := .Params.items | default "generated" }} +
+ {{ range .Pages }} + {{ if or (ne $includeItems "generated") .Params.title }} + {{ $count := 0 }} + {{ $key := .Data.Term }} + {{ with index $.Data.Terms $key }} + {{ $count = .Count }} + {{ end }} + {{ $portrait := .Resources.GetMatch "*portrait*" }} + +
+ {{ with $portrait }} + {{ .Title }} + {{ else }} +
+ {{ substr .Title 0 1 }} +
+ {{ end }} +
+
+ {{ .Title }} ({{ $count }}) +
+
+ {{ end }} + {{ end }} +
+ \ No newline at end of file diff --git a/layouts/_partials/taxonomy-list-vertical-item.html b/layouts/_partials/taxonomy-list-vertical-item.html new file mode 100644 index 00000000..9e5da21c --- /dev/null +++ b/layouts/_partials/taxonomy-list-vertical-item.html @@ -0,0 +1,111 @@ +
+ + {{ $depictions := .Resources.Match "depiction.*" }} + {{ $hasDepiction := gt (len $depictions) 0 }} + + + + + {{ if $hasDepiction }} + + {{ end }} + +
+ +

+ + {{ .Title }} + + {{ if .Params.date }} + {{ $year := substr .Params.date 0 4 }} + + ({{ $year }}) + + {{ end }} + {{ with .Params.doi }} + + + DOI: {{ . }} + + + {{ end }} + {{ with .Params.kind }} + + {{ . | replaceRE "^.*:" "" }} + + {{ end }} + {{ if or .Params.source_code_url .Params.documentation_url}} + + {{ with .Params.source_code_url }} + {{ partial "icon.html" "mdi-code-not-equal-variant"}} + {{ end }} + {{ with .Params.documentation_url }} + {{ partial "icon.html" "mdi-file-document"}} + {{ end }} + {{ end }} +

+ + + {{ with .Params.author }} +
+ {{ range $i, $a := . }} + + {{ $a.given_name }} {{ $a.family_name }} + + {{ end }} +
+ {{ end }} + + + {{ with .Params.topic }} +
+ + Topics: + + {{ range . }} + + {{ .display_label }} +   + {{ end }} +
+ {{ end }} + + + {{ with .Params.license }} +
+ + License: + + {{ range . }} + + {{ .label }} + + {{ end }} +
+ {{ end }} +
+ {{ with index $depictions 0 }} + {{ if eq .MediaType.SubType "svg" }} + depiction of instrumet + {{ else }} + depiction of instrumet + {{ end }} + {{ end }} +
+ +
\ No newline at end of file diff --git a/layouts/_partials/taxonomy-list-vertical.html b/layouts/_partials/taxonomy-list-vertical.html new file mode 100644 index 00000000..683a5885 --- /dev/null +++ b/layouts/_partials/taxonomy-list-vertical.html @@ -0,0 +1,13 @@ +{{ $includeItems := .Params.items | default "generated" }} +
+
+
+ {{ range .Pages }} + {{ if or (ne $includeItems "generated") .Params.title }} + {{ partial "taxonomy-list-vertical-item.html" . }} + {{ end }} + {{ end }} +
+
+
+ \ No newline at end of file diff --git a/layouts/datasets/taxonomy.html b/layouts/datasets/taxonomy.html deleted file mode 100644 index 90645dcf..00000000 --- a/layouts/datasets/taxonomy.html +++ /dev/null @@ -1,67 +0,0 @@ -{{ define "main" }} -
- {{ if .Params.showBreadcrumbs | default (.Site.Params.list.showBreadcrumbs | default false) }} - {{ partial "breadcrumbs.html" . }} - {{ end }} -

{{ .Title }}

-
- {{ if .Content }} -
-
- {{ .Content | emojify }} -
-
- {{ end }} -
-
- - - -
- - - {{ $datasetPages := where .Site.Pages "Section" "datasets" }} - {{ $datasetPagesTerms := where $datasetPages "Kind" "term" }} -
- {{ range $i, $p := $datasetPagesTerms }} - {{ partial "dataset-item.html" $p }} - {{ end }} -
-
-
- - - - -
-{{ end }} diff --git a/layouts/instruments/taxonomy.html b/layouts/instruments/taxonomy.html deleted file mode 100644 index 25d001f4..00000000 --- a/layouts/instruments/taxonomy.html +++ /dev/null @@ -1,67 +0,0 @@ -{{ define "main" }} -
- {{ if .Params.showBreadcrumbs | default (.Site.Params.list.showBreadcrumbs | default false) }} - {{ partial "breadcrumbs.html" . }} - {{ end }} -

{{ .Title }}

-
- {{ if .Content }} -
-
- {{ .Content | emojify }} -
-
- {{ end }} -
-
- - - -
- - - {{ $instrumentPages := where .Site.Pages "Section" "instruments" }} - {{ $instrumentPagesTerms := where $instrumentPages "Kind" "term" }} -
- {{ range $i, $p := $instrumentPagesTerms }} - {{ partial "instrument-item.html" $p }} - {{ end }} -
-
-
- - - - -
-{{ end }} diff --git a/layouts/publications/taxonomy.html b/layouts/publications/taxonomy.html deleted file mode 100644 index c8aa0aa7..00000000 --- a/layouts/publications/taxonomy.html +++ /dev/null @@ -1,73 +0,0 @@ -{{ define "main" }} -
- {{ if .Params.showBreadcrumbs | default (.Site.Params.list.showBreadcrumbs | default false) }} - {{ partial "breadcrumbs.html" . }} - {{ end }} -

{{ .Title }}

-
- {{ if .Content }} -
-
- {{ .Content | emojify }} -
-
- {{ end }} -
-
- - - -
- - - {{ $pubPages := where .Site.Pages "Section" "publications" }} - {{ $pubPagesTerms := where $pubPages "Kind" "term" }} -
- {{ range $i, $p := $pubPagesTerms }} - {{ partial "publication-item.html" $p }} - {{ end }} -
-
-
- - - - -
-{{ end }} diff --git a/layouts/taxonomy.html b/layouts/taxonomy.html index 0137febf..b4b68449 100644 --- a/layouts/taxonomy.html +++ b/layouts/taxonomy.html @@ -12,25 +12,15 @@ {{ end }} -
- {{ range .Data.Terms }} - {{ if .Page.Params.title }} -
-

- {{ .Page.Title }} - {{ if $.Site.Params.taxonomy.showTermCount | default true }} - · - - {{ .Count }} - - {{ end }} -

-
+
+ {{ if and (isset .Params "filter") (eq .Params.filter true) }} + {{ partial "taxonomy-list-filter.html" . }} + {{ else }} + {{ if and (isset .Params "list_variant") (eq .Params.list_variant "vertical") }} + {{ partial "taxonomy-list-vertical.html" . }} + {{ else }} + {{ partial "taxonomy-list-grid.html" . }} {{ end }} {{ end }} -
-{{ end }} + +{{ end }} \ No newline at end of file diff --git a/static/filter-list.css b/static/filter-list.css index b3f45a4a..f0da21d8 100644 --- a/static/filter-list.css +++ b/static/filter-list.css @@ -59,6 +59,10 @@ border: 1px solid grey; } +.topic-chip { + cursor: pointer +} + .topic-chip.active { background-color: rgb(59 130 246 / 0.15); color: rgb(59 130 246); diff --git a/static/grid-list.css b/static/grid-list.css new file mode 100644 index 00000000..ba04fa03 --- /dev/null +++ b/static/grid-list.css @@ -0,0 +1,86 @@ +/* Grid */ +.items-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1rem; +} + +/* Card */ +.item-card { + text-decoration: none; + color: inherit; + display: flex; + flex-direction: column; + border-radius: 10px; + overflow: hidden; + border: 1px solid rgba(0,0,0,0.07); + background: #fff; + transition: box-shadow 0.2s, transform 0.2s; +} +.item-card:hover { + box-shadow: 0 4px 16px rgba(0,0,0,0.1); + transform: translateY(-2px); +} +html.dark .item-card { + background: #242424; + border-color: rgba(255,255,255,0.07); +} +html.dark .item-card:hover { + box-shadow: 0 4px 16px rgba(0,0,0,0.3); +} + +.item-depiction { + width: 100%; + aspect-ratio: 1; + overflow: hidden; + background: #e8e8e8; +} +html.dark .item-depiction { background: #333; } +.item-depiction img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} +.item-placeholder { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + font-size: 2.5rem; + font-weight: 700; + color: #aaa; + background: repeating-linear-gradient( + 45deg, + #ddd, + #ddd 10px, + #e8e8e8 10px, + #e8e8e8 20px + ); +} +html.dark .item-placeholder { + background: repeating-linear-gradient( + 45deg, + #2a2a2a, + #2a2a2a 10px, + #333 10px, + #333 20px + ); + color: #555; +} + +.item-title { + padding: 0.6rem 0.75rem; + font-size: 0.85rem; + font-weight: 600; + line-height: 1.3; + text-align: center; +} + +@media (max-width: 900px) { + .items-grid { grid-template-columns: repeat(3, 1fr); } +} +@media (max-width: 600px) { + .items-grid { grid-template-columns: repeat(2, 1fr); } +} \ No newline at end of file -- 2.52.0