From a0d366e4cdefee9a585ee0101965cf3f2c7f6eca Mon Sep 17 00:00:00 2001 From: lennartrommeiss Date: Mon, 10 Mar 2025 08:56:14 +0100 Subject: [PATCH 1/3] feat: add side menu and text styling Signed-off-by: lennartrommeiss --- assets/sass/fonts.scss | 3 + assets/sass/main.scss | 2 + assets/sass/sidemenu.scss | 20 ++++ assets/sass/styles.scss | 23 ++++ assets/sass/toc.scss | 15 +++ content/country/netherlands/index.de.md | 12 ++ content/country/netherlands/index.en.md | 12 ++ content/operator/eurostar/index.de.md | 3 + content/operator/eurostar/index.en.md | 3 + content/operator/ns/index.de.md | 7 ++ content/operator/ns/index.en.md | 7 ++ hugo.yaml | 9 +- i18n/de.yaml | 6 +- i18n/en.yaml | 4 +- layouts/country/single.html | 25 ++-- layouts/operator/single.html | 24 ++-- layouts/partials/sidemenu.html | 48 ++++++++ layouts/partials/toc.html | 145 ++++++++++++++++++++++++ layouts/shortcodes/highlight.html | 2 +- 19 files changed, 335 insertions(+), 35 deletions(-) create mode 100644 assets/sass/sidemenu.scss create mode 100644 assets/sass/toc.scss create mode 100644 content/country/netherlands/index.de.md create mode 100644 content/country/netherlands/index.en.md create mode 100644 content/operator/ns/index.de.md create mode 100644 content/operator/ns/index.en.md create mode 100644 layouts/partials/sidemenu.html create mode 100644 layouts/partials/toc.html diff --git a/assets/sass/fonts.scss b/assets/sass/fonts.scss index e408ee59..50920dd6 100644 --- a/assets/sass/fonts.scss +++ b/assets/sass/fonts.scss @@ -16,4 +16,7 @@ body { font-family: "Roboto",Arial,Helvetica,sans-serif; + word-wrap: break-word; + hyphens: auto; + text-align: justify; } \ No newline at end of file diff --git a/assets/sass/main.scss b/assets/sass/main.scss index 2eb9fd41..10a935ed 100644 --- a/assets/sass/main.scss +++ b/assets/sass/main.scss @@ -4,11 +4,13 @@ @import "styles.scss"; @import "fonts.scss"; @import "navigation.scss"; +@import "sidemenu.scss"; @import "stage.scss"; @import "teaser.scss"; @import "footer.scss"; @import "content.scss"; @import "textHighlight.scss"; +@import "toc.scss"; @import "headings.scss"; @import "form.scss"; @import "expander.scss"; \ No newline at end of file diff --git a/assets/sass/sidemenu.scss b/assets/sass/sidemenu.scss new file mode 100644 index 00000000..38042d99 --- /dev/null +++ b/assets/sass/sidemenu.scss @@ -0,0 +1,20 @@ +.sidemenu{ + flex-basis: 30%; + position: sticky; + top: 92px; +} + +.tableOfContents { + font-size: 1.4rem; + line-height: 1.5; +} + +.tableOfContents ul { + list-style-type: none; + list-style-position: outside; + padding-left: 0; +} + +.tableOfContents a { + text-decoration-line: none; +} \ No newline at end of file diff --git a/assets/sass/styles.scss b/assets/sass/styles.scss index 8434f015..38b4dc6d 100644 --- a/assets/sass/styles.scss +++ b/assets/sass/styles.scss @@ -59,6 +59,19 @@ main > .container { } } +main > .single-container { + margin-top: 7.3rem; + display: flex; + padding: 2rem; + align-items: flex-start; + gap: 2rem; + + @include media-breakpoint-down(sm) { + margin-top: 1.6rem; + } +} + + img { width: 100%; height: 100%; @@ -81,4 +94,14 @@ article p:last-child { @include media-breakpoint-down(sm) { max-width: calc(100% - 3.6rem); } +} + +.o-single { + padding: 2rem; + background-color: var(--bg-default); + border-radius: var(--border-radius-l); +} + +.main { + flex-basis: 70%; } \ No newline at end of file diff --git a/assets/sass/toc.scss b/assets/sass/toc.scss new file mode 100644 index 00000000..4fbd021d --- /dev/null +++ b/assets/sass/toc.scss @@ -0,0 +1,15 @@ +.toc li { + list-style-type: none; + } + +.toc ol { + padding: 0 0 0 1em; +} + +.toc > ol { + padding-left: 0; +} + +.toc-title { + font-weight: bold; +} \ No newline at end of file diff --git a/content/country/netherlands/index.de.md b/content/country/netherlands/index.de.md new file mode 100644 index 00000000..cefb03b1 --- /dev/null +++ b/content/country/netherlands/index.de.md @@ -0,0 +1,12 @@ +--- +date: "2024-10-17" +draft: false +title: "Niederlande" +country: "netherlands" +--- + +## FIP Hinweise + +## Allgemeine Bahnreise Hinweise + +## FIP Bewertung diff --git a/content/country/netherlands/index.en.md b/content/country/netherlands/index.en.md new file mode 100644 index 00000000..bfd49ae2 --- /dev/null +++ b/content/country/netherlands/index.en.md @@ -0,0 +1,12 @@ +--- +date: "2024-10-17" +draft: false +title: "Netherlands" +country: "netherlands" +--- + +## FIP Information + +## General Train Travel Information + +## FIP Rating diff --git a/content/operator/eurostar/index.de.md b/content/operator/eurostar/index.de.md index 986ff582..3c00688f 100644 --- a/content/operator/eurostar/index.de.md +++ b/content/operator/eurostar/index.de.md @@ -2,4 +2,7 @@ date: "2024-10-17" draft: false title: "Eurostar" +country: + - "belgium" + - "netherlands" --- diff --git a/content/operator/eurostar/index.en.md b/content/operator/eurostar/index.en.md index 986ff582..3c00688f 100644 --- a/content/operator/eurostar/index.en.md +++ b/content/operator/eurostar/index.en.md @@ -2,4 +2,7 @@ date: "2024-10-17" draft: false title: "Eurostar" +country: + - "belgium" + - "netherlands" --- diff --git a/content/operator/ns/index.de.md b/content/operator/ns/index.de.md new file mode 100644 index 00000000..a557b056 --- /dev/null +++ b/content/operator/ns/index.de.md @@ -0,0 +1,7 @@ +--- +date: "2024-10-17" +draft: false +title: "NS" +country: + - "netherlands" +--- diff --git a/content/operator/ns/index.en.md b/content/operator/ns/index.en.md new file mode 100644 index 00000000..a557b056 --- /dev/null +++ b/content/operator/ns/index.en.md @@ -0,0 +1,7 @@ +--- +date: "2024-10-17" +draft: false +title: "NS" +country: + - "netherlands" +--- diff --git a/hugo.yaml b/hugo.yaml index b085a2d9..75288a12 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -27,12 +27,17 @@ module: target: "static" related: + includeNewer: true indices: - name: country - weight: 1 - includeNewer: true + weight: 100 markup: tableOfContents: startLevel: 2 endLevel: 2 + +cascade: + toc: true # enable toc for all pages + target: + kind: 'page' \ No newline at end of file diff --git a/i18n/de.yaml b/i18n/de.yaml index f6bcbeb2..abe94406 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -15,9 +15,11 @@ information-disclaimer-short: Diese Informationen sind inoffiziell und ohne Gew highlight-important: Wichtige Information highlight-inofficial: Inoffizielle Information highlight-tip: Persönlicher Tipp -news-headline: Was gibt's neues? +news-headline: Was gibt's Neues? _operator__list_title: Betreiber _country__list_title: Länder _news__list_title: Neuigkeiten updateDate: Zuletzt aktualisiert -related: Verwandte Seiten \ No newline at end of file +related: Verwandte Seiten +toc_name: Inhalt +_operator__nearby: Angrenzende Betreiber \ No newline at end of file diff --git a/i18n/en.yaml b/i18n/en.yaml index a89fd4f1..5f4aba70 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -20,4 +20,6 @@ _operator__list_title: Operator _country__list_title: Countries _news__list_title: News updateDate: Last updated -related: Related Pages \ No newline at end of file +related: Related Pages +toc_name: Contents +_operator__nearby: Neighboring Operators \ No newline at end of file diff --git a/layouts/country/single.html b/layouts/country/single.html index 347c75b0..fde7b362 100644 --- a/layouts/country/single.html +++ b/layouts/country/single.html @@ -1,20 +1,15 @@ {{ define "main" }} -
-

{{ .Title }}

- - {{ partial "updateDate.html" . }} - -
-
- {{ .TableOfContents }} +
+
+ {{ partial "sidemenu.html" . }}
-
- -
- {{ .Content }} +
+

{{ .Title }}

+ {{ partial "updateDate.html" . }} + +
+ {{ .Content }} +
-
- {{ partial "related.html" . }} - {{ partial "terms.html" (dict "taxonomy" "tags" "page" .) }}
{{ end }} \ No newline at end of file diff --git a/layouts/operator/single.html b/layouts/operator/single.html index 302c6d19..fde7b362 100644 --- a/layouts/operator/single.html +++ b/layouts/operator/single.html @@ -1,19 +1,15 @@ {{ define "main" }} -
-

{{ .Title }}

- - {{ partial "updateDate.html" . }} - -
-
- {{ .TableOfContents }} +
+
+ {{ partial "sidemenu.html" . }}
-
-
- {{ .Content }} +
+

{{ .Title }}

+ {{ partial "updateDate.html" . }} + +
+ {{ .Content }} +
-
- {{ partial "related.html" . }} - {{ partial "terms.html" (dict "taxonomy" "tags" "page" .) }}
{{ end }} \ No newline at end of file diff --git a/layouts/partials/sidemenu.html b/layouts/partials/sidemenu.html new file mode 100644 index 00000000..de003387 --- /dev/null +++ b/layouts/partials/sidemenu.html @@ -0,0 +1,48 @@ +
+ {{ if eq .Page.Type "operator" }} +
    + {{ $related := .Site.RegularPages.RelatedIndices . "country" }} + {{ with $related }} + {{ range . }} + {{ if eq .Page.Type "country" }} + {{ .LinkTitle }}
    + {{ end }} + {{ end }} + {{ end }} +
+ {{ end }} + + + {{ partial "toc.html" (dict "context" . "startLevel" 2 "endLevel" 3 ) }} + + {{ if eq .Page.Type "country" }} + +
    + {{ $related := .Site.RegularPages.RelatedIndices . "country" }} + {{ with $related }} + {{ range . }} +
  • + {{ .LinkTitle }} + {{ partial "toc.html" (dict "context" . "startLevel" 2 "endLevel" 2 ) }} +
  • + {{ end }} + {{ end }} +
+ {{ end }} + {{ if eq .Page.Type "operator" }} + +
    + {{ $related := .Site.RegularPages.RelatedIndices . "country" }} + {{ with $related }} + {{ range . }} + {{ if eq .Page.Type "operator" }} +
  • + {{ .LinkTitle }} + {{ partial "toc.html" (dict "context" . "startLevel" 2 "endLevel" 2 ) }} +
  • + {{ end }} + {{ end }} + {{ end }} +
+ {{ end }} +
\ No newline at end of file diff --git a/layouts/partials/toc.html b/layouts/partials/toc.html new file mode 100644 index 00000000..f5c1aec2 --- /dev/null +++ b/layouts/partials/toc.html @@ -0,0 +1,145 @@ +{{- /* Last modified: 2025-03-08T12:47:53-08:00 */}} + +{{- /* +Copyright 2023 Veriphor, LLC + +Licensed under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy of +the License at + +https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations under +the License. +*/}} + +{{- /* +Renders a table of contents by walking .Page.Fragments.Headings. + +In site configuration, set the default start level, end level, and the minimum +number of headings required to show the table of contents: + + [params.toc] + startLevel = 2 # default is 2 + endLevel = 3 # default is 3 + minNumHeadings = 2 # default is 2 + +To display the table of contents on a page: + + +++ + title = 'Post 1' + toc = true + +++ + +To display the table of contents on a page, and override one or more of the +default settings: + + +++ + title = 'Post 1' + [toc] + startLevel = 2 # default is 2 + endLevel = 3 # default is 3 + minNumHeadings = 2 # default is 2 + +++ + +Start with these basic CSS rules to style the table of contents: + + .toc li { + list-style-type: none; + } + .toc ol { + padding: 0 0 0 1em; + } + .toc > ol { + padding-left: 0; + } + .toc-title { + font-weight: bold; + } + +@context {page} . + +@returns {template.HTML} + +@example {{ partial "toc.html" (dict "context" . "startLevel" 2 "endLevel" 3 ) }} +*/}} + +{{- /* Initialize. */}} +{{- $partialName := "toc-walk" }} + +{{- /* Verify minimum required version. */}} +{{- $minHugoVersion := "0.125.6" }} +{{- if lt hugo.Version $minHugoVersion }} + {{- errorf "The %q partial requires Hugo v%s or later." $partialName $minHugoVersion }} +{{- end }} + +{{- /* Determine content path for warning and error messages. */}} +{{- $contentPath := "" }} +{{- with .File }} + {{- $contentPath = .context.Path }} +{{- else }} + {{- $contentPath = .context.Path }} +{{- end }} + +{{- /* Check for duplicate heading IDs. */}} +{{- $duplicateIDs := slice }} +{{- range .context.Fragments.Identifiers }} + {{- if gt ($.Fragments.Identifiers.Count .) 1 }} + {{- $duplicateIDs = $duplicateIDs | append . }} + {{- end }} +{{- end }} +{{- with $duplicateIDs | uniq }} + {{- errorf "The %q partial detected duplicate heading IDs (%s) in %s" $partialName (delimit . ", ") $contentPath }} +{{- end }} + +{{- /* Render. */}} +{{- if .context.Params.toc }} + {{- with .context.Fragments.Headings }} + {{- $startLevel := or ($.startLevel | int ) ($.context.Param "toc.startLevel" | int) 2 }} + {{- $endLevel := or ($.endLevel | int ) ($.context.Param "toc.endLevel" | int) 3 }} + {{- $numHeadings := where (sort $.context.Fragments.HeadingsMap) "Level" "in" (seq $startLevel $endLevel) | len }} + {{- if ge $numHeadings (or ($.context.Param "toc.minNumHeadings" | int) 2) }} + + {{- end }} + {{- end }} +{{- end }} + +{{- /* Recursively walk the headings. */}} +{{- define "partials/inline/toc/walk.html" }} + {{- $ctx := . }} + {{- range $ctx.headings }} + {{- if and (ge .Level $ctx.startLevel) (le .Level $ctx.endLevel) }} +
  • + {{- if not .ID }} + {{- errorf "The %q partial detected that the %q heading has an empty ID attribute. See %s" $ctx.partialName .Title $ctx.contentPath }} + {{- end }} + {{- $href := printf "%s#%s" $ctx.page.RelPermalink .ID }} + {{ .Title | plainify | safeHTML }} + {{- with and (lt .Level $ctx.endLevel) .Headings }} +
      + {{- $ctx = merge $ctx (dict "headings" .) }} + {{- partial "inline/toc/walk.html" $ctx }} +
    + {{- end }} +
  • + {{- else }} + {{- $ctx = merge $ctx (dict "headings" .Headings) }} + {{- partial "inline/toc/walk.html" $ctx }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/layouts/shortcodes/highlight.html b/layouts/shortcodes/highlight.html index 28397ee7..1d05aa6e 100644 --- a/layouts/shortcodes/highlight.html +++ b/layouts/shortcodes/highlight.html @@ -1,4 +1,4 @@
    -

    {{ (.Get 1) | markdownify }}

    +

    {{ (.Get 1) }}

    {{ .Inner | markdownify }}

    \ No newline at end of file From 77c4ed50d7b1127a956a0fca0fccb0e31dfc77df Mon Sep 17 00:00:00 2001 From: lennartrommeiss Date: Mon, 10 Mar 2025 10:58:23 +0100 Subject: [PATCH 2/3] fix: add content dashboard link Signed-off-by: lennartrommeiss --- README.md | 4 ++++ content/_index.de.md | 2 ++ content/_index.en.md | 2 ++ 3 files changed, 8 insertions(+) diff --git a/README.md b/README.md index 33ecaa91..0183c14a 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ This project includes information and usage instructions for FIP as well as spec Contributing and providing information is always welcome. Instructions for editing information can be found [here in the Wiki](https://github.com/fipguide/fipguide.github.io/wiki/English). +You can see the current information status for operators here: [Content Status](https://github.com/orgs/fipguide/projects/3) + ❤️ A project by railway workers for railway workers. ℹ️ @@ -30,6 +32,8 @@ In diesem Projekt sind Informationen und Nutzungshinweise zu FIP sowie Besonderh Die Mitarbeit und das Beitragen von Informationen sind immer willkommen. Eine Anleitung zum Bearbeiten von Informationen befindet sich [hier im Wiki](https://github.com/fipguide/fipguide.github.io/wiki/Deutsch). +Der aktuellen Bearbeitungsstand der Informationen für Betreiber ist hier zu finden: [Content Status](https://github.com/orgs/fipguide/projects/3) + ❤️ Ein Projekt von Bahnern für Bahner. ℹ️ diff --git a/content/_index.de.md b/content/_index.de.md index da88cd9e..c1291a40 100644 --- a/content/_index.de.md +++ b/content/_index.de.md @@ -6,6 +6,8 @@ In diesem Projekt sind Informationen und Nutzungshinweise zu FIP sowie Besonderh Momentan gibt es die Infos für die Länder **Belgien** und **Slowakei**. +Der aktuellen Bearbeitungsstand der Informationen für Betreiber ist hier zu finden: [Content Status](https://github.com/orgs/fipguide/projects/3) + ### Unterstütze uns Du möchtest dein Wissen rund um FIP-Regelungen teilen? Schau auf unserem [GitHub Repository](https://github.com/fipguide/fipguide.github.io) vorbei, um Inhalte beizutragen. Alternativ kannst du uns auch über das [Kontaktformular]({{< ref "contact" >}}) schreiben. \ No newline at end of file diff --git a/content/_index.en.md b/content/_index.en.md index 062480fc..fcd2e01e 100644 --- a/content/_index.en.md +++ b/content/_index.en.md @@ -6,6 +6,8 @@ This project includes information and usage instructions for FIP as well as spec Currently, information for the countries **Belgium** and **Slovakia** are available. +You can see the current information status for operators here: [Content Status](https://github.com/orgs/fipguide/projects/3) + ### Support Us Would you like to share your knowledge about FIP regulations? Visit our [GitHub Repository](https://github.com/fipguide/fipguide.github.io) to contribute content. Alternatively, you can also write to us via the [contact form]({{< ref "contact" >}}). From 9e0af0ed96b02e073ce4d9eb938afe37691f7979 Mon Sep 17 00:00:00 2001 From: lennartrommeiss Date: Wed, 12 Mar 2025 09:40:14 +0100 Subject: [PATCH 3/3] fix: highlightHeadline Signed-off-by: lennartrommeiss --- assets/js/highlightHeadline.js | 92 ++++++++++++++++++++++++++++++++++ assets/js/main.js | 1 + assets/sass/toc.scss | 5 ++ 3 files changed, 98 insertions(+) create mode 100644 assets/js/highlightHeadline.js diff --git a/assets/js/highlightHeadline.js b/assets/js/highlightHeadline.js new file mode 100644 index 00000000..ccfa7966 --- /dev/null +++ b/assets/js/highlightHeadline.js @@ -0,0 +1,92 @@ +document.addEventListener('DOMContentLoaded', () => { + + alert('Die Highlight Funktion ist noch im Debug Modus. Folgendes ist noch zu tun: -Hight-Aktivierunglevel anpassen, Regelung für Seitentitel Finden (z.B. SNCB), Debug Logs entfernen'); + + // In this site's layout, the table of contents (.content) is an element that appears before any other content at the same hierarchy level + const headings = Array.from(document.querySelectorAll('.content :is(h2, h3, h4)')); + const windowPath = window.location.pathname; + if (headings.length === 0) { + return; // No headings? No business here + } + + // A few helper functions (.toc is the top-level ordered list) + const markTocItemActive = (a) => {return a.setAttribute('data-current', '');} + const markTocItemInactive = (a) => {return a.removeAttribute('data-current');}; + const getTocLinkFromHeading = (h) => {return document.querySelector(`.toc a[href="${windowPath}#${encodeURIComponent(h.id).replace(/%\w\w/g, match => match.toLowerCase())}"]`);} + + const getDocHeight = () => Math.floor(document.body.clientHeight); + + const visibleHeadings = new Set(); + let resizeDebounce; + let currentObserver; + let height = getDocHeight(); + + function beginObservation(docHeight) { + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + // Keep track of visible headings + if (entry.isIntersecting) { + visibleHeadings.add(entry.target); + } else { + visibleHeadings.delete(entry.target); + } + }); + + // Sort visible (intersecting) headings by inverted order of appearance, then grab the first item (i.e. last visible heading) + const lastVisible = Array.from(visibleHeadings.values()).sort((a, b) => headings.indexOf(b) - headings.indexOf(a))[0]; + if (!lastVisible) { + return; // If nothing is visible, weird — TOC are opt-in — but let's skip this logic + } + + headings.forEach((heading) => { + // Find the link in the TOC list matching the heading in this list of hheding elements + const tocLink = getTocLinkFromHeading(heading); + + // If it's the last visible item, mark it to make it stand out, else, revert to the default style + if (heading === lastVisible) { + console.log(`ACTIVE`); + console.log(heading); + console.log(`.toc a[href="${windowPath}#${encodeURIComponent(heading.id).replace(/%\w\w/g, match => match.toLowerCase())}"]`) + console.log(tocLink); + markTocItemActive(tocLink); + } else { + console.log(`INACTIVE`); + console.log(heading); + console.log(`.toc a[href="${windowPath}#${encodeURIComponent(heading.id).replace(/%\w\w/g, match => match.toLowerCase())}"]`) + console.log(tocLink); + markTocItemInactive(tocLink); + } + }); + }, + { + //? docHeight: Extend the detection above the heading so it's always considered as intersecting if above the scrollport + //? -33%: The element won't be considered as intersecting until it has gone _above_ the bottom third of the scrollport + rootMargin: `${docHeight}px 0px -33% 0px`, + threshold: 1, // Only considered intersecting if all the pixels are inside the intersection area + } + ); + + headings.forEach((heading) => observer.observe(heading)); + + return observer; + } + + // On page load... + markTocItemActive(getTocLinkFromHeading(headings[0])); // Mark the first item as active (even if the heading appears a bit further down) + currentObserver = beginObservation(height); // Start the intersection observer + + // On resize, replace the observer with a new one matching the updated body height, if different + window.addEventListener('resize', () => { + clearTimeout(resizeDebounce); + resizeDebounce = setTimeout(() => { + const heightAfterResize = getDocHeight(); + if (height !== heightAfterResize) { + if (currentObserver) { + currentObserver.disconnect(); + } + currentObserver = beginObservation(heightAfterResize); + } + }, 200); + }); +}); diff --git a/assets/js/main.js b/assets/js/main.js index 0995dd38..9474364c 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -2,3 +2,4 @@ import './mobileMenu.js'; import './countrySelector.js'; import './resizeObserver.js'; import './mediaqueries.js'; +import './highlightHeadline.js'; \ No newline at end of file diff --git a/assets/sass/toc.scss b/assets/sass/toc.scss index 4fbd021d..68fe431b 100644 --- a/assets/sass/toc.scss +++ b/assets/sass/toc.scss @@ -12,4 +12,9 @@ .toc-title { font-weight: bold; +} + +.toc a[data-current] { + font-weight: bold; + color: #007bff; } \ No newline at end of file