Merge branch 'marudor-darkMode'

This commit is contained in:
Daniel Friesel 2019-05-18 08:31:13 +02:00
commit c3071d54eb
43 changed files with 7466 additions and 94 deletions

3
.gitignore vendored
View file

@ -64,3 +64,6 @@ tags
[._]*.un~
# End of https://www.gitignore.io/api/vim,perl
### theme stuff ###
sass/node_modules

View file

@ -93,6 +93,23 @@ sub startup {
$self->defaults( layout => 'default' );
$self->hook(
before_dispatch => sub {
my ($self) = @_;
# The "theme" cookie is set client-side if the theme we delivered was
# changed by dark mode detection or by using the theme switcher). It's
# not part of Mojolicious' session data (and can't be, due to
# signing and HTTPOnly), so we need to add it here.
for my $cookie ( @{ $self->req->cookies } ) {
if ( $cookie->name eq 'theme' ) {
$self->session( theme => $cookie->value );
return;
}
}
}
);
$self->attr(
cache_iris_main => sub {
my ($self) = @_;

View file

@ -1,18 +1,19 @@
const CACHE_NAME = 'static-cache-v20';
const CACHE_NAME = 'static-cache-v21';
const FILES_TO_CACHE = [
'/favicon.ico',
'/offline.html',
'/static/v20/css/materialize.min.css',
'/static/v20/css/material-icons.css',
'/static/v20/css/local.css',
'/static/v20/fonts/MaterialIcons-Regular.woff2',
'/static/v20/fonts/MaterialIcons-Regular.woff',
'/static/v20/fonts/MaterialIcons-Regular.ttf',
'/static/v20/js/jquery-3.4.1.min.js',
'/static/v20/js/materialize.min.js',
'/static/v20/js/travelynx-actions.min.js',
'/static/v20/js/autocomplete.min.js',
'/static/v20/js/geolocation.min.js',
'/static/v21/css/light.min.css',
'/static/v21/css/dark.min.css',
'/static/v21/css/material-icons.css',
'/static/v21/css/local.css',
'/static/v21/fonts/MaterialIcons-Regular.woff2',
'/static/v21/fonts/MaterialIcons-Regular.woff',
'/static/v21/fonts/MaterialIcons-Regular.ttf',
'/static/v21/js/jquery-3.4.1.min.js',
'/static/v21/js/materialize.min.js',
'/static/v21/js/travelynx-actions.min.js',
'/static/v21/js/autocomplete.min.js',
'/static/v21/js/geolocation.min.js',
];
self.addEventListener('install', (evt) => {

12
public/static/css/dark.min.css vendored Normal file

File diff suppressed because one or more lines are too long

12
public/static/css/light.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -11,10 +11,6 @@ td.cancelled {
text-decoration: line-through;
}
a.unmarked {
color: rgba(0, 0, 0, 0.87);
}
h1 {
font-size: 2.92rem;
margin: 1.9466666667rem 0 1.168rem 0;

View file

@ -2,12 +2,12 @@
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(/static/v20/fonts/MaterialIcons-Regular.eot); /* For IE6-8 */
src: url(/static/v21/fonts/MaterialIcons-Regular.eot); /* For IE6-8 */
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(/static/v20/fonts/MaterialIcons-Regular.woff2) format('woff2'),
url(/static/v20/fonts/MaterialIcons-Regular.woff) format('woff'),
url(/static/v20/fonts/MaterialIcons-Regular.ttf) format('truetype');
url(/static/v21/fonts/MaterialIcons-Regular.woff2) format('woff2'),
url(/static/v21/fonts/MaterialIcons-Regular.woff) format('woff'),
url(/static/v21/fonts/MaterialIcons-Regular.ttf) format('truetype');
}
.material-icons {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
function upd_journey_data(){$(".countdown").each(function(){j_duration=$(this).data("duration"),j_arrival=$(this).data("arrival")})}function upd_countdown(){var t=Date.now()/1e3;j_arrival>0&&(j_arrival>t?$(".countdown").text("Ankunft in "+Math.round((j_arrival-t)/60)+" Minuten"):$(".countdown").text("Ziel erreicht"))}function tvly_run(t,a,e){var n='<i class="material-icons">error</i>',i=$('<div class="progress"><div class="indeterminate"></div></div>');t.hide(),t.after(i),$.post("/action",a,function(a){a.success?$(location).attr("href",a.redirect_to):(M.toast({html:n+" "+a.error}),i.remove(),e&&e(),t.append(" "+n),t.show())})}function tvly_update(){$.get("/ajax/status_card.html",function(t){$(".statuscol").html(t),tvly_reg_handlers(),upd_journey_data(),setTimeout(tvly_update,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update,5e3)})}function tvly_update_public(){var t;$(".publicstatuscol").each(function(){t=$(this).data("user")}),$.get("/ajax/status/"+t+".html",function(t){$(".publicstatuscol").html(t),upd_journey_data(),setTimeout(tvly_update_public,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update_public,5e3)})}function tvly_journey_progress(){var t=Date.now()/1e3,a=0;j_duration>0&&(a=1-(j_arrival-t)/j_duration,a<0&&(a=0),a>1&&(a=1),$(".progress .determinate").css("width",100*a+"%"),setTimeout(tvly_journey_progress,5e3))}function tvly_reg_handlers(){$(".action-checkin").click(function(){var t=$(this);tvly_run(t,{action:"checkin",station:t.data("station"),train:t.data("train")})}),$(".action-checkout").click(function(){var t=$(this),a={action:"checkout",station:t.data("station"),force:t.data("force")};tvly_run(t,a,function(){t.append(" Ohne Echtzeitdaten auschecken?"),t.data("force",!0)})}),$(".action-undo").click(function(){var t=$(this);tvly_run(t,{action:"undo",undo_id:t.data("id")})}),$(".action-cancelled-from").click(function(){var t=$(this);tvly_run(t,{action:"cancelled_from",station:t.data("station"),train:t.data("train")})}),$(".action-cancelled-to").click(function(){var t=$(this);tvly_run(t,{action:"cancelled_to",station:t.data("station"),force:!0})}),$(".action-delete").click(function(){var t=$(this),a={action:"delete",id:t.data("id"),checkin:t.data("checkin"),checkout:t.data("checkout")};really_delete=confirm("Diese Zugfahrt wirklich löschen? Der Eintrag wird sofort aus der Datenbank entfernt und kann nicht wiederhergestellt werden."),really_delete&&tvly_run(t,a)}),$(".action-share").click(function(){navigator.share&&(shareObj={text:$(this).data("text")},$(this).data("url")&&(shareObj.url=$(this).data("url")),navigator.share(shareObj))}),$(".action-share").length&&!navigator.share&&$(".action-share").css("display","none")}var j_duration=0,j_arrival=0;$(document).ready(function(){tvly_reg_handlers(),$(".statuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update,4e4),setTimeout(tvly_journey_progress,5e3)),$(".publicstatuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update_public,4e4),setTimeout(tvly_journey_progress,5e3)),$("a[href]").click(function(){$("nav .preloader-wrapper").addClass("active")})});
var j_duration=0,j_arrival=0;function upd_journey_data(){$(".countdown").each(function(){j_duration=$(this).data("duration"),j_arrival=$(this).data("arrival")})}function upd_countdown(){var t=Date.now()/1e3;0<j_arrival&&(t<j_arrival?$(".countdown").text("Ankunft in "+Math.round((j_arrival-t)/60)+" Minuten"):$(".countdown").text("Ziel erreicht"))}function tvly_run(a,t,e){var n='<i class="material-icons">error</i>',i=$('<div class="progress"><div class="indeterminate"></div></div>');a.hide(),a.after(i),$.post("/action",t,function(t){t.success?$(location).attr("href",t.redirect_to):(M.toast({html:n+" "+t.error}),i.remove(),e&&e(),a.append(" "+n),a.show())})}function tvly_update(){$.get("/ajax/status_card.html",function(t){$(".statuscol").html(t),tvly_reg_handlers(),upd_journey_data(),setTimeout(tvly_update,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update,5e3)})}function tvly_update_public(){var t;$(".publicstatuscol").each(function(){t=$(this).data("user")}),$.get("/ajax/status/"+t+".html",function(t){$(".publicstatuscol").html(t),upd_journey_data(),setTimeout(tvly_update_public,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update_public,5e3)})}function tvly_journey_progress(){var t=Date.now()/1e3,a=0;0<j_duration&&((a=1-(j_arrival-t)/j_duration)<0&&(a=0),1<a&&(a=1),$(".progress .determinate").css("width",100*a+"%"),setTimeout(tvly_journey_progress,5e3))}function tvly_reg_handlers(){$(".action-checkin").click(function(){var t=$(this),a={action:"checkin",station:t.data("station"),train:t.data("train")};tvly_run(t,a)}),$(".action-checkout").click(function(){var t=$(this),a={action:"checkout",station:t.data("station"),force:t.data("force")};tvly_run(t,a,function(){t.append(" Ohne Echtzeitdaten auschecken?"),t.data("force",!0)})}),$(".action-undo").click(function(){var t=$(this),a={action:"undo",undo_id:t.data("id")};tvly_run(t,a)}),$(".action-cancelled-from").click(function(){var t=$(this),a={action:"cancelled_from",station:t.data("station"),train:t.data("train")};tvly_run(t,a)}),$(".action-cancelled-to").click(function(){var t=$(this),a={action:"cancelled_to",station:t.data("station"),force:!0};tvly_run(t,a)}),$(".action-delete").click(function(){var t=$(this),a={action:"delete",id:t.data("id"),checkin:t.data("checkin"),checkout:t.data("checkout")};really_delete=confirm("Diese Zugfahrt wirklich löschen? Der Eintrag wird sofort aus der Datenbank entfernt und kann nicht wiederhergestellt werden."),really_delete&&tvly_run(t,a)}),$(".action-share").click(function(){navigator.share&&(shareObj={text:$(this).data("text")},$(this).data("url")&&(shareObj.url=$(this).data("url")),navigator.share(shareObj))}),$(".action-share").length&&!navigator.share&&$(".action-share").css("display","none")}$(document).ready(function(){tvly_reg_handlers(),$(".statuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update,4e4),setTimeout(tvly_journey_progress,5e3)),$(".publicstatuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update_public,4e4),setTimeout(tvly_journey_progress,5e3)),$("a[href]").click(function(){$("nav .preloader-wrapper").addClass("active")})});

View file

@ -3,27 +3,27 @@
"short_name": "Travelynx",
"scope": "/",
"icons": [{
"src": "/static/v20/icons/icon-128x128.png",
"src": "/static/v21/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
}, {
"src": "/static/v20/icons/icon-144x144.png",
"src": "/static/v21/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
}, {
"src": "/static/v20/icons/icon-152x152.png",
"src": "/static/v21/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
}, {
"src": "/static/v20/icons/icon-192x192.png",
"src": "/static/v21/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
}, {
"src": "/static/v20/icons/icon-256x256.png",
"src": "/static/v21/icons/icon-256x256.png",
"sizes": "256x256",
"type": "image/png"
}, {
"src": "/static/v20/icons/icon-512x512.png",
"src": "/static/v21/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}],

7
sass/.prettierrc Normal file
View file

@ -0,0 +1,7 @@
{
"singleQuote": true,
"tabWidth": 2,
"printWidth": 80,
"semi": true,
"trailingComma": "es5"
}

7153
sass/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

32
sass/package.json Normal file
View file

@ -0,0 +1,32 @@
{
"name": "travelynx",
"version": "1.0.0",
"description": "travelynx - Railway Travel Logger",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/derf/travelynx.git"
},
"author": "",
"license": "MIT",
"bugs": {
"url": "https://github.com/derf/travelynx/issues"
},
"homepage": "https://github.com/derf/travelynx#readme",
"devDependencies": {
"css-loader": "^2.1.1",
"cssnano": "^4.1.10",
"materialize-css": "^1.0.0-rc.2",
"mini-css-extract-plugin": "^0.6.0",
"node-sass": "^4.12.0",
"postcss": "^7.0.16",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.6.0",
"postcss-scss": "^2.0.0",
"sass-loader": "^7.1.0",
"webpack": "^4.31.0",
"webpack-cli": "^3.3.2"
}
}

View file

View file

@ -0,0 +1,31 @@
$customColors: (
'caution': $error-color,
'info': $info-color,
'contrast': $off-black,
'success': $success-color,
);
@each $name, $color in $customColors {
.#{$name}-color {
background-color: $color;
}
.#{$name}-color-text {
color: $color;
}
}
html {
background-color: $bg-color;
}
a.unmarked {
color: $off-black;
}
.pagination {
li {
a {
color: $off-black;
}
}
}

View file

@ -0,0 +1,18 @@
$bg-color: #101010 !default;
$info-color: color('blue-grey', 'darken-4');
$off-black: color('shades', 'white');
$primary-color: color('materialize-red', 'darken-2');
$secondary-color: color('cyan', 'darken-2');
$link-color: color('light-blue', 'darken-1');
$collection-link-color: color('cyan', 'darken-4');
$success-color: color('green', 'darken-2');
$error-color: color('red', 'darken-2');
$input-border-color: $off-black;
$radio-empty-color: $off-black !default;
$table-striped-color: color('grey', 'darken-4');
$button-flat-color: $off-black;
$card-bg-color: color('grey', 'darken-4');
$card-link-color: $link-color;

15
sass/src/dark/index.scss Normal file
View file

@ -0,0 +1,15 @@
@import '../../node_modules/materialize-css/sass/components/color-variables';
@import 'variables.scss';
@import '../../node_modules/materialize-css/sass/materialize.scss';
@import '../common/index.scss';
.progress.travel-progress {
background-color: color('purple', 'lighten-1');
& > .determinate {
background-color: color('purple', 'darken-1');
}
}
html {
background-color: $bg-color;
}

View file

@ -0,0 +1,5 @@
$bg-color: #fff;
$info-color: color('yellow', 'lighten-4');
$link-color: color('light-blue', 'darken-1');
$card-link-color: $link-color;
$card-bg-color: color('blue-grey', 'lighten-5');

11
sass/src/light/index.scss Normal file
View file

@ -0,0 +1,11 @@
@import '../../node_modules/materialize-css/sass/components/color-variables';
@import 'variables.scss';
@import '../../node_modules/materialize-css/sass/materialize.scss';
@import '../common/index.scss';
.progress.travel-progress {
background-color: color('purple', 'lighten-4');
& > .determinate {
background-color: color('purple', 'darken-3');
}
}

47
sass/webpack.config.js Normal file
View file

@ -0,0 +1,47 @@
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');
console.log(path.resolve('../public/static/css/'));
module.exports = {
mode: 'production',
entry: {
light: './src/light/index.scss',
dark: './src/dark/index.scss',
},
output: {
path: path.resolve('../public/static/css/'),
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].min.css',
chunkFilename: '[id].css',
}),
],
module: {
rules: [
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 2,
},
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: loader => [
require('postcss-preset-env')(),
require('cssnano')(),
],
},
},
'sass-loader',
],
},
],
},
};

View file

@ -1,4 +1,4 @@
<div class="card yellow lighten-4">
<div class="card info-color">
<div class="card-content">
<span class="card-title">Zugausfall dokumentieren</span>
<p>Prinzipiell wärest du nun eingecheckt in

View file

@ -1,4 +1,4 @@
<div class="card autorefresh blue-grey lighten-5">
<div class="card autorefresh">
<div class="card-content">
<i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
<span class="card-title">Eingecheckt in <%= $journey->{train_type} %> <%= $journey->{train_no} %></span>
@ -31,8 +31,8 @@
Ankunft in mehr als zwei Stunden
% }
</div>
<div class="progress purple lighten-4" style="height: 1ex;">
<div class="determinate purple darken-3" style="width: <%= sprintf('%.2f', 100 * ($journey->{journey_completion} // 0)); %>%;"></div>
<div class="progress " style="height: 1ex;">
<div class="determinate" style="width: <%= sprintf('%.2f', 100 * ($journey->{journey_completion} // 0)); %>%;"></div>
</div>
</p>
% if ($journey->{arr_name}) {

View file

@ -1,5 +1,5 @@
<div class="card grey darken-4">
<div class="card-content white-text">
<div class="card">
<div class="card-content">
<span class="card-title">Ausgecheckt</span>
<p>Aus <%= $journey->{train_type} %> <%= $journey->{train_no} %>
bis <a href="/s/<%= $journey->{arr_ds100} %>"><%= $journey->{arr_name} %></a></p>

View file

@ -1,6 +1,6 @@
<div class="row">
<div class="col s12">
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
<span class="card-title">Account wird gelöscht</span>
<p>

View file

@ -1,7 +1,7 @@
% if (@{$stats->{inconsistencies}}) {
<div class="row">
<div class="col s12">
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
<i class="material-icons small right">warning</i>
<span class="card-title">Inkonsistente Reisedaten</span>

View file

@ -1,6 +1,6 @@
<div class="row">
<div class="col s12">
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
% if ($invalid eq 'csrf') {
<span class="card-title">Ungültiger CSRF-Token</span>

View file

@ -1,5 +1,5 @@
% if ($journey->{checked_in}) {
<div class="card white autorefresh">
<div class="card autorefresh">
<div class="card-content">
<i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
<span class="card-title"><%= $name %> ist unterwegs</span>
@ -80,8 +80,8 @@
</div>
% }
% else {
<div class="card grey darken-4 autorefresh">
<div class="card-content white-text">
<div class="card autorefresh">
<div class="card-content">
<i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
<span class="card-title"><%= $name %> ist gerade nicht eingecheckt</span>
<p>

View file

@ -5,7 +5,7 @@
% if (my $success = flash('success')) {
<div class="row">
<div class="col s12">
<div class="card green darken-4">
<div class="card success-color">
<div class="card-content white-text">
% if ($success eq 'mail') {
<span class="card-title">Mail-Adresse geändert</span>
@ -119,7 +119,7 @@
<button class="btn waves-effect waves-light" type="submit" name="action" value="generate">
Generieren
</button>
<button class="btn waves-effect waves-light red" type="submit" name="action" value="delete">
<button class="btn waves-effect waves-light caution-color" type="submit" name="action" value="delete">
Löschen
</button>
%= end
@ -213,7 +213,7 @@
</div>
<div class="input-field col s12 m12 l4 center-align">
%= csrf_field
<button class="btn waves-effect waves-light red" type="submit" name="action" value="delete">
<button class="btn waves-effect waves-light caution-color" type="submit" name="action" value="delete">
Account löschen
</button>
</div>

View file

@ -2,7 +2,7 @@
% if (not get_oldest_journey_ts()) {
<div class="row">
<div class="col s12">
<div class="card yellow lighten-4">
<div class="card info-color">
<div class="card-content">
<span class="card-title">Hinweis</span>
<p>travelynx ist darauf ausgelegt, über die Hauptseite in
@ -16,7 +16,7 @@
% if ($error) {
<div class="row">
<div class="col s12">
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
<span class="card-title">Ungültige Eingabe</span>
<p><%= $error %></p>

View file

@ -5,7 +5,7 @@
% if (stash('success')) {
<div class="row">
<div class="col s12">
<div class="card green darken-4">
<div class="card success-color">
<div class="card-content white-text">
<span class="card-title">Mail-Änderung wird durchgeführt</span>
<p>

View file

@ -2,8 +2,8 @@
<div class="col s12">
% my $status = $self->get_user_status;
% if ($status->{checked_in}) {
<div class="card grey darken-4">
<div class="card-content white-text">
<div class="card">
<div class="card-content">
<span class="card-title">Aktuell eingecheckt</span>
<p>In <%= $status->{train_type} %> <%= $status->{train_no} %>
ab <%= $status->{dep_name} %></p>

View file

@ -2,7 +2,7 @@
% if ($error and $error eq 'notfound') {
<div class="row">
<div class="col s12">
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
<span class="card-title">Fehler</span>
<p>Zugfahrt nicht gefunden.</p>
@ -15,7 +15,7 @@
% if ($error) {
<div class="row">
<div class="col s12">
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
<span class="card-title">Ungültige Eingabe</span>
<p><%= $error %></p>

View file

@ -1,6 +1,6 @@
<div class="row">
<div class="col s12">
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
<span class="card-title">500 Internal Server Error</span>
<p>Das hätte nicht passieren sollen.</p>

View file

@ -1,7 +1,7 @@
% if ($error) {
<div class="row">
<div class="col s12">
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
<span class="card-title">Fehler</span>
<p>Zugfahrt nicht gefunden.</p>

View file

@ -2,7 +2,7 @@
% if (stash('error')) {
<div class="row">
<div class="col s12">
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
<span class="card-title">Backend-Fehler</span>
<p><%= stash('error') %></p>
@ -18,7 +18,7 @@
%= include '_checked_in', journey => $status;
% }
% elsif ($status->{cancelled}) {
<div class="card yellow lighten-4">
<div class="card info-color">
<div class="card-content">
<span class="card-title">Zugausfall dokumentieren</span>
<p>Prinzipiell wärest du nun eingecheckt in
@ -47,20 +47,20 @@
</div>
% }
% else {
<div class="card grey darken-4">
<div class="card-content white-text">
<div class="card">
<div class="card-content">
<span class="card-title">Hallo, <%= current_user()->{name} %>!</span>
<p>Du bist gerade nicht eingecheckt.</p>
<div class="geolocation">
<button class="btn waves-effect waves-light btn-flat white">Stationen in der Umgebung abfragen</button>
<button class="btn waves-effect waves-light btn-flat">Stationen in der Umgebung abfragen</button>
</div>
%= form_for 'list_departures' => begin
<div class="input-field">
%= text_field 'station', id => 'station', class => 'autocomplete white-text', required => undef
%= text_field 'station', id => 'station', class => 'autocomplete contrast-color-text', required => undef
<label for="station">Manuelle Eingabe (Name oder DS100)</label>
</div>
<div class="center-align">
<button class="btn waves-effect waves-light btn-flat white" type="submit" name="action" value="departures">
<button class="btn waves-effect waves-light btn-flat" type="submit" name="action" value="departures">
<i class="material-icons left">send</i>
Abfahrten
</button>

View file

@ -9,7 +9,7 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="Travelynx">
% my $av = 'v20'; # asset version
% my $av = 'v21'; # asset version
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-16x16.png" sizes="16x16">
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-96x96.png" sizes="96x96">
@ -18,7 +18,37 @@
<link rel="apple-touch-icon" sizes="152x152" href="/static/<%= $av %>/icons/icon-152x152.png">
<link rel="apple-touch-icon" sizes="167x167" href="/static/<%= $av %>/icons/icon-167x167.png">
<link rel="manifest" href="/static/<%= $av %>/manifest.json">
%= stylesheet "/static/${av}/css/materialize.min.css"
% if (session('theme') and session('theme') eq 'dark') {
%= stylesheet "/static/${av}/css/dark.min.css", id => 'theme'
% }
% else {
%= stylesheet "/static/${av}/css/light.min.css", id => 'theme'
% }
<script>
function addStyleSheet(name, id) {
var path = '/static/<%=$av%>/css/' + name + '.min.css';
var old = document.getElementById(id);
if (old && (old.href != path)) {
old.href = path;
document.cookie = 'theme=' + name;
}
}
var otherTheme = {
'dark': 'light',
'light': 'dark',
};
var currentTheme = localStorage.getItem('theme');
if (!otherTheme.hasOwnProperty(currentTheme)) {
currentTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
addStyleSheet(currentTheme, 'theme');
function toggleTheme() {
currentTheme = otherTheme[currentTheme] || 'light';
localStorage.setItem('theme', currentTheme);
addStyleSheet(currentTheme, 'theme');
}
</script>
%= stylesheet "/static/${av}/css/material-icons.css"
%= stylesheet "/static/${av}/css/local.css"
%= javascript "/static/${av}/js/jquery-3.4.1.min.js"
@ -51,6 +81,9 @@
</div>
</div>
</li>
<li class="waves-effect waves-light">
<a onClick="javascript:toggleTheme()"><i class="material-icons">invert_colors</i></a>
</li>
% if (is_user_authenticated()) {
<li class="<%= navbar_class('/history') %>"><a href='/history' title="History"><i class="material-icons">history</i></a></li>
<li class="<%= navbar_class('/account') %>"><a href="/account" title="Account"><i class="material-icons">account_circle</i></a></li>
@ -66,7 +99,7 @@
% if (app->mode eq 'development') {
<div class="container">
<div class="row">
<div class="col s12 red darken-4 white-text">
<div class="col s12 caution-color white-text">
Development Mode Datenbank: <%= app->config->{db}->{database} %>
@ <%= app->config->{db}->{host} %>
</div>
@ -87,10 +120,7 @@
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js')
.then((reg) => {
console.log('Service worker registered.', reg);
});
navigator.serviceWorker.register('/service-worker.js');
});
}
</script>

View file

@ -1,8 +1,8 @@
% if (my $user = current_user()) {
<div class="row">
<div class="col s12">
<div class="card grey darken-4">
<div class="card-content white-text">
<div class="card">
<div class="card-content">
<span class="card-title">Hallo, <%= $user->{name} %>!</span>
<p>
Du bist bereits angemeldet. Falls du mehrere Accounts hast
@ -27,8 +27,8 @@
<div class="row">
<div class="col s12">
% if ($from eq 'register') {
<div class="card grey darken-4">
<div class="card-content white-text">
<div class="card">
<div class="card-content">
<span class="card-title">Bitte warten</span>
<p>Ein Verifizierungslink wurde an die von dir angegebene
Mail-Adresse geschickt. Sobald du diesen angeklickt hast,
@ -37,7 +37,7 @@
</div>
% }
% elsif ($from eq 'verification') {
<div class="card green darken-4">
<div class="card success-color">
<div class="card-content white-text">
<span class="card-title">Account freigeschaltet</span>
<p>Du kannst dich nun anmelden.</p>

View file

@ -1,6 +1,6 @@
<div class="row">
<div class="col s12">
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
<span class="card-title">404 Not Found</span>
<p>Diese Seite gibt es hier nicht.</p>

View file

@ -14,7 +14,7 @@
<div class="input-field col s12">
<label>
%= check_box public_status => 1
<span class="black-text">Aktueller Status</span>
<span>Aktueller Status</span>
</label>
</div>
</div>

View file

@ -5,7 +5,7 @@
% if (stash('success')) {
<div class="row">
<div class="col s12">
<div class="card green darken-4">
<div class="card success-color">
<div class="card-content white-text">
<span class="card-title">Passwort-Reset wird durchgeführt</span>
<p>

View file

@ -8,7 +8,7 @@
<div class="row">
<div class="col s12">
% if ($hook->{errored}) {
<div class="card red darken-4">
<div class="card caution-color">
<div class="card-content white-text">
<span class="card-title">Web-Hook fehlerhaft</span>
<p><%= $hook->{output} %></p>
@ -16,7 +16,7 @@
</div>
% }
% else {
<div class="card green darken-4">
<div class="card success-color">
<div class="card-content white-text">
<span class="card-title">Web-Hook erfolgreich getestet</span>
<p><%= $hook->{output} %></p>