Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1944c1c
feat: Add support for dialogs
MoritzWeber0 Feb 8, 2026
ad787ce
fix: new lines for stena line booking source
MoritzWeber0 Feb 8, 2026
f585655
fix: show dialog triggers as inline text
MoritzWeber0 Feb 8, 2026
e38efc0
feat: Also open dialog on enter key
MoritzWeber0 Feb 8, 2026
083bb36
fix: z-index
MoritzWeber0 Feb 8, 2026
3989d85
refactor: improve naming of classes
MoritzWeber0 Feb 8, 2026
950ba4f
Merge branch 'main' into feat/add-dialogs
MoritzWeber0 Feb 8, 2026
d5598ef
fix: rounded scrollbar corners
MoritzWeber0 Feb 8, 2026
6be422b
refactor: rename button classes
MoritzWeber0 Feb 8, 2026
e5edbe9
Merge branch 'main' into feat/add-dialogs
MoritzWeber0 Feb 8, 2026
d393caf
feat: add issuer specific fip validity to operator pages
MoritzWeber0 Feb 8, 2026
f3fb427
feat: use cancel icon
MoritzWeber0 Feb 8, 2026
fca208d
refactor: transform to fip-validity shortcodes
MoritzWeber0 Feb 8, 2026
f99910a
fix: handle renfe and euskotren
MoritzWeber0 Feb 8, 2026
a8f8a46
fix: add missing translation key
MoritzWeber0 Feb 8, 2026
7302e11
feat: Add Deutsche Bahn FIP validity
MoritzWeber0 Feb 8, 2026
1e3d946
fix: change all "fip-coupon-relatives" to unknown
MoritzWeber0 Feb 8, 2026
2d7d3df
feat: Add FIP validity for SNCF employees
MoritzWeber0 Feb 8, 2026
0d8b948
feat: align db information to the existing style
MoritzWeber0 Feb 8, 2026
3ffed75
feat: add information for gb employees
MoritzWeber0 Feb 8, 2026
35235a5
fix: Unify fip relatives text for db
MoritzWeber0 Feb 8, 2026
583a26d
fix: hide current operator from table
MoritzWeber0 Feb 8, 2026
aa88623
feat: Use button-internal instead of custom button implementation
MoritzWeber0 Feb 8, 2026
c06ad25
feat: update archetarchetypess
MoritzWeber0 Feb 8, 2026
63d2c58
feat: use dvh instead vh
MoritzWeber0 Feb 8, 2026
48f2668
Merge branch 'feat/add-dialogs' into feat/fip-validity
MoritzWeber0 Feb 8, 2026
162c0cc
feat: add number of fields per coupon for gb
MoritzWeber0 Feb 9, 2026
2adf632
fix: add additional discount explanation
lenderom Feb 9, 2026
ee54aeb
fix: minor remove FIP 75 from other pages to make it consistent
lenderom Feb 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions archetypes/operator/index.de.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ country:
- "country2"
- "country3"
operator: "{{ .File.ContentBaseName }}"
Params:
fip-validity:
operator1:
fip-coupon:
status: valid
text: "1 Freifahrtschein mit jeweils 4 Feldern pro Jahr. Jedes Feld ist zwei Tage gültig."
fip-coupon-relatives:
status: invalid # oder valid mit entsprechendem Text
text: "Nicht verfügbar" # oder "1 Freifahrtschein mit jeweils 4 Feldern pro Jahr. Jedes Feld ist zwei Tage gültig."
fip-reduced-ticket:
status: valid
text: "50 % Rabatt"
---

<!-- Entferne das "WIP" Snippet, wenn die Inhalte der Seite vollständig sind -->
Expand All @@ -33,10 +45,18 @@ operator: "{{ .File.ContentBaseName }}"
Die Ticketkategorien können je nach Betreiber abweichen.
-->

FIP Freifahrtschein: <✅/⛔> \
FIP Freifahrt Angehörige: <✅/⛔> \
FIP 50 Tickets: <✅/⛔> \
FIP Globalpreis: <✅/⛔>
<!--
Verwende die folgenden Shortcodes, um die FIP-Gültigkeit anzuzeigen. Die folgenden Parameter können übergeben werden:
- `type`: fip-coupon, fip-coupon-relatives, fip-reduced-ticket, fip-global-fare, additional
- `status`: valid, invalid, unknown
- `text`: Optionaler benutzerdefinierter Text zur Anzeige
- `disable_dialog`: true/false (Standard: false) - Auf true setzen, um den Dialog zu deaktivieren
-->

{{< fip-validity type="fip-coupon" status="valid" >}}
{{< fip-validity type="fip-coupon-relatives" status="unknown" >}}
{{< fip-validity type="fip-reduced-ticket" status="valid" >}}
{{< fip-validity type="fip-global-fare" status="valid" >}}

<!--
Wo gelten FIP 50 Tickets/FIP Freifahrtscheine und gibt es Einschränkungen? Welches Ticket wird bei Einreise benötigt (z. B. durchgehendes FIP 50 Ticket oder FIP Freifahrtscheine beider Länder)
Expand Down
28 changes: 24 additions & 4 deletions archetypes/operator/index.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ country:
- "country2"
- "country3"
operator: "{{ .File.ContentBaseName }}"
Params:
fip-validity:
operator1:
fip-coupon:
status: valid
text: "1 coupon with 4 fields each per year. Each field is valid for two days."
fip-coupon-relatives:
status: invalid # or valid with corresponding text
text: "Not available" # or "1 coupon with 4 fields each per year. Each field is valid for two days."
fip-reduced-ticket:
status: valid
text: "50% discount"
---

<!-- Remove the WIP snippet if the page is complete -->
Expand All @@ -33,10 +45,18 @@ operator: "{{ .File.ContentBaseName }}"
The ticket categories may vary depending on the operator.
-->

FIP Coupon: <✅/⛔> \
FIP Coupon for relatives: <✅/⛔> \
FIP 50 Tickets: <✅/⛔> \
FIP Global Fare: <✅/⛔>
<!--
Use the following shortcodes to display FIP validity. The following parameters can be passed:
- `type`: fip-coupon, fip-coupon-relatives, fip-reduced-ticket, fip-global-fare, additional
- `status`: valid, invalid, unknown
- `text`: Optional custom text to display
- `disable_dialog`: true/false (default: false) - Set to true to disable the dialog
-->

{{< fip-validity type="fip-coupon" status="valid" >}}
{{< fip-validity type="fip-coupon-relatives" status="unknown" >}}
{{< fip-validity type="fip-reduced-ticket" status="valid" >}}
{{< fip-validity type="fip-global-fare" status="valid" >}}

<!--
Where are FIP 50 Tickets/FIP Coupons valid and are there any restrictions? Which ticket is required for entry (e.g., continuous FIP 50 ticket or FIP Coupons of both countries)?
Expand Down
28 changes: 24 additions & 4 deletions archetypes/operator/index.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ country:
- "country2"
- "country3"
operator: "{{ .File.ContentBaseName }}"
Params:
fip-validity:
operator1:
fip-coupon:
status: valid
text: "1 coupon avec 4 champs chacun par an. Chaque champ est valable deux jours."
fip-coupon-relatives:
status: invalid # ou valid avec texte correspondant
text: "Pas disponible" # ou "1 coupon avec 4 champs chacun par an. Chaque champ est valable deux jours."
fip-reduced-ticket:
status: valid
text: "50 % de réduction"
---

<!-- Supprimez ce message si la page est complète -->
Expand All @@ -33,10 +45,18 @@ operator: "{{ .File.ContentBaseName }}"
Les catégories de billets peuvent varier selon l’opérateur.
-->

Coupon FIP : <✅/⛔> \
Coupon FIP pour les ayants droit : <✅/⛔> \
Billets FIP 50 : <✅/⛔> \
Tarif Global FIP : <✅/⛔>
<!--
Utilisez les shortcodes suivants pour afficher la validité FIP. Les paramètres suivants peuvent être transmis :
- `type` : fip-coupon, fip-coupon-relatives, fip-reduced-ticket, fip-global-fare, additional
- `status` : valid, invalid, unknown
- `text` : Texte personnalisé optionnel à afficher
- `disable_dialog` : true/false (par défaut : false) - Définir sur true pour désactiver la boîte de dialogue
-->

{{< fip-validity type="fip-coupon" status="valid" >}}
{{< fip-validity type="fip-coupon-relatives" status="unknown" >}}
{{< fip-validity type="fip-reduced-ticket" status="valid" >}}
{{< fip-validity type="fip-global-fare" status="valid" >}}

<!--
Où les Billets FIP 50 / Coupons FIP sont-ils valables et quelles sont les restrictions ? Quel billet est nécessaire pour le voyage (par ex. Billet FIP 50 continu ou Coupons FIP des deux pays) ?
Expand Down
60 changes: 60 additions & 0 deletions assets/js/dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {
openOverlay,
closeOverlay,
addOverlayClickListener,
} from "./overlay.js";

function openDialog(dialogId) {
const dialog = document.getElementById(dialogId);
if (!dialog) return;

dialog.show();
openOverlay("dialog");

const closeButton = dialog.querySelector(".o-dialog__header > .a-button");
if (closeButton) {
closeButton.addEventListener("click", () => closeDialog(dialog));
}
}

function closeDialog(dialog) {
dialog.close();
closeOverlay();
}

function closeAllDialogs() {
document.querySelectorAll("dialog[open]").forEach((dialog) => {
closeDialog(dialog);
});
}

function initDialogs() {
document.querySelectorAll("[data-dialog-trigger]").forEach((trigger) => {
const handler = (e) => {
if (e.type === "click" || (e.type === "keydown" && e.key === "Enter")) {
e.preventDefault();
const dialogId = trigger.getAttribute("data-dialog-trigger");
openDialog(dialogId);
}
};

trigger.addEventListener("click", handler);
trigger.addEventListener("keydown", handler);
});

addOverlayClickListener(() => {
closeAllDialogs();
});

document.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
closeAllDialogs();
}
});
}

if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initDialogs);
} else {
initDialogs();
}
1 change: 1 addition & 0 deletions assets/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ import "./dropdown.js";
import "./search.js";
import "./interactiveMap.js";
import "./expander.js";
import "./dialog.js";
20 changes: 20 additions & 0 deletions assets/sass/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ $tag-colors-dark: (
info: #d1d1d1,
);

$fip-validity-colors: (
valid: map-get($tag-colors, success),
invalid: map-get($tag-colors, error),
unknown: map-get($tag-colors, info),
);

$fip-validity-colors-dark: (
valid: map-get($tag-colors-dark, success),
invalid: map-get($tag-colors-dark, error),
unknown: map-get($tag-colors-dark, info),
);

$highlight-colors: (
tip: #116278,
inofficial: #42454a,
Expand Down Expand Up @@ -60,6 +72,10 @@ html {
--color-success: #096640;
--color-error: #ad1731;

@each $name, $color in $fip-validity-colors {
--fip-validity-#{$name}: #{$color};
}

@each $name, $color in $tag-colors {
--tag-#{$name}-bg: #{mix(white, $color, 90%)};
--tag-#{$name}-color: #{$color};
Expand Down Expand Up @@ -101,6 +117,10 @@ html[data-theme="dark"] {
--color-success: #2ea44f;
--color-error: #f85149;

@each $name, $color in $fip-validity-colors-dark {
--fip-validity-#{$name}: #{$color};
}

@each $name, $color in $tag-colors-dark {
--tag-#{$name}-bg: #{mix(black, $color, 65%)};
--tag-#{$name}-color: #{$color};
Expand Down
9 changes: 8 additions & 1 deletion assets/sass/button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
display: inline-flex;
align-items: center;
gap: 0.4rem;
border: 0.2rem solid var(--link-default);
border-radius: var(--border-radius-m);
font-size: 1.5rem;
cursor: pointer;
Expand All @@ -25,4 +24,12 @@
padding: 0.6rem;
display: block;
}

&__external {
border: 0.2rem solid var(--link-default);
}

&__internal {
border: none;
}
}
48 changes: 48 additions & 0 deletions assets/sass/dialog.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.o-dialog {
max-height: calc(100dvh - 14rem);
overflow: auto;

.a-anchorlink {
margin-bottom: 0;

&__link {
display: none;
}
}

&__wrapper {
width: fit-content;
position: fixed;
top: 7rem;
border: none;
padding: 0;
background-color: var(--bg-default);
color: var(--color-body);
border-radius: var(--border-radius-m);
z-index: 12;
border: var(--border);
overflow: hidden;
}

&__header {
display: flex;
column-gap: 1rem;
align-items: center;
justify-content: space-between;
padding: 1.6rem 2rem;
border-bottom: var(--border);
border-color: var(--color-table-border);

.o-divider {
display: none;
}
}

&__body {
padding: 2rem;

> *:last-child {
margin-bottom: 0;
}
}
}
11 changes: 11 additions & 0 deletions assets/sass/fip-validity.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.o-fip-validity {
display: flex;
align-items: center;
gap: 0.5rem;

@each $status in valid, invalid, unknown {
&--#{$status} {
color: var(--fip-validity-#{$status});
}
}
}
5 changes: 5 additions & 0 deletions assets/sass/header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@
z-index: 14;
}

#header:has(.overlay--dialog),
.overlay--dialog {
z-index: 10;
}

body:has(.overlay--show) {
overflow: hidden;
}
2 changes: 2 additions & 0 deletions assets/sass/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@
@import "tag.scss";
@import "floatImage.scss";
@import "teamMember.scss";
@import "dialog.scss";
@import "fip-validity.scss";
9 changes: 8 additions & 1 deletion assets/sass/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,16 @@ button {
@include focus-indicator(0.2rem);
}

a {
a,
.o-link {
color: var(--link-default);
transition:
color 0.3s ease,
background-color 0.3s ease;
text-underline-offset: 0.2rem;
border-radius: var(--border-radius-s);
text-decoration: underline;
cursor: pointer;

&:hover,
&:focus {
Expand All @@ -80,6 +83,10 @@ a {
display: none;
}
}

& > [data-icon="open_in_browser"] {
margin-left: 0.2rem;
}
}

main {
Expand Down
2 changes: 1 addition & 1 deletion content/country/belgium/index.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Additionally, international [Eurostar](/operator/eurostar "Eurostar") trains ope
Furthermore, international `TGV` trains of the [SNCF](/operator/sncf "SNCF") from France operate, for which the FIP Coupon of SNCB are not valid. Only special FIP Global Fares can be booked for these trains. For the Eurocity trains from Brussels to Paris operated by OUIGO, no FIP discounts apply.

{{< identify-operator sources="db-website,vagonweb" >}}
Not all trains in the country (e. g. `ICE`) are shown in the [SNCB / NMBS online timetable](https://www.belgiantrain.be/en/).
Not all trains in the country (e.g. `ICE`) are shown in the [SNCB / NMBS online timetable](https://www.belgiantrain.be/en/).
{{< /identify-operator >}}

## Interesting
Expand Down
2 changes: 2 additions & 0 deletions content/generalinformation/_index.de.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ Um länger als acht Tage in einem Land bzw. bei einem Betreiber Zug fahren zu k

FIP Berechtigte können reduzierte Tickets erwerben. Diese kosten im Regelfall 50% des flexiblen Preises. Daher sind diese Tickets nicht zuggebunden und flexibel auf der Strecke nutzbar, außer es handelt sich um reservierungspflichtige Züge. Einige Bahngesellschaften haben bilaterale Abkommen und gewähren gegenseitig einen höheren Rabatt z. B. 75%.

Bei welchen Bahngesellschaften welcher Rabatt gewährt wird ist auf der Seite der jeweiligen Bahngesellschaft im FIP Guide aufgeführt. Zur besseren Lesbarkeit werden im FIP Guide alle diese Tickets als FIP 50 Tickets bezeichnet, auch wenn teilweise 75 % Rabatt gewährt wird und sie oftmals als FIP 75 Ticket bezeichnet werden.

FIP 50 Tickets können jederzeit in beliebiger Anzahl gekauft werden. Mit FIP 50 besteht einfach eine Art Rabattkarte für viele Verbindungen. Ein FIP 50 Ticket kann dabei auch mehrere Betreiber abdecken.

Die Bestellung unterscheidet sich von FIP Freifahrtscheinen: während letztere von der eigenen Bahngesellschaft ausgestellt werden, können FIP 50 Tickets über unterschiedliche Wege erworben werden. Für eine Fahrt innerhalb eines Landes ist ein lokaler Ticketschalter bzw. Reisezentrum meist eine gute Anlaufstelle. Bei einigen Betreibern ist die Buchung auch online oder am Automaten möglich. Die Preise für FIP 50 Tickets können sich je nach Verkaufsstelle unterscheiden. Auf den jeweiligen Länder- und Betrieberseiten des FIP Guides versuchen wir, die Informationen zum Kauf der Tickets bestmöglich zusammenzufassen.
Expand Down
2 changes: 2 additions & 0 deletions content/generalinformation/_index.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ To travel by train for longer than eight days in one country or with one operato

FIP-eligible employees can purchase discounted tickets. These typically cost 50% of the flexible price. Therefore, these tickets are not train-specific and can be used flexibly on the route, unless the train requires a mandatory reservation. Some railway companies have bilateral agreements and grant each other higher discounts, for example 75%.

Which railway companies grant which discount is listed on the respective railway company's page in the FIP Guide. For better readability, the FIP Guide refers to all these tickets as FIP 50 Tickets, even if sometimes a 75% discount is granted and they are often called FIP 75 Tickets.

FIP 50 Tickets can be purchased at any time in any quantity. FIP 50 essentially functions as a discount card for many connections. A single FIP 50 Ticket can cover multiple operators.

The purchase process differs from FIP Coupons. While the latter are issued by your own railway company, FIP 50 Tickets can be purchased in various ways. For travel within a country, a local ticket counter or travel center is usually a good starting point. Some operators also allow booking online or via ticket machines. On the respective country and operator pages, we try to summarize the information on ticket purchases as comprehensively as possible. Prices for FIP 50 Tickets can vary depending on the sales outlet.
Expand Down
4 changes: 3 additions & 1 deletion content/generalinformation/_index.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ Pour voyager en train pendant plus de huit jours dans un pays ou avec un opérat

Les employés éligibles au FIP peuvent acheter des billets réduits. Ceux-ci coûtent généralement 50 % du prix flexible. Par conséquent, ces billets ne sont pas spécifiques à un train et peuvent être utilisés de manière flexible sur l’itinéraire, sauf si le train nécessite une réservation obligatoire. Certaines entreprises ferroviaires ont des accords bilatéraux et s’accordent des réductions plus élevées, par exemple 75 %.

Les Billets FIP 50 peuvent être achetés à tout moment en toute quantité. Le FIP 50 fonctionne essentiellement comme une carte de réduction pour de nombreuses liaisons. Un seul Billet FIP 50 peut couvrir plusieurs opérateurs.
Le niveau de réduction accordé par chaque compagnie ferroviaire est indiqué sur la page correspondante de la compagnie dans le FIP Guide. Pour simplifier la lecture, tous ces billets sont appelés Billets FIP 50 dans le FIP Guide, même si une réduction de 75 % est parfois accordée et qu’ils sont alors souvent désignés comme Billets FIP 75.

Les Billets FIP 50 peuvent être achetés à tout moment et en toute quantité. Le FIP 50 fonctionne essentiellement comme une carte de réduction pour de nombreuses liaisons. Un seul Billet FIP 50 peut couvrir plusieurs opérateurs.

Le processus d’achat diffère des Coupons FIP. Tandis que ces derniers sont émis par votre propre entreprise ferroviaire, les Billets FIP 50 peuvent être achetés de diverses façons. Pour voyager dans un pays, un guichet de billets local ou un centre de voyage est généralement un bon point de départ. Certains opérateurs permettent également de réserver en ligne ou via des distributeurs automatiques. Sur les pages pays et opérateurs respectifs, nous tentons de résumer les informations sur les achats de billets aussi complètement que possible. Les prix des Billets FIP 50 peuvent varier selon le point de vente.

Expand Down
Loading
Loading