From 7bdd5b2047679fed9415646d716052bbff6e9e4b Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Tue, 14 Oct 2025 23:37:28 +0200 Subject: [PATCH 01/20] feat: Add train category expander --- assets/sass/main.scss | 1 + assets/sass/trainCategory.scss | 150 +++++++++++++++++++++++++ content/operator/sncf/index.en.md | 100 +++++++++-------- layouts/partials/train-category.html | 61 ++++++++++ layouts/shortcodes/train-category.html | 17 +++ 5 files changed, 282 insertions(+), 47 deletions(-) create mode 100644 assets/sass/trainCategory.scss create mode 100644 layouts/partials/train-category.html create mode 100644 layouts/shortcodes/train-category.html diff --git a/assets/sass/main.scss b/assets/sass/main.scss index 639c39d7..73bd963b 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 "trainCategory.scss"; diff --git a/assets/sass/trainCategory.scss b/assets/sass/trainCategory.scss new file mode 100644 index 00000000..0afffb09 --- /dev/null +++ b/assets/sass/trainCategory.scss @@ -0,0 +1,150 @@ +.o-train-category__header { + width: 100%; + + &-content { + display: flex; + flex-direction: column; + gap: 0.8rem; + width: 100%; + } +} + +.o-train-category__title-wrapper { + width: 100%; +} + +.o-train-category__title { + display: flex; + align-items: center; + gap: 0.5rem; + font-weight: 600; + font-size: 1.6rem; + + &-text { + flex: 1; + } +} + +.o-train-category__tags { + display: flex; + flex-wrap: wrap; + gap: 0.6rem; +} + +.o-train-category__tag { + display: flex; + align-items: center; + gap: 0.4rem; + padding: 0.4rem 0.8rem; + border-radius: var(--border-radius-s); + font-size: 1.2rem; + font-weight: 500; + white-space: nowrap; + + &--accepted { + background: #d4edda; + color: #155724; + border: 0.1rem solid #c3e6cb; + } + + &--rejected { + background: #f8d7da; + color: #721c24; + border: 0.1rem solid #f5c6cb; + } + + &--required { + background: #fff3cd; + color: #856404; + border: 0.1rem solid #ffeaa7; + } + + &--possible { + background: #cce7ff; + color: #004085; + border: 0.1rem solid #b3d9ff; + } + + &--none { + background: #e2e3e5; + color: #383d41; + border: 0.1rem solid #d6d8db; + } + + &--info { + background: #e7f3ff; + color: #0c5460; + border: 0.1rem solid #bee5eb; + } +} + +.o-train-category__content { + margin-top: 1rem; +} + +.o-train-category__info { + padding: 0.8rem; + margin-bottom: 1rem; + background: #e7f3ff; + border: 0.1rem solid #bee5eb; + border-radius: var(--border-radius-s); + color: #0c5460; + font-style: italic; +} + +.o-expander__summary--train-category { + &:hover, + &:focus { + .o-train-category__title-text { + text-decoration: underline; + } + } +} + +html[data-theme="dark"] { + .o-train-category { + &__info { + background: #0c3544; + border-color: #17a2b8; + color: #bee5eb; + } + + &__tag { + &--accepted { + background: #2d5a3d; + color: #a3d5ab; + border-color: #4a7c59; + } + + &--rejected { + background: #5a2d32; + color: #f5a3ab; + border-color: #7c4a52; + } + + &--required { + background: #5a4d2d; + color: #f5e6a3; + border-color: #7c6a4a; + } + + &--possible { + background: #2d4a5a; + color: #a3d5f5; + border-color: #4a6a7c; + } + + &--none { + background: #3d3d3d; + color: #d0d0d0; + border-color: #5a5a5a; + } + + &--info { + background: #0c3544; + color: #bee5eb; + border-color: #17a2b8; + } + } + } +} diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index 96bfe07a..9cdb74be 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -37,78 +37,84 @@ Reservations are mandatory on all `TGV`, almost all `IC` trains, and some region ### Long-distance -{{% expander "Train à grande vitesse inOui (TGV inOui) ⚠️ℹ️" traincategory "long-distance" %}} -**Description:** \ +{{% train-category + title="Train à grande vitesse inOui (TGV inOui)" + fip_accepted=true + reservation_required=true + info_available=true +%}} The `TGV` inOui is SNCF's high-speed train, connecting many cities in France and international destinations (e.g. Munich, Frankfurt am Main, Barcelona, Luxembourg, Brussels, Zurich, Milan). [Route overview](https://www.sncf-connect.com/assets/media/2021-05/2014_axes-tgv_0.pdf). Each seat number exists twice in the carriage; the reserved seat is the one with the illuminated number. -ℹ️ SNCF also operates low-cost `TGV` trains under the name OuiGo, which are not valid with FIP. +{{% highlight inofficial %}} +SNCF also operates low-cost `TGV` trains under the name OuiGo, which are not valid with FIP. +{{% /highlight %}} + +{{% highlight important %}} +Special conditions apply for international connections, see International TGV inOui / ICE trains section below. +{{% /highlight %}} -⚠️ Special conditions apply for international connections, see [International TGV inOui / ICE trains](#international-tgv-inoui--ice-trains). \ -**Reservation possible:** yes \ -**Reservation required:** yes ⚠️ \ **Reservation cost:** \ Prices differ between peak and off-peak trains. Off-peak: €1.70 (1st/2nd class); peak: €15 (1st class), €10 (2nd class). The classification is not publicly available. -{{% /expander %}} +{{% /train-category %}} -{{% expander "Train à grande vitesse OuiGo (TGV OuiGo) / OuiGo Train Classique ⛔⚠️ℹ️" traincategory "long-distance" %}} -**Description:** \ +{{% train-category + title="Train à grande vitesse OuiGo (TGV OuiGo) / OuiGo Train Classique" + fip_accepted=false + reservation_required=true +%}} The `TGV` OuiGo is SNCF's low-cost high-speed train, serving many cities in France and some international destinations. +{{% /train-category %}} -ℹ️ SNCF also operates `TGV` trains under the inOui brand, which are valid with FIP. \ -**Reservation possible:** yes \ -**Reservation required:** yes ⚠️ \ -**FIP:** ⛔ FIP not accepted -{{% /expander %}} - -{{% expander "Intercity-Express (ICE) ⚠️" traincategory "long-distance" %}} -**Description:** \ +{{% train-category + title="Intercity-Express (ICE)" + fip_accepted=true + reservation_required=true +%}} International high-speed trains operated by SNCF in cooperation with Deutsche Bahn, running between France (Paris Est, Strasbourg) and Germany (Karlsruhe, Mannheim, Frankfurt am Main, Stuttgart, Munich). -⚠️ Special conditions apply for international connections, see [International TGV inOui / ICE trains](#international-tgv-inoui--ice-trains). \ -**Reservation possible:** yes \ -**Reservation required:** yes ⚠️ \ **Reservation cost:** \ Prices differ between peak and off-peak trains. Off-peak: €1.70 (1st/2nd class); peak: €15 (1st class), €10 (2nd class). The classification is not publicly available. -{{% /expander %}} +{{% /train-category %}} -{{% expander "Intercité (IC) ⚠️" traincategory "long-distance" %}} -**Description:** \ +{{% train-category + title="Intercité (IC)" + fip_accepted=true + reservation_required=true +%}} Intercity trains operated by SNCF, connecting various cities in France, mostly requiring reservations. -SNCF does not provide public information on which `IC` trains require reservations. If in doubt, check with SNCF or purchase a reservation. \ -**Reservation possible:** yes \ -**Reservation required:** mostly ⚠️ \ +SNCF does not provide public information on which `IC` trains require reservations. If in doubt, check with SNCF or purchase a reservation. + **Reservation cost:** \ Prices differ between peak and off-peak trains. Off-peak: €1.70 (1st/2nd class); peak: €15 (1st class), €10 (2nd class). The classification is not publicly available. -{{% /expander %}} +{{% /train-category %}} + +{{% train-category + title="Intercité de nuit" + fip_accepted=true + reservation_required=true +%}} +SNCF night trains within France. International Nightjet connections ended in December 2025. -{{% expander "Intercité de nuit ⚠️" traincategory "long-distance" %}} -**Description:** \ -SNCF night trains within France. International Nightjet connections ended in December 2025. \ -**Reservation possible:** yes \ -**Reservation required:** yes ⚠️ \ **Reservation cost:** depends on route and occupancy -{{% /expander %}} +{{% /train-category %}} ### Regional -{{% expander "Train express régional (TER) ⚠️ℹ️" traincategory "regional" %}} -**Description:** \ +{{% train-category + title="Train express régional (TER)" + fip_accepted=true + reservation_possible=true +%}} `TER` is SNCF's regional train, connecting various cities in France. +{{% /train-category %}} -ℹ️ On the Marseille – Toulon – Nice route, FIP is not valid as `TER` trains are operated by Transdev. \ -**Reservation possible:** sometimes \ -**Reservation required:** sometimes ⚠️ \ -Some lines from Paris require reservations, see [Reservation requirement in regional trains](#reservation-requirement-in-regional-trains) -{{% /expander %}} - -{{% expander "Réseau Express Régional (RER) ⚠️" traincategory "regional" %}} -**Description:** \ +{{% train-category + title="Réseau Express Régional (RER)" + fip_accepted=true +%}} RER is a suburban train operated by SNCF in Île de France (Greater Paris) and surrounding cities. - -⚠️ FIP is only valid on certain RER lines, see [Trains in Greater Paris](#trains-in-greater-paris) \ -**Reservation possible:** no -{{% /expander %}} +{{% /train-category %}} ## Ticket and Reservation Purchase diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html new file mode 100644 index 00000000..38f1c81e --- /dev/null +++ b/layouts/partials/train-category.html @@ -0,0 +1,61 @@ + +
+
+
+
+ {{- partial "icon" "train" -}} + {{- .title -}} +
+
+
+ {{- if eq .fip_accepted true -}} + + {{ partial "icon" "check_circle" }} + FIP Accepted + + {{- else -}} + + {{ partial "icon" "dangerous" }} + FIP Not Accepted + + {{- end -}} + + {{- if eq .reservation_required true -}} + + {{ partial "icon" "calendar_month" }} + Reservation Required + + {{- else if eq .reservation_possible true -}} + + {{ partial "icon" "free_cancellation" }} + Reservation Possible + + {{- else -}} + + {{ partial "icon" "close" }} + No Reservation Possible + + {{- end -}} + + {{- if .info_available -}} + + {{ partial "icon" "info" }} + Information Available + + {{- end -}} +
+
+
+ {{- partial "icon" "keyboard_arrow_down" -}} +
+ +
+ {{- if .content -}} +
+ {{- .content -}} +
+ {{- end -}} + {{- if not (eq .fip_accepted true) -}} + FIP is not accepted for this train category! + {{- end -}} +
diff --git a/layouts/shortcodes/train-category.html b/layouts/shortcodes/train-category.html new file mode 100644 index 00000000..62bf7e81 --- /dev/null +++ b/layouts/shortcodes/train-category.html @@ -0,0 +1,17 @@ +{{- $data := dict + "title" (.Get "title") + "fip_accepted" (default true (.Get "fip_accepted")) + "reservation_required" (default false (.Get "reservation_required")) + "reservation_possible" (default false (.Get "reservation_possible")) + "info_available" (default false (.Get "info_available")) + "content" (.Inner | .Page.RenderString) +-}} + + +
+ {{- partial "train-category" $data -}} +
+ +
+ {{- partial "train-category" $data -}} +
From 36bc71785971b9e79e3dbf36f5bae2e43655df73 Mon Sep 17 00:00:00 2001 From: MoritzWeber Date: Sat, 15 Nov 2025 07:26:15 +0100 Subject: [PATCH 02/20] feat: Improve train category tagging system --- assets/sass/_variables.scss | 29 +++++++ assets/sass/textHighlight.scss | 9 +++ assets/sass/trainCategory.scss | 100 ++++--------------------- content/operator/sncf/index.en.md | 17 ++++- i18n/de.yaml | 1 + i18n/en.yaml | 1 + i18n/fr.yaml | 1 + layouts/partials/train-category.html | 41 +++++++--- layouts/shortcodes/highlight.html | 2 +- layouts/shortcodes/train-category.html | 3 +- 10 files changed, 101 insertions(+), 103 deletions(-) diff --git a/assets/sass/_variables.scss b/assets/sass/_variables.scss index 5a55b60b..c43103aa 100644 --- a/assets/sass/_variables.scss +++ b/assets/sass/_variables.scss @@ -27,6 +27,18 @@ html { --color-onLight: #{$color-onLight}; --color-table-border: #{$color-table-border}; --color-body: rgb(33, 37, 41); + --tag-success-bg: #d4edda; + --tag-success-color: #155724; + --tag-success-border: #c3e6cb; + --tag-warning-bg: #fff3cd; + --tag-warning-color: #856404; + --tag-warning-border: #ffeaa7; + --tag-error-bg: #f8d7da; + --tag-error-color: #721c24; + --tag-error-border: #f5c6cb; + --tag-info-bg: #cce7ff; + --tag-info-color: #004085; + --tag-info-border: #b3d9ff; --border-radius-s: 0.4rem; --border-radius-m: 0.8rem; --border-radius-l: 1.6rem; @@ -37,6 +49,7 @@ html { --highlight-color-tip: #c4f2ff; --highlight-color-inofficial: #f0f3f5; --highlight-color-important: #ffe3d9; + --highlight-color-confusion: #ffe6cc; --border: 0.1rem solid transparent; --pagefind-ui-font: roboto, Arial, Helvetica, sans-serif; --outline-focus-indicator: #257fa8; @@ -54,9 +67,24 @@ html[data-theme="dark"] { --link-special: #ffffff; --bg-default: #151b23; --bg-neutral: #0d1117; + --bg-accent: #86761a; + --bg-accent2: #daba00; + --bg-accent3: #fff284; --color-onLight: #ffffff; --color-table-border: #555; --color-body: #e0e0e0; + --tag-success-bg: #1a4d2e; + --tag-success-color: #a8d5ba; + --tag-success-border: #2d6a4f; + --tag-warning-bg: #4a3a1a; + --tag-warning-color: #f0d98d; + --tag-warning-border: #6b5520; + --tag-error-bg: #4a1a1a; + --tag-error-color: #f5a9ae; + --tag-error-border: #6b2d2d; + --tag-info-bg: #1a3a5c; + --tag-info-color: #a8d5f5; + --tag-info-border: #2d5a8b; --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); @@ -64,6 +92,7 @@ html[data-theme="dark"] { --highlight-color-tip: #1a4a5c; --highlight-color-inofficial: #2a2d30; --highlight-color-important: #4a2a1a; + --highlight-color-confusion: #4a3a1a; --border: 0.1rem solid #3d444d; --outline-focus-indicator: #2e9acb; } diff --git a/assets/sass/textHighlight.scss b/assets/sass/textHighlight.scss index e2657c14..331332e5 100644 --- a/assets/sass/textHighlight.scss +++ b/assets/sass/textHighlight.scss @@ -54,3 +54,12 @@ border: 0.2rem solid #ba3d12; } } + +.m-text-highlight--confusion { + background-color: var(--highlight-color-confusion); + border-left: #ff9100e1 solid 1rem; + + @media print { + border: 0.2rem solid #ff9100e1; + } +} diff --git a/assets/sass/trainCategory.scss b/assets/sass/trainCategory.scss index 0afffb09..ed715975 100644 --- a/assets/sass/trainCategory.scss +++ b/assets/sass/trainCategory.scss @@ -41,40 +41,28 @@ font-weight: 500; white-space: nowrap; - &--accepted { - background: #d4edda; - color: #155724; - border: 0.1rem solid #c3e6cb; + &--success { + background: var(--tag-success-bg); + color: var(--tag-success-color); + border: 0.1rem solid var(--tag-success-border); } - &--rejected { - background: #f8d7da; - color: #721c24; - border: 0.1rem solid #f5c6cb; + &--warning { + background: var(--tag-warning-bg); + color: var(--tag-warning-color); + border: 0.1rem solid var(--tag-warning-border); } - &--required { - background: #fff3cd; - color: #856404; - border: 0.1rem solid #ffeaa7; - } - - &--possible { - background: #cce7ff; - color: #004085; - border: 0.1rem solid #b3d9ff; - } - - &--none { - background: #e2e3e5; - color: #383d41; - border: 0.1rem solid #d6d8db; + &--error { + background: var(--tag-error-bg); + color: var(--tag-error-color); + border: 0.1rem solid var(--tag-error-border); } &--info { - background: #e7f3ff; - color: #0c5460; - border: 0.1rem solid #bee5eb; + background: var(--tag-info-bg); + color: var(--tag-info-color); + border: 0.1rem solid var(--tag-info-border); } } @@ -82,16 +70,6 @@ margin-top: 1rem; } -.o-train-category__info { - padding: 0.8rem; - margin-bottom: 1rem; - background: #e7f3ff; - border: 0.1rem solid #bee5eb; - border-radius: var(--border-radius-s); - color: #0c5460; - font-style: italic; -} - .o-expander__summary--train-category { &:hover, &:focus { @@ -100,51 +78,3 @@ } } } - -html[data-theme="dark"] { - .o-train-category { - &__info { - background: #0c3544; - border-color: #17a2b8; - color: #bee5eb; - } - - &__tag { - &--accepted { - background: #2d5a3d; - color: #a3d5ab; - border-color: #4a7c59; - } - - &--rejected { - background: #5a2d32; - color: #f5a3ab; - border-color: #7c4a52; - } - - &--required { - background: #5a4d2d; - color: #f5e6a3; - border-color: #7c6a4a; - } - - &--possible { - background: #2d4a5a; - color: #a3d5f5; - border-color: #4a6a7c; - } - - &--none { - background: #3d3d3d; - color: #d0d0d0; - border-color: #5a5a5a; - } - - &--info { - background: #0c3544; - color: #bee5eb; - border-color: #17a2b8; - } - } - } -} diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index 9cdb74be..e9369a4e 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -41,11 +41,13 @@ Reservations are mandatory on all `TGV`, almost all `IC` trains, and some region title="Train à grande vitesse inOui (TGV inOui)" fip_accepted=true reservation_required=true - info_available=true + risk_of_confusion=true + important_info=true + type="highspeed" %}} The `TGV` inOui is SNCF's high-speed train, connecting many cities in France and international destinations (e.g. Munich, Frankfurt am Main, Barcelona, Luxembourg, Brussels, Zurich, Milan). [Route overview](https://www.sncf-connect.com/assets/media/2021-05/2014_axes-tgv_0.pdf). Each seat number exists twice in the carriage; the reserved seat is the one with the illuminated number. -{{% highlight inofficial %}} +{{% highlight confusion %}} SNCF also operates low-cost `TGV` trains under the name OuiGo, which are not valid with FIP. {{% /highlight %}} @@ -53,8 +55,15 @@ SNCF also operates low-cost `TGV` trains under the name OuiGo, which are not val Special conditions apply for international connections, see International TGV inOui / ICE trains section below. {{% /highlight %}} -**Reservation cost:** \ -Prices differ between peak and off-peak trains. Off-peak: €1.70 (1st/2nd class); peak: €15 (1st class), €10 (2nd class). The classification is not publicly available. +### Reservation + +Prices differ between peak and off-peak trains. The classification is not publicly available. + +| | 1st class | 2nd class | +| -------- | --------- | --------- | +| Off-peak | €1.70 | €1.70 | +| Peak | €15 | €10 | + {{% /train-category %}} {{% train-category diff --git a/i18n/de.yaml b/i18n/de.yaml index 084ce82a..183332c4 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -35,6 +35,7 @@ highlight: important: Wichtige Information inofficial: Inoffizielle Information tip: Persönlicher Tipp + confusion: Verwechslungsgefahr home-page-text: FIP Guide Startseite information-disclaimer-short: >- Diese Informationen sind inoffiziell und ohne Gewähr. Es besteht keine diff --git a/i18n/en.yaml b/i18n/en.yaml index 46bfa1ab..16f7c821 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -34,6 +34,7 @@ highlight: important: Important Information inofficial: Unofficial Information tip: Personal Tip + confusion: Risk of Confusion home-page-text: FIP Guide Home Page information-disclaimer-short: >- The information provided is unofficial and without guarantee. There is no diff --git a/i18n/fr.yaml b/i18n/fr.yaml index fba8e28a..3aa95938 100644 --- a/i18n/fr.yaml +++ b/i18n/fr.yaml @@ -31,6 +31,7 @@ footer-love: aria-label: Fait avec amour en Europe text: Fait avec ♥️ en Europe highlight: + confusion: Risque de confusion important: Informations importantes inofficial: Informations non officielles tip: Conseil personnel diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index 38f1c81e..3d9172a5 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -9,38 +9,55 @@
{{- if eq .fip_accepted true -}} - + {{ partial "icon" "check_circle" }} FIP Accepted + {{- else if eq .fip_accepted "partially" -}} + + {{ partial "icon" "info" }} + FIP Partially Accepted + {{- else -}} - + {{ partial "icon" "dangerous" }} FIP Not Accepted {{- end -}} {{- if eq .reservation_required true -}} - - {{ partial "icon" "calendar_month" }} + + {{ partial "icon" "calendar_add_on" }} Reservation Required + {{- else if eq .reservation_required true -}} + + {{ partial "icon" "calendar_add_on" }} + Reservation Partially Required + {{- else if eq .reservation_possible true -}} - - {{ partial "icon" "free_cancellation" }} + + {{ partial "icon" "calendar_check" }} Reservation Possible {{- else -}} - - {{ partial "icon" "close" }} + + {{ partial "icon" "calendar_lock" }} No Reservation Possible {{- end -}} - {{- if .info_available -}} - - {{ partial "icon" "info" }} - Information Available + {{- if .risk_of_confusion -}} + + {{ partial "icon" "question_exchange" }} + Risk of confusion + + {{- end -}} + + {{- if .important_info -}} + + {{ partial "icon" "campaign" }} + Important information {{- end -}}
diff --git a/layouts/shortcodes/highlight.html b/layouts/shortcodes/highlight.html index b8b5f402..1a4ddeea 100644 --- a/layouts/shortcodes/highlight.html +++ b/layouts/shortcodes/highlight.html @@ -1,5 +1,5 @@ {{- $param := .Get 0 -}} -{{ $iconMapping := dict "important" "error" "inofficial" "warning" "tip" "lightbulb_2" }} +{{ $iconMapping := dict "important" "error" "inofficial" "warning" "tip" "lightbulb_2" "confusion" "question_exchange" }}
diff --git a/layouts/shortcodes/train-category.html b/layouts/shortcodes/train-category.html index 62bf7e81..0e3caee2 100644 --- a/layouts/shortcodes/train-category.html +++ b/layouts/shortcodes/train-category.html @@ -3,7 +3,8 @@ "fip_accepted" (default true (.Get "fip_accepted")) "reservation_required" (default false (.Get "reservation_required")) "reservation_possible" (default false (.Get "reservation_possible")) - "info_available" (default false (.Get "info_available")) + "risk_of_confusion" (default false (.Get "risk_of_confusion")) + "important_info" (default false (.Get "important_info")) "content" (.Inner | .Page.RenderString) -}} From 8ed82f357d4c1fbc4bddb9b1417aa3c4d224fc84 Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Sat, 15 Nov 2025 21:25:24 +0100 Subject: [PATCH 03/20] feat: Generate some CSS rules --- assets/sass/_variables.scss | 52 ++++++++++++++++++---------------- assets/sass/trainCategory.scss | 28 ++++-------------- 2 files changed, 34 insertions(+), 46 deletions(-) diff --git a/assets/sass/_variables.scss b/assets/sass/_variables.scss index c43103aa..5fc4ff62 100644 --- a/assets/sass/_variables.scss +++ b/assets/sass/_variables.scss @@ -14,6 +14,20 @@ $bg-code: #fff284; $color-onLight: #000000; $color-table-border: #5b5b5b; +$tag-colors: ( + success: #155724, + warning: #b64900, + error: #b70000, + info: #004085, +); + +$tag-colors-dark: ( + success: #a8d5ba, + warning: #f0d98d, + error: #f5a9ae, + info: #a8d5f5, +); + html { --pagefind-ui-scale: 1 !important; --pagefind-ui-text: #000; @@ -27,18 +41,13 @@ html { --color-onLight: #{$color-onLight}; --color-table-border: #{$color-table-border}; --color-body: rgb(33, 37, 41); - --tag-success-bg: #d4edda; - --tag-success-color: #155724; - --tag-success-border: #c3e6cb; - --tag-warning-bg: #fff3cd; - --tag-warning-color: #856404; - --tag-warning-border: #ffeaa7; - --tag-error-bg: #f8d7da; - --tag-error-color: #721c24; - --tag-error-border: #f5c6cb; - --tag-info-bg: #cce7ff; - --tag-info-color: #004085; - --tag-info-border: #b3d9ff; + + @each $name, $color in $tag-colors { + --tag-#{$name}-bg: #{mix(white, $color, 90%)}; + --tag-#{$name}-color: #{$color}; + --tag-#{$name}-border: #{mix(white, $color, 50%)}; + } + --border-radius-s: 0.4rem; --border-radius-m: 0.8rem; --border-radius-l: 1.6rem; @@ -73,18 +82,13 @@ html[data-theme="dark"] { --color-onLight: #ffffff; --color-table-border: #555; --color-body: #e0e0e0; - --tag-success-bg: #1a4d2e; - --tag-success-color: #a8d5ba; - --tag-success-border: #2d6a4f; - --tag-warning-bg: #4a3a1a; - --tag-warning-color: #f0d98d; - --tag-warning-border: #6b5520; - --tag-error-bg: #4a1a1a; - --tag-error-color: #f5a9ae; - --tag-error-border: #6b2d2d; - --tag-info-bg: #1a3a5c; - --tag-info-color: #a8d5f5; - --tag-info-border: #2d5a8b; + + @each $name, $color in $tag-colors-dark { + --tag-#{$name}-bg: #{mix(black, $color, 65%)}; + --tag-#{$name}-color: #{$color}; + --tag-#{$name}-border: #{mix(black, $color, 50%)}; + } + --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/trainCategory.scss b/assets/sass/trainCategory.scss index ed715975..df51f8a7 100644 --- a/assets/sass/trainCategory.scss +++ b/assets/sass/trainCategory.scss @@ -41,28 +41,12 @@ font-weight: 500; white-space: nowrap; - &--success { - background: var(--tag-success-bg); - color: var(--tag-success-color); - border: 0.1rem solid var(--tag-success-border); - } - - &--warning { - background: var(--tag-warning-bg); - color: var(--tag-warning-color); - border: 0.1rem solid var(--tag-warning-border); - } - - &--error { - background: var(--tag-error-bg); - color: var(--tag-error-color); - border: 0.1rem solid var(--tag-error-border); - } - - &--info { - background: var(--tag-info-bg); - color: var(--tag-info-color); - border: 0.1rem solid var(--tag-info-border); + @each $name, $color in $tag-colors { + &--#{$name} { + background: var(--tag-#{$name}-bg); + color: var(--tag-#{$name}-color); + border: 0.1rem solid var(--tag-#{$name}-border); + } } } From d17c62abf39d82068012cf812fe792b4e4d0d00f Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Sat, 15 Nov 2025 21:53:40 +0100 Subject: [PATCH 04/20] refactor: Clean up CSS --- assets/sass/expander.scss | 2 +- assets/sass/trainCategory.scss | 23 +---- layouts/partials/train-category.html | 121 ++++++++++++--------------- layouts/shortcodes/expander.html | 2 +- 4 files changed, 60 insertions(+), 88 deletions(-) diff --git a/assets/sass/expander.scss b/assets/sass/expander.scss index 4091d161..2eb92583 100644 --- a/assets/sass/expander.scss +++ b/assets/sass/expander.scss @@ -47,7 +47,7 @@ } } - > div { + &-title { display: flex; align-items: center; gap: 0.5rem; diff --git a/assets/sass/trainCategory.scss b/assets/sass/trainCategory.scss index df51f8a7..28c4835e 100644 --- a/assets/sass/trainCategory.scss +++ b/assets/sass/trainCategory.scss @@ -1,16 +1,8 @@ .o-train-category__header { width: 100%; - - &-content { - display: flex; - flex-direction: column; - gap: 0.8rem; - width: 100%; - } -} - -.o-train-category__title-wrapper { - width: 100%; + display: flex; + flex-direction: column; + gap: 0.8rem; } .o-train-category__title { @@ -18,11 +10,6 @@ align-items: center; gap: 0.5rem; font-weight: 600; - font-size: 1.6rem; - - &-text { - flex: 1; - } } .o-train-category__tags { @@ -50,10 +37,6 @@ } } -.o-train-category__content { - margin-top: 1rem; -} - .o-expander__summary--train-category { &:hover, &:focus { diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index 3d9172a5..478ec8e0 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -1,78 +1,67 @@
-
-
-
- {{- partial "icon" "train" -}} - {{- .title -}} -
-
-
- {{- if eq .fip_accepted true -}} - - {{ partial "icon" "check_circle" }} - FIP Accepted - - {{- else if eq .fip_accepted "partially" -}} - - {{ partial "icon" "info" }} - FIP Partially Accepted - - {{- else -}} - - {{ partial "icon" "dangerous" }} - FIP Not Accepted - - {{- end -}} +
+ {{- partial "icon" "train" -}} + {{- .title -}} +
+
+ {{- if eq .fip_accepted true -}} + + {{ partial "icon" "check_circle" }} + FIP Accepted + + {{- else if eq .fip_accepted "partially" -}} + + {{ partial "icon" "info" }} + FIP Partially Accepted + + {{- else -}} + + {{ partial "icon" "dangerous" }} + FIP Not Accepted + + {{- end -}} - {{- if eq .reservation_required true -}} - - {{ partial "icon" "calendar_add_on" }} - Reservation Required - - {{- else if eq .reservation_required true -}} - - {{ partial "icon" "calendar_add_on" }} - Reservation Partially Required - - {{- else if eq .reservation_possible true -}} - - {{ partial "icon" "calendar_check" }} - Reservation Possible - - {{- else -}} - - {{ partial "icon" "calendar_lock" }} - No Reservation Possible - - {{- end -}} + {{- if eq .reservation_required true -}} + + {{ partial "icon" "calendar_add_on" }} + Reservation Required + + {{- else if eq .reservation_required true -}} + + {{ partial "icon" "calendar_add_on" }} + Reservation Partially Required + + {{- else if eq .reservation_possible true -}} + + {{ partial "icon" "calendar_check" }} + Reservation Possible + + {{- else -}} + + {{ partial "icon" "calendar_lock" }} + No Reservation Possible + + {{- end -}} - {{- if .risk_of_confusion -}} - - {{ partial "icon" "question_exchange" }} - Risk of confusion - - {{- end -}} + {{- if .risk_of_confusion -}} + + {{ partial "icon" "question_exchange" }} + Risk of confusion + + {{- end -}} - {{- if .important_info -}} - - {{ partial "icon" "campaign" }} - Important information - - {{- end -}} -
+ {{- if .important_info -}} + + {{ partial "icon" "campaign" }} + Important information + + {{- end -}}
{{- partial "icon" "keyboard_arrow_down" -}}
- {{- if .content -}} -
- {{- .content -}} -
- {{- end -}} - {{- if not (eq .fip_accepted true) -}} - FIP is not accepted for this train category! - {{- end -}} + {{- .content -}}
diff --git a/layouts/shortcodes/expander.html b/layouts/shortcodes/expander.html index 03ed31b1..63005d1d 100644 --- a/layouts/shortcodes/expander.html +++ b/layouts/shortcodes/expander.html @@ -4,7 +4,7 @@
-
+
{{- partial "icon" (index $iconMapping $param) -}} {{ (.Get 0) }}
From 4e895a52bbe7c9964c3bddc924ae12e84b07bec5 Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Sat, 15 Nov 2025 22:02:01 +0100 Subject: [PATCH 05/20] feat: Add translations --- i18n/de.yaml | 14 +++++++++++++- i18n/en.yaml | 14 +++++++++++++- i18n/fr.yaml | 12 ++++++++++++ layouts/partials/train-category.html | 18 +++++++++--------- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/i18n/de.yaml b/i18n/de.yaml index 183332c4..7642afef 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -32,10 +32,10 @@ footer-love: text: Made with ♥️ in Europe general: Übergreifendes highlight: + confusion: Verwechslungsgefahr important: Wichtige Information inofficial: Inoffizielle Information tip: Persönlicher Tipp - confusion: Verwechslungsgefahr home-page-text: FIP Guide Startseite information-disclaimer-short: >- Diese Informationen sind inoffiziell und ohne Gewähr. Es besteht keine @@ -102,6 +102,18 @@ support: href="/de/contact">Kontaktformular schreiben. title: Unterstütze uns toc_name: Inhalt +trainCategory: + acceptance: + accepted: FIP akzeptiert + notAccepted: FIP nicht akzeptiert + partiallyAccepted: FIP teilweise akzeptiert + importantInformation: Wichtige Informationen + reservation: + notPossible: Keine Reservierung möglich + partiallyRequired: Reservierung teilweise erforderlich + possible: Reservierung möglich + required: Reservierung erforderlich + riskOfConfusion: Verwechslungsgefahr updateDate: aria-label: Öffne die Commit-Verlauf der Seite label: Zuletzt aktualisiert diff --git a/i18n/en.yaml b/i18n/en.yaml index 16f7c821..0fda47e6 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -31,10 +31,10 @@ footer-love: text: Made with ♥️ in Europe general: general highlight: + confusion: Risk of Confusion important: Important Information inofficial: Unofficial Information tip: Personal Tip - confusion: Risk of Confusion home-page-text: FIP Guide Home Page information-disclaimer-short: >- The information provided is unofficial and without guarantee. There is no @@ -98,6 +98,18 @@ support: href="/en/contact">contact form. title: Support Us toc_name: Contents +trainCategory: + acceptance: + accepted: FIP accepted + notAccepted: FIP not accepted + partiallyAccepted: FIP partially accepted + importantInformation: Important information + reservation: + notPossible: No reservation possible + partiallyRequired: Reservation partially required + possible: Reservation possible + required: Reservation required + riskOfConfusion: Risk of confusion updateDate: aria-label: Open the commit history of the page label: Last updated diff --git a/i18n/fr.yaml b/i18n/fr.yaml index 3aa95938..c149a654 100644 --- a/i18n/fr.yaml +++ b/i18n/fr.yaml @@ -98,6 +98,18 @@ support: le formulaire de contact. title: Soutenez-nous toc_name: Sommaire +trainCategory: + acceptance: + accepted: FIP accepté + notAccepted: FIP non accepté + partiallyAccepted: FIP partiellement accepté + importantInformation: Informations importantes + reservation: + notPossible: Aucune réservation possible + partiallyRequired: Réservation partiellement requise + possible: Réservation possible + required: Réservation requise + riskOfConfusion: Risque de confusion updateDate: aria-label: Ouvrir l'historique des commits de la page label: Dernière mise à jour diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index 478ec8e0..2877c942 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -8,53 +8,53 @@ {{- if eq .fip_accepted true -}} {{ partial "icon" "check_circle" }} - FIP Accepted + {{ i18n "trainCategory.acceptance.accepted" }} {{- else if eq .fip_accepted "partially" -}} {{ partial "icon" "info" }} - FIP Partially Accepted + {{ i18n "trainCategory.acceptance.partiallyAccepted" }} {{- else -}} {{ partial "icon" "dangerous" }} - FIP Not Accepted + {{ i18n "trainCategory.acceptance.notAccepted" }} {{- end -}} {{- if eq .reservation_required true -}} {{ partial "icon" "calendar_add_on" }} - Reservation Required + {{ i18n "trainCategory.reservation.required" }} {{- else if eq .reservation_required true -}} {{ partial "icon" "calendar_add_on" }} - Reservation Partially Required + {{ i18n "trainCategory.reservation.partiallyRequired" }} {{- else if eq .reservation_possible true -}} {{ partial "icon" "calendar_check" }} - Reservation Possible + {{ i18n "trainCategory.reservation.possible" }} {{- else -}} {{ partial "icon" "calendar_lock" }} - No Reservation Possible + {{ i18n "trainCategory.reservation.notPossible" }} {{- end -}} {{- if .risk_of_confusion -}} {{ partial "icon" "question_exchange" }} - Risk of confusion + {{ i18n "trainCategory.riskOfConfusion" }} {{- end -}} {{- if .important_info -}} {{ partial "icon" "campaign" }} - Important information + {{ i18n "trainCategory.importantInformation" }} {{- end -}}
From e387a1369ab591d1d2ed3faeb60ad166a83c505c Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Sun, 16 Nov 2025 15:41:46 +0100 Subject: [PATCH 06/20] feat: Add support for different icons --- .opencode/command/update-traincategory.md | 37 +++++++++++++++++++++++ layouts/partials/train-category.html | 8 ++++- layouts/shortcodes/train-category.html | 1 + 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 .opencode/command/update-traincategory.md diff --git a/.opencode/command/update-traincategory.md b/.opencode/command/update-traincategory.md new file mode 100644 index 00000000..7ab94f80 --- /dev/null +++ b/.opencode/command/update-traincategory.md @@ -0,0 +1,37 @@ +--- +description: Update train category information +agent: build +--- + +Update the page $ARGUMENTS to new train category shortcodes. + +A shortcode looks like: + +``` +{{% train-category + title="title" + type="highspeed" (can be highspeed, regional, bus, funicular) + fip_accepted=true (can be true, false, partially) + reservation_required=true (can be true, false, partially) + reservation_possible=true (omit the attribute if false or if reservation_required is true) + risk_of_confusion=true (previously marked with ℹ️ in the title, omit the attribute if false) + important_info=true (if an important highlight is part of the train category, omit the attribute if false) +%}} +{{% /train-category %}} +``` + +Important information (previously paragraphs that started with ⚠️ in the text) should be changed to an important highlight shortcut (in the same position as the text was before): + +``` +{{% highlight important %}} +{{% /highlight %}} +``` + +If there is a risk of confusion (previously marked with ℹ️ in the text), add it as confusion highlight (in the same position the text was before): + +``` +{{% highlight confusion %}} +{{% /highlight %}} +``` + +Keep the "**Kosten für Reservierung:**" section. diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index 2877c942..5508ecd4 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -1,7 +1,13 @@
- {{- partial "icon" "train" -}} + {{ $iconMapping := dict + "highspeed" "train" + "regional" "directions_subway" + "funicular" "funicular" + "bus" "directions_bus" + }} + {{- partial "icon" (index $iconMapping .type) -}} {{- .title -}}
diff --git a/layouts/shortcodes/train-category.html b/layouts/shortcodes/train-category.html index 0e3caee2..f423fca3 100644 --- a/layouts/shortcodes/train-category.html +++ b/layouts/shortcodes/train-category.html @@ -1,5 +1,6 @@ {{- $data := dict "title" (.Get "title") + "type" (default "regional" (.Get "type")) "fip_accepted" (default true (.Get "fip_accepted")) "reservation_required" (default false (.Get "reservation_required")) "reservation_possible" (default false (.Get "reservation_possible")) From fdf63ca35887d75b0b9def0684f95f8a4a6ef3fb Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Sun, 16 Nov 2025 23:49:15 +0100 Subject: [PATCH 07/20] feat: Add buttons for route overview and additional info --- content/operator/sncf/index.en.md | 3 +- i18n/de.yaml | 2 + i18n/en.yaml | 2 + i18n/fr.yaml | 2 + layouts/partials/train-category.html | 154 ++++++++++++++----------- layouts/shortcodes/train-category.html | 11 +- 6 files changed, 97 insertions(+), 77 deletions(-) diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index e9369a4e..6aaa08e9 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -43,9 +43,10 @@ Reservations are mandatory on all `TGV`, almost all `IC` trains, and some region reservation_required=true risk_of_confusion=true important_info=true + route_overview_url="https://www.sncf-connect.com/assets/media/2021-05/2014_axes-tgv_0.pdf" type="highspeed" %}} -The `TGV` inOui is SNCF's high-speed train, connecting many cities in France and international destinations (e.g. Munich, Frankfurt am Main, Barcelona, Luxembourg, Brussels, Zurich, Milan). [Route overview](https://www.sncf-connect.com/assets/media/2021-05/2014_axes-tgv_0.pdf). Each seat number exists twice in the carriage; the reserved seat is the one with the illuminated number. +The `TGV` inOui is SNCF's high-speed train, connecting many cities in France and international destinations (e.g. Munich, Frankfurt am Main, Barcelona, Luxembourg, Brussels, Zurich, Milan). Each seat number exists twice in the carriage; the reserved seat is the one with the illuminated number. {{% highlight confusion %}} SNCF also operates low-cost `TGV` trains under the name OuiGo, which are not valid with FIP. diff --git a/i18n/de.yaml b/i18n/de.yaml index 7642afef..0937dd0c 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -107,6 +107,7 @@ trainCategory: accepted: FIP akzeptiert notAccepted: FIP nicht akzeptiert partiallyAccepted: FIP teilweise akzeptiert + additionalInformation: Zusätzliche Informationen importantInformation: Wichtige Informationen reservation: notPossible: Keine Reservierung möglich @@ -114,6 +115,7 @@ trainCategory: possible: Reservierung möglich required: Reservierung erforderlich riskOfConfusion: Verwechslungsgefahr + routeOverview: Streckenübersicht updateDate: aria-label: Öffne die Commit-Verlauf der Seite label: Zuletzt aktualisiert diff --git a/i18n/en.yaml b/i18n/en.yaml index 0fda47e6..a5cd013d 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -103,6 +103,7 @@ trainCategory: accepted: FIP accepted notAccepted: FIP not accepted partiallyAccepted: FIP partially accepted + additionalInformation: Additional information importantInformation: Important information reservation: notPossible: No reservation possible @@ -110,6 +111,7 @@ trainCategory: possible: Reservation possible required: Reservation required riskOfConfusion: Risk of confusion + routeOverview: Route overview updateDate: aria-label: Open the commit history of the page label: Last updated diff --git a/i18n/fr.yaml b/i18n/fr.yaml index c149a654..fc5ab05f 100644 --- a/i18n/fr.yaml +++ b/i18n/fr.yaml @@ -103,6 +103,7 @@ trainCategory: accepted: FIP accepté notAccepted: FIP non accepté partiallyAccepted: FIP partiellement accepté + additionalInformation: Informations complémentaires importantInformation: Informations importantes reservation: notPossible: Aucune réservation possible @@ -110,6 +111,7 @@ trainCategory: possible: Réservation possible required: Réservation requise riskOfConfusion: Risque de confusion + routeOverview: Aperçu de l'itinéraire updateDate: aria-label: Ouvrir l'historique des commits de la page label: Dernière mise à jour diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index 5508ecd4..2f504b84 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -1,73 +1,91 @@ - -
-
- {{ $iconMapping := dict - "highspeed" "train" - "regional" "directions_subway" - "funicular" "funicular" - "bus" "directions_bus" - }} - {{- partial "icon" (index $iconMapping .type) -}} - {{- .title -}} -
-
- {{- if eq .fip_accepted true -}} - - {{ partial "icon" "check_circle" }} - {{ i18n "trainCategory.acceptance.accepted" }} - - {{- else if eq .fip_accepted "partially" -}} - - {{ partial "icon" "info" }} - {{ i18n "trainCategory.acceptance.partiallyAccepted" }} - - {{- else -}} - - {{ partial "icon" "dangerous" }} - {{ i18n "trainCategory.acceptance.notAccepted" }} - - {{- end -}} +
+ +
+
+ {{ $iconMapping := dict + "highspeed" "train" + "regional" "directions_subway" + "funicular" "funicular" + "bus" "directions_bus" + }} + {{- partial "icon" (index $iconMapping .type) -}} + {{- .title -}} +
+
+ {{- if eq .fip_accepted true -}} + + {{ partial "icon" "check_circle" }} + {{ i18n "trainCategory.acceptance.accepted" }} + + {{- else if eq .fip_accepted "partially" -}} + + {{ partial "icon" "info" }} + {{ i18n "trainCategory.acceptance.partiallyAccepted" }} + + {{- else -}} + + {{ partial "icon" "dangerous" }} + {{ i18n "trainCategory.acceptance.notAccepted" }} + + {{- end -}} - {{- if eq .reservation_required true -}} - - {{ partial "icon" "calendar_add_on" }} - {{ i18n "trainCategory.reservation.required" }} - - {{- else if eq .reservation_required true -}} - - {{ partial "icon" "calendar_add_on" }} - {{ i18n "trainCategory.reservation.partiallyRequired" }} - - {{- else if eq .reservation_possible true -}} - - {{ partial "icon" "calendar_check" }} - {{ i18n "trainCategory.reservation.possible" }} - - {{- else -}} - - {{ partial "icon" "calendar_lock" }} - {{ i18n "trainCategory.reservation.notPossible" }} - - {{- end -}} + {{- if eq .reservation_required true -}} + + {{ partial "icon" "calendar_add_on" }} + {{ i18n "trainCategory.reservation.required" }} + + {{- else if eq .reservation_required true -}} + + {{ partial "icon" "calendar_add_on" }} + {{ i18n "trainCategory.reservation.partiallyRequired" }} + + {{- else if eq .reservation_possible true -}} + + {{ partial "icon" "calendar_check" }} + {{ i18n "trainCategory.reservation.possible" }} + + {{- else -}} + + {{ partial "icon" "calendar_lock" }} + {{ i18n "trainCategory.reservation.notPossible" }} + + {{- end -}} - {{- if .risk_of_confusion -}} - - {{ partial "icon" "question_exchange" }} - {{ i18n "trainCategory.riskOfConfusion" }} - - {{- end -}} + {{- if .risk_of_confusion -}} + + {{ partial "icon" "question_exchange" }} + {{ i18n "trainCategory.riskOfConfusion" }} + + {{- end -}} - {{- if .important_info -}} - - {{ partial "icon" "campaign" }} - {{ i18n "trainCategory.importantInformation" }} - - {{- end -}} + {{- if .important_info -}} + + {{ partial "icon" "campaign" }} + {{ i18n "trainCategory.importantInformation" }} + + {{- end -}} +
+ {{- partial "icon" "keyboard_arrow_down" -}} +
+ +
+ {{- .content -}} + {{- if .route_overview_url -}} + {{- partial "button" + (dict + "Destination" .route_overview_url + "Text" (T "trainCategory.routeOverview") + ) + -}} + {{- end -}} + {{- if .additional_information_url -}} + {{- partial "button" + (dict + "Destination" .additional_information_url + "Text" (T "trainCategory.additionalInformation") + ) + -}} + {{- end -}}
- {{- partial "icon" "keyboard_arrow_down" -}} -
- -
- {{- .content -}} -
+
diff --git a/layouts/shortcodes/train-category.html b/layouts/shortcodes/train-category.html index f423fca3..c6a67ac5 100644 --- a/layouts/shortcodes/train-category.html +++ b/layouts/shortcodes/train-category.html @@ -6,14 +6,9 @@ "reservation_possible" (default false (.Get "reservation_possible")) "risk_of_confusion" (default false (.Get "risk_of_confusion")) "important_info" (default false (.Get "important_info")) + "route_overview_url" (.Get "route_overview_url") + "additional_information_url" (.Get "additional_information_url") "content" (.Inner | .Page.RenderString) -}} - -
- {{- partial "train-category" $data -}} -
- -
- {{- partial "train-category" $data -}} -
+{{- partial "train-category" $data -}} From 2815884daea4f3ade36b11cc8db1b42b96b1a7f1 Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Mon, 17 Nov 2025 21:46:22 +0100 Subject: [PATCH 08/20] feat: Redesign highlight in train category expanders --- .opencode/command/update-traincategory.md | 6 +- assets/sass/trainCategory.scss | 14 ++++ content/operator/sncf/index.en.md | 92 ++++++++++++++++++----- layouts/partials/train-category.html | 8 +- layouts/shortcodes/highlight.html | 7 +- 5 files changed, 103 insertions(+), 24 deletions(-) diff --git a/.opencode/command/update-traincategory.md b/.opencode/command/update-traincategory.md index 7ab94f80..1cc56127 100644 --- a/.opencode/command/update-traincategory.md +++ b/.opencode/command/update-traincategory.md @@ -10,12 +10,14 @@ A shortcode looks like: ``` {{% train-category title="title" - type="highspeed" (can be highspeed, regional, bus, funicular) + type="highspeed" (can be highspeed, regional, bus, funicular, sleeper) fip_accepted=true (can be true, false, partially) reservation_required=true (can be true, false, partially) reservation_possible=true (omit the attribute if false or if reservation_required is true) risk_of_confusion=true (previously marked with ℹ️ in the title, omit the attribute if false) important_info=true (if an important highlight is part of the train category, omit the attribute if false) + route_overview_url="https://example.com" (if there is an route overview link in the description, otherwise omit the attribute) + additional_information_url="https://example.com" (if there is an additional information link in the description, otherwise omit the attribute) %}} {{% /train-category %}} ``` @@ -34,4 +36,4 @@ If there is a risk of confusion (previously marked with ℹ️ in the text), add {{% /highlight %}} ``` -Keep the "**Kosten für Reservierung:**" section. +Tranform the "**Reservation cost:**" (or language equivalent) section to a heading "### Reservation". diff --git a/assets/sass/trainCategory.scss b/assets/sass/trainCategory.scss index 28c4835e..0154b663 100644 --- a/assets/sass/trainCategory.scss +++ b/assets/sass/trainCategory.scss @@ -45,3 +45,17 @@ } } } +.o-train-category__content { + .m-text-highlight { + &--important, + &--confusion { + > .m-text-highlight__roofline { + color: var(--tag-warning-color); + } + + background-color: var(--tag-warning-bg); + border: var(--tag-warning-border) solid; + border-width: 1px 1px 1px 1rem; + } + } +} diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index 6aaa08e9..a3839613 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -39,12 +39,12 @@ Reservations are mandatory on all `TGV`, almost all `IC` trains, and some region {{% train-category title="Train à grande vitesse inOui (TGV inOui)" + type="highspeed" fip_accepted=true reservation_required=true risk_of_confusion=true important_info=true route_overview_url="https://www.sncf-connect.com/assets/media/2021-05/2014_axes-tgv_0.pdf" - type="highspeed" %}} The `TGV` inOui is SNCF's high-speed train, connecting many cities in France and international destinations (e.g. Munich, Frankfurt am Main, Barcelona, Luxembourg, Brussels, Zurich, Milan). Each seat number exists twice in the carriage; the reserved seat is the one with the illuminated number. @@ -69,25 +69,41 @@ Prices differ between peak and off-peak trains. The classification is not public {{% train-category title="Train à grande vitesse OuiGo (TGV OuiGo) / OuiGo Train Classique" + type="highspeed" fip_accepted=false reservation_required=true + risk_of_confusion=true %}} + The `TGV` OuiGo is SNCF's low-cost high-speed train, serving many cities in France and some international destinations. + +{{% highlight confusion %}} +SNCF also operates `TGV` trains under the inOui brand, which are valid with FIP. +{{% /highlight %}} {{% /train-category %}} {{% train-category title="Intercity-Express (ICE)" + type="highspeed" fip_accepted=true reservation_required=true %}} International high-speed trains operated by SNCF in cooperation with Deutsche Bahn, running between France (Paris Est, Strasbourg) and Germany (Karlsruhe, Mannheim, Frankfurt am Main, Stuttgart, Munich). -**Reservation cost:** \ -Prices differ between peak and off-peak trains. Off-peak: €1.70 (1st/2nd class); peak: €15 (1st class), €10 (2nd class). The classification is not publicly available. +### Reservation + +Prices differ between peak and off-peak trains. The classification is not publicly available. + +| | 1st class | 2nd class | +| -------- | --------- | --------- | +| Off-peak | €1.70 | €1.70 | +| Peak | €15 | €10 | + {{% /train-category %}} {{% train-category title="Intercité (IC)" + type="highspeed" fip_accepted=true reservation_required=true %}} @@ -95,24 +111,36 @@ Intercity trains operated by SNCF, connecting various cities in France, mostly r SNCF does not provide public information on which `IC` trains require reservations. If in doubt, check with SNCF or purchase a reservation. -**Reservation cost:** \ -Prices differ between peak and off-peak trains. Off-peak: €1.70 (1st/2nd class); peak: €15 (1st class), €10 (2nd class). The classification is not publicly available. +### Reservation + +Prices differ between peak and off-peak trains. The classification is not publicly available. + +| | 1st class | 2nd class | +| -------- | --------- | --------- | +| Off-peak | €1.70 | €1.70 | +| Peak | €15 | €10 | + {{% /train-category %}} {{% train-category title="Intercité de nuit" + type="sleeper" fip_accepted=true reservation_required=true %}} SNCF night trains within France. International Nightjet connections ended in December 2025. -**Reservation cost:** depends on route and occupancy +### Reservation + +Cost depends on route and occupancy. + {{% /train-category %}} ### Regional {{% train-category title="Train express régional (TER)" + type="regional" fip_accepted=true reservation_possible=true %}} @@ -121,6 +149,7 @@ SNCF night trains within France. International Nightjet connections ended in Dec {{% train-category title="Réseau Express Régional (RER)" + type="regional" fip_accepted=true %}} RER is a suburban train operated by SNCF in Île de France (Greater Paris) and surrounding cities. @@ -205,17 +234,32 @@ This validation requirement does not apply to FIP Coupons. ### International TGV inOui / ICE trains -{{% expander "TGV/ICE trains to Germany" info %}} +{{% train-category + title="TGV/ICE trains to Germany" + type="highspeed" + fip_accepted=partially + reservation_required=partially +%}} International `TGV` and `ICE` trains are reservation-required in the French section. In Germany, reservations are not required and FIP Coupons are valid. -{{% /expander %}} +{{% /train-category %}} -{{% expander "TGV trains to Italy, Spain, and Belgium" info %}} +{{% train-category + title="TGV trains to Italy, Spain, and Belgium" + type="highspeed" + fip_accepted=partially + reservation_required=true +%}} International `TGV` services from France to Italy, Spain, or Belgium are reservation-required throughout and FIP Coupons are not valid. Instead, FIP Global Fares can be purchased, which can be expensive (up to €130). [^1] -{{% /expander %}} +{{% /train-category %}} -{{% expander "TGV Lyria trains to Switzerland" info %}} +{{% train-category + title="TGV Lyria trains to Switzerland" + type="highspeed" + fip_accepted=partially + reservation_required=partially +%}} International `TGV` Lyria services from France to Switzerland are reservation-required in the French section and FIP Coupons are not valid. FIP Global Fares can be purchased. In Switzerland, reservations are not required and FIP Coupons are valid. -{{% /expander %}} +{{% /train-category %}} ### Trains in Greater Paris @@ -223,7 +267,11 @@ International `TGV` Lyria services from France to Switzerland are reservation-re RATP operates the Paris Métro, bus lines, and part of the tram and RER networks. SNCF operates the rest of the RER network and some tram lines. FIP discounts do not apply on RATP services. -{{% expander "RER trains" info %}} +{{% train-category + title="RER trains" + type="regional" + fip_accepted=partially +%}} Some RER lines are operated by SNCF. FIP discounts apply on the following sections: - RER Line A – only branches A3 & A5 west of Nanterre Préfecture to Poissy or Cergy-le-Haut @@ -233,15 +281,23 @@ Some RER lines are operated by SNCF. FIP discounts apply on the following sectio - RER Line E – entire line Note: For journeys between Gare du Nord and Châtelet – Les Halles, only SNCF-operated RER Line D can be used. FIP discounts are not valid on RATP-operated RER Line B on the same section. -{{% /expander %}} +{{% /train-category %}} -{{% expander "Transilien trains" info %}} +{{% train-category + title="Transilien trains" + type="regional" + fip_accepted=true +%}} FIP discounts apply on all Transilien lines H, J, K, L, N, P, R, U, and V. -{{% /expander %}} +{{% /train-category %}} -{{% expander "Trams" info %}} +{{% train-category + title="Trams" + type="tram" + fip_accepted=partially +%}} Tram lines T4 and T11 are operated by SNCF and can be used with FIP discounts. Tram lines T9 and T13 are operated by SNCF and Keolis; FIP validity is unclear. FIP discounts do not apply on other tram lines. -{{% /expander %}} +{{% /train-category %}} Contramarque de Passage diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index 2f504b84..de98a831 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -1,12 +1,14 @@ -
+
{{ $iconMapping := dict "highspeed" "train" "regional" "directions_subway" + "sleeper" "airline_seat_flat" "funicular" "funicular" "bus" "directions_bus" + "tram" "tram" }} {{- partial "icon" (index $iconMapping .type) -}} {{- .title -}} @@ -34,7 +36,7 @@ {{ partial "icon" "calendar_add_on" }} {{ i18n "trainCategory.reservation.required" }} - {{- else if eq .reservation_required true -}} + {{- else if eq .reservation_required "partially" -}} {{ partial "icon" "calendar_add_on" }} {{ i18n "trainCategory.reservation.partiallyRequired" }} @@ -69,7 +71,7 @@ {{- partial "icon" "keyboard_arrow_down" -}}
-
+
{{- .content -}} {{- if .route_overview_url -}} {{- partial "button" diff --git a/layouts/shortcodes/highlight.html b/layouts/shortcodes/highlight.html index 1a4ddeea..3959aaeb 100644 --- a/layouts/shortcodes/highlight.html +++ b/layouts/shortcodes/highlight.html @@ -1,5 +1,10 @@ {{- $param := .Get 0 -}} -{{ $iconMapping := dict "important" "error" "inofficial" "warning" "tip" "lightbulb_2" "confusion" "question_exchange" }} +{{ $iconMapping := dict + "important" "campaign" + "inofficial" "warning" + "tip" "lightbulb_2" + "confusion" "question_exchange" +}}
From d917ef5c28413ae4d397528d66768c279337a384 Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Mon, 17 Nov 2025 21:50:48 +0100 Subject: [PATCH 09/20] fix: Add option to hide reservation information --- content/operator/sncf/index.en.md | 5 ++++- layouts/partials/train-category.html | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index a3839613..2f022c9d 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -237,7 +237,7 @@ This validation requirement does not apply to FIP Coupons. {{% train-category title="TGV/ICE trains to Germany" type="highspeed" - fip_accepted=partially + fip_accepted=true reservation_required=partially %}} International `TGV` and `ICE` trains are reservation-required in the French section. In Germany, reservations are not required and FIP Coupons are valid. @@ -271,6 +271,7 @@ RATP operates the Paris Métro, bus lines, and part of the tram and RER networks title="RER trains" type="regional" fip_accepted=partially + reservation_possible=nil %}} Some RER lines are operated by SNCF. FIP discounts apply on the following sections: @@ -287,6 +288,7 @@ Note: For journeys between Gare du Nord and Châtelet – Les Halles, only SNCF- title="Transilien trains" type="regional" fip_accepted=true + reservation_possible=nil %}} FIP discounts apply on all Transilien lines H, J, K, L, N, P, R, U, and V. {{% /train-category %}} @@ -295,6 +297,7 @@ FIP discounts apply on all Transilien lines H, J, K, L, N, P, R, U, and V. title="Trams" type="tram" fip_accepted=partially + reservation_possible=nil %}} Tram lines T4 and T11 are operated by SNCF and can be used with FIP discounts. Tram lines T9 and T13 are operated by SNCF and Keolis; FIP validity is unclear. FIP discounts do not apply on other tram lines. {{% /train-category %}} diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index de98a831..60d10db6 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -46,7 +46,7 @@ {{ partial "icon" "calendar_check" }} {{ i18n "trainCategory.reservation.possible" }} - {{- else -}} + {{- else if eq .reservation_possible false -}} {{ partial "icon" "calendar_lock" }} {{ i18n "trainCategory.reservation.notPossible" }} From 631eda6a66c8f5ac14ff352fd93958d4f2fe4591 Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Mon, 17 Nov 2025 22:16:42 +0100 Subject: [PATCH 10/20] fix: Remove footnote --- content/operator/sncf/index.en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index 2f022c9d..a2511876 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -249,7 +249,7 @@ International `TGV` and `ICE` trains are reservation-required in the French sect fip_accepted=partially reservation_required=true %}} -International `TGV` services from France to Italy, Spain, or Belgium are reservation-required throughout and FIP Coupons are not valid. Instead, FIP Global Fares can be purchased, which can be expensive (up to €130). [^1] +International `TGV` services from France to Italy, Spain, or Belgium are reservation-required throughout and FIP Coupons are not valid. Instead, FIP Global Fares can be purchased, which can be expensive (up to €130). {{% /train-category %}} {{% train-category From ce6d895e2cdb87907abe640f1fdf5fed08b70bde Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Mon, 17 Nov 2025 22:43:04 +0100 Subject: [PATCH 11/20] feat: Also change booking expanders to tags --- assets/sass/booking.scss | 2 + assets/sass/main.scss | 1 + assets/sass/tag.scss | 18 +++++ assets/sass/trainCategory.scss | 19 ------ i18n/de.yaml | 6 ++ i18n/en.yaml | 6 ++ i18n/fr.yaml | 6 ++ layouts/partials/booking.html | 63 +++++++++++++----- layouts/partials/tag.html | 4 ++ layouts/partials/train-category.html | 99 ++++++++++++++++++---------- 10 files changed, 154 insertions(+), 70 deletions(-) create mode 100644 assets/sass/tag.scss create mode 100644 layouts/partials/tag.html diff --git a/assets/sass/booking.scss b/assets/sass/booking.scss index 678d7dc9..a1d529b2 100644 --- a/assets/sass/booking.scss +++ b/assets/sass/booking.scss @@ -73,6 +73,8 @@ flex-direction: column; align-items: center; justify-content: center; + gap: 0.6rem; + font-size: 1.1em; @media (max-width: #{$breakpoint-md}) { align-items: flex-start; diff --git a/assets/sass/main.scss b/assets/sass/main.scss index 73bd963b..bb57e276 100644 --- a/assets/sass/main.scss +++ b/assets/sass/main.scss @@ -18,3 +18,4 @@ @import "interactiveMap.scss"; @import "dropdown.scss"; @import "trainCategory.scss"; +@import "tag.scss"; diff --git a/assets/sass/tag.scss b/assets/sass/tag.scss new file mode 100644 index 00000000..4d09175f --- /dev/null +++ b/assets/sass/tag.scss @@ -0,0 +1,18 @@ +.a-tag { + display: flex; + align-items: center; + gap: 0.4rem; + padding: 0.4rem 0.8rem; + border-radius: var(--border-radius-s); + font-size: 0.7em; + font-weight: 500; + white-space: nowrap; + + @each $name, $color in $tag-colors { + &--#{$name} { + background: var(--tag-#{$name}-bg); + color: var(--tag-#{$name}-color); + border: 0.1rem solid var(--tag-#{$name}-border); + } + } +} diff --git a/assets/sass/trainCategory.scss b/assets/sass/trainCategory.scss index 0154b663..c87bc553 100644 --- a/assets/sass/trainCategory.scss +++ b/assets/sass/trainCategory.scss @@ -18,25 +18,6 @@ gap: 0.6rem; } -.o-train-category__tag { - display: flex; - align-items: center; - gap: 0.4rem; - padding: 0.4rem 0.8rem; - border-radius: var(--border-radius-s); - font-size: 1.2rem; - font-weight: 500; - white-space: nowrap; - - @each $name, $color in $tag-colors { - &--#{$name} { - background: var(--tag-#{$name}-bg); - color: var(--tag-#{$name}-color); - border: 0.1rem solid var(--tag-#{$name}-border); - } - } -} - .o-expander__summary--train-category { &:hover, &:focus { diff --git a/i18n/de.yaml b/i18n/de.yaml index 0937dd0c..d080c176 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -9,9 +9,15 @@ booking: second: 2. Klasse fee: Buchungsgebühr fip-50: FIP 50 Fahrkarten + fip-50-bookable: FIP 50 Fahrkarten buchbar + fip-50-not-bookable: FIP 50 Fahrkarten nicht buchbar fip-global-fare: FIP Globalpreis + fip-global-fare-bookable: FIP Globalpreis buchbar + fip-global-fare-not-bookable: FIP Globalpreis nicht buchbar reservation: Reservierung + reservation-bookable: Reservierung buchbar reservation-costs: Reservierungskosten + reservation-not-bookable: Reservierung nicht buchbar visit-additional-information-website: Weitere Informationen visit-booking-website: Zur Buchungsseite contentNavigation: diff --git a/i18n/en.yaml b/i18n/en.yaml index a5cd013d..5f7819ac 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -8,9 +8,15 @@ booking: second: 2nd Class fee: Booking Fee fip-50: FIP 50 Tickets + fip-50-bookable: FIP 50 Tickets bookable + fip-50-not-bookable: FIP 50 Tickets not bookable fip-global-fare: FIP Global Fare + fip-global-fare-bookable: FIP Global Fare bookable + fip-global-fare-not-bookable: FIP Global Fare not bookable reservation: Reservation + reservation-bookable: Reservation bookable reservation-costs: Reservation Costs + reservation-not-bookable: Reservation not bookable visit-additional-information-website: Additional Information visit-booking-website: To Booking Website contentNavigation: diff --git a/i18n/fr.yaml b/i18n/fr.yaml index fc5ab05f..c3d78eda 100644 --- a/i18n/fr.yaml +++ b/i18n/fr.yaml @@ -8,9 +8,15 @@ booking: second: 2nd classe fee: Frais de réservation fip-50: Billets FIP 50 + fip-50-bookable: Billets FIP 50 réservables + fip-50-not-bookable: Billets FIP 50 non réservables fip-global-fare: Tarif Global FIP + fip-global-fare-bookable: Tarif Global FIP réservable + fip-global-fare-not-bookable: Tarif Global FIP non réservable reservation: Réservation + reservation-bookable: Réservation réservable reservation-costs: Frais de réservation + reservation-not-bookable: Réservation non réservable visit-additional-information-website: Informations complémentaires visit-booking-website: Aller sur le site de réservation contentNavigation: diff --git a/layouts/partials/booking.html b/layouts/partials/booking.html index b92f0757..6f41d3b0 100644 --- a/layouts/partials/booking.html +++ b/layouts/partials/booking.html @@ -14,23 +14,56 @@ {{- end }}
- {{- if ne .reservations "nil" -}} -
- {{- T "booking.reservation" }} - {{ if .reservations -}}✅{{- else -}}⛔{{- end -}} -
+ {{- if eq .reservations true -}} + {{- partial "tag" ( + dict + "Icon" "confirmation_number" + "Text" "booking.reservation-bookable" + "Type" "success" + ) + -}} + {{ else if eq .reservations false -}} + {{- partial "tag" ( + dict + "Icon" "credit_card_off" + "Text" "booking.reservation-not-bookable" + "Type" "error" + ) + -}} {{- end -}} - {{- if ne .fip_50 "nil" -}} -
- {{- T "booking.fip-50" }} - {{ if .fip_50 -}}✅{{- else -}}⛔{{- end -}} -
+ {{- if eq .fip_50 true -}} + {{- partial "tag" ( + dict + "Icon" "confirmation_number" + "Text" "booking.fip-50-bookable" + "Type" "success" + ) + -}} + {{ else if eq .fip_50 false -}} + {{- partial "tag" ( + dict + "Icon" "credit_card_off" + "Text" "booking.fip-50-not-bookable" + "Type" "error" + ) + -}} {{- end -}} - {{- if ne .fip_global_fare "nil" -}} -
- {{- T "booking.fip-global-fare" }} - {{ if .fip_global_fare -}}✅{{- else -}}⛔{{- end -}} -
+ {{- if eq .fip_global_fare true -}} + {{- partial "tag" ( + dict + "Icon" "confirmation_number" + "Text" "booking.fip-global-fare-bookable" + "Type" "success" + ) + -}} + {{ else if eq .fip_global_fare false -}} + {{- partial "tag" ( + dict + "Icon" "credit_card_off" + "Text" "booking.fip-global-fare-not-bookable" + "Type" "error" + ) + -}} {{- end -}}
diff --git a/layouts/partials/tag.html b/layouts/partials/tag.html new file mode 100644 index 00000000..f0cb4354 --- /dev/null +++ b/layouts/partials/tag.html @@ -0,0 +1,4 @@ + + {{ partial "icon" .Icon }} + {{ i18n .Text }} + diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index 60d10db6..45a36952 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -15,56 +15,83 @@
{{- if eq .fip_accepted true -}} - - {{ partial "icon" "check_circle" }} - {{ i18n "trainCategory.acceptance.accepted" }} - + {{ partial "tag" ( + dict + "Icon" "check_circle" + "Text" "trainCategory.acceptance.accepted" + "Type" "success" + ) + }} {{- else if eq .fip_accepted "partially" -}} - - {{ partial "icon" "info" }} - {{ i18n "trainCategory.acceptance.partiallyAccepted" }} - + {{ partial "tag" ( + dict + "Icon" "info" + "Text" "trainCategory.acceptance.partiallyAccepted" + "Type" "warning" + ) + }} {{- else -}} - - {{ partial "icon" "dangerous" }} - {{ i18n "trainCategory.acceptance.notAccepted" }} - + {{ partial "tag" ( + dict + "Icon" "dangerous" + "Text" "trainCategory.acceptance.notAccepted" + "Type" "error" + ) + }} {{- end -}} {{- if eq .reservation_required true -}} - - {{ partial "icon" "calendar_add_on" }} - {{ i18n "trainCategory.reservation.required" }} - + {{ partial "tag" ( + dict + "Icon" "calendar_add_on" + "Text" "trainCategory.reservation.required" + "Type" "error" + ) + }} {{- else if eq .reservation_required "partially" -}} - - {{ partial "icon" "calendar_add_on" }} - {{ i18n "trainCategory.reservation.partiallyRequired" }} - + {{ partial "tag" ( + dict + "Icon" "calendar_add_on" + "Text" "trainCategory.reservation.partiallyRequired" + "Type" "warning" + ) + }} {{- else if eq .reservation_possible true -}} - - {{ partial "icon" "calendar_check" }} - {{ i18n "trainCategory.reservation.possible" }} - + {{ partial "tag" ( + dict + "Icon" "calendar_check" + "Text" "trainCategory.reservation.possible" + "Type" "info" + ) + }} {{- else if eq .reservation_possible false -}} - - {{ partial "icon" "calendar_lock" }} - {{ i18n "trainCategory.reservation.notPossible" }} - + {{ partial "tag" ( + dict + "Icon" "calendar_lock" + "Text" "trainCategory.reservation.notPossible" + "Type" "info" + ) + }} {{- end -}} {{- if .risk_of_confusion -}} - - {{ partial "icon" "question_exchange" }} - {{ i18n "trainCategory.riskOfConfusion" }} - + {{ partial "tag" ( + dict + "Icon" "question_exchange" + "Text" "trainCategory.riskOfConfusion" + "Type" "warning" + ) + }} {{- end -}} {{- if .important_info -}} - - {{ partial "icon" "campaign" }} - {{ i18n "trainCategory.importantInformation" }} - + {{ partial "tag" ( + dict + "Icon" "campaign" + "Text" "trainCategory.importantInformation" + "Type" "warning" + ) + }} {{- end -}}
From f31855481f7cf1cba38d84328e72ccf63f385d0c Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Mon, 17 Nov 2025 22:45:09 +0100 Subject: [PATCH 12/20] feat: Improve sleeper train icon --- layouts/partials/train-category.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index 45a36952..7d3d85c2 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -5,7 +5,7 @@ {{ $iconMapping := dict "highspeed" "train" "regional" "directions_subway" - "sleeper" "airline_seat_flat" + "sleeper" "hotel" "funicular" "funicular" "bus" "directions_bus" "tram" "tram" From 7a361811f0b508dfcc9963e0602c4d7d125a777e Mon Sep 17 00:00:00 2001 From: MoritzWeber Date: Tue, 18 Nov 2025 16:13:50 +0100 Subject: [PATCH 13/20] fix: Align content with main branch --- content/operator/sncf/index.en.md | 24 ++++++++++++++++++++---- package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index a2511876..d0a10466 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -53,7 +53,7 @@ SNCF also operates low-cost `TGV` trains under the name OuiGo, which are not val {{% /highlight %}} {{% highlight important %}} -Special conditions apply for international connections, see International TGV inOui / ICE trains section below. +Special conditions apply for international connections, see [International TGV inOui / ICE trains](#international-tgv-inoui--ice-trains). {{% /highlight %}} ### Reservation @@ -90,6 +90,10 @@ SNCF also operates `TGV` trains under the inOui brand, which are valid with FIP. %}} International high-speed trains operated by SNCF in cooperation with Deutsche Bahn, running between France (Paris Est, Strasbourg) and Germany (Karlsruhe, Mannheim, Frankfurt am Main, Stuttgart, Munich). +{{% highlight important %}} +Special conditions apply for international connections, see [International TGV inOui / ICE trains](#international-tgv-inoui--ice-trains). +{{% /highlight %}} + ### Reservation Prices differ between peak and off-peak trains. The classification is not publicly available. @@ -105,7 +109,7 @@ Prices differ between peak and off-peak trains. The classification is not public title="Intercité (IC)" type="highspeed" fip_accepted=true - reservation_required=true + reservation_required=partially %}} Intercity trains operated by SNCF, connecting various cities in France, mostly requiring reservations. @@ -142,17 +146,29 @@ Cost depends on route and occupancy. title="Train express régional (TER)" type="regional" fip_accepted=true - reservation_possible=true + reservation_required=partially + risk_of_confusion=true %}} `TER` is SNCF's regional train, connecting various cities in France. +Some lines from Paris require reservations, see [Reservation requirement in regional trains](#reservation-requirement-in-regional-trains). + +{{% highlight confusion %}} +On the Marseille – Toulon – Nice route, FIP is not valid as `TER` trains are operated by Transdev. +{{% /highlight %}} {{% /train-category %}} {{% train-category title="Réseau Express Régional (RER)" type="regional" - fip_accepted=true + fip_accepted=partially + reservation_possible=false + important_info=true %}} RER is a suburban train operated by SNCF in Île de France (Greater Paris) and surrounding cities. + +{{% highlight important %}} +FIP is only valid on certain RER lines, see [Trains in Greater Paris](#trains-in-greater-paris) +{{% /highlight %}} {{% /train-category %}} ## Ticket and Reservation Purchase diff --git a/package-lock.json b/package-lock.json index 44749d9d..22cfd218 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@fontsource/material-symbols-rounded": "^5.2.26", + "@fontsource/material-symbols-rounded": "^5.2.29", "@fontsource/roboto": "^5.2.8", "@fontsource/sansita": "^5.2.8", "@panzoom/panzoom": "^4.6.0", @@ -21,9 +21,9 @@ } }, "node_modules/@fontsource/material-symbols-rounded": { - "version": "5.2.26", - "resolved": "https://registry.npmjs.org/@fontsource/material-symbols-rounded/-/material-symbols-rounded-5.2.26.tgz", - "integrity": "sha512-uvafxIB7sAzXhhwpZHAaugvgULhfA+wyzPomU2CyI+xzNMfyR/42QOKlEQkac+/0alRlczMI1f9o07CtN3a9dw==", + "version": "5.2.29", + "resolved": "https://registry.npmjs.org/@fontsource/material-symbols-rounded/-/material-symbols-rounded-5.2.29.tgz", + "integrity": "sha512-7TajzVIcRvnHfbnOWQ9G9tDmZSp7xyX8jK52c/tVPYpUPVvSxZOmQOffYrF1tbqr1HH8DXJd2I+oMIRrrDd20Q==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" diff --git a/package.json b/package.json index 26efce55..2555ed29 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "homepage": "https://github.com/fipguide/fipguide.github.io#readme", "description": "", "dependencies": { - "@fontsource/material-symbols-rounded": "^5.2.26", + "@fontsource/material-symbols-rounded": "^5.2.29", "@fontsource/roboto": "^5.2.8", "@fontsource/sansita": "^5.2.8", "@panzoom/panzoom": "^4.6.0", From eb7a02d9de20d23f0c4cfcbe62239248be3353d2 Mon Sep 17 00:00:00 2001 From: MoritzWeber Date: Fri, 21 Nov 2025 18:03:13 +0100 Subject: [PATCH 14/20] fix: Replace dangerous icon with cancel --- layouts/partials/train-category.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index 7d3d85c2..8cef96f1 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -33,7 +33,7 @@ {{- else -}} {{ partial "tag" ( dict - "Icon" "dangerous" + "Icon" "cancel" "Text" "trainCategory.acceptance.notAccepted" "Type" "error" ) From 3588c0c59c5cf88d694cd07c219c10bc7d30b9a2 Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Fri, 21 Nov 2025 22:24:27 +0100 Subject: [PATCH 15/20] feat: Auto-derive important info and risk of confusion --- content/operator/sncf/index.en.md | 5 ----- layouts/shortcodes/train-category.html | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/content/operator/sncf/index.en.md b/content/operator/sncf/index.en.md index d0a10466..71092a02 100644 --- a/content/operator/sncf/index.en.md +++ b/content/operator/sncf/index.en.md @@ -42,8 +42,6 @@ Reservations are mandatory on all `TGV`, almost all `IC` trains, and some region type="highspeed" fip_accepted=true reservation_required=true - risk_of_confusion=true - important_info=true route_overview_url="https://www.sncf-connect.com/assets/media/2021-05/2014_axes-tgv_0.pdf" %}} The `TGV` inOui is SNCF's high-speed train, connecting many cities in France and international destinations (e.g. Munich, Frankfurt am Main, Barcelona, Luxembourg, Brussels, Zurich, Milan). Each seat number exists twice in the carriage; the reserved seat is the one with the illuminated number. @@ -72,7 +70,6 @@ Prices differ between peak and off-peak trains. The classification is not public type="highspeed" fip_accepted=false reservation_required=true - risk_of_confusion=true %}} The `TGV` OuiGo is SNCF's low-cost high-speed train, serving many cities in France and some international destinations. @@ -147,7 +144,6 @@ Cost depends on route and occupancy. type="regional" fip_accepted=true reservation_required=partially - risk_of_confusion=true %}} `TER` is SNCF's regional train, connecting various cities in France. Some lines from Paris require reservations, see [Reservation requirement in regional trains](#reservation-requirement-in-regional-trains). @@ -162,7 +158,6 @@ On the Marseille – Toulon – Nice route, FIP is not valid as `TER` trains are type="regional" fip_accepted=partially reservation_possible=false - important_info=true %}} RER is a suburban train operated by SNCF in Île de France (Greater Paris) and surrounding cities. diff --git a/layouts/shortcodes/train-category.html b/layouts/shortcodes/train-category.html index c6a67ac5..48022f4f 100644 --- a/layouts/shortcodes/train-category.html +++ b/layouts/shortcodes/train-category.html @@ -4,8 +4,8 @@ "fip_accepted" (default true (.Get "fip_accepted")) "reservation_required" (default false (.Get "reservation_required")) "reservation_possible" (default false (.Get "reservation_possible")) - "risk_of_confusion" (default false (.Get "risk_of_confusion")) - "important_info" (default false (.Get "important_info")) + "risk_of_confusion" (strings.Contains .Inner "m-text-highlight--confusion") + "important_info" (strings.Contains .Inner "m-text-highlight--important") "route_overview_url" (.Get "route_overview_url") "additional_information_url" (.Get "additional_information_url") "content" (.Inner | .Page.RenderString) From 3896fab1a8af479b50489665b10fa0e556381cb1 Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Fri, 21 Nov 2025 22:28:15 +0100 Subject: [PATCH 16/20] feat: Change info tag color to grey --- assets/sass/_variables.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/sass/_variables.scss b/assets/sass/_variables.scss index 5fc4ff62..2b433eb2 100644 --- a/assets/sass/_variables.scss +++ b/assets/sass/_variables.scss @@ -18,14 +18,14 @@ $tag-colors: ( success: #155724, warning: #b64900, error: #b70000, - info: #004085, + info: #414141, ); $tag-colors-dark: ( success: #a8d5ba, warning: #f0d98d, error: #f5a9ae, - info: #a8d5f5, + info: #d1d1d1, ); html { From 3962ebd91ead98d2182c8a1eff7e49e1e5dcaf4f Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Sun, 23 Nov 2025 16:37:27 +0100 Subject: [PATCH 17/20] fix: Remove risk_of_confusion and important_info from AI command --- .opencode/command/update-traincategory.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/.opencode/command/update-traincategory.md b/.opencode/command/update-traincategory.md index 1cc56127..3a3a26a1 100644 --- a/.opencode/command/update-traincategory.md +++ b/.opencode/command/update-traincategory.md @@ -14,8 +14,6 @@ A shortcode looks like: fip_accepted=true (can be true, false, partially) reservation_required=true (can be true, false, partially) reservation_possible=true (omit the attribute if false or if reservation_required is true) - risk_of_confusion=true (previously marked with ℹ️ in the title, omit the attribute if false) - important_info=true (if an important highlight is part of the train category, omit the attribute if false) route_overview_url="https://example.com" (if there is an route overview link in the description, otherwise omit the attribute) additional_information_url="https://example.com" (if there is an additional information link in the description, otherwise omit the attribute) %}} From 67eb974c37b792a57c94e91651fbf2e708d01719 Mon Sep 17 00:00:00 2001 From: MoritzWeber Date: Sat, 29 Nov 2025 22:34:22 +0100 Subject: [PATCH 18/20] fix: Change back to old style booking expanders --- assets/sass/booking.scss | 2 -- i18n/de.yaml | 6 ---- i18n/en.yaml | 6 ---- i18n/fr.yaml | 6 ---- layouts/partials/booking.html | 63 +++++++++-------------------------- 5 files changed, 15 insertions(+), 68 deletions(-) diff --git a/assets/sass/booking.scss b/assets/sass/booking.scss index a1d529b2..678d7dc9 100644 --- a/assets/sass/booking.scss +++ b/assets/sass/booking.scss @@ -73,8 +73,6 @@ flex-direction: column; align-items: center; justify-content: center; - gap: 0.6rem; - font-size: 1.1em; @media (max-width: #{$breakpoint-md}) { align-items: flex-start; diff --git a/i18n/de.yaml b/i18n/de.yaml index d080c176..0937dd0c 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -9,15 +9,9 @@ booking: second: 2. Klasse fee: Buchungsgebühr fip-50: FIP 50 Fahrkarten - fip-50-bookable: FIP 50 Fahrkarten buchbar - fip-50-not-bookable: FIP 50 Fahrkarten nicht buchbar fip-global-fare: FIP Globalpreis - fip-global-fare-bookable: FIP Globalpreis buchbar - fip-global-fare-not-bookable: FIP Globalpreis nicht buchbar reservation: Reservierung - reservation-bookable: Reservierung buchbar reservation-costs: Reservierungskosten - reservation-not-bookable: Reservierung nicht buchbar visit-additional-information-website: Weitere Informationen visit-booking-website: Zur Buchungsseite contentNavigation: diff --git a/i18n/en.yaml b/i18n/en.yaml index 5f7819ac..a5cd013d 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -8,15 +8,9 @@ booking: second: 2nd Class fee: Booking Fee fip-50: FIP 50 Tickets - fip-50-bookable: FIP 50 Tickets bookable - fip-50-not-bookable: FIP 50 Tickets not bookable fip-global-fare: FIP Global Fare - fip-global-fare-bookable: FIP Global Fare bookable - fip-global-fare-not-bookable: FIP Global Fare not bookable reservation: Reservation - reservation-bookable: Reservation bookable reservation-costs: Reservation Costs - reservation-not-bookable: Reservation not bookable visit-additional-information-website: Additional Information visit-booking-website: To Booking Website contentNavigation: diff --git a/i18n/fr.yaml b/i18n/fr.yaml index c3d78eda..fc5ab05f 100644 --- a/i18n/fr.yaml +++ b/i18n/fr.yaml @@ -8,15 +8,9 @@ booking: second: 2nd classe fee: Frais de réservation fip-50: Billets FIP 50 - fip-50-bookable: Billets FIP 50 réservables - fip-50-not-bookable: Billets FIP 50 non réservables fip-global-fare: Tarif Global FIP - fip-global-fare-bookable: Tarif Global FIP réservable - fip-global-fare-not-bookable: Tarif Global FIP non réservable reservation: Réservation - reservation-bookable: Réservation réservable reservation-costs: Frais de réservation - reservation-not-bookable: Réservation non réservable visit-additional-information-website: Informations complémentaires visit-booking-website: Aller sur le site de réservation contentNavigation: diff --git a/layouts/partials/booking.html b/layouts/partials/booking.html index 6f41d3b0..b92f0757 100644 --- a/layouts/partials/booking.html +++ b/layouts/partials/booking.html @@ -14,56 +14,23 @@ {{- end }}
- {{- if eq .reservations true -}} - {{- partial "tag" ( - dict - "Icon" "confirmation_number" - "Text" "booking.reservation-bookable" - "Type" "success" - ) - -}} - {{ else if eq .reservations false -}} - {{- partial "tag" ( - dict - "Icon" "credit_card_off" - "Text" "booking.reservation-not-bookable" - "Type" "error" - ) - -}} + {{- if ne .reservations "nil" -}} +
+ {{- T "booking.reservation" }} + {{ if .reservations -}}✅{{- else -}}⛔{{- end -}} +
{{- end -}} - {{- if eq .fip_50 true -}} - {{- partial "tag" ( - dict - "Icon" "confirmation_number" - "Text" "booking.fip-50-bookable" - "Type" "success" - ) - -}} - {{ else if eq .fip_50 false -}} - {{- partial "tag" ( - dict - "Icon" "credit_card_off" - "Text" "booking.fip-50-not-bookable" - "Type" "error" - ) - -}} + {{- if ne .fip_50 "nil" -}} +
+ {{- T "booking.fip-50" }} + {{ if .fip_50 -}}✅{{- else -}}⛔{{- end -}} +
{{- end -}} - {{- if eq .fip_global_fare true -}} - {{- partial "tag" ( - dict - "Icon" "confirmation_number" - "Text" "booking.fip-global-fare-bookable" - "Type" "success" - ) - -}} - {{ else if eq .fip_global_fare false -}} - {{- partial "tag" ( - dict - "Icon" "credit_card_off" - "Text" "booking.fip-global-fare-not-bookable" - "Type" "error" - ) - -}} + {{- if ne .fip_global_fare "nil" -}} +
+ {{- T "booking.fip-global-fare" }} + {{ if .fip_global_fare -}}✅{{- else -}}⛔{{- end -}} +
{{- end -}}
From 83641b2f49a30b2e1915a4b2e9dcfa9255eddb6d Mon Sep 17 00:00:00 2001 From: MoritzWeber Date: Thu, 20 Nov 2025 18:22:49 +0100 Subject: [PATCH 19/20] feat: Only show icon for expanders on mobile --- assets/sass/trainCategory.scss | 11 ++++++++++- layouts/partials/tag.html | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/assets/sass/trainCategory.scss b/assets/sass/trainCategory.scss index c87bc553..4cb21fe3 100644 --- a/assets/sass/trainCategory.scss +++ b/assets/sass/trainCategory.scss @@ -18,7 +18,7 @@ gap: 0.6rem; } -.o-expander__summary--train-category { +details.o-expander__summary--train-category { &:hover, &:focus { .o-train-category__title-text { @@ -26,6 +26,15 @@ } } } + +details.o-expander--train-category:not([open]) { + @media (max-width: $breakpoint-md) { + .a-tag__text { + display: none; + } + } +} + .o-train-category__content { .m-text-highlight { &--important, diff --git a/layouts/partials/tag.html b/layouts/partials/tag.html index f0cb4354..c53e1662 100644 --- a/layouts/partials/tag.html +++ b/layouts/partials/tag.html @@ -1,4 +1,4 @@ {{ partial "icon" .Icon }} - {{ i18n .Text }} + {{ i18n .Text }} From 3adb4d5ef1c8caeaef38a52a73cd1432a7c148d0 Mon Sep 17 00:00:00 2001 From: MoritzWeber0 Date: Sun, 7 Dec 2025 22:38:13 +0100 Subject: [PATCH 20/20] feat: Add partially possible reservation and subway --- .opencode/command/update-traincategory.md | 10 ++++-- i18n/de.yaml | 1 + i18n/en.yaml | 1 + i18n/fr.yaml | 1 + layouts/partials/train-category.html | 43 ++++++++++++++--------- 5 files changed, 38 insertions(+), 18 deletions(-) diff --git a/.opencode/command/update-traincategory.md b/.opencode/command/update-traincategory.md index 3a3a26a1..13767619 100644 --- a/.opencode/command/update-traincategory.md +++ b/.opencode/command/update-traincategory.md @@ -10,16 +10,18 @@ A shortcode looks like: ``` {{% train-category title="title" - type="highspeed" (can be highspeed, regional, bus, funicular, sleeper) + type="highspeed" (can be highspeed, regional, subway, bus, funicular, sleeper) fip_accepted=true (can be true, false, partially) reservation_required=true (can be true, false, partially) - reservation_possible=true (omit the attribute if false or if reservation_required is true) + reservation_possible=true (can be true, false, partially; omit the attribute if false or if reservation_required is true) route_overview_url="https://example.com" (if there is an route overview link in the description, otherwise omit the attribute) additional_information_url="https://example.com" (if there is an additional information link in the description, otherwise omit the attribute) %}} {{% /train-category %}} ``` +Do not use brackets around boolean attributes like true and false. Place each attribute in a new line. + Important information (previously paragraphs that started with ⚠️ in the text) should be changed to an important highlight shortcut (in the same position as the text was before): ``` @@ -35,3 +37,7 @@ If there is a risk of confusion (previously marked with ℹ️ in the text), add ``` Tranform the "**Reservation cost:**" (or language equivalent) section to a heading "### Reservation". + +If there is additional information in the text that can't be represented in the shortcode, add the information to the text. For example "**Reservation required:** ⚠️ sometimes (marked with _R_)" becomes "A reservation is required for some trains (marked with _R_)." + +Make sure to remove the old expanders after adding the shortcode. diff --git a/i18n/de.yaml b/i18n/de.yaml index 0937dd0c..4fe810fa 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -111,6 +111,7 @@ trainCategory: importantInformation: Wichtige Informationen reservation: notPossible: Keine Reservierung möglich + partiallyPossible: Reservierung teilweise möglich partiallyRequired: Reservierung teilweise erforderlich possible: Reservierung möglich required: Reservierung erforderlich diff --git a/i18n/en.yaml b/i18n/en.yaml index a5cd013d..bfc30a1b 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -107,6 +107,7 @@ trainCategory: importantInformation: Important information reservation: notPossible: No reservation possible + partiallyPossible: Reservation partially possible partiallyRequired: Reservation partially required possible: Reservation possible required: Reservation required diff --git a/i18n/fr.yaml b/i18n/fr.yaml index fc5ab05f..1c011dc5 100644 --- a/i18n/fr.yaml +++ b/i18n/fr.yaml @@ -107,6 +107,7 @@ trainCategory: importantInformation: Informations importantes reservation: notPossible: Aucune réservation possible + partiallyPossible: Réservation partiellement possible partiallyRequired: Réservation partiellement requise possible: Réservation possible required: Réservation requise diff --git a/layouts/partials/train-category.html b/layouts/partials/train-category.html index 8cef96f1..d0568579 100644 --- a/layouts/partials/train-category.html +++ b/layouts/partials/train-category.html @@ -5,6 +5,7 @@ {{ $iconMapping := dict "highspeed" "train" "regional" "directions_subway" + "subway" "subway" "sleeper" "hotel" "funicular" "funicular" "bus" "directions_bus" @@ -64,6 +65,14 @@ "Type" "info" ) }} + {{- else if eq .reservation_possible "partially" -}} + {{ partial "tag" ( + dict + "Icon" "calendar_lock" + "Text" "trainCategory.reservation.partiallyPossible" + "Type" "info" + ) + }} {{- else if eq .reservation_possible false -}} {{ partial "tag" ( dict @@ -100,21 +109,23 @@
{{- .content -}} - {{- if .route_overview_url -}} - {{- partial "button" - (dict - "Destination" .route_overview_url - "Text" (T "trainCategory.routeOverview") - ) - -}} - {{- end -}} - {{- if .additional_information_url -}} - {{- partial "button" - (dict - "Destination" .additional_information_url - "Text" (T "trainCategory.additionalInformation") - ) - -}} - {{- end -}} +
+ {{- if .route_overview_url -}} + {{- partial "button" + (dict + "Destination" .route_overview_url + "Text" (T "trainCategory.routeOverview") + ) + -}} + {{- end -}} + {{- if .additional_information_url -}} + {{- partial "button" + (dict + "Destination" .additional_information_url + "Text" (T "trainCategory.additionalInformation") + ) + -}} + {{- end -}} +