Merge branch 'staging' into 'input-val'

# Conflicts:
#   templates/ergo.html.tera
#   templates/includes/macros.html.tera
This commit is contained in:
PhilippHofer 2023-11-08 17:02:32 +00:00
commit 04958d80a4
25 changed files with 299 additions and 147 deletions

View File

@ -8,6 +8,8 @@ export interface choiceMap {
let choiceObjects: choiceMap = {};
document.addEventListener('DOMContentLoaded', function() {
changeTheme();
initcolorTheme();
initSearch();
initSidebar();
initToggle();
@ -20,6 +22,73 @@ document.addEventListener('DOMContentLoaded', function() {
setCurrentdate(<HTMLInputElement>document.querySelector('#departure'));
});
function changeTheme() {
let toggleBtn = <HTMLElement>document.querySelector('#theme-toggle-js');
if(toggleBtn) {
toggleBtn.addEventListener('click', function() {
if(toggleBtn.dataset.theme === 'light') {
setTheme('dark', true);
} else {
setTheme('light', true);
}
});
}
}
/***
* init javascript
* 1) detect native color scheme or use set theme in local storage
* 2) detect view (desktop or responsive) if on mobile device with touch screen
* 3) set base font size to 112.5% -> 18px
*/
function initcolorTheme() {
colorThemeWatcher();
let theme = localStorage.getItem('theme');
if (theme == null || theme === 'auto') {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
setTheme('dark', false);
} else {
setTheme('light', false);
}
} else {
setTheme(theme)
}
}
/***
* Listener operating system native color configuration
*/
function colorThemeWatcher() {
try {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
setTheme(e.matches ? 'dark' : 'light');
});
} catch {
console.warn('color theme watcher not supported');
}
}
/**
* Define color scheme, colors without losing the base font size configuration
* and add data-theme to html tag
* @param theme
*/
function setTheme(theme: string, setLocalStorage = true) {
let toggleBtn = document.querySelector('#theme-toggle-js');
if (setLocalStorage) {
localStorage.setItem('theme', theme);
}
if (toggleBtn) toggleBtn.setAttribute('data-theme', theme);
if (document.documentElement.classList.contains('dark') && theme === 'light') {
document.documentElement.classList.remove('dark');
} else if(theme === 'dark'){
document.documentElement.classList.add('dark');
}
}
function setCurrentdate(input: HTMLInputElement) {
if(input) {
const now = new Date();

View File

@ -10,3 +10,4 @@
@import 'components/alert';
@import 'components/status';
@import 'components/chart';
@import 'components/search';

View File

@ -6,11 +6,11 @@
}
&-dark {
@apply bg-primary-900 hover:bg-primary-950 focus-visible:outline-primary-950;
@apply bg-primary-900 hover:bg-primary-950 dark:bg-primary-950 dark:hover:bg-primary-700 focus-visible:outline-primary-950;
}
&-gray {
@apply bg-gray-400 hover:bg-gray-500 focus-visible:outline-primary-500;
@apply bg-gray-400 hover:bg-gray-500 dark:bg-primary-600 focus-visible:outline-primary-500;
}
&-attention {

View File

@ -1,7 +1,7 @@
.h1 {
@apply text-center text-3xl uppercase tracking-wide font-bold text-primary-900;
@apply text-center text-3xl uppercase tracking-wide font-bold text-primary-900 dark:text-white;
}
.h2 {
@apply font-bold uppercase tracking-wide text-center rounded-t-md text-primary-950 bg-gray-200 bg-opacity-80 text-lg px-3 py-3;
@apply font-bold uppercase tracking-wide text-center rounded-t-md text-primary-950 dark:text-white bg-gray-200 dark:bg-primary-950 bg-opacity-80 text-lg px-3 py-3;
}

View File

@ -1,5 +1,5 @@
.input {
@apply relative block w-full border-0 py-1.5 px-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:z-10 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6;
@apply relative block w-full bg-white dark:bg-black border-0 py-1.5 px-2 text-gray-900 dark:text-white ring-1 ring-inset ring-gray-300 dark:ring-black placeholder:text-gray-400 focus:z-10 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6;
}
select {
@ -7,7 +7,7 @@ select {
background-repeat: no-repeat;
background-position: right .75rem center;
background-size: 16px 12px;
background-color: white;
@apply bg-white dark:bg-black;
-webkit-appearance: none;
appearance: none;
}
@ -32,7 +32,7 @@ select {
}
.choices.is-disabled .choices__inner,
.choices.is-disabled .choices__input {
background-color: #eaeaea;
@apply bg-white dark:bg-black;
cursor: not-allowed;
-webkit-user-select: none;
user-select: none;
@ -52,8 +52,7 @@ select {
display: block;
width: 100%;
padding: 10px;
@apply border-0 ring-1 ring-inset ring-gray-300;
background-color: #fff;
@apply bg-white dark:bg-black border-0 ring-1 ring-inset ring-gray-300 dark:ring-primary-600;
margin: 0;
}
.choices[data-type*=select-one] .choices__button {
@ -93,7 +92,7 @@ select {
pointer-events: none;
}
.choices[data-type*=select-one].is-open::after {
@apply border-0 ring-1 ring-inset ring-gray-300;
@apply border-0 ring-1 ring-inset ring-gray-300 dark:ring-primary-600;
margin-top: -7.5px;
}
.choices[data-type*=select-one][dir=rtl]::after {
@ -135,10 +134,10 @@ select {
}
.choices__inner {
@apply input rounded-md bg-white;
@apply input rounded-md bg-white dark:bg-black;
}
.is-focused .choices__inner, .is-open .choices__inner {
@apply border-0 ring-1 ring-inset ring-gray-300;
@apply border-0 ring-1 ring-inset ring-gray-300 dark:ring-primary-600;
}
.is-open .choices__inner {
border-radius: 0;
@ -190,7 +189,7 @@ select {
@apply bg-primary-900;
}
.is-disabled .choices__list--multiple .choices__item {
@apply bg-gray-600;
@apply bg-gray-600 dark:bg-primary-900;
}
.choices__list--dropdown, .choices__list[aria-expanded] {
@ -198,8 +197,7 @@ select {
z-index: 1;
position: absolute;
width: 100%;
background-color: #fff;
@apply border;
@apply border bg-white dark:bg-black dark:text-white;
top: 100%;
margin-top: -1px;
border-bottom-left-radius: 2.5px;
@ -212,7 +210,7 @@ select {
visibility: visible;
}
.is-open .choices__list--dropdown, .is-open .choices__list[aria-expanded] {
@apply border-0 ring-1 ring-inset ring-gray-300;
@apply border-0 ring-1 ring-inset ring-gray-300 dark:ring-primary-600;
}
.is-flipped .choices__list--dropdown, .is-flipped .choices__list[aria-expanded] {
top: auto;
@ -260,7 +258,7 @@ select {
}
}
.choices__list--dropdown .choices__item--selectable.is-highlighted, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
@apply bg-gray-100;
@apply bg-gray-100 dark:bg-primary-950;
}
.choices__list--dropdown .choices__item--selectable.is-highlighted::after, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted::after {
opacity: 0.5;
@ -309,6 +307,8 @@ select {
border: 0;
border-radius: 0;
max-width: 100%;
@apply bg-transparent;
}
.choices__input:focus {
outline: 0;

View File

@ -1,6 +1,6 @@
.link {
&-primary {
@apply text-primary-600 hover:text-primary-900 underline;
@apply text-primary-600 dark:text-primary-200 hover:text-primary-900 hover:dark:text-primary-300 underline;
}
&-dark {

View File

@ -0,0 +1,13 @@
.search {
&-bar {
@apply w-full relative block rounded-md border-0 py-1.5 px-2 bg-white dark:bg-black text-gray-900 dark:text-white ring-1 ring-inset ring-gray-300 dark:ring-black placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6 mb-2 md:mb-0;
}
&-wrapper {
@apply bg-gray-200 dark:bg-primary-600 p-3 mt-4 rounded-t-md;
}
&-result {
@apply bg-gray-200 dark:bg-primary-600 text-primary-950 dark:text-white pb-3 px-3 text-right;
}
}

View File

@ -3,14 +3,12 @@
position: fixed;
overflow-y: scroll;
top: 0;
background: white;
z-index: 2000;
width: 0;
max-width: 0;
box-shadow: 0 1rem 3rem rgba(0,0,0,.175);
&.open {
background-color: rgba(255, 255, 255, 100%);
display: block;
height: 100vh;
right: 0;

View File

@ -40,5 +40,7 @@ export default {
},
},
plugins: [],
important: true,
darkMode: 'class',
}

View File

@ -17,11 +17,12 @@ use tera::Context;
use crate::model::{
log::Log,
user::{AdminUser, NonGuestUser, User},
user::{AdminUser, User},
};
#[derive(Serialize)]
struct ErgoStat {
id: i64,
name: String,
dob: Option<String>,
weight: Option<String>,
@ -33,7 +34,7 @@ struct ErgoStat {
async fn send(db: &State<SqlitePool>, _user: AdminUser) -> Template {
let thirty = sqlx::query_as!(
ErgoStat,
"SELECT name, dirty_thirty as result, dob, weight, sex FROM user WHERE deleted = 0 AND dirty_thirty is not null ORDER BY result DESC"
"SELECT id, name, dirty_thirty as result, dob, weight, sex FROM user WHERE deleted = 0 AND dirty_thirty is not null ORDER BY result DESC"
)
.fetch_all(db.inner())
.await
@ -41,7 +42,7 @@ async fn send(db: &State<SqlitePool>, _user: AdminUser) -> Template {
let dozen= sqlx::query_as!(
ErgoStat,
"SELECT name, dirty_dozen as result, dob, weight, sex FROM user WHERE deleted = 0 AND dirty_dozen is not null ORDER BY result DESC"
"SELECT id, name, dirty_dozen as result, dob, weight, sex FROM user WHERE deleted = 0 AND dirty_dozen is not null ORDER BY result DESC"
)
.fetch_all(db.inner())
.await
@ -66,13 +67,41 @@ async fn reset(db: &State<SqlitePool>, _user: AdminUser) -> Flash<Redirect> {
)
}
#[get("/<challenge>/user/<user_id>/new?<new>")]
async fn update(
db: &State<SqlitePool>,
_admin: AdminUser,
challenge: &str,
user_id: i64,
new: &str,
) -> Flash<Redirect> {
if challenge == "thirty" {
sqlx::query!("UPDATE user SET dirty_thirty = ? WHERE id=?", new, user_id)
.execute(db.inner())
.await
.unwrap();
Flash::success(Redirect::to("/ergo"), "Succ")
} else if challenge == "dozen" {
sqlx::query!("UPDATE user SET dirty_dozen = ? WHERE id=?", new, user_id)
.execute(db.inner())
.await
.unwrap();
Flash::success(Redirect::to("/ergo"), "Succ")
} else {
Flash::error(
Redirect::to("/ergo"),
"Challenge not found (should be thirty or dozen)",
)
}
}
#[get("/")]
async fn index(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage<'_>>) -> Template {
let users = User::ergo(db).await;
let thirty = sqlx::query_as!(
ErgoStat,
"SELECT name, dirty_thirty as result, dob, weight, sex FROM user WHERE deleted = 0 AND dirty_thirty is not null ORDER BY result DESC"
"SELECT id, name, dirty_thirty as result, dob, weight, sex FROM user WHERE deleted = 0 AND dirty_thirty is not null ORDER BY result DESC"
)
.fetch_all(db.inner())
.await
@ -80,7 +109,7 @@ async fn index(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage<'_
let dozen= sqlx::query_as!(
ErgoStat,
"SELECT name, dirty_dozen as result, dob, weight, sex FROM user WHERE deleted = 0 AND dirty_dozen is not null ORDER BY result DESC"
"SELECT id, name, dirty_dozen as result, dob, weight, sex FROM user WHERE deleted = 0 AND dirty_dozen is not null ORDER BY result DESC"
)
.fetch_all(db.inner())
.await
@ -180,7 +209,7 @@ async fn new_dozen(
}
pub fn routes() -> Vec<Route> {
routes![index, new_thirty, new_dozen, send, reset]
routes![index, new_thirty, new_dozen, send, reset, update]
}
#[cfg(test)]

View File

@ -30,26 +30,29 @@
</form>
<!-- START filterBar -->
<div class="bg-primary-200 p-3 mt-4 rounded-t-md">
<div class="search-wrapper">
<label for="name" class="sr-only">Suche</label>
<input type="search" name="name" id="filter-js" class="w-full relative block rounded-md border-0 py-1.5 px-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6 mb-2 md:mb-0" placeholder="Suchen nach..."/>
<input type="search" name="name" id="filter-js" class="search-bar" placeholder="Suchen nach..."/>
</div>
<!-- END filterBar -->
<div class="bg-primary-100 p-3 rounded-b-md grid gap-4">
<div id="filter-result-js" class="text-primary-950"></div>
<div class="bg-primary-100 dark:bg-primary-950 p-3 rounded-b-md grid gap-4">
<div id="filter-result-js" class="text-primary-950 dark:text-white text-right"></div>
{% for user in users %}
<div data-filterable="true" data-filter="{{ user.name }}">
<form action="/admin/user" method="post" class="bg-white p-3 rounded-md flex items-end md:items-center justify-between w-full">
<div class="w-full">
<form action="/admin/user" method="post" class="bg-white dark:bg-primary-900 p-3 rounded-md w-full">
<div class="w-full grid gap-3">
<input type="hidden" name="id" value="{{ user.id }}"/>
<div class="font-bold mb-1">{{ user.name }}
<div class="font-bold mb-1 text-black dark:text-white">{{ user.name }}
{% if user.last_access %}
(last access:
{{ user.last_access | date }})
{% endif %}
{% if user.pw %}
<a class="block mt-1 font-normal text-primary-600 dark:text-primary-200 hover:text-primary-900 dark:hover:text-primary-300 underline" href="/admin/user/{{ user.id }}/reset-pw">Passwort zurücksetzen</a>
{% endif %}
</div>
<div class="grid md:grid-cols-3">
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-3">
{{ macros::checkbox(label='Scheckbuch', name='is_guest', id=loop.index , checked=user.is_guest) }}
{{ macros::checkbox(label='Steuerberechtigter', name='is_cox', id=loop.index , checked=user.is_cox) }}
{{ macros::checkbox(label='Technical', name='is_tech', id=loop.index , checked=user.is_tech) }}
@ -58,16 +61,13 @@
{{ macros::input(label='Weight (kg)', name='weight', id=loop.index, type="text", value=user.weight) }}
{{ macros::input(label='Sex', name='sex', id=loop.index, type="text", value=user.sex) }}
</div>
{% if user.pw %}
<a class="inline-block mt-1 text-primary-600 hover:text-primary-900 underline" href="/admin/user/{{ user.id }}/reset-pw">Passwort zurücksetzen</a>
{% endif %}
</div>
<div class="grid gap-3">
<a href="/admin/user/{{ user.id }}/delete" class="inline-block btn btn-alert" onclick="return confirm('Wirklich löschen?');">
<div class="mt-3 text-right">
<a href="/admin/user/{{ user.id }}/delete" class="w-28 btn btn-alert" onclick="return confirm('Wirklich löschen?');">
{% include "includes/delete-icon" %}
Löschen
</a>
<input value="Ändern" type="submit" class="w-28 btn btn-primary"/>
<input value="Ändern" type="submit" class="w-28 btn btn-primary ml-1"/>
</div>
</form>
</div>

View File

@ -9,7 +9,7 @@
<link rel="icon" type="image/x-icon" href="/public/images/favicon.ico">
<title>Ruderassistent - ASKÖ Ruderverein Donau Linz</title>
</head>
<body class="bg-gray-100">
<body class="bg-gray-100 dark:bg-black">
{% if loggedin_user %}
{{ macros::header(loggedin_user=loggedin_user) }}
{% endif %}
@ -30,7 +30,7 @@
</header>
{% endif %}
<div class="flex min-h-screen {%if not loggedin_user and not show_kiosk_header %} items-center {% else %} items-start {% endif %} justify-center px-4 py-12 sm:px-6 lg:px-8"> {% block content %}{% endblock content %}
<div class="flex min-h-screen {%if not loggedin_user and not show_kiosk_header %} items-center dark:bg-primary-900 {% else %} items-start {% endif %} justify-center px-4 py-12 sm:px-6 lg:px-8"> {% block content %}{% endblock content %}
</div>
{% if loggedin_user %}

View File

@ -38,24 +38,24 @@
</div>
</div>
<div class="bg-gray-200 p-3 mt-4 rounded-t-md">
<div class="search-wrapper">
<label for="name" class="sr-only">Suche</label>
<input type="search" name="name" id="filter-js" class="w-full relative block rounded-md border-0 py-1.5 px-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6 mb-2 md:mb-0" placeholder="Suchen nach Namen...">
<input type="search" name="name" id="filter-js" class="search-bar" placeholder="Suchen nach Namen...">
</div>
<div id="filter-result-js" class="bg-gray-200 text-primary-950 pb-3 px-3 text-right"></div>
<div id="filter-result-js" class="search-result"></div>
{% for boatdamage in boatdamages | sort(attribute="verified") %}
<div data-filterable="true" data-filter="{{ boatdamage.boat.name }} {{ boatdamage.user_created.name }}" class="w-full border-t bg-white p-3 {% if boatdamage.verified_at %} opacity-50 {% endif %}">
<div data-filterable="true" data-filter="{{ boatdamage.boat.name }} {{ boatdamage.user_created.name }}" class="w-full border-t bg-white dark:bg-primary-900 text-black dark:text-white p-3 {% if boatdamage.verified_at %} opacity-50 {% endif %}">
<div class="w-full">
<strong>{{ boatdamage.created_at | date(format='%d.%m.%Y') }} <span class="font-normal text-gray-600">({{ boatdamage.boat.name }})</span></strong>{% if boatdamage.boat.damage %}<small class="block text-gray-600">(Boot gesperrt)</small>{% endif %}
<strong>{{ boatdamage.created_at | date(format='%d.%m.%Y') }} <span class="font-normal text-gray-600 dark:text-gray-100">({{ boatdamage.boat.name }})</span></strong>{% if boatdamage.boat.damage %}<small class="block text-gray-600 dark:text-gray-100">(Boot gesperrt)</small>{% endif %}
<div>{{ boatdamage.desc }}</div>
<small class="block text-gray-600">
<small class="block text-gray-600 dark:text-gray-100">
Schaden eingetragen von {{ boatdamage.user_created.name }} am/um {{ boatdamage.created_at | date(format='%d.%m.%Y (%H:%M)') }}
</small>
{% if boatdamage.fixed_at %}
<small class="block text-gray-600">Repariert von {{ boatdamage.user_fixed.name }} am/um {{ boatdamage.fixed_at | date(format='%d.%m.%Y (%H:%M)') }}</small>
<small class="block text-gray-600 dark:text-gray-100">Repariert von {{ boatdamage.user_fixed.name }} am/um {{ boatdamage.fixed_at | date(format='%d.%m.%Y (%H:%M)') }}</small>
{% else %}
{% if loggedin_user.is_cox %}
<form action="/boatdamage/{{ boatdamage.id }}/fixed" method="post" class="flex justify-between mt-3">
@ -70,7 +70,7 @@
{% endif %}
{% if boatdamage.verified_at %}
<small class="block text-gray-600">Verifziert von {{ boatdamage.user_verified.name }} am/um {{ boatdamage.verified_at | date(format='%d.%m.%Y (%H:%M)') }}</small>
<small class="block text-gray-600 dark:text-gray-100">Verifziert von {{ boatdamage.user_verified.name }} am/um {{ boatdamage.verified_at | date(format='%d.%m.%Y (%H:%M)') }}</small>
{% else %}
{% if loggedin_user.is_tech and boatdamage.fixed_at %}
<form action="/boatdamage/{{ boatdamage.id }}/verified" method="post" class="flex justify-between mt-3">

View File

@ -1,4 +1,4 @@
<div class="sidebar slide-in from-right" id="sidebar" aria-modal="false">
<div class="sidebar slide-in from-right bg-white dark:bg-primary-950 dark:text-white" id="sidebar" aria-modal="false">
<div class="bg-primary-900 text-white px-2 py-3 flex justify-between sidebar-header">
<div>
<span class="ps-1 header-js">

View File

@ -12,11 +12,11 @@
<div class="grid gap-3">
<details class="bg-white rounded-md p-2 mt-5 shadow">
<details class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md p-2 mt-5 shadow">
<summary class="cursor-pointer">Deine Daten</summary>
<div class="pt-3">
<p>
Folgende Daten hat der Ruderassistent von dir. Wenn diese nicht mehr aktuell sind, bitte gewünschte Änderungen an Philipp melden (Tel. nr siehe Signal, oder an <a href="mailto:it@rudernlinz.at" class="text-primary-600 hover:text-primary-950 underline" target="_blank">it@rudernlinz.at</a>).
Folgende Daten hat der Ruderassistent von dir. Wenn diese nicht mehr aktuell sind, bitte gewünschte Änderungen an Philipp melden (Tel. nr siehe Signal, oder an <a href="mailto:it@rudernlinz.at" class="text-primary-600 dark:text-primary-200 hover:text-primary-950 hover:dark:text-primary-300 underline" target="_blank">it@rudernlinz.at</a>).
<br /><br />
<ul>
<li>Geburtsdatum: {{ loggedin_user.dob }}</li>
@ -27,7 +27,7 @@
</div>
</details>
<div class="bg-white rounded-md block shadow grid gap-3">
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow grid gap-3">
<h2 class="h2">Neuer Eintrag</h1>
<details class="p-2">
@ -35,7 +35,7 @@
<div class="mt-3">
<form action="/ergo/thirty" class="grid gap-3" method="post" enctype="multipart/form-data">
<div>
<label for="user-thirty" class="text-sm text-gray-600">Ergo-Fahrer</label>
<label for="user-thirty" class="text-sm text-gray-600 dark:text-gray-100">Ergo-Fahrer</label>
<select name="user" id="user-thirty" class="input rounded-md">
<option disabled="disabled">User auswählen</option>
{% for user in users %}
@ -51,8 +51,8 @@
{{ macros::input(label="Distanz [m]", name="result", required=true, type="number", class="input rounded-md") }}
<div>
<label for="file-thirty" class="text-sm text-gray-600">Ergebnis-Foto vom Ergo-Display</label>
<input type="file" id="file-thirty" name="proof" class="input rounded-md" accept="image/*" capture="camera">
<label for="file-thirty" class="text-sm text-gray-600 dark:text-gray-100">Ergebnis-Foto vom Ergo-Display</label>
<input type="file" id="file-thirty" name="proof" class="input rounded-md" accept="image/*">
</div>
<div class="text-end">
<input type="submit" value="Speichern" class="btn btn-primary btn-fw m-auto"/>
@ -66,7 +66,7 @@
<div class="mt-3">
<form action="/ergo/dozen" class="grid gap-3" method="post" enctype="multipart/form-data">
<div>
<label for="user-dozen" class="text-sm text-gray-600">Ergo-Fahrer</label>
<label for="user-dozen" class="text-sm text-gray-600 dark:text-gray-100">Ergo-Fahrer</label>
<select name="user" id="user-dozen" class="input rounded-md">
<option disabled="disabled">User auswählen</option>
{% for user in users %}
@ -79,11 +79,11 @@
</select>
</div>
{{ macros::input(label="Zeit [(hh:)mm:ss]/Distanz [m]", name="result", required=true, type="text", class="input rounded-md", pattern="(?:\d+:\d{2}:\d{2}\.\d+|\d{1,2}:\d{2}\.\d+|\d+(\.\d+)?)") }}
{{ macros::input(label="Zeit [hh:mm:ss.s] oder Distanz [m]", name="result", required=true, type="text", class="input rounded-md", pattern="(?:\d+:\d{2}:\d{2}\.\d+|\d{1,2}:\d{2}\.\d+|\d+(\.\d+)?)") }}
<div>
<label for="file-dozen" class="text-sm text-gray-600">Ergebnis-Foto vom Ergo-Display</label>
<input type="file" id="file-dozen" name="proof" class="input rounded-md" accept="image/*" capture="camera">
<label for="file-dozen" class="text-sm text-gray-600 dark:text-gray-100">Ergebnis-Foto vom Ergo-Display</label>
<input type="file" id="file-dozen" name="proof" class="input rounded-md" accept="image/*">
</div>
<div class="text-end">
<input type="submit" value="Speichern" class="btn btn-primary btn-fw m-auto"/>
@ -94,7 +94,7 @@
</div>
<div class="bg-white rounded-md block shadow grid gap-3">
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow grid gap-3">
<h2 class="h2">Aktuelle Woche</h2>
<details class="p-2">
@ -120,6 +120,43 @@
</details>
</div>
</div>
{% if loggedin_user.is_admin %}
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow grid gap-3">
<h2 class="h2">Update</h2>
<details class="p-2">
<summary class="cursor-pointer">Dirty Thirty <small class="text-gray-600">({{thirty | length}})</small></summary>
<div class="mt-3">
<ol>
{% for stat in thirty %}
<li>
<form action="/ergo/thirty/user/{{ stat.id }}/new" method="get">
{{ stat.name }}: <input type="text" value="{{stat.result}}" name="new" style="color: black;"/><input type="submit"/>
</form>
</li>
{% endfor %}
</ol>
</div>
</details>
<details class="p-2">
<summary class="cursor-pointer">Dirty Dozen <small class="text-gray-600">({{dozen | length}})</small></summary>
<div class="mt-3">
<ol>
{% for stat in dozen %}
<li>
<form action="/ergo/dozen/user/{{ stat.id }}/new" method="get">
{{ stat.name }}: <input type="text" value="{{stat.result}}" name="new" style="color: black;"/><input type="submit"/>
</form>
</li>
{% endfor %}
</ol>
</div>
</details>
</div>
</div>
{% endif %}
</div>
{% endblock content%}

View File

@ -1,12 +1,23 @@
<footer class="bg-primary-950 text-white w-full flex justify-center p-3">
<div class="max-w-screen-xl w-full flex justify-between">
<footer class="bg-primary-950 dark:bg-primary-900 text-white w-full flex justify-center p-3">
<div class="max-w-screen-xl w-full flex justify-between items-center">
<div>
<span class="text-[#ff0000]">&hearts;</span>
ASKÖ Ruderverein Donau Linz
</div>
<div>
&copy;
{{ now() | date(format="%Y") }}
ASKÖ Ruderverein Donau Linz <small class="text-primary-100">&copy; {{ now() | date(format="%Y") }}</smalL>
</div>
<div>
<button id="theme-toggle-js" type="button" data-theme="light" class="btn btn-primary">
<span class="hidden dark:inline">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z"/>
</svg>
</span>
<span class="inline dark:hidden">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278zM4.858 1.311A7.269 7.269 0 0 0 1.025 7.71c0 4.02 3.279 7.276 7.319 7.276a7.316 7.316 0 0 0 5.205-2.162c-.337.042-.68.063-1.029.063-4.61 0-8.343-3.714-8.343-8.29 0-1.167.242-2.278.681-3.286z"/>
</svg>
</span>
</button>
</div>
</div>
</footer>

View File

@ -28,21 +28,21 @@
</div>
</div>
</div>
<div class="bg-gray-200 p-3 mt-4 rounded-t-md">
<div class="search-wrapper">
<label for="name" class="sr-only">Suche</label>
<input type="search" name="name" id="filter-js" class="w-full relative block rounded-md border-0 py-1.5 px-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6 mb-2 md:mb-0" placeholder="Suchen nach Namen...">
<input type="search" name="name" id="filter-js" class="search-bar" placeholder="Suchen nach Namen...">
</div>
<div id="filter-result-js" class="bg-gray-200 text-primary-950 pb-3 px-3 text-right"></div>
<div id="filter-result-js" class="search-result"></div>
{% endmacro new %}
{% macro edit(boat, uuid) %}
<div data-filterable="true" data-filter="{{ boat.name }}" class="w-full border-t">
<form action="/admin/boat/{{ boat.id }}" data-filterable="true" method="post" class="bg-white p-4 w-full">
<form action="/admin/boat/{{ boat.id }}" data-filterable="true" method="post" class="bg-white dark:bg-primary-900 p-4 w-full">
<div class="w-full">
<input type="hidden" name="id" value="{{ boat.id }}"/>
<div class="font-bold mb-1">{{ boat.name }}<br/></div>
<div class="font-bold mb-1 text-black dark:text-white">{{ boat.name }}<br/></div>
<div class="grid md:grid-cols-3 gap-3">
{{ macros::input(label='Name', name='name', type='text', value=boat.name) }}
{{ macros::input(label='Plätze', name='amount_seats', type='number', min=0, value=boat.amount_seats) }}

View File

@ -9,11 +9,11 @@
{% endif %}
{% for amount_seats, grouped_boats in boats | group_by(attribute="amount_seats") %}
<div class="pb-2">
<div class="bg-gray-100 text-primary-950 text-center text-sm mb-2">
<div class="bg-gray-100 dark:bg-primary-600 text-primary-950 dark:text-white text-center text-sm mb-2">
<strong>{{ amount_seats }}x</strong>
</div>
{% for boat in grouped_boats %}
<div id="boat-{{ boat.id }}" class="px-3 boats-js cursor-pointer" {% if boat.damage != 'locked' %} data-seats="{{boat.amount_seats}}" data-default_shipmaster_only_steering="{{boat.default_shipmaster_only_steering}}" data-onclick="true" {% endif %} data-id="{{ boat.id }}">
<div id="boat-{{ boat.id }}" class="px-3 boats-js text-black dark:text-white {% if boat.damage != 'locked' and not boat.on_water %} cursor-pointer hover:text-primary-900 dark:hover:text-gray-100 {% endif %}" {% if boat.damage != 'locked' and not boat.on_water %} data-seats="{{boat.amount_seats}}" data-default_shipmaster_only_steering="{{boat.default_shipmaster_only_steering}}" data-onclick="true" {% endif %} data-id="{{ boat.id }}">
<span class="status-damage status-damage-{{ boat.damage }}"></span>
<span {% if boat.damage == 'locked' or boat.on_water %} class="opacity-50" {% endif %}>{{ boat.name }}
{% if boat.owner %}
@ -32,7 +32,7 @@
{{ log::boat_select(only_ones=only_ones) }}
{% if not only_ones %}
<div class="col-span-4 md:col-span-1">
<div class="text-sm text-gray-600">Bootssteuerung</div>
<div class="text-sm text-gray-600 dark:text-gray-100">Bootssteuerung</div>
<div class="h-10 flex items-center">
{{ macros::checkbox(label='handgesteuert', name='shipmaster_only_steering', disabled=true) }}
</div>
@ -46,7 +46,7 @@
{{ macros::input(label='Abfahrtszeit', name='departure', type='datetime-local', required=true, wrapper_class='col-span-2') }}
{{ macros::input(label='Ankunftszeit', name='arrival', type='datetime-local', wrapper_class='col-span-2') }}
<div class="relative col-span-2">
<label for="destination" class="text-sm text-gray-600">Ziel</label>
<label for="destination" class="text-sm text-gray-600 dark:text-gray-100">Ziel</label>
<input class="input rounded-md set-distance-js" type="search" list="destinations" placeholder="Destination" id="destination" name="destination" value="" data-relation="distance_in_km"/>
<datalist id="destinations">
{% for distance in distances %}<option value="{{ distance.0 }}" distance="{{ distance.1 }}" />
@ -55,7 +55,7 @@
</div>
<div class="relative col-span-2">
{{ macros::input(label="Distanz", name="distance_in_km", id="distance_in_km" , type="number", min=0, value='', class="rounded-md") }}
<span class="absolute right-0 bottom-0 py-1.5 px-2 bg-white border-0 text-gray-600 ring-1 ring-inset ring-gray-300 rounded-br-md rounded-tr-md">km</span>
<span class="absolute right-0 bottom-0 py-1.5 px-2 bg-white dark:bg-primary-950 border-0 text-gray-600 dark:text-gray-100 ring-1 ring-inset ring-gray-300 dark:ring-primary-950 rounded-br-md rounded-tr-md">km</span>
</div>
{{ macros::input(label="Kommentar", name="comments", type="text", wrapper_class="col-span-4") }}
{{ macros::select(label="Typ", data=logtypes, name='logtype', default="Normal", wrapper_class="col-span-4") }}
@ -76,7 +76,7 @@
{% macro rower_select(id, selected, amount_seats='', class='', init='false', cox_on_boat='', steering_person_id='') %}
{#{% if not amount_seats or amount_seats > 1 %}#}
<div class="{{ class }}">
<label for="{{id}}" class="text-sm text-gray-600 ">Ruderer (inkl. Schiffsführer und Steuerperson)</label>
<label for="{{id}}" class="text-sm text-gray-600 dark:text-gray-100">Ruderer (inkl. Schiffsführer und Steuerperson)</label>
<select style="width: 100%;" multiple name="rowers[]" id="{{id}}" class="w-full" data-seats="{{amount_seats}}" data-init={{init}}>
{% for user in users %}
{% set_global sel = false %}
@ -103,7 +103,7 @@
<div class="w-full">
<div class="flex justify-between items-center">
<div>
<strong class="block text-primary-900">
<strong class="block text-primary-900 dark:text-white">
{{ log.departure | date(format="%H:%M") }}
Uhr
</strong>
@ -135,7 +135,7 @@
{% endif %}
{% for rower in log.rowers %}
<p>{{ rower.name }} {% if rower.id == log.shipmaster or rower.id == log.steering_person %}<small class="text-gray-600">({% if rower.id == log.shipmaster %}Schiffsführer{% endif %}{% if rower.id == log.shipmaster and rower.id == log.steering_person %}/{% endif %}{% if rower.id == log.steering_person%}Steuerperson{% endif %})</small>{% endif %}</p>
<p>{{ rower.name }} {% if rower.id == log.shipmaster or rower.id == log.steering_person %}<small class="text-gray-600 dark:text-primary-100">({% if rower.id == log.shipmaster %}Schiffsführer{% endif %}{% if rower.id == log.shipmaster and rower.id == log.steering_person %}/{% endif %}{% if rower.id == log.steering_person%}Steuerperson{% endif %})</small>{% endif %}</p>
{% endfor %}
{% set amount_rowers = log.rowers | length %}
@ -156,7 +156,7 @@
{% endmacro show %}
{% macro show_old(log, state, allowed_to_close=false, only_ones, index) %}
<div class="border-t bg-white py-3 px-4 relative" data-filterable="true" data-filter="{{ log.boat.name }} {% for rower in log.rowers %} {{ rower.name }} {% endfor %}">
<div class="border-t bg-white dark:bg-primary-900 py-3 px-4 relative" data-filterable="true" data-filter="{{ log.boat.name }} {% for rower in log.rowers %} {{ rower.name }} {% endfor %}">
{% if log.logtype %}
<div class="absolute top-0 right-0 bg-primary-100 rounded-bl-md text-primary-950 text-xs w-32 px-2 py-1 text-center font-bold">
{% if log.logtype == 1 %}
@ -171,8 +171,8 @@
</div>
{% endif %}
<div {% if log.logtype %} class="mt-4 sm:mt-0" {% endif %}>
<strong>{{ log.boat.name }}</strong> <small class="text-gray-600">({{ log.shipmaster_user.name }}{% if log.shipmaster_only_steering %} - handgesteuert {% endif %})</small>
<small class="block text-gray-600">
<strong class="text-black dark:text-white">{{ log.boat.name }}</strong> <small class="text-gray-600 dark:text-gray-100">({{ log.shipmaster_user.name }}{% if log.shipmaster_only_steering %} - handgesteuert {% endif %})</small>
<small class="block text-gray-600 dark:text-gray-100">
{% if state == "completed" and log.departure | date(format='%d.%m.%Y') == log.arrival | date(format='%d.%m.%Y') %}
{{ log.departure | date(format='%d.%m.%Y')}} ({{ log.departure | date(format='%H:%M')}} - {{ log.arrival | date(format='%H:%M')}})
@ -185,10 +185,10 @@
{% if allowed_to_close and state == "on_water" %}
{{ log::home(log=log, only_ones=only_ones) }}
{% else %}
<div>
<div class="text-black dark:text-white">
{{ log.destination }}
{% if state == "completed" %}
<small class="text-gray-600">({{ log.distance_in_km }} km)</small>
<small class="text-gray-600 dark:text-gray-100">({{ log.distance_in_km }} km)</small>
{% endif %}
{% if log.comments %}
@ -196,13 +196,13 @@
{% endif %}
</div>
{% if amount_guests > 0 or log.rowers | length > 0 %}
<div class="text-sm text-gray-600">
<div class="text-sm text-gray-600 dark:text-gray-100">
Ruderer:
{% for rower in log.rowers %}
{{ rower.name }}{% if not loop.last or amount_guests > 0 %}, {% endif %}
{% endfor %}
{% if amount_guests > 0 %}
Gäste <small class="text-gray-600">(ohne Account)</small>: {{ amount_guests }}
Gäste <small class="text-gray-600 dark:text-gray-100">(ohne Account)</small>: {{ amount_guests }}
{% endif %}
</div>
{% endif %}
@ -216,19 +216,19 @@
{{ macros::input(label='Ankunftszeit', name='arrival', type='datetime-local', required=true, class="change-id-js rounded-md current-date-time") }}
<div>
<label for="destination" class="text-sm text-gray-600">Ziel</label>
<label for="destination" class="text-sm text-gray-600 dark:text-gray-100">Ziel</label>
<input class="input rounded-md set-distance-js change-id-js" type="search" list="destinations" placeholder="Destination" required="required" id="destination{{ log.id }}" name="destination" value="{{log.destination}}" data-relation="distance_in_km{{log.id}}"/>
</div>
<div class="relative">
{{ macros::input(label="Distanz", name="distance_in_km", id="distance_in_km" ~ log.id , type="number", min=0, value=log.distance_in_km, required=true, class="rounded-md change-id-js") }}
<span class="absolute right-0 bottom-0 py-1.5 px-2 bg-white border-0 text-gray-600 ring-1 ring-inset ring-gray-300 rounded-br-md rounded-tr-md">km</span>
<span class="absolute right-0 bottom-0 py-1.5 px-2 bg-white dark:bg-primary-950 border-0 text-gray-600 dark:text-gray-100 ring-1 ring-inset ring-gray-300 dark:ring-primary-950 rounded-br-md rounded-tr-md">km</span>
</div>
{{ macros::input(label="Kommentar", name="comments", id="comments" ~ log.id, type="text", value=log.comments, class="rounded-md change-id-js") }}
<details class="bg-gray-200 bg-opacity-80 rounded-md p-2">
<details class="bg-gray-200 bg-opacity-80 dark:bg-primary-900 rounded-md p-2">
<summary class="cursor-pointer">Details ändern</summary>
<div class="grid grid-cols-1 gap-3">
{{ macros::input(label='Abfahrtszeit', name='departure', type='datetime-local', required=true, class="change-id-js rounded-md", value=log.departure) }}

View File

@ -124,7 +124,7 @@
{% endif %}
<a
href="/auth/logout"
class="inline-flex justify-center rounded-md bg-primary-600 ml-1 px-3 py-2 text-sm font-semibold text-white hover:bg-primary-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600 cursor-pointer"
class="inline-flex justify-center rounded-md bg-gray-200 ml-1 px-3 py-2 text-sm font-semibold text-primary-950 hover:bg-gray-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600 cursor-pointer"
>
<svg
class="inline h-4"
@ -158,15 +158,15 @@
{% endmacro input %}
{% macro checkbox(label, name, id='', checked=false, class='', disabled=false) %}
<label for="{{ name }}{{ id }}" class="flex items-center cursor-pointer hover:text-gray-900 {{ class }}">
<input type="checkbox" id="{{ name }}{{ id }}" name="{{ name }}" {% if checked %} checked {% endif %} {% if disabled %} disabled {% endif %} class="h-4 w-4 accent-primary-600 mr-2"/>
<label for="{{ name }}{{ id }}" class="flex items-center cursor-pointer text-black dark:text-white hover:text-gray-900 dark:hover:text-gray-100 {{ class }}">
<input type="checkbox" id="{{ name }}{{ id }}" name="{{ name }}" {% if checked %} checked {% endif %} {% if disabled %} disabled {% endif %} class="h-4 w-4 accent-primary-600 dark:accent-primary-200 mr-2"/>
{{ label }}
</label>
{% endmacro checkbox %}
{% macro select(label, data, name='trip_type', default='', id='', selected_id='', display='', extras='', class='', wrapper_class='', required=false, show_seats=false) %}
<div class="{{wrapper_class}}">
<label for="{{ name }}" class="text-sm text-gray-600">{{ label }}</label>
<label for="{{ name }}" class="text-sm text-gray-600 dark:text-gray-100">{{ label }}</label>
{% if display == '' %}
{% set display = ["name"] %}
{% endif %}
@ -175,7 +175,7 @@
<option selected value>{{ default }}</option>
{% endif %}
{% for d in data %}
<option value="{{ d.id }}" {% if d.id == selected_id %} selected {% endif %} {% if extras != '' %} {% for extra in extras %} {% if extra != 'on_water' %} data- {{extra}}={{d[extra]}} {% else %} {% if d[extra] %} disabled {% endif %} {% endif %} {% endfor %} {% endif %} {% if show_seats %} data-custom-properties='{"amount_seats": {{ d["amount_seats"] }}, "owner": "{{ d["owner"] }}"}'{% endif %}>
<option value="{{ d.id }}" {% if d.id == selected_id %} selected {% endif %} {% if extras != '' %} {% for extra in extras %} {% if extra != 'on_water' %} data-{{extra}}={{d[extra]}} {% else %} {% if d[extra] %} disabled {% endif %} {% endif %} {% endfor %} {% endif %} {% if show_seats %} data-custom-properties='{"amount_seats": {{ d["amount_seats"] }}, "owner": "{{ d["owner"] }}"}'{% endif %}>
{% for displa in display -%}
{%- if d[displa] -%}
{{- d[displa] -}}
@ -204,10 +204,10 @@
{% for rower in participants %}
{{ rower.name }}
{% if rower.is_guest %}
<small class="text-gray-600">(Scheckbuch)</small>
<small class="text-gray-600 dark:text-gray-100">(Scheckbuch)</small>
{% endif %}
{% if rower.is_real_guest %}
<small class="text-gray-600">(Gast)</small>
<small class="text-gray-600 dark:text-gray-100">(Gast)</small>
{% if allow_removing %}
<a href="/remove/{{ trip_details_id }}/{{ rower.name }}" class="btn btn-attention btn-fw">Abmelden</a>
{% endif %}

View File

@ -23,10 +23,10 @@
{% endfor %}
{% endif %}
<div class="bg-white rounded-md flex justify-between flex-col shadow reset-js" style="min-height: 10rem;" data-trips="{{ amount_trips }}" data-month="{{ day.day| date(format='%m') }}" data-coxneeded="{{ day_cox_needed }}">
<div class="bg-white dark:bg-primary-900 rounded-md flex justify-between flex-col shadow reset-js" style="min-height: 10rem;" data-trips="{{ amount_trips }}" data-month="{{ day.day| date(format='%m') }}" data-coxneeded="{{ day_cox_needed }}">
<div>
<h2 class="font-bold uppercase tracking-wide text-center rounded-t-md {% if day.is_pinned %} text-white bg-primary-950 {% else %} text-primary-950 bg-gray-200 bg-opacity-80 {% endif %} text-lg px-3 py-3 ">{{ day.day| date(format="%d.%m.%Y") }}
<small class="inline-block ml-1 text-xs {% if day.is_pinned %} text-gray-200 {% else %} text-gray-500 {% endif %}">{{ day.day | date(format="%A", locale="de_AT") }}</small>
<h2 class="font-bold uppercase tracking-wide text-center rounded-t-md {% if day.is_pinned %} text-white bg-primary-950 {% else %} text-primary-950 dark:text-white bg-gray-200 dark:bg-primary-950 bg-opacity-80 {% endif %} text-lg px-3 py-3 ">{{ day.day| date(format="%d.%m.%Y") }}
<small class="inline-block ml-1 text-xs {% if day.is_pinned %} text-gray-200 {% else %} text-gray-500 dark:text-gray-100 {% endif %}">{{ day.day | date(format="%A", locale="de_AT") }}</small>
</h2>
{% if day.planned_events | length > 0 or day.trips | length > 0 %}
@ -38,18 +38,14 @@
{% for planned_event in day.planned_events | sort(attribute="planned_starting_time") %}
{% set amount_cur_cox = planned_event.cox | length %}
{% set amount_cox_missing = planned_event.planned_amount_cox - amount_cur_cox %}
<div class="pt-2 px-3 border-t" style="order: {{ planned_event.planned_starting_time | replace(from=":", to="") }}">
<div class="pt-2 px-3 border-t border-gray-200" style="order: {{ planned_event.planned_starting_time | replace(from=":", to="") }}">
<div class="flex justify-between items-center">
<div class="mr-1">
<strong class="text-primary-900">
<strong class="text-primary-900 dark:text-white">
{{ planned_event.planned_starting_time }}
Uhr
</strong>
<small class="text-gray-600">({{ planned_event.name }}
{% if planned_event.trip_type %}
-
{{ planned_event.trip_type.icon | safe }}{{ planned_event.trip_type.name }}
{% endif %})</small><br/>
<small class="text-gray-600 dark:text-gray-100">({{ planned_event.name }}{% if planned_event.trip_type %} - {{ planned_event.trip_type.icon | safe }} {{ planned_event.trip_type.name }}{% endif %})</small><br/>
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>{{ planned_event.planned_starting_time }} Uhr</strong> ({{ planned_event.name }}){% if planned_event.trip_type %}<small class='block'>{{ planned_event.trip_type.desc }}</small>{% endif %}{% if planned_event.notes %}<small class='block'>{{ planned_event.notes }}</small>{% endif %}" data-body="#event{{ planned_event.trip_details_id }}" class="inline-block link-primary mr-3">
Details
@ -121,8 +117,8 @@
{% if loggedin_user.is_admin %}
<form action="/join/{{ planned_event.trip_details_id }}" method="get" />
{{ macros::input(label='Gast', name='user_note', type='text', required=true) }}
<input value="Gast hinzufügen" class="btn btn-primary" type="submit"/>
{{ macros::input(label='Gast', class="input rounded-t", name='user_note', type='text', required=true) }}
<input value="Gast hinzufügen" class="btn btn-primary w-full !rounded-t-none" type="submit"/>
</form>
{% endif %}
@ -134,8 +130,8 @@
{% if loggedin_user.is_admin %}
{# --- START Edit Form --- #}
<div class="bg-gray-100 p-3 mt-4 rounded-md">
<h3 class="text-primary-950 font-bold uppercase tracking-wide mb-2">Ausfahrt bearbeiten</h3>
<div class="bg-gray-100 dark:bg-primary-900 p-3 mt-4 rounded-md">
<h3 class="text-primary-950 dark:text-white font-bold uppercase tracking-wide mb-2">Ausfahrt bearbeiten</h3>
<form action="/admin/planned-event" method="post" class="grid gap-3">
<input type="hidden" name="_method" value="put"/>
<input type="hidden" name="id" value="{{ planned_event.id }}"/>
@ -170,7 +166,7 @@
{# --- START Trips --- #}
{% if day.trips | length > 0 %}
{% for trip in day.trips | sort(attribute="planned_starting_time") %}
<div class="pt-2 px-3 reset-js border-t" style="order: {{ trip.planned_starting_time | replace(from=":", to="") }}" data-coxneeded="false">
<div class="pt-2 px-3 reset-js border-t border-gray-200" style="order: {{ trip.planned_starting_time | replace(from=":", to="") }}" data-coxneeded="false">
<div class="flex justify-between items-center">
<div class="mr-1">
{% if trip.max_people == 0 %}
@ -184,13 +180,9 @@
{{ trip.trip_type.icon | safe }}{{ trip.trip_type.name }}
{% endif %})</small>
{% else %}
<strong class="text-primary-900">{{ trip.planned_starting_time }}
<strong class="text-primary-900 dark:text-white">{{ trip.planned_starting_time }}
Uhr</strong>
<small class="text-gray-600">({{ trip.cox_name }}
{% if trip.trip_type %}
-
{{ trip.trip_type.icon | safe }}{{ trip.trip_type.name }}
{% endif %})</small>
<small class="text-gray-600 dark:text-gray-100">({{ trip.cox_name }}{% if trip.trip_type %} - {{ trip.trip_type.icon | safe }} {{ trip.trip_type.name }}{% endif %})</small>
{% endif %}
<br/>
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>{% if trip.max_people == 0 %}&#9888; {% endif %}{{ trip.planned_starting_time }} Uhr</strong> ({{ trip.cox_name }}){% if trip.trip_type %}<small class='block'>{{ trip.trip_type.desc }}</small>{% endif %}{% if trip.notes %}<small class='block'>{{ trip.notes }}</small>{% endif %}" data-body="#trip{{ trip.trip_details_id }}" class="inline-block link-primary mr-3">
@ -224,16 +216,16 @@
{{ macros::box(participants=trip.rower, empty_seats=trip.max_people - amount_cur_rower, bg='primary-100', color='black', trip_details_id=trip.trip_details_id, allow_removing=loggedin_user.id == trip.cox_id) }}
{% if trip.cox_id == loggedin_user.id %}
<form action="/join/{{ trip.trip_details_id }}" method="get" />
{{ macros::input(label='Gast', name='user_note', type='text', required=true) }}
<input value="Gast hinzufügen" class="btn btn-primary" type="submit"/>
{{ macros::input(label='Gast', class="input rounded-t", name='user_note', type='text', required=true) }}
<input value="Gast hinzufügen" class="btn btn-primary w-full !rounded-t-none" type="submit"/>
</form>
{% endif %}
{% endif %}
{# --- START Edit Form --- #}
{% if trip.cox_id == loggedin_user.id %}
<div class="bg-gray-100 p-3 mt-4 rounded-md">
<h3 class="text-primary-950 font-bold uppercase tracking-wide mb-2">Ausfahrt bearbeiten</h3>
<div class="bg-gray-100 dark:bg-primary-900 p-3 mt-4 rounded-md">
<h3 class="text-primary-950 dark:text-white font-bold uppercase tracking-wide mb-2">Ausfahrt bearbeiten</h3>
<form action="/cox/trip/{{ trip.id }}" method="post" class="grid gap-3">
{{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=trip.max_people, min='0') }}
{{ macros::input(label='Anmerkungen', name='notes', type='input', value=trip.notes) }}
@ -269,7 +261,7 @@
{% if loggedin_user.is_admin or loggedin_user.is_cox %}
<div class="grid {% if loggedin_user.is_admin %} grid-cols-2 {% endif %} text-center">
{% if loggedin_user.is_admin %}
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>Event</strong> am {{ day.day| date(format='%d.%m.%Y') }} erstellen" data-day="{{ day.day }}" data-body="#addEventForm" class="relative inline-block w-full bg-primary-900 hover:bg-primary-950 focus:bg-primary-950 text-white py-2 rounded-bl-md text-sm font-semibold">
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>Event</strong> am {{ day.day| date(format='%d.%m.%Y') }} erstellen" data-day="{{ day.day }}" data-body="#addEventForm" class="relative inline-block w-full bg-primary-900 hover:bg-primary-950 focus:bg-primary-950 dark:bg-primary-950 text-white py-2 rounded-bl-md text-sm font-semibold">
<span class="absolute inset-y-0 left-0 flex items-center pl-3">
{% include "includes/plus-icon" %}
</span>
@ -278,7 +270,7 @@
{% endif %}
{% if loggedin_user.is_cox%}
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>Ausfahrt</strong> am {{ day.day| date(format='%d.%m.%Y') }} erstellen" data-day="{{ day.day }}" data-body="#sidebarForm" class="relative inline-block w-full py-2 text-primary-900 hover:text-primary-950 focus:text-primary-950 text-sm font-semibold bg-gray-100 hover:bg-gray-200 focus:bg-gray-200 {% if loggedin_user.is_admin %} rounded-br-md {% else %} rounded-b-md {% endif %}">
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>Ausfahrt</strong> am {{ day.day| date(format='%d.%m.%Y') }} erstellen" data-day="{{ day.day }}" data-body="#sidebarForm" class="relative inline-block w-full py-2 text-primary-900 hover:text-primary-950 dark:bg-primary-600 dark:text-white dark:hover:bg-primary-500 dark:hover:text-white focus:text-primary-950 text-sm font-semibold bg-gray-100 hover:bg-gray-200 focus:bg-gray-200 {% if loggedin_user.is_admin %} rounded-br-md {% else %} rounded-b-md {% endif %}">
<span class="absolute inset-y-0 left-0 flex items-center pl-3">
{% include "includes/plus-icon" %}
</span>

View File

@ -15,20 +15,20 @@
{% endif %}
<div class="w-full grid md:grid-cols-5 gap-3 mt-5">
<div class="bg-white rounded-md hidden md:block shadow">
<div class="bg-white dark:bg-primary-900 rounded-md hidden md:block shadow">
<h2 class="h2">Boote</h2>
<div>
{{ log::show_boats(only_ones=false) }}
</div>
</div>
<div class="md:col-span-3 bg-white rounded-md shadow">
<div class="md:col-span-3 bg-white dark:bg-primary-900 rounded-md shadow">
<h2 class="h2">Neue Ausfahrt</h2>
<div class="p-3">
{{ log::new(only_ones=false, shipmaster=-1) }}
</div>
</div>
<div class="bg-white rounded-md shadow">
<div class="bg-white dark:bg-primary-900 rounded-md shadow">
<h2 class="h2">Am Wasser</h2>
<div>

View File

@ -9,12 +9,12 @@
<h1 class="h1">Logbuch</h1>
<div class="mt-3">
<div class="bg-gray-200 p-3 mt-4 rounded-t-md">
<div class="search-wrapper">
<label for="name" class="sr-only">Suche</label>
<input type="search" name="name" id="filter-js" class="w-full relative block rounded-md border-0 py-1.5 px-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6 mb-2 md:mb-0" placeholder="Suchen nach Bootsname oder Ruderer...">
<input type="search" name="name" id="filter-js" class="search-bar" placeholder="Suchen nach Bootsname oder Ruderer...">
</div>
<div id="filter-result-js" class="bg-gray-200 text-primary-950 pb-3 px-3 text-right"></div>
<div id="filter-result-js" class="search-result"></div>
{% for log in logs %}
{{ log::show_old(log=log, state="completed", only_ones=false, index=loop.index) }}
{% endfor %}

View File

@ -14,20 +14,20 @@
{% endif %}
<div class="w-full grid md:grid-cols-5 gap-3 mt-5">
<div class="bg-white rounded-md hidden md:block shadow">
<div class="bg-white dark:bg-primary-900 rounded-md hidden md:block shadow">
<h2 class="h2">Boote</h2>
<div>
{{ log::show_boats(only_ones=false) }}
</div>
</div>
<div class="md:col-span-3 bg-white rounded-md shadow">
<div class="md:col-span-3 bg-white dark:bg-primary-900 rounded-md shadow">
<h2 class="h2">Neue Ausfahrt</h2>
<div class="p-3">
{{ log::new(only_ones=loggedin_user.is_cox==false, shipmaster=loggedin_user.id) }}
</div>
</div>
<div class="bg-white rounded-md shadow">
<div class="bg-white dark:bg-primary-900 rounded-md shadow">
<h2 class="h2">Am Wasser</h2>
{% if on_water | length > 0 %}

View File

@ -5,19 +5,19 @@
{% block content %}
<div class="max-w-screen-lg w-full">
<h1 class="h1">Bootsauswertung</h1>
<div class="bg-gray-200 p-3 mt-4 rounded-t-md">
<div class="search-wrapper">
<label for="name" class="sr-only">Suche</label>
<input type="search" name="name" id="filter-js" class="w-full relative block rounded-md border-0 py-1.5 px-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6 mb-2 md:mb-0" placeholder="Suchen nach Bootsnamen...">
<input type="search" name="name" id="filter-js" class="search-bar" placeholder="Suchen nach Bootsnamen...">
</div>
<div id="filter-result-js" class="bg-gray-200 text-primary-950 pb-3 px-3 text-right"></div>
<div id="filter-result-js" class="search-result"></div>
<div class="border-r border-l">
<div class="border-r border-l border-gray-200 dark:border-primary-600">
{% set_global km = 0 %}
{% set_global index = 1 %}
{% for s in stat %}
<div class="border-t {% if loop.last %} border-b {% endif %} bg-white flex justify-between items-center px-3 py-1" data-filterable="true" data-filter="{{ s.name }}">
<span class="text-sm text-gray-600 w-10">
<div class="border-t border-gray-200 dark:border-primary-600 {% if loop.last %} border-b {% endif %} bg-white dark:bg-primary-900 text-black dark:text-white flex justify-between items-center px-3 py-1" data-filterable="true" data-filter="{{ s.name }}">
<span class="text-sm text-gray-600 dark:text-gray-100 w-10">
{% if km != s.rowed_km %}
{{loop.index}}
{% set_global index = loop.index %}

View File

@ -7,19 +7,19 @@
<div class="max-w-screen-lg w-full">
<h1 class="h1">Statistik</h1>
<div class="bg-gray-200 p-3 mt-4 rounded-t-md">
<div class="search-wrapper">
<label for="name" class="sr-only">Suche</label>
<input type="search" name="name" id="filter-js" class="w-full relative block rounded-md border-0 py-1.5 px-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6 mb-2 md:mb-0" placeholder="Suchen nach Namen...">
<input type="search" name="name" id="filter-js" class="search-bar" placeholder="Suchen nach Namen...">
</div>
<div id="filter-result-js" class="bg-gray-200 text-primary-950 pb-3 px-3 text-right"></div>
<div id="filter-result-js" class="search-result"></div>
<div class="border-r border-l">
<div class="border-r border-l border-gray-200 dark:border-primary-600">
{% set_global km = 0 %}
{% set_global index = 1 %}
{% for s in stat %}
<div class="border-t {% if loop.last %} border-b {% endif %} bg-white flex justify-between items-center px-3 py-1" data-filterable="true" data-filter="{{ s.name }}">
<span class="text-sm text-gray-600 w-10">
<div class="border-t border-gray-200 dark:border-primary-600 {% if loop.last %} border-b {% endif %} bg-white dark:bg-primary-900 text-black dark:text-white flex justify-between items-center px-3 py-1" data-filterable="true" data-filter="{{ s.name }}">
<span class="text-sm text-gray-600 dark:text-gray-100 w-10">
{% if km != s.rowed_km %}
{{loop.index}}
{% set_global index = loop.index %}