Files
datecalc/templates/index.html

247 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% macro format_date(date_str) %}
{%- if date_str and '-' in date_str and date_str|length == 10 -%}
{{ date_str[8:10] }}.{{ date_str[5:7] }}.{{ date_str[0:4] }}
{%- else -%}
{{ date_str }}
{%- endif -%}
{% endmacro %}
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Elpatrons Datumsrechner Open Source Kalender- und Datumsberechnungen</title>
<meta name="description" content="Elpatrons Datumsrechner: Open Source Web-App für Kalender- und Datumsberechnungen. Tage, Werktage, Wochen, Monate, Kalenderwochen, Wochentage und mehr berechnen barrierefrei, werbefrei, trackingfrei, kostenlos.">
<meta name="keywords" content="Datum, Kalender, Datumsrechner, Werktage, Tage zählen, Kalenderwoche, Wochentag, Open Source, Python, Flask, barrierefreiheit, barrierefrei, kostenlos, werbefrei, trackingfrei, cookiefrei">
<meta property="og:title" content="Elpatrons Datumsrechner Open Source Kalender- und Datumsberechnungen">
<meta property="og:description" content="Open Source Web-App für Kalender- und Datumsberechnungen. Werbefrei, trackingfrei, kostenlos.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://codeberg.org/elpatron/datecalc">
<meta property="og:image" content="/static/logo.svg">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="HandheldFriendly" content="true">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="format-detection" content="telephone=no">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="application-name" content="Elpatrons Datumsrechner">
<meta name="msapplication-TileColor" content="#2563eb">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" href="/static/style.css">
<link rel="manifest" href="/static/manifest.json">
<meta name="theme-color" content="#2563eb">
<script>
function setToday(id) {
const today = new Date().toISOString().split('T')[0];
document.getElementById(id).value = today;
}
function openAccordion(idx) {
const headers = document.querySelectorAll('.accordion-header');
const panels = document.querySelectorAll('.accordion-content');
headers.forEach((btn, i) => {
btn.classList.toggle('active', i === idx);
btn.setAttribute('aria-expanded', i === idx ? 'true' : 'false');
});
panels.forEach((el, i) => {
el.classList.toggle('active', i === idx);
});
}
document.addEventListener('DOMContentLoaded', function() {
openAccordion(parseInt("{{ active_idx|default(0) }}"));
// Tastatursteuerung für Accordion
const headers = document.querySelectorAll('.accordion-header');
headers.forEach((header, idx) => {
header.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
openAccordion(idx);
headers[idx].focus();
} else if (e.key === 'ArrowDown') {
e.preventDefault();
const next = (idx + 1) % headers.length;
headers[next].focus();
} else if (e.key === 'ArrowUp') {
e.preventDefault();
const prev = (idx - 1 + headers.length) % headers.length;
headers[prev].focus();
}
});
});
});
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/static/service-worker.js');
});
}
</script>
</head>
<body>
<div class="container">
<div style="text-align:center; margin-bottom:1.2em;">
<div style="font-size:1.1em; font-style:italic; color:#64748b;">Elpatrons</div>
<h1 style="margin:0;">Datumsrechner</h1>
<div style="font-size:0.9em; color:#353535; margin-top:0.3em;">
Eine <em>freie</em> Web-App: barriere<em>frei</em>, werbe<em>frei</em>, tracking<em>frei</em>, lizenz<em>frei</em> und kosten<em>frei</em>.
</div>
</div>
<div class="accordion">
<div class="accordion-item">
<button type="button" class="accordion-header header-tage" id="accordion-header-0" aria-expanded="true" aria-controls="accordion-panel-0" role="button" tabindex="0" onclick="openAccordion(0)">
<span style="vertical-align:middle;display:inline-block;width:1.5em;">
<!-- Kalender mit Doppelpfeil -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="3" y="5" width="18" height="16" rx="4" fill="#fff" stroke="#2563eb" stroke-width="2"/><rect x="3" y="5" width="18" height="4" rx="2" fill="#2563eb"/><rect x="6" y="2" width="2" height="4" rx="1" fill="#2563eb"/><rect x="16" y="2" width="2" height="4" rx="1" fill="#2563eb"/><path d="M8 15h8M8 15l2-2M8 15l2 2M16 15l-2-2M16 15l-2 2" stroke="#2563eb" stroke-width="1.5" stroke-linecap="round"/></svg>
</span>
Anzahl der Tage/Werktage zwischen zwei Daten
</button>
<div class="accordion-content" id="accordion-panel-0" role="region" aria-labelledby="accordion-header-0">
<form method="post">
<label for="start1">Startdatum:<br>
<span class="date-row">
<input type="date" name="start1" id="start1">
<button type="button" class="today-btn" onclick="setToday('start1')">Heute</button>
</span>
</label>
<label for="end1">Enddatum:<br>
<span class="date-row">
<input type="date" name="end1" id="end1">
<button type="button" class="today-btn" onclick="setToday('end1')">Heute</button>
</span>
</label>
<fieldset style="display:flex;align-items:center;gap:0.5em;margin-top:0.7em; border:none; padding:0;">
<legend class="sr-only">Optionen</legend>
<input type="checkbox" name="werktage" id="werktage" {% if request.form.get('werktage') %}checked{% endif %} aria-checked="{{ 'true' if request.form.get('werktage') else 'false' }}">
<label for="werktage" style="margin:0;">Nur Werktage</label>
</fieldset>
<button name="action" value="tage_werktage" type="submit">Berechnen</button>
</form>
{% if tage is not none %}
<div class="result" aria-live="polite">
{% if request.form.get('werktage') %}
Anzahl der Werktage zwischen <b>{{ format_date(request.form.get('start1', '')) }}</b> und <b>{{ format_date(request.form.get('end1', '')) }}</b>: {{ tage }}
{% else %}
Anzahl der Tage zwischen <b>{{ format_date(request.form.get('start1', '')) }}</b> und <b>{{ format_date(request.form.get('end1', '')) }}</b>: {{ tage }}
{% endif %}
</div>
{% endif %}
</div>
</div>
<div class="accordion-item">
<button type="button" class="accordion-header header-wochentag" id="accordion-header-1" aria-expanded="false" aria-controls="accordion-panel-1" role="button" tabindex="0" onclick="openAccordion(1)">
<span style="vertical-align:middle;display:inline-block;width:1.5em;">
<!-- Kalender mit W -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="3" y="5" width="18" height="16" rx="4" fill="#fff" stroke="#2563eb" stroke-width="2"/><rect x="3" y="5" width="18" height="4" rx="2" fill="#2563eb"/><rect x="6" y="2" width="2" height="4" rx="1" fill="#2563eb"/><rect x="16" y="2" width="2" height="4" rx="1" fill="#2563eb"/><text x="12" y="17" text-anchor="middle" font-size="12" font-family="Segoe UI, Arial, sans-serif" fill="#2563eb" font-weight="bold">W</text></svg>
</span>
Wochentag eines Datums
</button>
<div class="accordion-content" id="accordion-panel-1" role="region" aria-labelledby="accordion-header-1">
<form method="post">
<label for="datum3">Datum:<br>
<span class="date-row">
<input type="date" name="datum3" id="datum3">
<button type="button" class="today-btn" onclick="setToday('datum3')">Heute</button>
</span>
</label>
<button name="action" value="wochentag" type="submit">Anzeigen</button>
</form>
{% if wochentag is not none %}
<div class="result" aria-live="polite">Wochentag von <b>{{ format_date(request.form.get('datum3', '')) }}</b>: {{ wochentag }}</div>
{% endif %}
</div>
</div>
<div class="accordion-item">
<button type="button" class="accordion-header header-kw-datum" id="accordion-header-2" aria-expanded="false" aria-controls="accordion-panel-2" role="button" tabindex="0" onclick="openAccordion(2)">
<span style="vertical-align:middle;display:inline-block;width:1.5em;">
<!-- Kalender mit # -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="3" y="5" width="18" height="16" rx="4" fill="#fff" stroke="#2563eb" stroke-width="2"/><rect x="3" y="5" width="18" height="4" rx="2" fill="#2563eb"/><rect x="6" y="2" width="2" height="4" rx="1" fill="#2563eb"/><rect x="16" y="2" width="2" height="4" rx="1" fill="#2563eb"/><text x="12" y="17" text-anchor="middle" font-size="13" font-family="Segoe UI, Arial, sans-serif" fill="#2563eb" font-weight="bold">#</text></svg>
</span>
Kalenderwoche eines Datums
</button>
<div class="accordion-content" id="accordion-panel-2" role="region" aria-labelledby="accordion-header-2">
<form method="post">
<label for="datum6">Datum:<br>
<span class="date-row">
<input type="date" name="datum6" id="datum6">
<button type="button" class="today-btn" onclick="setToday('datum6')">Heute</button>
</span>
</label>
<button name="action" value="kw_berechnen" type="submit">Kalenderwoche berechnen</button>
</form>
{% if kw_berechnen is not none %}
<div class="result" aria-live="polite">Kalenderwoche von <b>{{ format_date(request.form.get('datum6', '')) }}</b>: {{ kw_berechnen }}</div>
{% endif %}
</div>
</div>
<div class="accordion-item">
<button type="button" class="accordion-header header-kw" id="accordion-header-3" aria-expanded="false" aria-controls="accordion-panel-3" role="button" tabindex="0" onclick="openAccordion(3)">
<span style="vertical-align:middle;display:inline-block;width:1.5em;">
<!-- Kalender mit Pfeil nach außen -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="3" y="5" width="18" height="16" rx="4" fill="#fff" stroke="#2563eb" stroke-width="2"/><rect x="3" y="5" width="18" height="4" rx="2" fill="#2563eb"/><rect x="6" y="2" width="2" height="4" rx="1" fill="#2563eb"/><rect x="16" y="2" width="2" height="4" rx="1" fill="#2563eb"/><path d="M7 17l5-5 5 5" stroke="#2563eb" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><text x="12" y="12" text-anchor="middle" font-size="8" font-family="Segoe UI, Arial, sans-serif" fill="#2563eb" font-weight="bold">KW</text></svg>
</span>
Start-/Enddatum zu Kalenderwoche
</button>
<div class="accordion-content" id="accordion-panel-3" role="region" aria-labelledby="accordion-header-3">
<form method="post">
<label for="jahr7">Jahr:<br>
<input type="number" name="jahr7" id="jahr7" min="1900" max="2100" style="width: 7em;">
</label>
<label for="kw7">Kalenderwoche:<br>
<input type="number" name="kw7" id="kw7" min="1" max="53" style="width: 5em;">
</label>
<button name="action" value="kw_datum" type="submit">Start-/Enddatum berechnen</button>
</form>
{% if kw_datum is not none %}
<div class="result" aria-live="polite">Start-/Enddatum der KW <b>{{ request.form.get('kw7', '') }}</b> im Jahr <b>{{ request.form.get('jahr7', '') }}</b>: {{ kw_datum }}</div>
{% endif %}
</div>
</div>
<div class="accordion-item">
<button type="button" class="accordion-header header-plusminus" id="accordion-header-4" aria-expanded="false" aria-controls="accordion-panel-4" role="button" tabindex="0" onclick="openAccordion(4)">
<span style="vertical-align:middle;display:inline-block;width:1.5em;">
<!-- Kalender mit ± -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="3" y="5" width="18" height="16" rx="4" fill="#fff" stroke="#2563eb" stroke-width="2"/><rect x="3" y="5" width="18" height="4" rx="2" fill="#2563eb"/><rect x="6" y="2" width="2" height="4" rx="1" fill="#2563eb"/><rect x="16" y="2" width="2" height="4" rx="1" fill="#2563eb"/><text x="12" y="17" text-anchor="middle" font-size="16" font-family="Segoe UI, Arial, sans-serif" fill="#2563eb" font-weight="bold">±</text></svg>
</span>
Datum plus/minus X Tage/Wochen/Monate
</button>
<div class="accordion-content" id="accordion-panel-4" role="region" aria-labelledby="accordion-header-4">
<form method="post">
<label for="datum_pm">Datum:<br>
<span class="date-row">
<input type="date" name="datum_pm" id="datum_pm">
<button type="button" class="today-btn" onclick="setToday('datum_pm')">Heute</button>
</span>
</label>
<label for="anzahl_pm">Anzahl:<br>
<input type="number" name="anzahl_pm" id="anzahl_pm" style="width: 6em;">
</label>
<fieldset class="date-calc-row" style="border:none; padding:0;">
<legend class="sr-only">Rechenrichtung</legend>
<label for="richtung_pm_add"><input type="radio" name="richtung_pm" id="richtung_pm_add" value="add" checked> addieren</label>
<label for="richtung_pm_sub"><input type="radio" name="richtung_pm" id="richtung_pm_sub" value="sub"> subtrahieren</label>
</fieldset>
<fieldset style="display:flex; align-items:center; gap:0.5em; margin-top:0.7em; border:none; padding:0;">
<legend class="sr-only">Einheit und Werktage</legend>
<label for="einheit_pm" style="margin:0;">Einheit:
<select name="einheit_pm" id="einheit_pm">
<option value="tage">Tage</option>
<option value="wochen">Wochen</option>
<option value="monate">Monate</option>
</select>
</label>
<input type="checkbox" name="werktage_pm" id="werktage_pm">
<label for="werktage_pm" style="margin:0;">Nur Werktage</label>
</fieldset>
<button name="action" value="plusminus" type="submit">Berechnen</button>
</form>
{% if plusminus_result is not none %}
<div class="result" aria-live="polite">{{ plusminus_result }}</div>
{% endif %}
</div>
</div>
</div>
</div>
<footer style="text-align:center; margin-top:2em; color:#64748b; font-size:0.98em; padding-bottom:1.5em;">
Dies ist ein werbe- und trackingfreier <a href="https://codeberg.org/elpatron/datecalc/src/branch/main/README.md" target="_blank" style="color:#2563eb; text-decoration:underline;">Open Source Datumsrechner</a><br>
<a href="/api-docs" target="_blank" style="color:#2563eb; text-decoration:underline;">REST API Dokumentation (Swagger)</a><br>
© 2025 <a href="mailto:elpatron@mailbox.org?subject=Datumsrechner" style="color:#2563eb; text-decoration:underline;">M. Busche</a>
</footer>
</body>
</html>