mirror of
https://github.com/Garmelon/Arbeitszeitdokumentationsgenerator.git
synced 2026-04-13 01:05:04 +02:00
Switch from maud to el
This commit is contained in:
parent
28fcb43832
commit
b174b796ed
5 changed files with 347 additions and 219 deletions
59
Cargo.lock
generated
59
Cargo.lock
generated
|
|
@ -110,9 +110,9 @@ dependencies = [
|
|||
"axum",
|
||||
"axum-extra",
|
||||
"clap",
|
||||
"el",
|
||||
"fontdb 0.23.0",
|
||||
"jiff",
|
||||
"maud",
|
||||
"serde",
|
||||
"tokio",
|
||||
"typst",
|
||||
|
|
@ -610,6 +610,16 @@ version = "1.13.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "el"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16d62f2117df9caa2f568124894462af4ba7dfd9a2ab8b82b79c29ce3b0c16eb"
|
||||
dependencies = [
|
||||
"axum-core",
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-io"
|
||||
version = "0.4.0"
|
||||
|
|
@ -1307,30 +1317,6 @@ version = "0.7.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||
|
||||
[[package]]
|
||||
name = "maud"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df518b75016b4289cdddffa1b01f2122f4a49802c93191f3133f6dc2472ebcaa"
|
||||
dependencies = [
|
||||
"axum-core",
|
||||
"http",
|
||||
"itoa",
|
||||
"maud_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maud_macros"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa453238ec218da0af6b11fc5978d3b5c3a45ed97b722391a2a11f3306274e18"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
|
|
@ -1658,29 +1644,6 @@ dependencies = [
|
|||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.92"
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ anyhow = "1.0.94"
|
|||
axum = "0.7.9"
|
||||
axum-extra = { version = "0.9.6", features = ["form"] }
|
||||
clap = { version = "4.5.23", features = ["derive", "deprecated"] }
|
||||
el = { version = "0.1.2", features = ["axum"] }
|
||||
fontdb = "0.23.0"
|
||||
jiff = "0.1.15"
|
||||
maud = { version = "0.26.0", features = ["axum"] }
|
||||
serde = { version = "1.0.216", features = ["derive"] }
|
||||
tokio = { version = "1.42.0", features = ["full"] }
|
||||
typst = "0.12.0"
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
use maud::{html, Markup};
|
||||
use el::{html::*, Document, ElementComponent};
|
||||
|
||||
pub mod index;
|
||||
pub mod tsg;
|
||||
|
||||
fn page(head: Markup, body: Markup) -> Markup {
|
||||
html! {
|
||||
(maud::DOCTYPE)
|
||||
html lang="en" {
|
||||
head {
|
||||
meta charset="utf-8";
|
||||
meta name="viewport" content="width=device-width, initial-scale=1";
|
||||
title { "AbzDokGen" }
|
||||
(head)
|
||||
}
|
||||
body { (body) }
|
||||
}
|
||||
}
|
||||
fn page(head: impl ElementComponent, body: impl ElementComponent) -> Document {
|
||||
html((
|
||||
el::html::head((
|
||||
meta((
|
||||
attr::name("viewport"),
|
||||
attr::content("width=device-width, initial-scale=1"),
|
||||
)),
|
||||
title("AbzDokGen"),
|
||||
head,
|
||||
)),
|
||||
el::html::body(body),
|
||||
))
|
||||
.into_document()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use std::iter;
|
||||
|
||||
use axum::{
|
||||
http::{header, StatusCode},
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use axum_extra::extract::Form;
|
||||
use el::{html::*, Document};
|
||||
use jiff::{ToSpan, Zoned};
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -12,7 +14,12 @@ use crate::{
|
|||
render::{self, Entry, Note, Timesheet, WorkingArea},
|
||||
};
|
||||
|
||||
pub async fn get() -> Markup {
|
||||
const LINK_SOURCE: &str = "https://github.com/Garmelon/Arbeitszeitdokumentationsgenerator";
|
||||
const LINK_TSG: &str = "https://github.com/kit-sdq/TimeSheetGenerator";
|
||||
const LINK_TEMPLATE: &str =
|
||||
"https://github.com/Garmelon/Arbeitszeitdokumentationsgenerator/blob/master/kit_timesheet.md";
|
||||
|
||||
pub async fn get() -> Document {
|
||||
// We assume that people still want to fill out the previous month's time
|
||||
// sheet during the first two weeks of the following month.
|
||||
let month = Zoned::now()
|
||||
|
|
@ -20,117 +27,252 @@ pub async fn get() -> Markup {
|
|||
.unwrap()
|
||||
.strftime("%Y-%m");
|
||||
|
||||
page(
|
||||
html! {
|
||||
style { (PreEscaped(include_str!("index.css"))) }
|
||||
script type="module" { (PreEscaped(include_str!("index.js"))) }
|
||||
},
|
||||
html! {
|
||||
form #form {
|
||||
h1 {
|
||||
"Arbeitszeitdokumentationsgenerator "
|
||||
a #source href="https://github.com/Garmelon/Arbeitszeitdokumentationsgenerator" { "(source)" }
|
||||
}
|
||||
let head = (
|
||||
style(include_str!("index.css")),
|
||||
script((attr::TypeScript::Module, include_str!("index.js"))),
|
||||
);
|
||||
|
||||
p {
|
||||
"Du kannst auch "
|
||||
a href="tsg/" { "JSON eingeben" }
|
||||
", das kompatibel mit dem "
|
||||
a href="https://github.com/kit-sdq/TimeSheetGenerator" { "TimeSheetGenerator" }
|
||||
" ist, oder das dem Generator zugrunde liegende "
|
||||
a href="https://github.com/Garmelon/Arbeitszeitdokumentationsgenerator/blob/master/kit_timesheet.md" { "Typst-Template" }
|
||||
" direkt benutzen."
|
||||
}
|
||||
let body = form((
|
||||
attr::id("form"),
|
||||
h1((
|
||||
"Arbeitszeitdokumentationsgenerator ",
|
||||
a((attr::id("source"), attr::href(LINK_SOURCE), "(source)")),
|
||||
)),
|
||||
p((
|
||||
"Du kannst auch ",
|
||||
a((attr::href("tsg/"), "JSON eingeben")),
|
||||
", das kompatibel mit dem ",
|
||||
a((attr::href(LINK_TSG), "TimeSheetGenerator")),
|
||||
" ist, oder das dem Generator zugrunde liegende ",
|
||||
a((attr::href(LINK_TEMPLATE), "Typst-Template")),
|
||||
" direkt benutzen.",
|
||||
)),
|
||||
div((
|
||||
attr::id("header"),
|
||||
label((attr::id("l-month"), attr::r#for("i-month"), "Monat / Jahr:")),
|
||||
input((
|
||||
attr::id("i-month"),
|
||||
attr::name("month"),
|
||||
attr::TypeInput::Month,
|
||||
attr::placeholder(&month),
|
||||
attr::value(&month),
|
||||
)),
|
||||
label((
|
||||
attr::id("l-name"),
|
||||
attr::r#for("i-name"),
|
||||
"Name, Vorname des/r Beschäftigten:",
|
||||
)),
|
||||
input((
|
||||
attr::id("i-name"),
|
||||
attr::class("twocol"),
|
||||
attr::name("name"),
|
||||
attr::TypeInput::Text,
|
||||
attr::placeholder("McStudentface, Student"),
|
||||
)),
|
||||
label((
|
||||
attr::id("l-staffid"),
|
||||
attr::r#for("i-staffid"),
|
||||
"Personalnummer:",
|
||||
)),
|
||||
input((
|
||||
attr::id("i-staffid"),
|
||||
attr::name("staff_id"),
|
||||
attr::TypeInput::Text,
|
||||
attr::placeholder("1337420"),
|
||||
)),
|
||||
div((
|
||||
attr::id("gfub"),
|
||||
label((
|
||||
attr::id("l-gf"),
|
||||
attr::title("Großforschung"),
|
||||
"GF: ",
|
||||
input((
|
||||
attr::id("i-gf"),
|
||||
attr::name("working_area"),
|
||||
attr::TypeInput::Radio,
|
||||
attr::value("GF"),
|
||||
)),
|
||||
)),
|
||||
label((
|
||||
attr::id("l-ub"),
|
||||
attr::title("Unibereich"),
|
||||
"UB: ",
|
||||
input((
|
||||
attr::id("i-ub"),
|
||||
attr::name("working_area"),
|
||||
attr::TypeInput::Radio,
|
||||
attr::value("UB"),
|
||||
attr::checked(),
|
||||
)),
|
||||
)),
|
||||
)),
|
||||
label((
|
||||
attr::id("l-department"),
|
||||
attr::r#for("i-department"),
|
||||
attr::title("Institut/Organisationseinheit"),
|
||||
"OE:",
|
||||
)),
|
||||
input((
|
||||
attr::id("i-department"),
|
||||
attr::class("twocol"),
|
||||
attr::name("department"),
|
||||
attr::TypeInput::Text,
|
||||
attr::placeholder("Institut für Informatik"),
|
||||
attr::value("Institut für Informatik"),
|
||||
)),
|
||||
label((
|
||||
attr::id("l-monthlyhours"),
|
||||
attr::r#for("i-monthlyhours"),
|
||||
"Vertraglich vereinbarte Arbeitszeit:",
|
||||
)),
|
||||
div((
|
||||
attr::id("mhhr"),
|
||||
attr::class("twocol"),
|
||||
span((
|
||||
input((
|
||||
attr::id("i-monthlyhours"),
|
||||
attr::name("monthly_hours"),
|
||||
attr::TypeInput::Number,
|
||||
attr::value(40),
|
||||
attr::min(0),
|
||||
)),
|
||||
" Std.",
|
||||
)),
|
||||
span((
|
||||
label((
|
||||
attr::id("l-hourlywage"),
|
||||
attr::r#for("i-hourlywage"),
|
||||
"Stundensatz: ",
|
||||
)),
|
||||
input((
|
||||
attr::id("i-hourlywage"),
|
||||
attr::name("hourly_wage"),
|
||||
attr::TypeInput::Number,
|
||||
attr::step(0.01),
|
||||
attr::value(14.09),
|
||||
)),
|
||||
" €",
|
||||
)),
|
||||
)),
|
||||
div((
|
||||
attr::id("carry"),
|
||||
attr::class("twocol"),
|
||||
span((
|
||||
label((
|
||||
attr::id("l-carry"),
|
||||
attr::r#for("i-carry"),
|
||||
"Übertrag vom Vormonat: ",
|
||||
)),
|
||||
input((
|
||||
attr::id("i-carry"),
|
||||
attr::class("i-dur"),
|
||||
attr::name("carry_prev_month"),
|
||||
attr::TypeInput::Text,
|
||||
attr::placeholder("00:00"),
|
||||
)),
|
||||
)),
|
||||
)),
|
||||
label((
|
||||
attr::id("check"),
|
||||
attr::title(concat!(
|
||||
"Die Tabelleneinträge werden chronologisch sortiert,",
|
||||
" anstatt dass ihre Reihenfolge beibehalten wird."
|
||||
)),
|
||||
"Einträge sortieren ",
|
||||
input((
|
||||
attr::name("sort"),
|
||||
attr::TypeInput::Checkbox,
|
||||
attr::value(true),
|
||||
attr::checked(),
|
||||
)),
|
||||
)),
|
||||
label((
|
||||
attr::id("validate"),
|
||||
attr::title(concat!(
|
||||
"Die Tabelleneinträge werden auf Konsistenz und Korrektheit überprüft,",
|
||||
" bevor das Dokument generiert wird."
|
||||
)),
|
||||
"Einträge validieren ",
|
||||
input((
|
||||
attr::name("validate"),
|
||||
attr::TypeInput::Checkbox,
|
||||
attr::value(true),
|
||||
attr::checked(),
|
||||
)),
|
||||
)),
|
||||
)),
|
||||
div((
|
||||
attr::id("table"),
|
||||
div((
|
||||
attr::id("task"),
|
||||
"Tätigkeit",
|
||||
br(()),
|
||||
"(Stichwort, Projekt)",
|
||||
)),
|
||||
div("Tag"),
|
||||
div("Beginn"),
|
||||
div("Ende"),
|
||||
div("Pause"),
|
||||
div("Arbeitszeit"),
|
||||
div(()),
|
||||
div("(hh:mm)"),
|
||||
div("(hh:mm)"),
|
||||
div("(hh:mm)"),
|
||||
div(()),
|
||||
iter::repeat((
|
||||
div(input((
|
||||
attr::class("i-task"),
|
||||
attr::name("task"),
|
||||
attr::TypeInput::Text,
|
||||
))),
|
||||
div(input((
|
||||
attr::class("i-day"),
|
||||
attr::name("day"),
|
||||
attr::TypeInput::Number,
|
||||
attr::placeholder(1),
|
||||
attr::min(1),
|
||||
attr::max(31),
|
||||
))),
|
||||
div(input((
|
||||
attr::class("i-dur"),
|
||||
attr::name("start"),
|
||||
attr::TypeInput::Text,
|
||||
attr::placeholder("12:34"),
|
||||
))),
|
||||
div(input((
|
||||
attr::class("i-dur"),
|
||||
attr::name("end"),
|
||||
attr::TypeInput::Text,
|
||||
attr::placeholder("12:34"),
|
||||
))),
|
||||
div(input((
|
||||
attr::class("i-dur"),
|
||||
attr::name("rest"),
|
||||
attr::TypeInput::Text,
|
||||
attr::placeholder("00:00"),
|
||||
))),
|
||||
div(select((
|
||||
attr::name("note"),
|
||||
attr::value(""),
|
||||
option((attr::value(""), "Normal")),
|
||||
option((attr::value("U"), "Urlaub")),
|
||||
option((attr::value("K"), "Krankheit")),
|
||||
option((attr::value("F"), "Feiertag")),
|
||||
option((attr::value("S"), "Sonstiges")),
|
||||
))),
|
||||
))
|
||||
.take(22)
|
||||
.collect::<Vec<_>>(),
|
||||
)),
|
||||
button((
|
||||
attr::id("submit"),
|
||||
attr::TypeButton::Button,
|
||||
"Arbeitszeitdokumentation generieren",
|
||||
)),
|
||||
pre(attr::id("info")),
|
||||
));
|
||||
|
||||
div #header {
|
||||
label #l-month for="i-month" { "Monat / Jahr:" }
|
||||
input #i-month name="month" type="month" placeholder=(month) value=(month) {}
|
||||
|
||||
label #l-name for="i-name" { "Name, Vorname des/r Beschäftigten:" }
|
||||
input #i-name .twocol name="name" type="text" placeholder="McStudentface, Student" {}
|
||||
|
||||
label #l-staffid for="i-staffid" { "Personalnummer:" }
|
||||
input #i-staffid name="staff_id" type="text" placeholder="1337420" {}
|
||||
|
||||
div #gfub {
|
||||
label #l-gf title="Großforschung" { "GF: "
|
||||
input #i-gf name="working_area" type="radio" value="GF" {}
|
||||
}
|
||||
|
||||
label #l-ub for="i-ub" title="Unibereich" { "UB: "
|
||||
input #i-ub name="working_area" type="radio" value="UB" checked {}
|
||||
}
|
||||
}
|
||||
|
||||
label #l-department for="i-department" title="Organisationseinheit" { "OE:" }
|
||||
input #i-department .twocol name="department" type="text" placeholder="Institut für Informatik" value="Institut für Informatik" {}
|
||||
|
||||
label #l-monthlyhours for="i-monthlyhours" { "Vertraglich vereinbarte Arbeitszeit:" }
|
||||
div #mhhr .twocol {
|
||||
span {
|
||||
input #i-monthlyhours name="monthly_hours" type="number" value="40" min="0" {}
|
||||
" Std."
|
||||
}
|
||||
span {
|
||||
label #l-hourlywage for="i-hourlywage" { "Stundensatz: " }
|
||||
input #i-hourlywage name="hourly_wage" type="number" step="0.01" value="14.09" {}
|
||||
" €"
|
||||
}
|
||||
}
|
||||
|
||||
div #carry .twocol {
|
||||
span {
|
||||
label #l-carry for="i-carry" { "Übertrag vom Vormonat: " }
|
||||
input #i-carry .i-dur name="carry_prev_month" type="text" placeholder="00:00" {}
|
||||
}
|
||||
}
|
||||
|
||||
label #check title="Die Tabelleneinträge werden chronologisch sortiert, anstatt dass ihre Reihenfolge beibehalten wird." {
|
||||
"Einträge sortieren "
|
||||
input name="sort" type="checkbox" value="true" checked {}
|
||||
}
|
||||
|
||||
label #validate title="Die Tabelleneinträge werden auf Konsistenz und Korrektheit überprüft, bevor das Dokument generiert wird." {
|
||||
"Einträge validieren "
|
||||
input name="validate" type="checkbox" value="true" checked {}
|
||||
}
|
||||
}
|
||||
|
||||
div #table {
|
||||
div #task { "Tätigkeit" br; "(Stichwort, Projekt)" }
|
||||
div { "Tag" }
|
||||
div { "Beginn" }
|
||||
div { "Ende" }
|
||||
div { "Pause" }
|
||||
div { "Arbeitszeit" }
|
||||
div { }
|
||||
div { "(hh:mm)" }
|
||||
div { "(hh:mm)" }
|
||||
div { "(hh:mm)" }
|
||||
div { }
|
||||
|
||||
@for _ in 0..22 {
|
||||
div { input .i-task name="task" type="text" {} }
|
||||
div { input .i-day name="day" type="number" placeholder="1" min="1" max="31" {} }
|
||||
div { input .i-dur name="start" type="text" placeholder="12:34" {} }
|
||||
div { input .i-dur name="end" type="text" placeholder="12:34" {} }
|
||||
div { input .i-dur name="rest" type="text" placeholder="00:00" {} }
|
||||
div { select name="note" value="" {
|
||||
option value="" { "Normal" }
|
||||
option value="U" { "Urlaub" }
|
||||
option value="K" { "Krankheit" }
|
||||
option value="F" { "Feiertag" }
|
||||
option value="S" { "Sonstiges" }
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
button #submit type="button" { "Arbeitszeitdokumentation generieren" }
|
||||
|
||||
pre #info {}
|
||||
}
|
||||
},
|
||||
)
|
||||
page(head, body)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use axum::{
|
|||
response::{IntoResponse, Response},
|
||||
Json,
|
||||
};
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
use el::{html::*, Document};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -11,53 +11,76 @@ use crate::{
|
|||
render::{self, Entry, Note, Timesheet, WorkingArea},
|
||||
};
|
||||
|
||||
pub async fn get() -> Markup {
|
||||
page(
|
||||
html! {
|
||||
style { (PreEscaped(include_str!("tsg.css"))) }
|
||||
script type="module" { (PreEscaped(include_str!("tsg.js"))) }
|
||||
},
|
||||
html! {
|
||||
form #form {
|
||||
h1 {
|
||||
"Arbeitszeitdokumentationsgenerator "
|
||||
a #source href="https://github.com/Garmelon/Arbeitszeitdokumentationsgenerator" { "(source)" }
|
||||
}
|
||||
const LINK_SOURCE: &str = "https://github.com/Garmelon/Arbeitszeitdokumentationsgenerator";
|
||||
|
||||
p {
|
||||
"Du kannst deine Daten auch in einem "
|
||||
a href=".." { "coolen Formular" }
|
||||
" eingeben."
|
||||
}
|
||||
pub async fn get() -> Document {
|
||||
let head = (
|
||||
style(include_str!("tsg.css")),
|
||||
script((attr::TypeScript::Module, include_str!("tsg.js"))),
|
||||
);
|
||||
|
||||
p {
|
||||
label for="i-global" { "Global.json" }
|
||||
textarea #i-global name="global" placeholder="{}" {}
|
||||
}
|
||||
let body = form((
|
||||
attr::id("form"),
|
||||
h1((
|
||||
"Arbeitszeitdokumentationsgenerator ",
|
||||
a((attr::id("source"), attr::href(LINK_SOURCE), "(source)")),
|
||||
)),
|
||||
p((
|
||||
"Du kannst deine Daten auch in einem ",
|
||||
a((attr::href(".."), "coolen Formular")),
|
||||
" eingeben.",
|
||||
)),
|
||||
p((
|
||||
label((attr::r#for("i-global"), "Global.json")),
|
||||
textarea((
|
||||
attr::id("i-global"),
|
||||
attr::name("global"),
|
||||
attr::placeholder("{}"),
|
||||
)),
|
||||
)),
|
||||
p((
|
||||
label((attr::r#for("i-month"), "Month.json")),
|
||||
textarea((
|
||||
attr::id("i-month"),
|
||||
attr::name("month"),
|
||||
attr::placeholder("{}"),
|
||||
)),
|
||||
)),
|
||||
p((
|
||||
label((
|
||||
attr::title(concat!(
|
||||
"Die Einträge werden chronologisch sortiert,",
|
||||
" anstatt dass ihre Reihenfolge beibehalten wird."
|
||||
)),
|
||||
input((
|
||||
attr::name("sort"),
|
||||
attr::TypeInput::Checkbox,
|
||||
attr::checked(),
|
||||
)),
|
||||
" Einträge sortieren",
|
||||
)),
|
||||
label((
|
||||
attr::title(concat!(
|
||||
"Die Einträge werden auf Konsistenz und Korrektheit überprüft,",
|
||||
" bevor das Dokument generiert wird."
|
||||
)),
|
||||
input((
|
||||
attr::name("validate"),
|
||||
attr::TypeInput::Checkbox,
|
||||
attr::checked(),
|
||||
)),
|
||||
" Einträge validieren",
|
||||
)),
|
||||
)),
|
||||
button((
|
||||
attr::id("submit"),
|
||||
attr::TypeButton::Button,
|
||||
"Arbeitszeitdokumentation generieren",
|
||||
)),
|
||||
pre(attr::id("info")),
|
||||
));
|
||||
|
||||
p {
|
||||
label for="i-month" { "Month.json" }
|
||||
textarea #i-month name="month" placeholder="{}" {}
|
||||
}
|
||||
|
||||
p {
|
||||
label title="Die Einträge werden chronologisch sortiert, anstatt dass ihre Reihenfolge beibehalten wird." {
|
||||
input name="sort" type="checkbox" checked {}
|
||||
" Einträge sortieren"
|
||||
}
|
||||
|
||||
label title="Die Einträge werden auf Konsistenz und Korrektheit überprüft, bevor das Dokument generiert wird." {
|
||||
input name="validate" type="checkbox" checked {}
|
||||
" Einträge validieren"
|
||||
}
|
||||
}
|
||||
|
||||
button #submit type="button" { "Arbeitszeitdokumentation generieren" }
|
||||
|
||||
pre #info {}
|
||||
}
|
||||
},
|
||||
)
|
||||
page(head, body)
|
||||
}
|
||||
|
||||
fn default_vacation() -> bool {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue