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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ jobs:
run: npm run lint
- name: Check formatting
run: npm run format:check
- name: Check dashes
run: npm run check:dashes
- name: Build
run: npm run build
- name: Validate built pages
Expand Down
19 changes: 19 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# CLAUDE.md

Die Seite ist auf Deutsch. Texte folgen der deutschen Rechtschreibung und Typografie (Duden), nicht der englischen.

## Striche

| Zeichen | Name | Verwendung | Beispiel |
| ------- | -------------------------------- | ------------------------------------------------- | ---------------------------------------------------------- |
| `-` | Bindestrich | Zusammensetzungen, Ergänzungen | `Mitarbeiter-App`, `Arbeitszeit- und Abwesenheitsdaten` |
| `–` | Gedankenstrich (mit Leerzeichen) | Einschub, Nachtrag, Trenner in Titeln | `Zeiten erfassen – mit der App`, `title: Kalender – Hilfe` |
| `–` | Bis-Strich (ohne Leerzeichen) | Bereiche bei Zahlen, Zeiten, Wochentagen | `8–12 Uhr`, `S. 1–32`, `Mo–Fr` |
| `—` | Geviertstrich | **nicht verwenden**, das ist englische Typografie | – |

- Den Gedankenstrich und den Bis-Strich immer als Zeichen `–` (U+2013) schreiben, nie als `–`, `—` oder `-`.
`title` und `description` aus dem Front Matter werden mit `{{title}}` escaped ausgegeben, ein `–` stünde dort als Text im Browser-Tab und im Suchergebnis.
- Bei „von … bis“ das Wort ausschreiben statt eines Strichs: `vom 23.11. bis 27.11.`, nicht `vom 23.11.–27.11.`.

`npm run check:dashes` (läuft auch in der CI) meldet Geviertstriche, `–`/`—`, einen Bindestrich mit Leerzeichen als Gedankenstrich im Fließtext und Bereiche mit Leerzeichen um den Strich.
Bereiche ohne Leerzeichen mit Bindestrich (`8-12 Uhr`) erkennt der Check nicht, da sie von Datumsangaben, Versionen und Hausnummern nicht zu unterscheiden sind.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Diese Checks laufen auch in der CI bei jedem Pull Request:
```bash
npm run lint # ESLint für JavaScript
npm run format:check # Prettier für CSS, HTML, Markdown und SVG
npm run check:dashes # Gedankenstriche und Bis-Striche in src (siehe CLAUDE.md)
npm run check:dist # validiert die gebauten Seiten in dist (vorher npm run build)
```

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"scripts": {
"lint": "eslint src lib scripts .eleventy.js",
"format:check": "prettier --check 'src/**/*.{css,html,md,svg}'",
"check:dashes": "node scripts/check-dashes.js",
"clean": "rm -rf $npm_package_config_outdir",
"predev": "npm run clean",
"dev": "concurrently 'npm:dev:*'",
Expand Down
81 changes: 81 additions & 0 deletions scripts/check-dashes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Checks the dashes in the page sources (German typography, see CLAUDE.md).
//
// The site wrote the Gedankenstrich four different ways (" - ", " – ", " — "
// and "–"). Only the literal en dash "–" is allowed: the em dash is
// English typography, and entities end up as visible text when a front matter
// title or description is rendered escaped with {{title}}.

import fs from "node:fs";
import path from "node:path";

const root = "src";

const everywhere = [
{ pattern: /—/g, message: 'em dash "—", use "–"' },
{
pattern: /&(ndash|mdash|#821[12]|#x201[34]);/gi,
message: 'dash entity, write the character "–" instead',
},
];

const prose = [
{
pattern: /[\p{L}.,!?)*_"”’] - [\p{L}(*_„"]/gu,
message: 'hyphen as Gedankenstrich, use " – "',
},
{ pattern: /\d - \d/g, message: 'spaced range, use "–" without spaces' },
];

// Markup and code in which " - " is not a dash, replaced by spaces so that
// the reported columns stay correct.
const notProse = [
/<script[\s\S]*?<\/script>/g,
/<style[\s\S]*?<\/style>/g,
/^```[\s\S]*?^```/gm,
/\{\{[\s\S]*?\}\}/g,
/`[^`\n]*`/g,
/^\s*- /gm,
];

function blank(text) {
return notProse.reduce(
(result, pattern) =>
result.replace(pattern, match => match.replace(/[^\n]/g, " ")),
text,
);
}

function check(file) {
const source = fs.readFileSync(file, "utf8");
const rules = file.endsWith(".js") ? everywhere : [...everywhere, ...prose];
const text = file.endsWith(".js") ? source : blank(source);
const lines = text.split("\n");

const errors = [];
for (const [index, line] of lines.entries()) {
for (const { pattern, message } of rules) {
for (const match of line.matchAll(pattern)) {
const column = match.index + match[0].search(/[-—&]/) + 1;
errors.push(`${file}:${index + 1}:${column} ${message}`);
}
}
}
return errors;
}

const files = fs
.readdirSync(root, { recursive: true })
.map(entry => path.join(root, entry))
.filter(file => /\.(md|hbs)$|\.11tydata\.js$/.test(file))
.sort();

const errors = files.flatMap(check);
for (const error of errors) {
console.error(error);
}

if (errors.length > 0) {
process.exit(1);
}

console.log(`${files.length} files checked, no problems found.`);
2 changes: 1 addition & 1 deletion src/404.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
layout: layout
eleventyExcludeFromCollections: true
title: Es tut uns leid - hier ist etwas schiefgelaufen
title: Es tut uns leid – hier ist etwas schiefgelaufen
description: Die angeforderte Seite wurde leider nicht gefunden.
permalink: 404.html
---
Expand Down
10 changes: 5 additions & 5 deletions src/_includes/partials/footer.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<div class="footer__app">
<h2 class="section-title-pill">Testen</h2>
<p class="mt-8">
<span class="font-bold">Direkt laden und loslegen.</span><br />Im AppStore oder bei Google Play.
<span class="font-bold">Direkt laden und loslegen.</span><br />Im App Store oder bei Google Play.
</p>
<div class="mt-4 flex flex-row gap-4 items-center">
<a href="{{links.appleAppStore}}" class="hover:outline-0">
Expand Down Expand Up @@ -92,13 +92,13 @@
<div class="footer__social">
<ul class="flex flex-row gap-8">
<li>
<a href="{{links.linkedIn}}" class="hover:outline-0" title="linkedIn">
<a href="{{links.linkedIn}}" class="hover:outline-0" title="LinkedIn">
<span class="sr-only">LinkedIn</span><img src="/static/img/linkedin-white.png" width="32" alt="" />
</a>
</li>
<li>
<a href="{{links.github}}" class="hover:outline-0" title="Github">
<span class="sr-only">Github</span><img src="/static/img/GitHub_Invertocat_White.svg" width="32" alt="" />
<a href="{{links.github}}" class="hover:outline-0" title="GitHub">
<span class="sr-only">GitHub</span><img src="/static/img/GitHub_Invertocat_White.svg" width="32" alt="" />
</a>
</li>
<li>
Expand All @@ -115,7 +115,7 @@
<a href="/impressum/">Impressum</a>
</p>
<p>
© {{date page.date 'yyyy'}} Focus Shift Software Gmbh
© {{date page.date 'yyyy'}} Focus Shift Software GmbH
</p>
</div>
</footer>
Expand Down
6 changes: 3 additions & 3 deletions src/_includes/partials/jetzt-testen.hbs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<div class="page-subgrid-full px-page-grid-gap lg:grid-flow-col">
<h3 class="col-span-full section-title-pill place-self-start lg:col-start-2">Kostenlos Testen</h3>
<h3 class="col-span-full section-title-pill place-self-start lg:col-start-2">Kostenlos testen</h3>
<p class="mt-8 col-span-full text-4xl lg:text-5xl lg:col-start-2">
Einfach testen,&nbsp;<br class="hidden sm:inline" /> <span class="font-basteleur">selbst erleben.</span>
</p>
<p class="col-span-full mt-8 text-xl md:text-2xl lg:text-3xl lg:col-start-2 lg:col-span-6 lg:mt-16">
Nutze jetzt 30 Tage kostenlose unser Tool und erlebe selbst, was focus:<span class="font-basteleur">shift</span> für dein Team leisten kann.
Nutze jetzt 30 Tage kostenlos unser Tool und erlebe selbst, was focus:<span class="font-basteleur">shift</span> für dein Team leisten kann.
</p>
<p class="col-span-full mt-8 flex items-center gap-2 md:col-span-4 md:place-self-start md:mt-16 lg:col-start-2 lg:col-span-6 lg:mt-8">
{{> partials/dots-horizontal color="bg-lila" }}
<a href="{{links.registration}}" class="button button--orange">Jetzt testen</a>
</p>
<div class="mt-8 col-span-full highlight-box bg-white border-lila px-5 py-6 flex flex-col gap-4 md:mt-16 md:col-start-5 lg:col-start-8 lg:col-span-4 lg:self-start lg:row-span-2">
<p>
<span class="font-bold">Direkt laden und loslegen.</span><br />Im AppStore oder bei Google Play.
<span class="font-bold">Direkt laden und loslegen.</span><br />Im App Store oder bei Google Play.
</p>
<div class="flex flex-row gap-4 items-center">
<a href="{{links.appleAppStore}}" class="hover:outline-0">
Expand Down
24 changes: 12 additions & 12 deletions src/_includes/partials/price.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
<div class="price-section-switch">
<button id="price-button-cloud" type="button" class="price-section-toggle price-section-toggle--cloud">Cloud</button>
<label class="checkbox-switch checkbox-switch--noir">
<span class="sr-only">On Premise</span>
<span class="sr-only">On-Premise</span>
<input type="checkbox" name="on-premise">
</label>
<button id="price-button-on-premise" type="button" class="price-section-toggle price-section-toggle--on-premise">On Premise</button>
<button id="price-button-on-premise" type="button" class="price-section-toggle price-section-toggle--on-premise">On-Premise</button>
</div>
</div>

Expand All @@ -16,7 +16,7 @@
<span class="text-lila font-bold text-lg">focus:shift</span> <span class="bg-green px-2 py-px rounded-full text-sm uppercase">meistgewählt</span>
</h3>
<p class="font-bold text-lg">
Registrieren und direkt Starten!
Registrieren und direkt starten!
</p>
<ul class="list-disc list-outside pl-5">
<li>
Expand All @@ -29,7 +29,7 @@
Sicherheitsupdates
</li>
<li>
Single Sign On
Single Sign-On
</li>
<li>
Backups
Expand Down Expand Up @@ -84,10 +84,10 @@
</form>
<div class="mt-8 col-span-full lg:col-start-2 lg:col-span-4">
<p class="font-bold lg:text-lg">Ihr habt mehr als 250 Mitarbeitende?</p>
<p>Meldet euch bei uns für ein individuelles Angebot</p>
<p>Meldet euch bei uns für ein individuelles Angebot.</p>
<p class="mt-4 ci-dots-button-group">
{{> partials/dots-horizontal color="bg-lila" }}
<a href="{{links.individualPriceRequest}}" class="button button--green">Preis Anfragen</a>
<a href="{{links.individualPriceRequest}}" class="button button--green">Preis anfragen</a>
</p>
</div>
</div>
Expand All @@ -99,30 +99,30 @@
<div class="highlight-box bg-white border-lila p-8 grid">
<h3 class="font-bold text-lila text-lg">Open-Source-Software</h3>
<p class="mt-2 max-w-prose">
Du willst dich um Setup, Backup &amp; Updates selbst kümmern? Dann geht es hier direkt zu Github.
Du willst dich um Setup, Backup &amp; Updates selbst kümmern? Dann geht es hier direkt zu GitHub.
Wir freuen uns über Feedback und Mitgestaltung!
</p>
<ul class="mt-8 list-disc list-outside pl-5">
<li>Offene Quellen</li>
<li>Aktive Community</li>
<li>Transparente Weiterentwicklung</li>
<li>Support via Github</li>
<li>Support via GitHub</li>
</ul>
<p class="mt-8 flex items-center gap-2">
{{> partials/dots-horizontal color="bg-lila" }}
<a href="https://github.com/urlaubsverwaltung" class="button button--light-blue">Zu Github</a>
<a href="https://github.com/urlaubsverwaltung" class="button button--light-blue">Zu GitHub</a>
</p>
</div>
</li>
<li class="col-span-full lg:col-span-4">
<div class="highlight-box bg-white border-lila p-8 grid">
<h3 class="font-bold text-lila text-lg">On-Premise Support</h3>
<h3 class="font-bold text-lila text-lg">On-Premise-Support</h3>
<p class="mt-2 max-w-prose">
Wir sind an deiner Seite. Wir stellen dir einen individuellen Supportvertrag zur Verfügung,
der auf deine Anforderungen zugeschnitten ist. Er könnte zum Beispiel folgende Leistungen beinhalten:
</p>
<ul class="mt-8 list-disc list-outside pl-5">
<li>Servicezeit: Mo-Fr (9:00 - 17:00 Uhr)</li>
<li>Servicezeit: Mo–Fr (9:00–17:00 Uhr)</li>
<li>Support-Kanal: E-Mail</li>
<li>Max. Antwortzeit: 8h</li>
<li>12 Serviceanfragen</li>
Expand All @@ -136,7 +136,7 @@
</li>
<li class="col-span-full lg:col-span-4">
<div class="highlight-box bg-white border-lila p-8 grid">
<h3 class="font-bold text-lila text-lg">On Premise Installation</h3>
<h3 class="font-bold text-lila text-lg">On-Premise-Installation</h3>
<p class="mt-2 max-w-prose">
Wir unterstützen dich gerne bei der Einrichtung der Urlaubsverwaltung &amp; Zeiterfassung
auf deinen eigenen Servern.
Expand Down
2 changes: 1 addition & 1 deletion src/_includes/partials/section-vision-and-values.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<li class="values-list-item">
<img src="/static/img/icon-transparenz.svg" alt="" class="values-list-item__icon">
<h3 class="values-list-item__title">Transparenz für Selbstfürsorge</h3>
<p class="values-list-item__text">Wir geben Teams Daten an die Hand, die zeigen, wann die Belastungsgrenze erreicht ist &dash; bevor es zu spät ist.</p>
<p class="values-list-item__text">Wir geben Teams Daten an die Hand, die zeigen, wann die Belastungsgrenze erreicht ist – bevor es zu spät ist.</p>
</li>
<li class="values-list-item">
<img src="/static/img/icon-wertschaetzung.svg" alt="" class="values-list-item__icon">
Expand Down
14 changes: 7 additions & 7 deletions src/_includes/software/feature-detail-app.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<div class="mt-8 flex flex-col gap-8 md:mt-16 md:gap-16">
<div class="grid grid-cols-1 gap-8 md:grid-cols-2 md:grid-flow-col md:gap-16">
<div class="space-y-4">
<h4 class="font-bold">Schnell und einfach Abwesenheiten beantragen oder Zeiten erfassen - mit der Mitarbeiter App (Android &amp; iOS)</h4>
<h4 class="font-bold">Schnell und einfach Abwesenheiten beantragen oder Zeiten erfassen – mit der Mitarbeiter-App (Android &amp; iOS)</h4>
Comment thread
derTobsch marked this conversation as resolved.
<p>Einfach und von überall deine Arbeitszeit erfassen.</p>
<p class="font-bold">Vorteile</p>
<ul class="list-disc list-outside pl-5 flex flex-col gap-1">
Expand All @@ -18,7 +18,7 @@
Stoppuhr unterwegs starten und stoppen
</li>
<li>
Synchronisation by Design - Keine Daten auf dem Handy gespeichert
Synchronisation by Design – keine Daten auf dem Handy gespeichert
</li>
<li>
Eigene App, eigener Prozess
Expand All @@ -38,7 +38,7 @@
</ul>
</div>
<div class="col-start-1 image-mask--beige">
<img src="app-hero.png" alt="Drei Smartphones mit der Urlaubsverwaltung App, daneben die Merkmale „Security first“, „Stoppuhr starten und stoppen“, „Alle Funktionen und Daten wie im Browser“ und „Schnelle Freigabe“ sowie die Download-Badges für Apple App Store und Google Play" class="object-fit" />
<img src="app-hero.png" alt="Drei Smartphones mit der Urlaubsverwaltung-App, daneben die Merkmale „Security first“, „Stoppuhr starten und stoppen“, „Alle Funktionen und Daten wie im Browser“ und „Schnelle Freigabe“ sowie die Download-Badges für Apple App Store und Google Play" class="object-fit" />
</div>
</div>
<div class="grid grid-cols-1 gap-8 md:grid-cols-2 md:grid-flow-col md:gap-16">
Expand All @@ -55,7 +55,7 @@
<div class="space-y-4">
<h4 class="font-bold">Wer ist da, wer ist abwesend?</h4>
<p>Erhalte eine Übersicht über die Anwesenheit deiner Kollegen und Kolleginnen aus deiner Abteilung.</p>
<p>Sehe, wer im Urlaub ist, wer krank ist oder wer sich im Homeoffice befindet.</p>
<p>Sieh, wer im Urlaub ist, wer krank ist oder wer sich im Homeoffice befindet.</p>
</div>
<div class="col-start-1 image-mask--beige">
<img src="detail-app-uv-abwesenheitsuebersicht.png" width="420" height="750" alt="Abwesenheitsübersicht in der App mit Filtern für Jahr, Monat und Abteilung sowie einer Tabelle, die je Person und Tag im September 2026 die Abwesenheiten zeigt" />
Expand All @@ -74,8 +74,8 @@
<div class="grid grid-cols-1 gap-8 md:grid-cols-2 md:grid-flow-col md:gap-16">
<div class="space-y-4">
<h4 class="font-bold">Arbeitszeiten unterwegs erfassen</h4>
<p>Starte die Stoppuhr noch bevor dein Rechner hochgefahren ist. Hast du vergessen die Stoppuhr anzuhalten? Kein Problem, das kannst du auch von unterwegs erledigen.</p>
<p>Erstelle Zeiteinträge und erfasse deine Arbeitszeiten auf dem Heimweg</p>
<p>Starte die Stoppuhr, noch bevor dein Rechner hochgefahren ist. Hast du vergessen, die Stoppuhr anzuhalten? Kein Problem, das kannst du auch von unterwegs erledigen.</p>
<p>Erstelle Zeiteinträge und erfasse deine Arbeitszeiten auf dem Heimweg.</p>
</div>
<div class="col-start-1 image-mask--beige">
<img src="detail-app-ze-zeiterfassung.png" width="420" height="570" alt="Zeiterfassung in der App: Formular „Neuen Zeiteintrag erfassen“ mit Kommentar, Von, Bis und Dauer, oben die Start-Schaltfläche der Stoppuhr, darunter die Summen für Woche und Tag" />
Expand All @@ -84,7 +84,7 @@
<div class="grid grid-cols-1 gap-8 md:grid-cols-2 md:grid-flow-col md:gap-16">
<div class="space-y-4">
<h4 class="font-bold">Schneller Blick auf die erfassten Arbeitszeiten</h4>
<p>Bist du noch im Soll? Werfe schnell einen Blick auf die Statistik und vergewissere dich, dass du deine Arbeitszeiten erfasst hast.</p>
<p>Bist du noch im Soll? Wirf schnell einen Blick auf die Statistik und vergewissere dich, dass du deine Arbeitszeiten erfasst hast.</p>
</div>
<div class="col-start-1 image-mask--beige">
<img src="detail-app-ze-berichte.png" width="420" height="570" alt="Bericht der erfassten Arbeitszeiten in der App: Wochenansicht mit Balkendiagramm je Wochentag, Saldo von plus 42:15 Stunden und darunter die einzelnen Zeiteinträge eines Tages" />
Expand Down
Loading