Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion content/awards/awards.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Thanks to our amazing community, FORRT has become an ***award-winning*** grassro

### [FORWARD: A UNESCO Decade of Science Programme](../educators-corner/023-forward-a-unesco-decade-of-science-programme/)

<img src="unesco_recognition.webp" width="200" align="left" style="margin-right: 10px;" alt="FORWARD: A UNESCO Decade of Science Programme">
<img src="unesco_recognition.webp" width="200" height="207" align="left" style="margin-right: 10px;" alt="FORWARD: A UNESCO Decade of Science Programme">

**FORRT** is one of the few initiatives worldwide to be formally endorsed as a **Programme** of the [International Decade of Sciences for Sustainable Development (IDSSD, 2024–2033)](https://www.un-sciences-decade.org/en/endorsed-activities/forward-forrt-world-development-fostering-open-research-reproducibility-worldwide-accessible?hub=63) , led by UNESCO and the United Nations (UN). This endorsement reflects the highest level of UN policy recognition and positions FORRT’s work in Education & Pedagogy (Curriculum Hub), Metascience & Research (Replication Hub) and Social Justice & DEIA as an **essential contribution to the UN’s strategy for achieving the Sustainable Development Goals (SDGs)**.

Expand Down
2 changes: 1 addition & 1 deletion content/home/5-achievements.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ title = "Achievements &amp; Awards"

### [FORWARD: A UNESCO Decade of Science Programme](../educators-corner/023-forward-a-unesco-decade-of-science-programme/)

<img src="../awards/unesco_recognition.webp" width="200" align="left" style="margin-right: 10px;" alt="FORWARD: A UNESCO Decade of Science Programme">
<img src="../awards/unesco_recognition.webp" width="200" height="207" align="left" style="margin-right: 10px;" alt="FORWARD: A UNESCO Decade of Science Programme">

**FORRT** is one of the few initiatives worldwide to be formally endorsed as a **Programme** of the [International Decade of Sciences for Sustainable Development (IDSSD, 2024–2033)](https://www.un-sciences-decade.org/en/endorsed-activities/forward-forrt-world-development-fostering-open-research-reproducibility-worldwide-accessible?hub=63) , led by UNESCO and the United Nations (UN). This endorsement reflects the highest level of UN policy recognition and positions FORRT’s work in Education & Pedagogy (Curriculum Hub), Metascience & Research (Replication Hub) and Social Justice & DEIA as an **essential contribution to the UN’s strategy for achieving the Sustainable Development Goals (SDGs)**.

Expand Down
2 changes: 1 addition & 1 deletion content/home/5-get-involved.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ title = "How can you help?"
# icon = "users"
# icon_pack = "fas"
img = "teamwork.webp"
imgalttext = "Image of a megaphone"
imgalttext = "Several hands stacked on top of each other. Illustration."
name = "Join Our Teams"
description = "Everything we develop and produce is in the open and open to anyone willing to help. Check out our [several teams here](/about/teams) and our [get-involved page](/about/get-involved) too."

Expand Down
28 changes: 28 additions & 0 deletions layouts/_default/_markup/render-image.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{{/* Markdown image hook: reproduce Hugo's default <img> and add intrinsic width/height
so the browser reserves the image's box before it loads. The site stylesheet sets
`img { height: auto; max-width: 100% }`, so the attributes fix the aspect ratio
without freezing the rendered size or breaking responsive scaling.

Dimensions come from the page bundle's own resource first, then from static/, and
are skipped for remote images and for formats Hugo cannot measure (SVG). */}}
{{- $dest := .Destination -}}
{{- $dims := "" -}}
{{- $raster := slice "png" "jpeg" "gif" "webp" -}}
{{- if not (or (strings.HasPrefix $dest "http") (strings.HasPrefix $dest "//") (strings.HasPrefix $dest "data:")) -}}
{{- with .PageInner.Resources.Get (strings.TrimPrefix "./" $dest) -}}
{{/* Match Hugo's default hook, which links page-bundle images by permalink rather
than by the author's page-relative path. */}}
{{- $dest = .RelPermalink -}}
{{- if in $raster .MediaType.SubType -}}
{{- $dims = printf "width=\"%d\" height=\"%d\"" .Width .Height -}}
{{- end -}}
{{- else -}}
{{- $static := printf "static/%s" (strings.TrimPrefix "/" $dest) -}}
{{- if and (fileExists $static) (in (slice ".png" ".jpg" ".jpeg" ".gif" ".webp") (path.Ext $static | lower)) -}}
{{- with imageConfig $static -}}
{{- $dims = printf "width=\"%d\" height=\"%d\"" .Width .Height -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
<img src="{{ $dest | safeURL }}" alt="{{ .PlainText }}"{{ with .Title }} title="{{ . }}"{{ end }}{{ with $dims }} {{ . | safeHTMLAttr }}{{ end }}>
4 changes: 2 additions & 2 deletions layouts/partials/chatbot.html
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@
{{ if $active }}
<!-- Toggle Button -->
<button id="just-os-btn" onclick="toggleJustOS()" aria-label="Open Chatbot">
<img id="just-os-img" src="/img/just_os_icon.webp" alt="Chat with us">
<img id="just-os-img" src="/img/just_os_icon.webp" {{ partial "functions/static_img_dims" "just_os_icon.webp" }} alt="Chat with us">
<div id="just-os-bubble">
How can I help you?
</div>
Expand Down Expand Up @@ -933,7 +933,7 @@
{{ else }}
<!-- Inactive state: icon links to the standalone page where the full offline notice lives -->
<a id="just-os-btn" href="/just_os_chatbot/" aria-label="JUST-OS chatbot is offline — open status page">
<img id="just-os-img" src="/img/just_os_icon.webp" alt="JUST-OS chatbot (offline)">
<img id="just-os-img" src="/img/just_os_icon.webp" {{ partial "functions/static_img_dims" "just_os_icon.webp" }} alt="JUST-OS chatbot (offline)">
<span id="just-os-offline-badge" aria-hidden="true" title="Chatbot offline">
<!-- Unplugged plug icon -->
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
Expand Down
23 changes: 23 additions & 0 deletions layouts/partials/functions/logo_dims.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{{/* Intrinsic width/height attributes for the site logo, so the navbar reserves the
brand's box before the image loads. The stylesheet sizes the logo by height with
`width: auto`, which leaves its width unknown until the file arrives and shifts
the menu sideways on first paint.
Input: the logo resource (as returned by functions/get_logo).
Output: `width="W" height="H"` (safe attribute string), or empty when unavailable.

Hugo exposes .Width/.Height on raster resources only, so the SVG's aspect ratio is
read from the first viewBox in the file, which is the root <svg> element's. */}}
{{ $dims := "" }}
{{ with . }}
{{ if eq (path.Ext .Name | lower) ".svg" }}
{{ with (findRE `viewBox="[^"]+"` .Content 1) }}
{{ $nums := findRE `[0-9]+(\.[0-9]+)?` (index . 0) }}
{{ if eq (len $nums) 4 }}
{{ $dims = printf "width=\"%.0f\" height=\"%.0f\"" (float (index $nums 2)) (float (index $nums 3)) }}
{{ end }}
{{ end }}
{{ else }}
{{ $dims = printf "width=\"%d\" height=\"%d\"" .Width .Height }}
{{ end }}
{{ end }}
{{ return ($dims | safeHTMLAttr) }}
6 changes: 4 additions & 2 deletions layouts/partials/navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
{{ $show_logo := site.Params.main_menu.show_logo | default true }}
{{ $has_logo := fileExists "assets/images/logo.webp" | or (fileExists "assets/images/logo.svg") }}
{{ $logo := "" }}
{{ $logo_dims := "" }}
{{ if $has_logo }}
{{ $logo = (partial "functions/get_logo" (dict "constraint" "max_height" "size" 70)) }}
{{ $logo_dims = partial "functions/logo_dims" $logo }}
{{ end }}

<nav class="navbar navbar-expand-lg navbar-light compensate-for-scrollbar" id="navbar-main">
Expand All @@ -15,7 +17,7 @@
<div class="d-none d-lg-inline-flex">
<a class="navbar-brand" href="{{ "/" | relLangURL }}">
{{- if $has_logo -}}
<img src="{{ $logo.RelPermalink }}" alt="{{ site.Title }} Logo. Link to homepage">
<img src="{{ $logo.RelPermalink }}" {{ $logo_dims }} alt="{{ site.Title }} Logo. Link to homepage">
{{- else -}}
{{- site.Title -}}
{{- end -}}
Expand All @@ -34,7 +36,7 @@
<div class="navbar-brand-mobile-wrapper d-inline-flex d-lg-none">
<a class="navbar-brand" href="{{ "/" | relLangURL }}">
{{- if $has_logo -}}
<img src="{{ $logo.RelPermalink }}" alt="{{ site.Title }}">
<img src="{{ $logo.RelPermalink }}" {{ $logo_dims }} alt="{{ site.Title }}">
{{- else -}}
{{- site.Title -}}
{{- end -}}
Expand Down
10 changes: 5 additions & 5 deletions layouts/shortcodes/forward_unesco_sdgs_card.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ <h3>FORWARD (FORRT for World Development)</h3>

<div class="sdg-icons-wrapper">
<a href="https://sdgs.un.org/goals/goal4" target="_blank" rel="noopener noreferrer">
<img src="/img/forward_unesco_sdgs/4.webp" alt="SDG 4: Quality Education"
<img src="/img/forward_unesco_sdgs/4.webp" {{ partial "functions/static_img_dims" "forward_unesco_sdgs/4.webp" }} alt="SDG 4: Quality Education"
title="SDG 4: Quality Education">
</a>
<a href="https://sdgs.un.org/goals/goal5" target="_blank" rel="noopener noreferrer">
<img src="/img/forward_unesco_sdgs/5.webp" alt="SDG 5: Gender Equality" title="SDG 5: Gender Equality">
<img src="/img/forward_unesco_sdgs/5.webp" {{ partial "functions/static_img_dims" "forward_unesco_sdgs/5.webp" }} alt="SDG 5: Gender Equality" title="SDG 5: Gender Equality">
</a>
<a href="https://sdgs.un.org/goals/goal10" target="_blank" rel="noopener noreferrer">
<img src="/img/forward_unesco_sdgs/10.webp" alt="SDG 10: Reduced Inequalities"
<img src="/img/forward_unesco_sdgs/10.webp" {{ partial "functions/static_img_dims" "forward_unesco_sdgs/10.webp" }} alt="SDG 10: Reduced Inequalities"
title="SDG 10: Reduced Inequalities">
</a>
<a href="https://sdgs.un.org/goals/goal16" target="_blank" rel="noopener noreferrer">
<img src="/img/forward_unesco_sdgs/16.webp" alt="SDG 16: Peace, Justice and Strong Institutions"
<img src="/img/forward_unesco_sdgs/16.webp" {{ partial "functions/static_img_dims" "forward_unesco_sdgs/16.webp" }} alt="SDG 16: Peace, Justice and Strong Institutions"
title="SDG 16: Peace, Justice and Strong Institutions">
</a>
<a href="https://sdgs.un.org/goals/goal17" target="_blank" rel="noopener noreferrer">
<img src="/img/forward_unesco_sdgs/17.webp" alt="SDG 17: Partnerships for the Goals"
<img src="/img/forward_unesco_sdgs/17.webp" {{ partial "functions/static_img_dims" "forward_unesco_sdgs/17.webp" }} alt="SDG 17: Partnerships for the Goals"
title="SDG 17: Partnerships for the Goals">
</a>
</div>
Expand Down
27 changes: 22 additions & 5 deletions scripts/check_seo_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
not count; language-mermaid blocks belong to Mermaid), and mermaid.min.js
exactly on pages with a language-mermaid block.
4. Every <img> carries an alt attribute (a bare `alt` counts as present).
5. Every homepage <img> carries both width and height, so the browser reserves
its box before the file loads (#869).

Report-only sections (never fail): pages with zero or several <h1>, and the
count of homepage images that carry both width and height.
site-wide share of images that carry both width and height.
"""

import os
Expand Down Expand Up @@ -87,6 +89,11 @@ def has_mermaid_code(self):
def imgs_without_alt(self):
return [img for img in self.imgs if "alt" not in img]

@property
def imgs_without_dims(self):
return [img for img in self.imgs
if "width" not in img or "height" not in img]


def load_pages(public_dir):
pages = []
Expand Down Expand Up @@ -127,6 +134,12 @@ def check_conditional_assets(pages):
}


def check_homepage_img_dims(home):
if home is None:
return ["index.html (homepage not found)"]
return [img.get("src", "(no src)") for img in home.imgs_without_dims]


def check_img_alt(pages):
return ["%s (%d image(s))" % (p.path, len(p.imgs_without_alt))
for p in pages if p.imgs_without_alt]
Expand All @@ -149,6 +162,7 @@ def main(public_dir):
'1. no <h1>Search</h1>': check_no_search_heading(pages),
"2. homepage free of mermaid/highlight.js assets": check_homepage_assets(home),
"4. every <img> has an alt attribute": check_img_alt(pages),
"5. every homepage <img> has width and height": check_homepage_img_dims(home),
}
conditional = check_conditional_assets(pages)
results["3. conditional highlight.js / mermaid loading"] = [
Expand All @@ -167,14 +181,17 @@ def main(public_dir):
if items:
print_items(reason, items)
else:
print_items("pages", results[title])
# Check 5 lists offending image sources, every other check lists pages.
print_items("images" if title.startswith("5.") else "pages", results[title])

print("\nReport only (never fails)")
print_items("pages with no <h1>", [p.path for p in pages if not p.h1_texts])
print_items("pages with several <h1>", [p.path for p in pages if len(p.h1_texts) > 1])
if home is not None:
sized = [i for i in home.imgs if "width" in i and "height" in i]
print(" homepage images: %d, with width and height: %d" % (len(home.imgs), len(sized)))
all_imgs = sum(len(p.imgs) for p in pages)
unsized = sum(len(p.imgs_without_dims) for p in pages)
if all_imgs:
print(" images site-wide: %d, with width and height: %d (%.1f%%)"
% (all_imgs, all_imgs - unsized, 100.0 * (all_imgs - unsized) / all_imgs))

return 1 if any(results.values()) else 0

Expand Down