From 654935f7583de9f64a6db9c6e56f3886b231a58e Mon Sep 17 00:00:00 2001 From: MoritzWeber Date: Fri, 21 Nov 2025 18:00:33 +0100 Subject: [PATCH 1/5] feat: Render FIP Validity from params --- archetypes/operator/index.en.md | 16 ++-- assets/sass/fipValidity.scss | 44 +++++++++++ assets/sass/main.scss | 1 + content/operator/sncf/index.de.md | 10 ++- content/operator/sncf/index.en.md | 10 ++- content/operator/sncf/index.fr.md | 10 ++- i18n/de.yaml | 5 ++ i18n/en.yaml | 5 ++ i18n/fr.yaml | 5 ++ layouts/shortcodes/fip-validity.html | 108 +++++++++++++++++++++++++++ 10 files changed, 196 insertions(+), 18 deletions(-) create mode 100644 assets/sass/fipValidity.scss create mode 100644 layouts/shortcodes/fip-validity.html diff --git a/archetypes/operator/index.en.md b/archetypes/operator/index.en.md index 31fe5d27..e99b24e2 100644 --- a/archetypes/operator/index.en.md +++ b/archetypes/operator/index.en.md @@ -8,6 +8,11 @@ country: - "country2" - "country3" operator: "{{ .File.ContentBaseName }}" +Params: + fip_coupon: true # + fip_coupon_relatives: false # + fip_50_ticket: true # + fip_global_fare: true # --- @@ -30,15 +35,14 @@ operator: "{{ .File.ContentBaseName }}" ## Validity of FIP Tickets +{{< fip-validity >}}{{< /fip-validity >}} + -FIP Coupon: <✅/⛔> \ -FIP Coupon for relatives: <✅/⛔> \ -FIP 50 Tickets: <✅/⛔> \ -FIP Global Fare: <✅/⛔> - diff --git a/assets/sass/fipValidity.scss b/assets/sass/fipValidity.scss new file mode 100644 index 00000000..55250f3a --- /dev/null +++ b/assets/sass/fipValidity.scss @@ -0,0 +1,44 @@ +.o-fip-validity { + display: flex; + flex-direction: column; + gap: 0.8rem; + margin-bottom: 1.2rem; + + &__tags { + display: flex; + flex-wrap: wrap; + gap: 0.6rem; + } + + &__footnotes { + display: flex; + flex-direction: column; + gap: 0.4rem; + font-size: 0.9em; + } + + &__footnote { + display: flex; + gap: 0.4rem; + align-items: baseline; + } + + &__footnote-number { + font-weight: 600; + flex-shrink: 0; + } + + &__footnote-text { + p { + margin: 0; + display: inline; + } + } + + &__note { + p { + margin: 0; + display: inline; + } + } +} diff --git a/assets/sass/main.scss b/assets/sass/main.scss index 639c39d7..a280e780 100644 --- a/assets/sass/main.scss +++ b/assets/sass/main.scss @@ -17,3 +17,4 @@ @import "startpage.scss"; @import "interactiveMap.scss"; @import "dropdown.scss"; +@import "fipValidity.scss"; diff --git a/content/operator/sncf/index.de.md b/content/operator/sncf/index.de.md index 22fe6bd4..a3099f24 100644 --- a/content/operator/sncf/index.de.md +++ b/content/operator/sncf/index.de.md @@ -10,6 +10,11 @@ country: - "belgium" - "luxembourg" operator: "sncf" +Params: + fip_coupon: true + fip_coupon_relatives: false + fip_50_ticket: true + fip_global_fare: true --- Die SNCF (Société Nationale des Chemins de fer Français) ist die französische Staatsbahn und die wichtigste Bahngesellschaft in Frankreich. Sie betreibt fast alle Fern- und Regionalzüge in Frankreich. @@ -24,10 +29,7 @@ Die SNCF (Société Nationale des Chemins de fer Français) ist die französisch ## Gültigkeit FIP Tickets -FIP Freifahrtschein: ✅ \ -FIP Freifahrt Angehörige: ⛔ \ -FIP 50 Tickets: ✅ \ -FIP Globalpreis: ✅ (Für internationale `TGV` Züge, siehe [Grenzüberschreitende TGV inOui / ICE Züge](#grenzüberschreitende-tgv-inoui--ice-züge)) +{{< fip-validity fip_global_fare_footnote="Für internationale `TGV` Züge, siehe [Grenzüberschreitende TGV inOui / ICE Züge](#grenzüberschreitende-tgv-inoui--ice-züge)">}} FIP Freifahrtscheine und FIP 50 Tickets sind auf Verbindungen der SNCF gültig. Bei grenzüberschreitenden Fahrten im Nahverkehr muss entweder ein durchgängiges FIP 50 Ticket oder FIP Freifahrtscheine beider Länder vorhanden sein. Auf internationalen Fernverkehrsverbindungen mittels `TGV` oder `ICE` gelten jedoch Globalpreise, siehe [Grenzüberschreitende TGV inOui / ICE Züge](#grenzüberschreitende-tgv-inoui--ice-züge). diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index 96bfe07a..7a8cc8e7 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -10,6 +10,11 @@ country: - "belgium" - "luxembourg" operator: "sncf" +Params: + fip_coupon: true + fip_coupon_relatives: false + fip_50_ticket: true + fip_global_fare: true --- SNCF (Société Nationale des Chemins de fer Français) is the French national railway company and the main rail operator in France. It operates almost all long-distance and regional trains in France. @@ -24,10 +29,7 @@ SNCF (Société Nationale des Chemins de fer Français) is the French national r ## Validity of FIP Tickets -FIP Coupon: ✅ \ -FIP Coupon for relatives: ⛔ \ -FIP 50 Ticket: ✅ \ -FIP Global Fare: ✅ (For international `TGV` trains, see [International TGV inOui / ICE trains](#international-tgv-inoui--ice-trains)) +{{< fip-validity fip_global_fare_footnote="For international `TGV` trains, see [International TGV inOui / ICE trains](#international-tgv-inoui--ice-trains)">}} FIP Coupons and FIP 50 Tickets are valid on SNCF services. For cross-border journeys on local trains, either a continuous FIP 50 Ticket or FIP Coupons for both countries are required. For international long-distance services (`TGV` or `ICE`), global fares apply (see [International TGV inOui / ICE trains](#international-tgv-inoui--ice-trains)). diff --git a/content/operator/sncf/index.fr.md b/content/operator/sncf/index.fr.md index 987479c2..8c84104c 100644 --- a/content/operator/sncf/index.fr.md +++ b/content/operator/sncf/index.fr.md @@ -10,6 +10,11 @@ country: - "belgium" - "luxembourg" operator: "sncf" +Params: + fip_coupon: true + fip_coupon_relatives: false + fip_50_ticket: true + fip_global_fare: true --- La SNCF (Société Nationale des Chemins de fer Français) est la compagnie ferroviaire nationale française et le principal opérateur ferroviaire en France. Elle exploite la quasi-totalité des trains grandes lignes et régionaux du pays. @@ -24,10 +29,7 @@ La SNCF (Société Nationale des Chemins de fer Français) est la compagnie ferr ## Validité des Billets FIP -Coupon FIP : ✅ \ -Coupon FIP accompagnant : ⛔ \ -Billet FIP 50 : ✅ \ -Tarif Global FIP : ✅ (pour les trains internationaux `TGV`, voir [Trains TGV inOui / ICE internationaux](#trains-tgv-inoui--ice-internationaux)) +{{< fip-validity fip_global_fare_footnote="pour les trains internationaux `TGV`, voir [Trains TGV inOui / ICE internationaux](#trains-tgv-inoui--ice-internationaux)">}} Les Coupons FIP et Billets FIP 50 sont valables sur les services SNCF. Pour les trajets transfrontaliers en trains régionaux, il faut soit un Billet FIP 50 continu, soit des Coupons FIP valables dans chaque pays. Sur les trains grandes lignes internationaux (`TGV` ou `ICE`), des Tarifs Globaux s’appliquent (voir [Trains TGV inOui / ICE internationaux](#trains-tgv-inoui--ice-internationaux)). diff --git a/i18n/de.yaml b/i18n/de.yaml index 084ce82a..5a7eee2c 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -27,6 +27,11 @@ country: other: Länder discord: FIP Guide Community editPage: Seite bearbeiten +fipValidity: + fip-50-ticket: FIP 50 Ticket + fip-coupon: FIP Freifahrtschein + fip-coupon-relatives: FIP Freifahrt Angehörige + fip-global-fare: FIP Globalpreis footer-love: aria-label: Made with love in Europe text: Made with ♥️ in Europe diff --git a/i18n/en.yaml b/i18n/en.yaml index 46bfa1ab..868ced39 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -26,6 +26,11 @@ country: other: countries discord: FIP Guide Community editPage: Edit page +fipValidity: + fip-50-ticket: FIP 50 Ticket + fip-coupon: FIP Coupon + fip-coupon-relatives: FIP Coupon for relatives + fip-global-fare: FIP Global Fare footer-love: aria-label: Made with love in Europe text: Made with ♥️ in Europe diff --git a/i18n/fr.yaml b/i18n/fr.yaml index fba8e28a..041b9a2c 100644 --- a/i18n/fr.yaml +++ b/i18n/fr.yaml @@ -27,6 +27,11 @@ country: countryselection: Choisir un pays discord: Communauté FIP Guide editPage: Modifier la page +fipValidity: + fip-50-ticket: Billet FIP 50 + fip-coupon: Coupon FIP + fip-coupon-relatives: Coupon FIP accompagnant + fip-global-fare: Tarif Global FIP footer-love: aria-label: Fait avec amour en Europe text: Fait avec ♥️ en Europe diff --git a/layouts/shortcodes/fip-validity.html b/layouts/shortcodes/fip-validity.html new file mode 100644 index 00000000..4a611d25 --- /dev/null +++ b/layouts/shortcodes/fip-validity.html @@ -0,0 +1,108 @@ +{{- $page := .Page -}} +{{- $footnotes := dict -}} + +{{- with .Get "fip_coupon_footnote" -}} + {{- $footnotes = merge $footnotes (dict "fip_coupon" .) -}} +{{- end -}} +{{- with .Get "fip_coupon_relatives_footnote" -}} + {{- $footnotes = merge $footnotes (dict "fip_coupon_relatives" .) -}} +{{- end -}} +{{- with .Get "fip_50_ticket_footnote" -}} + {{- $footnotes = merge $footnotes (dict "fip_50_ticket" .) -}} +{{- end -}} +{{- with .Get "fip_global_fare_footnote" -}} + {{- $footnotes = merge $footnotes (dict "fip_global_fare" .) -}} +{{- end -}} + +{{- $footnoteCounter := 0 -}} +{{- $footnoteMap := dict -}} + + +
+
+ {{- if isset $page.Params "fip_coupon" -}} + {{- $accepted := $page.Params.fip_coupon -}} + {{- $footnoteNum := "" -}} + {{- if isset $footnotes "fip_coupon" -}} + {{- $footnoteCounter = add $footnoteCounter 1 -}} + {{- $footnoteNum = printf "%d)" $footnoteCounter -}} + {{- $footnoteMap = merge $footnoteMap (dict (string $footnoteCounter) (index $footnotes "fip_coupon")) -}} + {{- end -}} + {{- partial "tag" ( + dict + "Icon" (cond $accepted "check_circle" "cancel") + "Text" "fipValidity.fip-coupon" + "Type" (cond $accepted "success" "error") + "Footnote" $footnoteNum + ) + }} + {{- end -}} + + {{- if isset $page.Params "fip_coupon_relatives" -}} + {{- $accepted := $page.Params.fip_coupon_relatives -}} + {{- $footnoteNum := "" -}} + {{- if isset $footnotes "fip_coupon_relatives" -}} + {{- $footnoteCounter = add $footnoteCounter 1 -}} + {{- $footnoteNum = printf "%d)" $footnoteCounter -}} + {{- $footnoteMap = merge $footnoteMap (dict (string $footnoteCounter) (index $footnotes "fip_coupon_relatives")) -}} + {{- end -}} + {{- partial "tag" ( + dict + "Icon" (cond $accepted "check_circle" "cancel") + "Text" "fipValidity.fip-coupon-relatives" + "Type" (cond $accepted "success" "error") + "Footnote" $footnoteNum + ) + }} + {{- end -}} + + {{- if isset $page.Params "fip_50_ticket" -}} + {{- $accepted := $page.Params.fip_50_ticket -}} + {{- $footnoteNum := "" -}} + {{- if isset $footnotes "fip_50_ticket" -}} + {{- $footnoteCounter = add $footnoteCounter 1 -}} + {{- $footnoteNum = printf "%d)" $footnoteCounter -}} + {{- $footnoteMap = merge $footnoteMap (dict (string $footnoteCounter) (index $footnotes "fip_50_ticket")) -}} + {{- end -}} + {{- partial "tag" ( + dict + "Icon" (cond $accepted "check_circle" "cancel") + "Text" "fipValidity.fip-50-ticket" + "Type" (cond $accepted "success" "error") + "Footnote" $footnoteNum + ) + }} + {{- end -}} + + {{- if isset $page.Params "fip_global_fare" -}} + {{- $accepted := $page.Params.fip_global_fare -}} + {{- $footnoteNum := "" -}} + {{- if isset $footnotes "fip_global_fare" -}} + {{- $footnoteCounter = add $footnoteCounter 1 -}} + {{- $footnoteNum = printf "%d)" $footnoteCounter -}} + {{- $footnoteMap = merge $footnoteMap (dict (string $footnoteCounter) (index $footnotes "fip_global_fare")) -}} + {{- end -}} + {{- partial "tag" ( + dict + "Icon" (cond $accepted "check_circle" "cancel") + "Text" "fipValidity.fip-global-fare" + "Type" (cond $accepted "success" "error") + "Footnote" $footnoteNum + ) + }} + {{- end -}} +
+ + {{- if gt (len $footnoteMap) 0 -}} +
+ {{- range $index, $text := $footnoteMap -}} +
+ {{ $index }}) + {{ $text | $page.RenderString }} +
+ {{- end -}} +
+ {{- end -}} +
From 68f6006a1b6ff633bc94848171b9f14d0b2369ba Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Fri, 21 Nov 2025 23:03:05 +0100 Subject: [PATCH 2/5] feat: Try another design for fip validity --- assets/sass/fipValidity.scss | 34 +---------- assets/sass/fipValidityItem.scss | 31 ++++++++++ assets/sass/main.scss | 1 + content/operator/sncf/index.en.md | 2 +- layouts/partials/fip-validity-item.html | 9 +++ layouts/shortcodes/fip-validity.html | 78 +++++++------------------ 6 files changed, 63 insertions(+), 92 deletions(-) create mode 100644 assets/sass/fipValidityItem.scss create mode 100644 layouts/partials/fip-validity-item.html diff --git a/assets/sass/fipValidity.scss b/assets/sass/fipValidity.scss index 55250f3a..7b29ceb2 100644 --- a/assets/sass/fipValidity.scss +++ b/assets/sass/fipValidity.scss @@ -5,40 +5,8 @@ margin-bottom: 1.2rem; &__tags { - display: flex; - flex-wrap: wrap; - gap: 0.6rem; - } - - &__footnotes { display: flex; flex-direction: column; - gap: 0.4rem; - font-size: 0.9em; - } - - &__footnote { - display: flex; - gap: 0.4rem; - align-items: baseline; - } - - &__footnote-number { - font-weight: 600; - flex-shrink: 0; - } - - &__footnote-text { - p { - margin: 0; - display: inline; - } - } - - &__note { - p { - margin: 0; - display: inline; - } + gap: 0.8rem; } } diff --git a/assets/sass/fipValidityItem.scss b/assets/sass/fipValidityItem.scss new file mode 100644 index 00000000..1cca4076 --- /dev/null +++ b/assets/sass/fipValidityItem.scss @@ -0,0 +1,31 @@ +.a-fip-validity-item { + display: flex; + align-items: flex-start; + gap: 0.5rem; + font-size: 0.95em; + font-weight: 400; + line-height: 1.2em; + + @each $name, $color in $tag-colors { + &--#{$name} { + color: var(--tag-#{$name}-color); + } + } + + &__content { + display: flex; + flex-direction: column; + gap: 0.2rem; + } + + &__note { + font-size: 0.8em; + color: var(--color-body); + font-weight: 400; + + p { + margin: 0; + display: inline; + } + } +} diff --git a/assets/sass/main.scss b/assets/sass/main.scss index a280e780..fdbd0771 100644 --- a/assets/sass/main.scss +++ b/assets/sass/main.scss @@ -18,3 +18,4 @@ @import "interactiveMap.scss"; @import "dropdown.scss"; @import "fipValidity.scss"; +@import "fipValidityItem.scss"; diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index 7a8cc8e7..14bcb38a 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -29,7 +29,7 @@ SNCF (Société Nationale des Chemins de fer Français) is the French national r ## Validity of FIP Tickets -{{< fip-validity fip_global_fare_footnote="For international `TGV` trains, see [International TGV inOui / ICE trains](#international-tgv-inoui--ice-trains)">}} +{{< fip-validity fip_global_fare_footnote="Only for international `TGV` trains, see [International TGV inOui / ICE trains](#international-tgv-inoui--ice-trains)">}} FIP Coupons and FIP 50 Tickets are valid on SNCF services. For cross-border journeys on local trains, either a continuous FIP 50 Ticket or FIP Coupons for both countries are required. For international long-distance services (`TGV` or `ICE`), global fares apply (see [International TGV inOui / ICE trains](#international-tgv-inoui--ice-trains)). diff --git a/layouts/partials/fip-validity-item.html b/layouts/partials/fip-validity-item.html new file mode 100644 index 00000000..8d06d68b --- /dev/null +++ b/layouts/partials/fip-validity-item.html @@ -0,0 +1,9 @@ +
+ {{ partial "icon" .Icon }} +
+ {{ i18n .Text }} + {{- with .Note -}} + {{ . }} + {{- end -}} +
+
diff --git a/layouts/shortcodes/fip-validity.html b/layouts/shortcodes/fip-validity.html index 4a611d25..df5ebf54 100644 --- a/layouts/shortcodes/fip-validity.html +++ b/layouts/shortcodes/fip-validity.html @@ -1,108 +1,70 @@ {{- $page := .Page -}} -{{- $footnotes := dict -}} - -{{- with .Get "fip_coupon_footnote" -}} - {{- $footnotes = merge $footnotes (dict "fip_coupon" .) -}} -{{- end -}} -{{- with .Get "fip_coupon_relatives_footnote" -}} - {{- $footnotes = merge $footnotes (dict "fip_coupon_relatives" .) -}} -{{- end -}} -{{- with .Get "fip_50_ticket_footnote" -}} - {{- $footnotes = merge $footnotes (dict "fip_50_ticket" .) -}} -{{- end -}} -{{- with .Get "fip_global_fare_footnote" -}} - {{- $footnotes = merge $footnotes (dict "fip_global_fare" .) -}} -{{- end -}} - -{{- $footnoteCounter := 0 -}} -{{- $footnoteMap := dict -}}
{{- if isset $page.Params "fip_coupon" -}} {{- $accepted := $page.Params.fip_coupon -}} - {{- $footnoteNum := "" -}} - {{- if isset $footnotes "fip_coupon" -}} - {{- $footnoteCounter = add $footnoteCounter 1 -}} - {{- $footnoteNum = printf "%d)" $footnoteCounter -}} - {{- $footnoteMap = merge $footnoteMap (dict (string $footnoteCounter) (index $footnotes "fip_coupon")) -}} + {{- $note := "" -}} + {{- with .Get "fip_coupon_footnote" -}} + {{- $note = $page.RenderString . -}} {{- end -}} - {{- partial "tag" ( + {{- partial "fip-validity-item" ( dict "Icon" (cond $accepted "check_circle" "cancel") "Text" "fipValidity.fip-coupon" "Type" (cond $accepted "success" "error") - "Footnote" $footnoteNum + "Note" $note ) }} {{- end -}} {{- if isset $page.Params "fip_coupon_relatives" -}} {{- $accepted := $page.Params.fip_coupon_relatives -}} - {{- $footnoteNum := "" -}} - {{- if isset $footnotes "fip_coupon_relatives" -}} - {{- $footnoteCounter = add $footnoteCounter 1 -}} - {{- $footnoteNum = printf "%d)" $footnoteCounter -}} - {{- $footnoteMap = merge $footnoteMap (dict (string $footnoteCounter) (index $footnotes "fip_coupon_relatives")) -}} + {{- $note := "" -}} + {{- with .Get "fip_coupon_relatives_footnote" -}} + {{- $note = $page.RenderString . -}} {{- end -}} - {{- partial "tag" ( + {{- partial "fip-validity-item" ( dict "Icon" (cond $accepted "check_circle" "cancel") "Text" "fipValidity.fip-coupon-relatives" "Type" (cond $accepted "success" "error") - "Footnote" $footnoteNum + "Note" $note ) }} {{- end -}} {{- if isset $page.Params "fip_50_ticket" -}} {{- $accepted := $page.Params.fip_50_ticket -}} - {{- $footnoteNum := "" -}} - {{- if isset $footnotes "fip_50_ticket" -}} - {{- $footnoteCounter = add $footnoteCounter 1 -}} - {{- $footnoteNum = printf "%d)" $footnoteCounter -}} - {{- $footnoteMap = merge $footnoteMap (dict (string $footnoteCounter) (index $footnotes "fip_50_ticket")) -}} + {{- $note := "" -}} + {{- with .Get "fip_50_ticket_footnote" -}} + {{- $note = $page.RenderString . -}} {{- end -}} - {{- partial "tag" ( + {{- partial "fip-validity-item" ( dict "Icon" (cond $accepted "check_circle" "cancel") "Text" "fipValidity.fip-50-ticket" "Type" (cond $accepted "success" "error") - "Footnote" $footnoteNum + "Note" $note ) }} {{- end -}} {{- if isset $page.Params "fip_global_fare" -}} {{- $accepted := $page.Params.fip_global_fare -}} - {{- $footnoteNum := "" -}} - {{- if isset $footnotes "fip_global_fare" -}} - {{- $footnoteCounter = add $footnoteCounter 1 -}} - {{- $footnoteNum = printf "%d)" $footnoteCounter -}} - {{- $footnoteMap = merge $footnoteMap (dict (string $footnoteCounter) (index $footnotes "fip_global_fare")) -}} + {{- $note := "" -}} + {{- with .Get "fip_global_fare_footnote" -}} + {{- $note = $page.RenderString . -}} {{- end -}} - {{- partial "tag" ( + {{- partial "fip-validity-item" ( dict "Icon" (cond $accepted "check_circle" "cancel") "Text" "fipValidity.fip-global-fare" "Type" (cond $accepted "success" "error") - "Footnote" $footnoteNum + "Note" $note ) }} {{- end -}}
- - {{- if gt (len $footnoteMap) 0 -}} -
- {{- range $index, $text := $footnoteMap -}} -
- {{ $index }}) - {{ $text | $page.RenderString }} -
- {{- end -}} -
- {{- end -}}
From eb7392a5234ba1a7b54fd2acaa3ed91e84100e53 Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Sat, 22 Nov 2025 22:07:28 +0100 Subject: [PATCH 3/5] feat: Show FIP coupon for relatives for each operator --- assets/js/main.js | 1 + assets/js/modal.js | 50 +++++++++ assets/sass/_variables.scss | 14 +++ assets/sass/fipValidityItem.scss | 48 +++++++- assets/sass/main.scss | 1 + assets/sass/modal.scss | 139 ++++++++++++++++++++++++ content/operator/sncf/index.de.md | 4 +- content/operator/sncf/index.en.md | 4 +- content/operator/sncf/index.fr.md | 4 +- i18n/de.yaml | 11 ++ i18n/en.yaml | 11 ++ i18n/fr.yaml | 11 ++ layouts/partials/fip-validity-item.html | 117 +++++++++++++++++++- layouts/shortcodes/fip-validity.html | 9 +- 14 files changed, 413 insertions(+), 11 deletions(-) create mode 100644 assets/js/modal.js create mode 100644 assets/sass/modal.scss diff --git a/assets/js/main.js b/assets/js/main.js index b2b525c6..14301965 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -8,3 +8,4 @@ import "./dropdown.js"; import "./darkmode.js"; import "./search.js"; import "./interactiveMap.js"; +import "./modal.js"; diff --git a/assets/js/modal.js b/assets/js/modal.js new file mode 100644 index 00000000..19901ff1 --- /dev/null +++ b/assets/js/modal.js @@ -0,0 +1,50 @@ +document.addEventListener("DOMContentLoaded", () => { + const modalTriggers = document.querySelectorAll("[data-modal-trigger]"); + const modalCloseButtons = document.querySelectorAll("[data-modal-close]"); + + modalTriggers.forEach((trigger) => { + trigger.addEventListener("click", (e) => { + e.preventDefault(); + const modalId = trigger.getAttribute("data-modal-trigger"); + const modal = document.getElementById(modalId); + if (modal) { + openModal(modal); + } + }); + }); + + modalCloseButtons.forEach((button) => { + button.addEventListener("click", () => { + const modal = button.closest(".o-modal"); + if (modal) { + closeModal(modal); + } + }); + }); + + document.addEventListener("keydown", (e) => { + if (e.key === "Escape") { + const openModal = document.querySelector('.o-modal[aria-hidden="false"]'); + if (openModal) { + closeModal(openModal); + } + } + }); + + function openModal(modal) { + modal.setAttribute("aria-hidden", "false"); + document.body.style.overflow = "hidden"; + + const firstFocusable = modal.querySelector( + 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])', + ); + if (firstFocusable) { + firstFocusable.focus(); + } + } + + function closeModal(modal) { + modal.setAttribute("aria-hidden", "true"); + document.body.style.overflow = ""; + } +}); diff --git a/assets/sass/_variables.scss b/assets/sass/_variables.scss index 5a55b60b..7f5bc397 100644 --- a/assets/sass/_variables.scss +++ b/assets/sass/_variables.scss @@ -14,6 +14,14 @@ $bg-code: #fff284; $color-onLight: #000000; $color-table-border: #5b5b5b; +$fip-validity-accepted: #155724; +$fip-validity-rejected: #b70000; +$fip-validity-warning: #b64900; + +$fip-validity-accepted-dark: #a8d5ba; +$fip-validity-rejected-dark: #f5a9ae; +$fip-validity-warning-dark: #f0d98d; + html { --pagefind-ui-scale: 1 !important; --pagefind-ui-text: #000; @@ -27,6 +35,9 @@ html { --color-onLight: #{$color-onLight}; --color-table-border: #{$color-table-border}; --color-body: rgb(33, 37, 41); + --fip-validity-accepted: #{$fip-validity-accepted}; + --fip-validity-rejected: #{$fip-validity-rejected}; + --fip-validity-warning: #{$fip-validity-warning}; --border-radius-s: 0.4rem; --border-radius-m: 0.8rem; --border-radius-l: 1.6rem; @@ -57,6 +68,9 @@ html[data-theme="dark"] { --color-onLight: #ffffff; --color-table-border: #555; --color-body: #e0e0e0; + --fip-validity-accepted: #{$fip-validity-accepted-dark}; + --fip-validity-rejected: #{$fip-validity-rejected-dark}; + --fip-validity-warning: #{$fip-validity-warning-dark}; --pagefind-ui-border: #555; --box-shadow: 0 0.4rem 1rem rgba(0, 0, 0, 0.5); --box-shadow-light: 0.4rem 0.4rem 0.4rem rgba(0, 0, 0, 0.3); diff --git a/assets/sass/fipValidityItem.scss b/assets/sass/fipValidityItem.scss index 1cca4076..24cf6b7c 100644 --- a/assets/sass/fipValidityItem.scss +++ b/assets/sass/fipValidityItem.scss @@ -6,10 +6,21 @@ font-weight: 400; line-height: 1.2em; - @each $name, $color in $tag-colors { - &--#{$name} { - color: var(--tag-#{$name}-color); - } + svg { + margin-top: 0.15em; + } + + &--success { + color: var(--fip-validity-accepted); + } + + &--error { + color: var(--fip-validity-rejected); + } + + &--info { + color: var(--color-body); + opacity: 0.85; } &__content { @@ -18,6 +29,35 @@ gap: 0.2rem; } + &__text { + display: flex; + align-items: center; + gap: 0.3rem; + } + + &__info-button { + background: none; + border: none; + padding: 0; + cursor: pointer; + color: var(--color-body); + display: inline-flex; + align-items: center; + justify-content: center; + opacity: 0.7; + transition: opacity 0.2s ease; + + &:hover { + opacity: 1; + } + + svg { + width: 1.2em; + height: 1.2em; + margin-top: 0; + } + } + &__note { font-size: 0.8em; color: var(--color-body); diff --git a/assets/sass/main.scss b/assets/sass/main.scss index fdbd0771..c8323ba1 100644 --- a/assets/sass/main.scss +++ b/assets/sass/main.scss @@ -19,3 +19,4 @@ @import "dropdown.scss"; @import "fipValidity.scss"; @import "fipValidityItem.scss"; +@import "modal.scss"; diff --git a/assets/sass/modal.scss b/assets/sass/modal.scss new file mode 100644 index 00000000..b9a464cf --- /dev/null +++ b/assets/sass/modal.scss @@ -0,0 +1,139 @@ +.o-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + opacity: 0; + pointer-events: none; + transition: opacity 0.3s ease; + + &[aria-hidden="false"] { + opacity: 1; + pointer-events: auto; + } + + &__overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + } + + &__container { + position: relative; + background: var(--bg-default); + border-radius: var(--border-radius-m); + box-shadow: var(--box-shadow); + max-width: 90vw; + max-height: 90vh; + width: 60rem; + display: flex; + flex-direction: column; + z-index: 1; + } + + &__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1.5rem; + border-bottom: var(--border); + } + + &__title { + margin: 0; + font-size: 1.5rem; + font-weight: 600; + } + + &__close { + background: none; + border: none; + padding: 0.5rem; + cursor: pointer; + color: var(--color-body); + display: flex; + align-items: center; + justify-content: center; + border-radius: var(--border-radius-s); + transition: background 0.2s ease; + + &:hover { + background: var(--bg-neutral); + } + + svg { + width: 1.5rem; + height: 1.5rem; + } + } + + &__content { + padding: 0 1.5rem 1.5rem 1.5rem; + overflow: hidden; + display: flex; + flex-direction: column; + } + + &__description { + margin-bottom: 1.5rem; + color: var(--color-body); + flex-shrink: 0; + } + + &__table-wrapper { + overflow-y: auto; + flex: 1; + min-height: 0; + } + + &__table { + width: 100%; + margin-left: 0; + margin-bottom: 0; + + &--body { + margin-top: 0; + } + + a { + color: var(--link-default); + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + } + + &__status { + display: flex; + align-items: center; + gap: 0.5rem; + + svg { + width: 1.2rem; + height: 1.2rem; + } + + &--yes { + color: var(--fip-validity-accepted); + } + + &--no { + color: var(--fip-validity-rejected); + } + + &--unknown { + color: var(--color-body); + opacity: 0.6; + } + } +} diff --git a/content/operator/sncf/index.de.md b/content/operator/sncf/index.de.md index a3099f24..f0acc517 100644 --- a/content/operator/sncf/index.de.md +++ b/content/operator/sncf/index.de.md @@ -12,7 +12,9 @@ country: operator: "sncf" Params: fip_coupon: true - fip_coupon_relatives: false + fip_coupon_relatives: + oebb: true + renfe: false fip_50_ticket: true fip_global_fare: true --- diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index 14bcb38a..0efcdeca 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -12,7 +12,9 @@ country: operator: "sncf" Params: fip_coupon: true - fip_coupon_relatives: false + fip_coupon_relatives: + oebb: true + renfe: false fip_50_ticket: true fip_global_fare: true --- diff --git a/content/operator/sncf/index.fr.md b/content/operator/sncf/index.fr.md index 8c84104c..ef59f9ff 100644 --- a/content/operator/sncf/index.fr.md +++ b/content/operator/sncf/index.fr.md @@ -12,7 +12,9 @@ country: operator: "sncf" Params: fip_coupon: true - fip_coupon_relatives: false + fip_coupon_relatives: + oebb: true + renfe: false fip_50_ticket: true fip_global_fare: true --- diff --git a/i18n/de.yaml b/i18n/de.yaml index 5a7eee2c..b424d0c1 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -28,10 +28,21 @@ country: discord: FIP Guide Community editPage: Seite bearbeiten fipValidity: + close-modal: Schließen fip-50-ticket: FIP 50 Ticket fip-coupon: FIP Freifahrtschein fip-coupon-relatives: FIP Freifahrt Angehörige fip-global-fare: FIP Globalpreis + issuer: Aussteller des FIP Ausweises + relatives-available: FIP Freifahrt Angehörige verfügbar + relatives-modal-description: >- + Die Verfügbarkeit von FIP Freifahrt Angehörige hängt von der + Bahngesellschaft ab, die deinen FIP Ausweis ausgestellt hat. + relatives-modal-title: FIP Freifahrt Angehörige nach Betreiber + show-relatives-info: Informationen zu FIP Freifahrt Angehörige anzeigen + status-no: Nicht akzeptiert + status-unknown: Unbekannt + status-yes: Akzeptiert footer-love: aria-label: Made with love in Europe text: Made with ♥️ in Europe diff --git a/i18n/en.yaml b/i18n/en.yaml index 868ced39..2453a217 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -27,10 +27,21 @@ country: discord: FIP Guide Community editPage: Edit page fipValidity: + close-modal: Close fip-50-ticket: FIP 50 Ticket fip-coupon: FIP Coupon fip-coupon-relatives: FIP Coupon for relatives fip-global-fare: FIP Global Fare + issuer: Issuer of the FIP card + relatives-available: FIP Coupon for relatives available + relatives-modal-description: >- + The availability of FIP Coupon for relatives depends on the railway company + that issued your FIP card. + relatives-modal-title: FIP Coupon for relatives by Operator + show-relatives-info: Show information about FIP Coupon for relatives + status-no: Not accepted + status-unknown: Unknown + status-yes: Accepted footer-love: aria-label: Made with love in Europe text: Made with ♥️ in Europe diff --git a/i18n/fr.yaml b/i18n/fr.yaml index 041b9a2c..709114ed 100644 --- a/i18n/fr.yaml +++ b/i18n/fr.yaml @@ -28,10 +28,21 @@ countryselection: Choisir un pays discord: Communauté FIP Guide editPage: Modifier la page fipValidity: + close-modal: Fermer fip-50-ticket: Billet FIP 50 fip-coupon: Coupon FIP fip-coupon-relatives: Coupon FIP accompagnant fip-global-fare: Tarif Global FIP + issuer: Émetteur de la carte FIP + relatives-available: Coupon FIP accompagnant disponible + relatives-modal-description: >- + La disponibilité du Coupon FIP accompagnant dépend de la compagnie + ferroviaire qui a émis votre carte FIP. + relatives-modal-title: Coupon FIP accompagnant par opérateur + show-relatives-info: Afficher les informations sur le Coupon FIP accompagnant + status-no: Non accepté + status-unknown: Inconnu + status-yes: Accepté footer-love: aria-label: Fait avec amour en Europe text: Fait avec ♥️ en Europe diff --git a/layouts/partials/fip-validity-item.html b/layouts/partials/fip-validity-item.html index 8d06d68b..d77e98db 100644 --- a/layouts/partials/fip-validity-item.html +++ b/layouts/partials/fip-validity-item.html @@ -1,9 +1,124 @@
{{ partial "icon" .Icon }}
- {{ i18n .Text }} + + {{ i18n .Text }} + {{- if .ShowRelativesInfo -}} + + {{- end -}} + {{- with .Note -}} {{ . }} {{- end -}}
+ +{{- if .ShowRelativesInfo -}} + +{{- end -}} diff --git a/layouts/shortcodes/fip-validity.html b/layouts/shortcodes/fip-validity.html index df5ebf54..50fc8ae2 100644 --- a/layouts/shortcodes/fip-validity.html +++ b/layouts/shortcodes/fip-validity.html @@ -20,17 +20,20 @@ {{- end -}} {{- if isset $page.Params "fip_coupon_relatives" -}} - {{- $accepted := $page.Params.fip_coupon_relatives -}} {{- $note := "" -}} + {{- with .Get "fip_coupon_relatives_footnote" -}} {{- $note = $page.RenderString . -}} {{- end -}} + {{- partial "fip-validity-item" ( dict - "Icon" (cond $accepted "check_circle" "cancel") + "Icon" "help" "Text" "fipValidity.fip-coupon-relatives" - "Type" (cond $accepted "success" "error") + "Type" "info" "Note" $note + "ShowRelativesInfo" true + "Page" $page ) }} {{- end -}} From 0d13efc9aa102a73d1255ed7895bb76899b65269 Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Sun, 23 Nov 2025 16:32:19 +0100 Subject: [PATCH 4/5] feat: Add modals for FIP 50 ticket and FIP coupon --- content/operator/sncf/index.de.md | 6 + content/operator/sncf/index.en.md | 6 + content/operator/sncf/index.fr.md | 6 + i18n/de.yaml | 13 ++ i18n/en.yaml | 13 ++ i18n/fr.yaml | 13 ++ layouts/partials/fip-validity-item.html | 200 ++++++++++++++++++++++++ layouts/shortcodes/fip-validity.html | 4 + 8 files changed, 261 insertions(+) diff --git a/content/operator/sncf/index.de.md b/content/operator/sncf/index.de.md index f0acc517..956ad015 100644 --- a/content/operator/sncf/index.de.md +++ b/content/operator/sncf/index.de.md @@ -12,10 +12,16 @@ country: operator: "sncf" Params: fip_coupon: true + fip_coupon_fields: + oebb: 4 + renfe: 2 fip_coupon_relatives: oebb: true renfe: false fip_50_ticket: true + fip_50_ticket_discount: + oebb: 25 + renfe: 75 fip_global_fare: true --- diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index 0efcdeca..6ff0efac 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -12,10 +12,16 @@ country: operator: "sncf" Params: fip_coupon: true + fip_coupon_fields: + oebb: 4 + renfe: 2 fip_coupon_relatives: oebb: true renfe: false fip_50_ticket: true + fip_50_ticket_discount: + oebb: 25 + renfe: 75 fip_global_fare: true --- diff --git a/content/operator/sncf/index.fr.md b/content/operator/sncf/index.fr.md index ef59f9ff..801913c4 100644 --- a/content/operator/sncf/index.fr.md +++ b/content/operator/sncf/index.fr.md @@ -12,10 +12,16 @@ country: operator: "sncf" Params: fip_coupon: true + fip_coupon_fields: + oebb: 4 + renfe: 2 fip_coupon_relatives: oebb: true renfe: false fip_50_ticket: true + fip_50_ticket_discount: + oebb: 25 + renfe: 75 fip_global_fare: true --- diff --git a/i18n/de.yaml b/i18n/de.yaml index b424d0c1..c8753a72 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -29,8 +29,19 @@ discord: FIP Guide Community editPage: Seite bearbeiten fipValidity: close-modal: Schließen + discount: Rabatt + fields: Felder fip-50-ticket: FIP 50 Ticket + fip-50-ticket-discount-modal-description: >- + Der Rabatt auf den regulären Fahrpreis für FIP 50 Tickets hängt von der + Bahngesellschaft ab, die deinen FIP Ausweis ausgestellt hat. + fip-50-ticket-discount-modal-title: FIP 50 Ticket Rabatt nach Betreiber fip-coupon: FIP Freifahrtschein + fip-coupon-fields-modal-description: >- + Die maximale Anzahl der Felder auf dem FIP Freifahrtschein hängt von der + Bahngesellschaft ab, die deinen FIP Ausweis ausgestellt hat. + fip-coupon-fields-modal-title: FIP Freifahrtschein Felder nach Betreiber + fip-coupon-fields-value: '%d Felder' fip-coupon-relatives: FIP Freifahrt Angehörige fip-global-fare: FIP Globalpreis issuer: Aussteller des FIP Ausweises @@ -39,6 +50,8 @@ fipValidity: Die Verfügbarkeit von FIP Freifahrt Angehörige hängt von der Bahngesellschaft ab, die deinen FIP Ausweis ausgestellt hat. relatives-modal-title: FIP Freifahrt Angehörige nach Betreiber + show-50-ticket-discount-info: Informationen zu FIP 50 Ticket Rabatten anzeigen + show-coupon-fields-info: Informationen zu FIP Freifahrtschein Feldern anzeigen show-relatives-info: Informationen zu FIP Freifahrt Angehörige anzeigen status-no: Nicht akzeptiert status-unknown: Unbekannt diff --git a/i18n/en.yaml b/i18n/en.yaml index 2453a217..34808d6f 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -28,8 +28,19 @@ discord: FIP Guide Community editPage: Edit page fipValidity: close-modal: Close + discount: Discount + fields: Fields fip-50-ticket: FIP 50 Ticket + fip-50-ticket-discount-modal-description: >- + The discount on the regular fare for FIP 50 Tickets depends on the railway + company that issued your FIP card. + fip-50-ticket-discount-modal-title: FIP 50 Ticket Discount by Operator fip-coupon: FIP Coupon + fip-coupon-fields-modal-description: >- + The maximum number of fields on the FIP Coupon depends on the railway + company that issued your FIP card. + fip-coupon-fields-modal-title: FIP Coupon Fields by Operator + fip-coupon-fields-value: '%d fields' fip-coupon-relatives: FIP Coupon for relatives fip-global-fare: FIP Global Fare issuer: Issuer of the FIP card @@ -38,6 +49,8 @@ fipValidity: The availability of FIP Coupon for relatives depends on the railway company that issued your FIP card. relatives-modal-title: FIP Coupon for relatives by Operator + show-50-ticket-discount-info: Show information about FIP 50 Ticket discounts + show-coupon-fields-info: Show information about FIP Coupon fields show-relatives-info: Show information about FIP Coupon for relatives status-no: Not accepted status-unknown: Unknown diff --git a/i18n/fr.yaml b/i18n/fr.yaml index 709114ed..e4d6d441 100644 --- a/i18n/fr.yaml +++ b/i18n/fr.yaml @@ -29,8 +29,19 @@ discord: Communauté FIP Guide editPage: Modifier la page fipValidity: close-modal: Fermer + discount: Réduction + fields: Champs fip-50-ticket: Billet FIP 50 + fip-50-ticket-discount-modal-description: >- + La réduction sur le tarif régulier pour les Billets FIP 50 dépend de la + compagnie ferroviaire qui a émis votre carte FIP. + fip-50-ticket-discount-modal-title: Réduction Billet FIP 50 par opérateur fip-coupon: Coupon FIP + fip-coupon-fields-modal-description: >- + Le nombre maximum de champs sur le Coupon FIP dépend de la compagnie + ferroviaire qui a émis votre carte FIP. + fip-coupon-fields-modal-title: Champs du Coupon FIP par opérateur + fip-coupon-fields-value: '%d champs' fip-coupon-relatives: Coupon FIP accompagnant fip-global-fare: Tarif Global FIP issuer: Émetteur de la carte FIP @@ -39,6 +50,8 @@ fipValidity: La disponibilité du Coupon FIP accompagnant dépend de la compagnie ferroviaire qui a émis votre carte FIP. relatives-modal-title: Coupon FIP accompagnant par opérateur + show-50-ticket-discount-info: Afficher les informations sur les réductions Billet FIP 50 + show-coupon-fields-info: Afficher les informations sur les champs du Coupon FIP show-relatives-info: Afficher les informations sur le Coupon FIP accompagnant status-no: Non accepté status-unknown: Inconnu diff --git a/layouts/partials/fip-validity-item.html b/layouts/partials/fip-validity-item.html index d77e98db..6e5df3f4 100644 --- a/layouts/partials/fip-validity-item.html +++ b/layouts/partials/fip-validity-item.html @@ -3,6 +3,24 @@
{{ i18n .Text }} + {{- if .ShowCouponFieldsInfo -}} + + {{- end -}} + {{- if .Show50TicketDiscountInfo -}} + + {{- end -}} {{- if .ShowRelativesInfo -}}
+{{- if .ShowCouponFieldsInfo -}} + +{{- end -}} + +{{- if .Show50TicketDiscountInfo -}} + +{{- end -}} + {{- if .ShowRelativesInfo -}}