diff --git a/assets/css/style.css b/assets/css/style.css index 9708038..4930cd5 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -321,10 +321,6 @@ } /* Global */ -.hero { - height: 350px !important; -} - .section { padding: 100px 0 !important; } @@ -575,8 +571,17 @@ header { /* Home */ /* Hero */ -.hero { - height: 350px !important; +/* Page banner: sized to its title, with room on top for the fixed site header */ +.hero:not(.homeHero) { + height: auto !important; + min-height: 230px; + padding: 100px 1rem 40px; + overflow: hidden; +} + +.hero:not(.homeHero) h1 { + font-size: clamp(2rem, 7vw, 3rem) !important; + margin-bottom: 0; } .homeHero { @@ -1239,6 +1244,296 @@ ol.custom-ordered-list li::before { } } +/* Tools pages: in-page nav, readable intro */ +.tools-page.section { + padding-top: 48px !important; +} + +/* #d17128 is 3.4:1 on white; this shade meets WCAG AA (4.5:1) for body-size text */ +.tools-page .content a { + color: #b35a14 !important; +} + +.tools-page:not(.tools-page--single) .content > p { + max-width: 70ch; +} + +.tools-page:not(.tools-page--single) .content > p:first-child { + font-size: 1.125rem; + line-height: 1.6; +} + +.tools-page:not(.tools-page--single) .content h2 { + font-size: 1.75rem; + font-weight: 700; + margin: 3.5rem 0 0.75rem; + padding-top: 2rem; + border-top: 1px solid #e3e6ea; +} + +.tools-page .content h2, +.tools-page .content h3 { + scroll-margin-top: 140px; +} + +.tools-nav { + position: sticky; + /* Sits directly below the fixed site header */ + top: 78px; + z-index: 900; + background: #fff; + border-bottom: 1px solid #e3e6ea; +} + +.tools-nav ul { + display: flex; + gap: 0.5rem 1.75rem; + margin: 0; + padding: 0; + list-style: none; + overflow-x: auto; + white-space: nowrap; +} + +.tools-nav a { + display: block; + padding: 0.9rem 0; + color: #114b7c; + font-weight: 500; + text-decoration: none; + border-bottom: 2px solid transparent; +} + +.tools-nav a:hover, +.tools-nav a:focus-visible { + border-bottom-color: #d17128; +} + +/* Tool rows: horizontal cards used by the "featured" and "compact" tool-grid variants */ +.tool-rows { + display: grid; + gap: 1.25rem; + margin: 1.5rem 0; +} + +.tool-rows--featured { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.tool-row { + position: relative; + display: flex; + gap: 1rem; + align-items: flex-start; + padding: 1.25rem; + background: #fff; + border: 1px solid #e3e6ea; + border-radius: 8px; + transition: box-shadow 0.2s ease, border-color 0.2s ease; +} + +.tool-row:hover, +.tool-row:focus-within { + border-color: #114b7c; + box-shadow: 0 4px 12px -4px rgba(17, 75, 124, 0.25); +} + +.tool-row__logo { + flex: 0 0 72px; + width: 72px; + height: 72px; + display: flex; + align-items: center; + justify-content: center; +} + +.tool-row__logo img { + max-width: 100%; + max-height: 100%; + width: auto; + height: auto; + object-fit: contain; + border-radius: 6px; +} + +.tool-row__body { + display: flex; + flex-direction: column; + align-self: stretch; + min-width: 0; + flex: 1; +} + +.tool-row__meta { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.5rem; + margin: 0 0 0.35rem !important; + font-size: 0.75rem; + line-height: 1.4; +} + +.tool-row__task { + color: #585c67; + font-weight: 600; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.tool-row__tech { + padding: 0.1rem 0.5rem; + color: #114b7c; + background: #e8f1f8; + border-radius: 999px; + font-weight: 500; +} + +.content .tool-row__title { + margin: 0 0 0.35rem; + font-size: 1.2rem; + font-weight: 600; +} + +.tools-page .content a.tool-row__link { + color: #114b7c !important; +} + +/* Makes the whole card a link to the tool page */ +.tool-row__link::after { + content: ""; + position: absolute; + inset: 0; + border-radius: 8px; +} + +.content .tool-row__desc { + margin: 0 0 0.75rem; + color: #4a4e58; + font-size: 0.95rem; + line-height: 1.5; +} + +.tool-row__install { + position: relative; + z-index: 1; + align-self: flex-start; + max-width: 100%; + margin-bottom: 0.9rem; + padding: 0.3rem 0.6rem; + overflow-x: auto; + white-space: nowrap; + color: #171b26; + background: #f3f5f7; + border-radius: 4px; + font-size: 0.8125rem; +} + +.tool-row__actions { + position: relative; + z-index: 1; + display: flex; + align-items: center; + gap: 1rem; + margin-top: auto; + align-self: flex-start; + font-size: 0.875rem; + font-weight: 500; +} + +.tools-page .content a.tool-row__docs { + padding: 0.4rem 1rem; + color: #fff !important; + background: #114b7c; + border-radius: 4px; +} + +.tools-page .content a.tool-row__docs:hover { + background: #0d3a61; + text-decoration: none !important; +} + +.tools-page .content a.tool-row__source { + padding: 0.4rem 0; + color: #4a4e58 !important; +} + +.tools-page .content a.tool-row__source:hover { + color: #114b7c !important; +} + +/* Compact rows: a denser list for secondary tools, grouped into columns */ +.tool-columns { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 2rem; + align-items: start; + margin-top: 1.5rem; +} + +.content .tool-group__title { + margin: 0; + font-size: 1.125rem; + font-weight: 700; +} + +.tool-rows--compact { + gap: 0.75rem; + margin: 1rem 0 0; +} + +.tool-rows--compact .tool-row { + padding: 0.9rem 1rem; + gap: 0.85rem; +} + +.tool-rows--compact .tool-row__logo { + flex-basis: 48px; + width: 48px; + height: 48px; +} + +.content .tool-rows--compact .tool-row__title { + font-size: 1rem; +} + +.content .tool-rows--compact .tool-row__desc { + margin-bottom: 0.5rem; + font-size: 0.875rem; +} + +.tools-page .content .tool-rows--compact a.tool-row__docs { + padding: 0.4rem 0; + color: #114b7c !important; + background: none; +} + +.tools-page .content .tool-rows--compact a.tool-row__docs:hover { + text-decoration: underline !important; +} + +@media (max-width: 1199px) { + .tool-rows--featured { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 991px) { + .tool-columns { + grid-template-columns: 1fr; + } +} + +@media (max-width: 767px) { + .hero:not(.homeHero) { + min-height: 190px; + padding: 90px 1rem 30px; + } + .tool-rows--featured { + grid-template-columns: 1fr; + } +} + /* Training Materials pages */ a.next-page-btn { background-color: white; @@ -1256,10 +1551,6 @@ a.next-page-btn:hover { padding: 60px 0 !important; } -.community-gallery .hero { - height: 300px !important; -} - .community-gallery .section:first-of-type { padding: 40px 0 !important; } @@ -1269,10 +1560,6 @@ a.next-page-btn:hover { padding: 40px 0 !important; } - .community-gallery .hero { - height: 250px !important; - } - .community-gallery .section:first-of-type { padding: 30px 0 !important; } diff --git a/content/tools/core/_index.md b/content/tools/core/_index.md index 3759f67..495a832 100644 --- a/content/tools/core/_index.md +++ b/content/tools/core/_index.md @@ -1,26 +1,31 @@ --- title: "Core NWB Tools" description: "Glossary of Core NWB Tools" +page_nav: + - name: "Start here" + anchor: "start-here" + - name: "Extending NWB" + anchor: "extending-nwb" + - name: "Schemas & specification" + anchor: "schemas-specification" + - name: "Core development" + anchor: "core-development" --- -The glossary shown here provides a quick overview of the key software packages of the core NWB software stack. For a more general discussion of the overall organization of the core NWB software stack see the [NWB Software Ecosystem](https://www.nwb.org/nwb-software) page on the main NWB website. +The core NWB tools are the software packages maintained by the NWB team for reading, writing, converting, validating, and extending NWB data. For how the pieces fit together, see the [NWB Software Ecosystem](/nwb-software/) overview. -## Read/Write NWB File APIs +## Start here {#start-here} -{{< tool-grid category="read-write-api" >}} +Most people need only these. Pick the API for your language to read and write NWB files, use NeuroConv or NWB GUIDE to convert existing data, and run NWB Inspector before you share a file. -## Converting Data to NWB +{{< tool-grid category="read-write-api,data-conversion,validation" variant="featured" >}} -{{< tool-grid category="data-conversion" >}} +## For extension authors and developers {#advanced} -## Validating NWB Files +Tools for extending the NWB standard, the schemas that define it, and the libraries the core APIs are built on. -{{< tool-grid category="validation" >}} - -## Extending NWB - -{{< tool-grid category="extension" >}} - -## Core Development - -{{< tool-grid category="core-development" >}} +{{< tool-columns >}} +{{< tool-grid category="extension" variant="compact" title="Extending NWB" id="extending-nwb" >}} +{{< tool-grid category="schema" variant="compact" title="Schemas & specification" id="schemas-specification" >}} +{{< tool-grid category="core-development" variant="compact" title="Core development" id="core-development" >}} +{{< /tool-columns >}} diff --git a/content/tools/core/aqnwb.md b/content/tools/core/aqnwb.md index 4a1d300..98f70ae 100644 --- a/content/tools/core/aqnwb.md +++ b/content/tools/core/aqnwb.md @@ -6,6 +6,8 @@ image: "/images/aqnwb_logo.png" source_url: "https://github.com/NeurodataWithoutBorders/aqnwb" docs_url: "https://nwb.org/aqnwb/" weight: 25 +task: "Read & write" +tech: "C++" --- ## Description diff --git a/content/tools/core/hdmf-common-schema.md b/content/tools/core/hdmf-common-schema.md index d5ceca6..87426f3 100644 --- a/content/tools/core/hdmf-common-schema.md +++ b/content/tools/core/hdmf-common-schema.md @@ -1,7 +1,7 @@ --- title: "HDMF Common Schema" description: "Schema of common, general data structures used throughout the NWB Standard Schema" -category: "extension" +category: "schema" image: "/images/hdmf_common_schema_logo_framed.png" source_url: "https://github.com/hdmf-dev/hdmf-common-schema" docs_url: "https://hdmf-common-schema.readthedocs.io/en/stable/" diff --git a/content/tools/core/hdmf-specification-language.md b/content/tools/core/hdmf-specification-language.md index a916b82..baeed13 100644 --- a/content/tools/core/hdmf-specification-language.md +++ b/content/tools/core/hdmf-specification-language.md @@ -1,7 +1,7 @@ --- title: "HDMF Specification Language" description: "Formal structures for describing the organization of complex data" -category: "extension" +category: "schema" image: "/images/specification_language_logo_framed.png" source_url: "https://github.com/hdmf-dev/hdmf-schema-language" docs_url: "https://hdmf-schema-language.readthedocs.io/en/latest/" diff --git a/content/tools/core/matnwb.md b/content/tools/core/matnwb.md index 54ddb68..c81bb70 100644 --- a/content/tools/core/matnwb.md +++ b/content/tools/core/matnwb.md @@ -6,6 +6,8 @@ image: "/images/matnwb_logo_framed.png" source_url: "https://github.com/NeurodataWithoutBorders/matnwb/" docs_url: "https://matnwb.readthedocs.io/" weight: 20 +task: "Read & write" +tech: "MATLAB" --- ## Description diff --git a/content/tools/core/neuroconv.md b/content/tools/core/neuroconv.md index dbf9deb..488f304 100644 --- a/content/tools/core/neuroconv.md +++ b/content/tools/core/neuroconv.md @@ -6,6 +6,9 @@ image: "/images/nwbconversiontools_logo_framed.png" source_url: "https://github.com/catalystneuro/neuroconv" docs_url: "https://neuroconv.readthedocs.io/en/main/index.html" weight: 30 +task: "Convert" +tech: "Python" +install: "pip install neuroconv" --- ## Description diff --git a/content/tools/core/nwb-guide.md b/content/tools/core/nwb-guide.md index fdba941..bbed296 100644 --- a/content/tools/core/nwb-guide.md +++ b/content/tools/core/nwb-guide.md @@ -6,6 +6,8 @@ image: "/images/guide_logo_framed.png" source_url: "https://github.com/NeurodataWithoutBorders/nwb-guide" docs_url: "https://nwb-guide.readthedocs.io/en/stable/" weight: 40 +task: "Convert" +tech: "Desktop app" --- ## Description diff --git a/content/tools/core/nwb-schema.md b/content/tools/core/nwb-schema.md index e842861..e728706 100644 --- a/content/tools/core/nwb-schema.md +++ b/content/tools/core/nwb-schema.md @@ -1,7 +1,7 @@ --- title: "NWB Schema" description: "The NWB data standard format specification" -category: "extension" +category: "schema" image: "/images/nwbschema_logo_framed.png" source_url: "https://github.com/NeurodataWithoutBorders/nwb-schema" docs_url: "https://nwb-schema.readthedocs.io/en/latest/" diff --git a/content/tools/core/nwbinspector.md b/content/tools/core/nwbinspector.md index d96f499..44a7a6f 100644 --- a/content/tools/core/nwbinspector.md +++ b/content/tools/core/nwbinspector.md @@ -6,6 +6,9 @@ image: "/images/nwbinspector_logo_framed.png" source_url: "https://github.com/NeurodataWithoutBorders/nwbinspector" docs_url: "https://nwbinspector.readthedocs.io/" weight: 50 +task: "Validate" +tech: "Python ยท CLI" +install: "pip install nwbinspector" --- ## Description diff --git a/content/tools/core/pynwb.md b/content/tools/core/pynwb.md index eb23b29..ff94516 100644 --- a/content/tools/core/pynwb.md +++ b/content/tools/core/pynwb.md @@ -6,6 +6,9 @@ image: "/images/pynwb_logo_framed.png" source_url: "https://github.com/NeurodataWithoutBorders/pynwb/" docs_url: "https://pynwb.readthedocs.io/en/stable/" weight: 10 +task: "Read & write" +tech: "Python" +install: "pip install pynwb" --- ## Description diff --git a/hugo.yaml b/hugo.yaml index df8463b..2eed56b 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -24,3 +24,6 @@ module: mounts: - source: assets target: assets + # Lets templates resize images kept under static/images (see partials/tools/image.html) + - source: static/images + target: assets/images diff --git a/layouts/partials/tools/image.html b/layouts/partials/tools/image.html new file mode 100644 index 0000000..5eb037b --- /dev/null +++ b/layouts/partials/tools/image.html @@ -0,0 +1,16 @@ +{{- /* + Renders a tool image, downscaled to fit the given box and converted to WebP + when the source is a PNG or JPEG under static/images (mounted as assets). + Anything else (GIF, SVG, remote URL) is emitted unchanged. + + Params: page (the tool page), fit (e.g. "640x400") +*/ -}} +{{- $src := .page.Params.image -}} +{{- $alt := .alt | default "" -}} +{{- $img := resources.Get (strings.TrimPrefix "/" $src) -}} +{{- if and $img (in (slice "png" "jpeg") $img.MediaType.SubType) -}} + {{- $small := $img.Fit (printf "%s webp" .fit) -}} + {{ $alt }} +{{- else -}} + {{ $alt }} +{{- end -}} diff --git a/layouts/shortcodes/tool-columns.html b/layouts/shortcodes/tool-columns.html new file mode 100644 index 0000000..5d33794 --- /dev/null +++ b/layouts/shortcodes/tool-columns.html @@ -0,0 +1,4 @@ +{{- /* Lays out the titled tool-grid groups nested inside it as side-by-side columns. */ -}} +
+ {{ .Inner }} +
diff --git a/layouts/shortcodes/tool-grid.html b/layouts/shortcodes/tool-grid.html index 68dad5f..4c66aaa 100644 --- a/layouts/shortcodes/tool-grid.html +++ b/layouts/shortcodes/tool-grid.html @@ -1,11 +1,29 @@ +{{- /* + Lists the tools in one or more categories. + + Params: + category one category, or several separated by commas + variant "card" (default), "featured" or "compact" + title optional heading rendered above the group + id optional id for that heading (defaults to the anchorized title) +*/ -}} +{{- $categories := split (.Get "category") "," -}} +{{- $variant := .Get "variant" | default "card" -}} +{{- $title := .Get "title" -}} +{{- /* Rows sit one level below the heading that introduces them. */ -}} +{{- $heading := cond (ne $title "") "h4" "h3" -}} +{{- $tools := where (where .Site.RegularPages "Section" "tools") "Params.category" "in" $categories -}} +{{ if $title }} +
+

{{ $title }}

+{{ end }} +{{ if eq $variant "card" }}
- {{ $category := .Get "category" }} - {{ range where .Site.RegularPages "Section" "tools" }} - {{ if eq .Params.category $category }} + {{ range $tools }}
{{ if .Params.image }}
- {{ .Title }} + {{ partial "tools/image.html" (dict "page" . "fit" "640x400" "alt" .Title) }}
{{ end }}
@@ -26,6 +44,44 @@

{{ .Title }}

- {{ end }} {{ end }} +{{ else }} +
+ {{ range $tools }} + {{ $tool := . }} +
+ {{ if .Params.image }} + + {{ end }} +
+ {{ if and (eq $variant "featured") (or .Params.task .Params.tech) }} +

+ {{ with .Params.task }}{{ . }}{{ end }} + {{ with .Params.tech }}{{ . }}{{ end }} +

+ {{ end }} + {{ printf `<%s class="tool-row__title">` $heading | safeHTML }}{{ .Title }}{{ printf `` $heading | safeHTML }} +

{{ .Params.description }}

+ {{ if eq $variant "featured" }} + {{ with .Params.install }}{{ . }}{{ end }} + {{ end }} +
+ {{ with .Params.docs_url }} + Docs: {{ $tool.Title }} + {{ end }} + {{ with .Params.source_url }} + Source: {{ $tool.Title }} + {{ end }} +
+
+
+ {{ end }} +
+{{ end }} +{{ if $title }} +
+{{ end }} diff --git a/layouts/tools/list.html b/layouts/tools/list.html index bff2075..f505d3d 100644 --- a/layouts/tools/list.html +++ b/layouts/tools/list.html @@ -9,7 +9,18 @@

{{ .Title | markdownify {{/* End Hero Section */}} {{/* Content Section */}} -
+{{ with .Params.page_nav }} + +{{ end }} +
{{ .Content }} diff --git a/layouts/tools/single.html b/layouts/tools/single.html index 3c9f5aa..57ad299 100644 --- a/layouts/tools/single.html +++ b/layouts/tools/single.html @@ -9,7 +9,7 @@

{{ .Title | markdownify {{/* End Hero Section */}} {{/* Tool Content Section */}} -
+