Migrate to Bootstrap 5, improve notifications, add supporter confetti (#954)
This commit is contained in:
parent
4eefe8f576
commit
380cd461b9
39 changed files with 2354 additions and 1994 deletions
|
|
@ -1,4 +1,4 @@
|
|||
module.exports = {
|
||||
stories: ["../assets/js/**/*.stories.mdx", "../assets/js/**/*.stories.@(js|jsx|ts|tsx)"],
|
||||
addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
|
||||
addons: ["@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-postcss"],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,2 +1,4 @@
|
|||
<link href="/css/bootstrap.min.css" rel="stylesheet" />
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
|
||||
<link href="/css/app.css" rel="stylesheet" />
|
||||
|
|
|
|||
|
|
@ -31,6 +31,5 @@
|
|||
</script>
|
||||
|
||||
<div id="app"></div>
|
||||
<div id="toasts"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import "../css/app.css";
|
||||
import "bootstrap/dist/css/bootstrap.min.css";
|
||||
import "popper.js";
|
||||
import "bootstrap";
|
||||
import Vue from "vue";
|
||||
import axios from "axios";
|
||||
import App from "./views/App";
|
||||
import Toasts from "./components/Toasts";
|
||||
import router from "./router";
|
||||
import store from "./store";
|
||||
|
||||
|
|
@ -14,29 +12,21 @@ axios.defaults.baseURL =
|
|||
loc.protocol + "//" + loc.hostname + (loc.port ? ":" + loc.port : "") + loc.pathname + "api";
|
||||
axios.defaults.headers.post["Content-Type"] = "application/json";
|
||||
|
||||
window.toasts = new Vue({
|
||||
el: "#toasts",
|
||||
window.app = new Vue({
|
||||
el: "#app",
|
||||
router,
|
||||
data: { store, notifications: [] },
|
||||
render: function (h) {
|
||||
return h(Toasts, { props: { items: this.items, count: this.count } });
|
||||
return h(App, { props: { notifications: this.notifications } });
|
||||
},
|
||||
data: {
|
||||
items: {},
|
||||
count: 0,
|
||||
},
|
||||
name: "ToastsRoot",
|
||||
methods: {
|
||||
raise: function (msg) {
|
||||
let found = false;
|
||||
Object.keys(this.items).forEach(function (k) {
|
||||
let m = this.items[k];
|
||||
if (m.type == msg.type && m.message == msg.message) {
|
||||
found = true;
|
||||
}
|
||||
}, this);
|
||||
if (!found) {
|
||||
msg.id = this.count++;
|
||||
Vue.set(this.items, msg.id, msg);
|
||||
}
|
||||
console[msg.type](msg);
|
||||
const withoutThisMsg = this.notifications.filter((m) => m.message !== msg.message);
|
||||
this.notifications = [msg, ...withoutThisMsg];
|
||||
},
|
||||
clear: function () {
|
||||
this.notifications = [];
|
||||
},
|
||||
error: function (msg) {
|
||||
msg.type = "error";
|
||||
|
|
@ -46,22 +36,11 @@ window.toasts = new Vue({
|
|||
msg.type = "warn";
|
||||
this.raise(msg);
|
||||
},
|
||||
remove: function (msg) {
|
||||
Vue.delete(this.items, msg.id);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
router,
|
||||
data: { store },
|
||||
render: (h) => h(App),
|
||||
});
|
||||
|
||||
window.setInterval(function () {
|
||||
axios.get("health").catch(function (res) {
|
||||
res.message = "Server unavailable";
|
||||
window.toasts.error(res);
|
||||
axios.get("health").catch(function () {
|
||||
window.app.error({ message: "Server unavailable" });
|
||||
});
|
||||
}, 5000);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export const KeinUpdate = Template.bind({});
|
|||
KeinUpdate.args = {
|
||||
version: { installed: "0.40" },
|
||||
};
|
||||
|
||||
export const UpdateVerfuegbar = Template.bind({});
|
||||
UpdateVerfuegbar.args = {
|
||||
version: {
|
||||
|
|
@ -25,6 +26,15 @@ UpdateVerfuegbar.args = {
|
|||
},
|
||||
};
|
||||
|
||||
export const Sponsor = Template.bind({});
|
||||
Sponsor.args = {
|
||||
version: {
|
||||
installed: "0.36",
|
||||
available: "0.40",
|
||||
},
|
||||
sponsor: "naltatis",
|
||||
};
|
||||
|
||||
export const Updater = Template.bind({});
|
||||
Updater.args = {
|
||||
version: {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,10 @@
|
|||
<template>
|
||||
<footer class="py-3 py-md-5 mt-3 mt-md-5 border-top">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<Version v-bind="version" />
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<small class="text-black">
|
||||
<a href="https://github.com/sponsors/andig" target="_blank" class="link">
|
||||
<fa-icon icon="heart" class="icon mr-1"></fa-icon
|
||||
><span class="d-none d-sm-inline">Projekt </span>unterstützen
|
||||
</a>
|
||||
</small>
|
||||
</div>
|
||||
<footer class="container">
|
||||
<div class="py-3 py-md-5 mt-3 mt-md-5 border-top">
|
||||
<div class="d-flex justify-content-between">
|
||||
<Version v-bind="version" />
|
||||
<!-- Please don't mess with the sponsor status. You risk loosing your mojo. -->
|
||||
<Sponsor :sponsor="sponsor" />
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
|
@ -20,21 +12,14 @@
|
|||
|
||||
<script>
|
||||
import Version from "./Version";
|
||||
import Sponsor from "./Sponsor";
|
||||
|
||||
export default {
|
||||
name: "Footer",
|
||||
components: { Version },
|
||||
components: { Version, Sponsor },
|
||||
props: {
|
||||
version: Object,
|
||||
sponsor: String,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.icon {
|
||||
color: #0fdd42;
|
||||
}
|
||||
.text-black a {
|
||||
color: #18191a;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export default {
|
|||
chargeCurrent: Number,
|
||||
socCapacity: Number,
|
||||
connectedDuration: Number,
|
||||
chargeCurrents: Object,
|
||||
chargeCurrents: Array,
|
||||
chargeConfigured: Boolean,
|
||||
chargeRemainingEnergy: Number,
|
||||
},
|
||||
|
|
@ -119,7 +119,7 @@ export default {
|
|||
this.mode = response.data.mode;
|
||||
}.bind(this)
|
||||
)
|
||||
.catch(window.toasts.error);
|
||||
.catch(window.app.error);
|
||||
},
|
||||
setTargetSoC: function (soc) {
|
||||
axios
|
||||
|
|
@ -130,7 +130,7 @@ export default {
|
|||
this.targetSoC = response.data.targetSoC;
|
||||
}.bind(this)
|
||||
)
|
||||
.catch(window.toasts.error);
|
||||
.catch(window.app.error);
|
||||
},
|
||||
},
|
||||
destroyed: function () {
|
||||
|
|
|
|||
|
|
@ -5,17 +5,17 @@
|
|||
<div class="mb-2 value">
|
||||
Leistung
|
||||
<fa-icon
|
||||
class="text-primary ml-1"
|
||||
class="text-primary ms-1"
|
||||
icon="temperature-low"
|
||||
v-if="climater == 'heating'"
|
||||
></fa-icon>
|
||||
<fa-icon
|
||||
class="text-primary ml-1"
|
||||
class="text-primary ms-1"
|
||||
icon="temperature-high"
|
||||
v-if="climater == 'cooling'"
|
||||
></fa-icon>
|
||||
<fa-icon
|
||||
class="text-primary ml-1"
|
||||
class="text-primary ms-1"
|
||||
icon="thermometer-half"
|
||||
v-if="climater == 'on'"
|
||||
></fa-icon>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,50 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="mb-3">Modus</div>
|
||||
<div class="btn-group btn-group-toggle bg-white shadow-none w-100">
|
||||
<label class="btn btn-outline-primary first" :class="{ active: mode == 'off' }">
|
||||
<input type="radio" value="off" @click="setTargetMode('off')" />Stop
|
||||
</label>
|
||||
<label class="btn btn-outline-primary" :class="{ active: mode == 'now' }">
|
||||
<input type="radio" value="now" @click="setTargetMode('now')" />Sofort
|
||||
</label>
|
||||
<label class="btn btn-outline-primary" :class="{ active: mode == 'minpv' }">
|
||||
<input type="radio" value="minpv" @click="setTargetMode('minpv')" />
|
||||
<div class="btn-group w-100" role="group">
|
||||
<input
|
||||
id="mode_off"
|
||||
type="radio"
|
||||
name="mode"
|
||||
class="btn-check"
|
||||
value="off"
|
||||
@click="setTargetMode('off')"
|
||||
:checked="mode == 'off'"
|
||||
/>
|
||||
<label for="mode_off" class="btn btn-outline-primary"> Stop </label>
|
||||
<input
|
||||
id="mode_now"
|
||||
type="radio"
|
||||
name="mode"
|
||||
class="btn-check"
|
||||
value="now"
|
||||
@click="setTargetMode('now')"
|
||||
:checked="mode == 'now'"
|
||||
/>
|
||||
<label for="mode_now" class="btn btn-outline-primary"> Sofort </label>
|
||||
<input
|
||||
id="mode_minpv"
|
||||
type="radio"
|
||||
name="mode"
|
||||
class="btn-check"
|
||||
value="minpv"
|
||||
@click="setTargetMode('minpv')"
|
||||
:checked="mode == 'minpv'"
|
||||
/>
|
||||
<label for="mode_minpv" class="btn btn-outline-primary">
|
||||
<span class="d-inline d-sm-none">Min</span>
|
||||
<span class="d-none d-sm-inline">Min + PV</span>
|
||||
</label>
|
||||
<label class="btn btn-outline-primary" :class="{ active: mode == 'pv' }">
|
||||
<input type="radio" value="pv" @click="setTargetMode('pv')" />
|
||||
<input
|
||||
id="mode_pv"
|
||||
type="radio"
|
||||
name="mode"
|
||||
class="btn-check"
|
||||
value="pv"
|
||||
@click="setTargetMode('pv')"
|
||||
:checked="mode == 'pv'"
|
||||
/>
|
||||
<label for="mode_pv" class="btn btn-outline-primary">
|
||||
<span class="d-inline d-sm-none">PV</span>
|
||||
<span class="d-none d-sm-inline">Nur PV</span>
|
||||
</label>
|
||||
|
|
|
|||
32
assets/js/components/Notifications.stories.js
Normal file
32
assets/js/components/Notifications.stories.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import Notifications from "./Notifications.vue";
|
||||
|
||||
export default {
|
||||
title: "Main/Notifications",
|
||||
component: Notifications,
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
const Template = (args, { argTypes }) => ({
|
||||
props: Object.keys(argTypes),
|
||||
components: { Notifications },
|
||||
template: '<Notifications v-bind="$props"></Notifications>',
|
||||
});
|
||||
|
||||
export const Base = Template.bind({});
|
||||
Base.args = {
|
||||
notifications: [
|
||||
{
|
||||
message: "Server unavailable",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
message: "charger out of sync: expected disabled, got enabled",
|
||||
type: "warn",
|
||||
},
|
||||
{
|
||||
message:
|
||||
"Amet irure quis incididunt voluptate esse. Commodo ea sunt est ipsum tempor nisi laboris voluptate labore elit laborum. Ex irure commodo reprehenderit consequat consequat do ad tempor aliquip deserunt eu. Laboris minim nostrud quis nisi. Dolor occaecat reprehenderit velit dolore exercitation cupidatat et voluptate. Nulla pariatur deserunt esse minim nisi nisi nulla. Sit eiusmod do incididunt sint minim pariatur aute.",
|
||||
type: "warn",
|
||||
},
|
||||
],
|
||||
};
|
||||
91
assets/js/components/Notifications.vue
Normal file
91
assets/js/components/Notifications.vue
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<template>
|
||||
<div>
|
||||
<button
|
||||
v-show="iconVisible"
|
||||
href="#"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#notificationModal"
|
||||
class="btn btn-link text-decoration-none link-light text-nowrap"
|
||||
>
|
||||
<fa-icon :class="iconClass" icon="exclamation-triangle"></fa-icon>
|
||||
</button>
|
||||
|
||||
<div
|
||||
id="notificationModal"
|
||||
class="modal fade"
|
||||
tabindex="-1"
|
||||
role="dialog"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Meldungen</h5>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p
|
||||
v-for="(notification, index) in notifications"
|
||||
:key="index"
|
||||
class="d-flex align-items-baseline"
|
||||
>
|
||||
<fa-icon
|
||||
:class="{
|
||||
'text-danger': notification.type === 'error',
|
||||
'text-warning': notification.type === 'warn',
|
||||
}"
|
||||
class="flex-grow-0 d-block"
|
||||
icon="exclamation-triangle"
|
||||
></fa-icon>
|
||||
<span class="flex-grow-1 px-2 py-1">{{ notification.message }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
@click="clear"
|
||||
class="btn btn-outline-secondary"
|
||||
>
|
||||
Meldungen entfernen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import "../icons";
|
||||
import formatter from "../mixins/formatter";
|
||||
|
||||
export default {
|
||||
name: "Notifications",
|
||||
props: {
|
||||
notifications: Array,
|
||||
},
|
||||
computed: {
|
||||
iconVisible: function () {
|
||||
return this.notifications.length > 0;
|
||||
},
|
||||
iconClass: function () {
|
||||
return this.notifications.find((m) => m.type === "error")
|
||||
? "text-danger"
|
||||
: "text-warning";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clear: function () {
|
||||
window.app.clear();
|
||||
},
|
||||
},
|
||||
mixins: [formatter],
|
||||
};
|
||||
</script>
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
<template v-for="(loadpoint, id) in loadpoints">
|
||||
<hr class="w-100 my-4" v-if="id > 0" :key="id + '_hr'" />
|
||||
<Loadpoint
|
||||
:key="loadpoint"
|
||||
:key="id"
|
||||
v-bind="loadpoint"
|
||||
:single="loadpoints.length === 1"
|
||||
:id="id"
|
||||
|
|
@ -43,7 +43,7 @@ export default {
|
|||
batteryConfigured: Boolean,
|
||||
batteryPower: Number,
|
||||
batterySoC: Number,
|
||||
gridCurrents: Object,
|
||||
gridCurrents: Array,
|
||||
prioritySoC: Number,
|
||||
},
|
||||
components: { SiteDetails, Loadpoint },
|
||||
|
|
|
|||
23
assets/js/components/Sponsor.stories.js
Normal file
23
assets/js/components/Sponsor.stories.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import Sponsor from "./Sponsor.vue";
|
||||
|
||||
export default {
|
||||
title: "Main/Footer/Sponsor",
|
||||
component: Sponsor,
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
const Template = (args, { argTypes }) => ({
|
||||
props: Object.keys(argTypes),
|
||||
components: { Sponsor },
|
||||
template: '<Sponsor v-bind="$props"></Sponsor>',
|
||||
});
|
||||
|
||||
export const Standard = Template.bind({});
|
||||
Standard.args = {
|
||||
sponsor: undefined,
|
||||
};
|
||||
|
||||
export const IsSponsor = Template.bind({});
|
||||
IsSponsor.args = {
|
||||
sponsor: "naltatis",
|
||||
};
|
||||
83
assets/js/components/Sponsor.vue
Normal file
83
assets/js/components/Sponsor.vue
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<template>
|
||||
<div
|
||||
ref="sponsor"
|
||||
v-if="sponsor"
|
||||
class="btn btn-link pe-0 text-decoration-none link-dark text-nowrap sponsor-button"
|
||||
@click.stop.prevent="surprise"
|
||||
>
|
||||
Danke<span class="d-none d-sm-inline"> {{ sponsor }}</span>
|
||||
<fa-icon :icon="['fas', 'heart']" class="icon ms-1"></fa-icon>
|
||||
</div>
|
||||
<a
|
||||
v-else
|
||||
href="https://github.com/sponsors/andig"
|
||||
target="_blank"
|
||||
class="btn btn-link pe-0 text-decoration-none link-dark text-nowrap support-button"
|
||||
>
|
||||
<span class="d-none d-sm-inline">Projekt </span>unterstützen
|
||||
<fa-icon :icon="['far', 'heart']" class="icon ms-1 outline"></fa-icon>
|
||||
<fa-icon :icon="['fas', 'heart']" class="icon ms-1 solid"></fa-icon>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import confetti from "canvas-confetti";
|
||||
|
||||
export default {
|
||||
name: "sponsor",
|
||||
props: {
|
||||
sponsor: String,
|
||||
},
|
||||
methods: {
|
||||
surprise: function () {
|
||||
console.log(this.$refs.sponsor);
|
||||
const { top, height, left, width } = this.$refs.sponsor.getBoundingClientRect();
|
||||
const x = (left + width / 2) / window.innerWidth;
|
||||
const y = (top + height / 2) / window.innerHeight;
|
||||
const origin = { x, y };
|
||||
|
||||
confetti({
|
||||
origin,
|
||||
angle: 90 + Math.random() * 35,
|
||||
particleCount: 75 + Math.random() * 50,
|
||||
spread: 50 + Math.random() * 50,
|
||||
drift: -0.5,
|
||||
scalar: 1.3,
|
||||
colors: [
|
||||
"#0d6efd",
|
||||
"#0fdd42",
|
||||
"#408458",
|
||||
"#4923BA",
|
||||
"#5BC8EC",
|
||||
"#C54482",
|
||||
"#CC444A",
|
||||
"#EE8437",
|
||||
"#F7C144",
|
||||
"#FFFD54",
|
||||
],
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.icon {
|
||||
color: #0fdd42;
|
||||
display: inline-block;
|
||||
}
|
||||
.sponsor-button {
|
||||
/* prevent double-tap zoom */
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
}
|
||||
.support-button .solid {
|
||||
display: none;
|
||||
}
|
||||
.support-button:hover .solid {
|
||||
display: inline-block;
|
||||
}
|
||||
.support-button:hover .outline {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<template>
|
||||
<div class="toast" data-delay="10000" :data-autohide="true">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto" v-if="item.type != 'warn'"
|
||||
><fa-icon class="text-danger" icon="exclamation-triangle"></fa-icon> Error</strong
|
||||
>
|
||||
<strong class="mr-auto" v-if="item.type == 'warn'"
|
||||
><fa-icon class="text-warning" icon="exclamation-triangle"></fa-icon>
|
||||
Warning</strong
|
||||
>
|
||||
<small v-if="item.status">HTTP {{ item.status }}</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">{{ item.message }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import "../icons";
|
||||
import $ from "jquery";
|
||||
|
||||
export default {
|
||||
name: "ToastMessage",
|
||||
props: ["item"],
|
||||
mounted: function () {
|
||||
const id = "#message-id-" + this.item.id;
|
||||
$(id).toast("show");
|
||||
$(id).on(
|
||||
"hidden.bs.toast",
|
||||
function () {
|
||||
window.toasts.remove(this.item);
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import Toasts from "./Toasts.vue";
|
||||
|
||||
export default {
|
||||
title: "Main/Toasts",
|
||||
component: Toasts,
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
const Template = (args, { argTypes }) => ({
|
||||
props: Object.keys(argTypes),
|
||||
components: { Toasts },
|
||||
template: '<Toasts v-bind="$props"></Toasts>',
|
||||
});
|
||||
|
||||
export const Base = Template.bind({});
|
||||
Base.args = {
|
||||
items: {
|
||||
id: 1,
|
||||
message: "Evil warning",
|
||||
type: "warn",
|
||||
},
|
||||
};
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
<template>
|
||||
<div aria-atomic="true" style="position: absolute; top: 4rem; right: 0.5rem">
|
||||
<!-- Position it -->
|
||||
<ToastMessage
|
||||
v-for="item in items"
|
||||
:item="item"
|
||||
:id="'message-id-' + item.id"
|
||||
:key="item.id"
|
||||
>
|
||||
</ToastMessage>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import "../icons";
|
||||
import ToastMessage from "./ToastMessage";
|
||||
|
||||
export default {
|
||||
name: "Toasts",
|
||||
components: { ToastMessage },
|
||||
props: {
|
||||
items: Object,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
></div>
|
||||
</div>
|
||||
<div
|
||||
v-if="hasVehicle && visibleTargetSoC"
|
||||
v-if="connected && hasVehicle && visibleTargetSoC"
|
||||
class="target"
|
||||
:class="{ 'target--max': visibleTargetSoC === 100 }"
|
||||
>
|
||||
|
|
@ -161,7 +161,7 @@ export default {
|
|||
color: var(--white);
|
||||
}
|
||||
.bg-light {
|
||||
color: var(--dark);
|
||||
color: var(--bs-gray-dark);
|
||||
}
|
||||
.target-label {
|
||||
width: 3em;
|
||||
|
|
@ -170,7 +170,7 @@ export default {
|
|||
position: absolute;
|
||||
top: calc((var(--label-height) + var(--thumb-overlap)) * -1);
|
||||
text-align: center;
|
||||
color: var(--dark);
|
||||
color: var(--bs-gray-dark);
|
||||
font-size: 1rem;
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease 1s;
|
||||
|
|
@ -189,6 +189,7 @@ export default {
|
|||
}
|
||||
/* Note: Safari,Chrome,Blink and Firefox specific styles need to be in separate definitions to work */
|
||||
.target-slider::-webkit-slider-runnable-track {
|
||||
position: relative;
|
||||
background: transparent;
|
||||
border: none;
|
||||
height: 100%;
|
||||
|
|
@ -209,7 +210,7 @@ export default {
|
|||
padding: var(--label-height) var(--thumb-horizontal-padding) 0;
|
||||
box-sizing: content-box;
|
||||
background-clip: content-box;
|
||||
background-color: var(--dark);
|
||||
background-color: var(--bs-gray-dark);
|
||||
cursor: grab;
|
||||
border: none;
|
||||
opacity: 1;
|
||||
|
|
@ -220,10 +221,10 @@ export default {
|
|||
top: calc(var(--label-height) * -1);
|
||||
height: 100%;
|
||||
width: var(--thumb-width);
|
||||
padding: 0 var(--thumb-horizontal-padding);
|
||||
padding: var(--label-height) var(--thumb-horizontal-padding) 0;
|
||||
box-sizing: content-box;
|
||||
background-clip: content-box;
|
||||
background-color: var(--dark);
|
||||
background-color: var(--bs-gray-dark);
|
||||
cursor: grab;
|
||||
border: none;
|
||||
opacity: 1;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<div class="d-flex justify-content-between align-items-center">
|
||||
<small class="text-secondary">
|
||||
<span v-if="minSoCActive">
|
||||
<fa-icon class="text-muted mr-1" icon="exclamation-circle"></fa-icon>
|
||||
<fa-icon class="text-muted me-1" icon="exclamation-circle"></fa-icon>
|
||||
Mindestladung bis {{ minSoC }}%
|
||||
</span>
|
||||
</small>
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
}"
|
||||
>
|
||||
{{ targetTimeLabel() }}
|
||||
<fa-icon class="ml-1" icon="clock"></fa-icon>
|
||||
<fa-icon class="ms-1" icon="clock"></fa-icon>
|
||||
</small>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Version from "./Version.vue";
|
||||
|
||||
export default {
|
||||
title: "Main/Version",
|
||||
title: "Main/Footer/Version",
|
||||
component: Version,
|
||||
argTypes: {},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,102 +1,96 @@
|
|||
<template>
|
||||
<div>
|
||||
<small class="text-black">
|
||||
<a href="#" @click.prevent="showModal" v-if="newVersionAvailable">
|
||||
<fa-icon icon="gift" class="icon mr-1"></fa-icon>Update<span
|
||||
class="d-none d-sm-inline"
|
||||
>
|
||||
verfügbar</span
|
||||
>:
|
||||
{{ available }}
|
||||
</a>
|
||||
<a :href="releaseNotesUrl(installed)" target="_blank" v-else>
|
||||
Version {{ installed }}
|
||||
</a>
|
||||
</small>
|
||||
<button
|
||||
href="#"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#updateModal"
|
||||
v-if="newVersionAvailable"
|
||||
class="btn btn-link ps-0 text-decoration-none link-dark text-nowrap"
|
||||
>
|
||||
<fa-icon icon="gift" class="icon me-1"></fa-icon>
|
||||
Update<span class="d-none d-sm-inline"> verfügbar</span>: {{ available }}
|
||||
</button>
|
||||
<a
|
||||
:href="releaseNotesUrl(installed)"
|
||||
target="_blank"
|
||||
class="btn btn-link ps-0 text-decoration-none link-dark text-nowrap"
|
||||
v-else
|
||||
>
|
||||
Version {{ installed }}
|
||||
</a>
|
||||
|
||||
<transition name="fade">
|
||||
<div id="updateModal" class="dialog" tabindex="-1" role="dialog" v-if="modalActive">
|
||||
<div
|
||||
class="modal-dialog modal-dialog-centered modal-dialog-scrollable"
|
||||
role="document"
|
||||
>
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title font-weight-bold">Update verfügbar</h4>
|
||||
<div id="updateModal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Update verfügbar</h5>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div v-if="updateStarted">
|
||||
<p>Nach der Aktualisierung wird evcc neu gestartet.</p>
|
||||
<div class="progress my-3">
|
||||
<div
|
||||
class="progress-bar progress-bar-striped progress-bar-animated"
|
||||
role="progressbar"
|
||||
:style="{ width: uploadProgress + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<p>{{ updateStatus }}{{ uploadMessage }}</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>
|
||||
<small>Aktuell installierte Version: {{ installed }}</small>
|
||||
</p>
|
||||
<div v-if="releaseNotes" v-html="releaseNotes"></div>
|
||||
<p v-else>
|
||||
Keine Releasenotes verfügbar. Mehr Informationen zur neuen Version
|
||||
findest du
|
||||
<a :href="releaseNotesUrl(available)">hier</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer d-flex justify-content-between">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
:disabled="updateStarted"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Abbrechen
|
||||
</button>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
class="btn btn-primary"
|
||||
v-if="hasUpdater"
|
||||
:disabled="updateStarted"
|
||||
@click="closeModal"
|
||||
@click="update"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div v-if="updateStarted">
|
||||
<p>Nach der Aktualisierung wird evcc neu gestartet.</p>
|
||||
<div class="progress my-3">
|
||||
<div
|
||||
class="progress-bar progress-bar-striped progress-bar-animated"
|
||||
role="progressbar"
|
||||
:style="{ width: uploadProgress + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<p>{{ updateStatus }}{{ uploadMessage }}</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>
|
||||
<small>Aktuell installierte Version: {{ installed }}</small>
|
||||
</p>
|
||||
<div v-if="releaseNotes" v-html="releaseNotes"></div>
|
||||
<p v-else>
|
||||
Keine Releasenotes verfügbar. Mehr Informationen zur neuen
|
||||
Version findest du
|
||||
<a :href="releaseNotesUrl(available)">hier</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer d-flex justify-content-between">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
:disabled="updateStarted"
|
||||
@click="closeModal"
|
||||
>
|
||||
Abbrechen
|
||||
</button>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
v-if="hasUpdater"
|
||||
:disabled="updateStarted"
|
||||
@click="update"
|
||||
>
|
||||
<span v-if="updateStarted">
|
||||
<span
|
||||
class="spinner-border spinner-border-sm"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
>
|
||||
</span>
|
||||
Akualisieren
|
||||
<span v-if="updateStarted">
|
||||
<span
|
||||
class="spinner-border spinner-border-sm"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
>
|
||||
</span>
|
||||
<span v-else>Jetzt aktualisieren</span>
|
||||
</button>
|
||||
<a
|
||||
:href="releaseNotesUrl(available)"
|
||||
class="btn btn-primary"
|
||||
v-else
|
||||
>
|
||||
Download
|
||||
</a>
|
||||
</div>
|
||||
Akualisieren
|
||||
</span>
|
||||
<span v-else>Jetzt aktualisieren</span>
|
||||
</button>
|
||||
<a :href="releaseNotesUrl(available)" class="btn btn-primary" v-else>
|
||||
Download
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -116,18 +110,11 @@ export default {
|
|||
},
|
||||
data: function () {
|
||||
return {
|
||||
modalActive: false,
|
||||
updateStarted: false,
|
||||
updateStatus: "",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
showModal: function () {
|
||||
this.modalActive = true;
|
||||
},
|
||||
closeModal: function () {
|
||||
this.modalActive = false;
|
||||
},
|
||||
update: async function () {
|
||||
try {
|
||||
await axios.post("update");
|
||||
|
|
@ -155,28 +142,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.25s ease-in;
|
||||
}
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
.dialog {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1050;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
outline: 0;
|
||||
}
|
||||
.icon {
|
||||
color: #0fdd42;
|
||||
}
|
||||
.text-black a {
|
||||
color: #18191a;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ import { faSun } from "@fortawesome/free-solid-svg-icons/faSun";
|
|||
import { faTemperatureHigh } from "@fortawesome/free-solid-svg-icons/faTemperatureHigh";
|
||||
import { faTemperatureLow } from "@fortawesome/free-solid-svg-icons/faTemperatureLow";
|
||||
import { faThermometerHalf } from "@fortawesome/free-solid-svg-icons/faThermometerHalf";
|
||||
import { faHeart } from "@fortawesome/free-solid-svg-icons/faHeart";
|
||||
import { faHeart as farHeart } from "@fortawesome/free-regular-svg-icons/faHeart";
|
||||
import { faHeart as fasHeart } from "@fortawesome/free-solid-svg-icons/faHeart";
|
||||
import { faGift } from "@fortawesome/free-solid-svg-icons/faGift";
|
||||
import { faBox } from "@fortawesome/free-solid-svg-icons/faBox";
|
||||
import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons/faExclamationCircle";
|
||||
|
|
@ -40,7 +41,8 @@ library.add(
|
|||
faTemperatureHigh,
|
||||
faTemperatureLow,
|
||||
faThermometerHalf,
|
||||
faHeart,
|
||||
farHeart,
|
||||
fasHeart,
|
||||
faGift,
|
||||
faBox,
|
||||
faExclamationCircle
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ const store = {
|
|||
},
|
||||
update: function (msg) {
|
||||
Object.keys(msg).forEach(function (k) {
|
||||
if (typeof window.toasts[k] === "function") {
|
||||
window.toasts[k]({ message: msg[k] });
|
||||
if (typeof window.app[k] === "function") {
|
||||
window.app[k]({ message: msg[k] });
|
||||
} else {
|
||||
setProperty(store.state, k.split("."), msg[k]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,27 +6,36 @@
|
|||
<a class="navbar-brand" href="https://github.com/andig/evcc">
|
||||
<Logo class="logo"></Logo>
|
||||
</a>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-toggle="collapse"
|
||||
data-target="#navbarNavAltMarkup"
|
||||
aria-controls="navbarNavAltMarkup"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
|
||||
<div class="navbar-nav mr-auto"></div>
|
||||
<div class="navbar-nav">
|
||||
<a
|
||||
class="nav-item nav-link"
|
||||
href="https://github.com/andig/evcc/discussions"
|
||||
target="_blank"
|
||||
<div class="d-flex">
|
||||
<div class="d-flex">
|
||||
<Notifications :notifications="notifications" />
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarNavAltMarkup"
|
||||
aria-controls="navbarNavAltMarkup"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
Support
|
||||
</a>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="collapse navbar-collapse flex-lg-grow-0"
|
||||
id="navbarNavAltMarkup"
|
||||
>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link"
|
||||
href="https://github.com/andig/evcc/discussions"
|
||||
target="_blank"
|
||||
>
|
||||
Support
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -36,7 +45,7 @@
|
|||
class="flex-grow-1 d-flex flex-column justify-content-stretch"
|
||||
></router-view>
|
||||
</div>
|
||||
<Footer :version="version"></Footer>
|
||||
<Footer :version="version" :sponsor="sponsor"></Footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -44,11 +53,13 @@
|
|||
import "../icons";
|
||||
import Logo from "../components/Logo";
|
||||
import Footer from "../components/Footer";
|
||||
import Notifications from "../components/Notifications";
|
||||
|
||||
import store from "../store";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
components: { Logo, Footer },
|
||||
components: { Logo, Footer, Notifications },
|
||||
data: function () {
|
||||
return {
|
||||
compact: false,
|
||||
|
|
@ -80,7 +91,7 @@ export default {
|
|||
var msg = JSON.parse(evt.data);
|
||||
store.update(msg);
|
||||
} catch (e) {
|
||||
window.toasts.error(e, evt.data);
|
||||
window.app.error(e, evt.data);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
|
@ -96,6 +107,12 @@ export default {
|
|||
uploadProgress: this.store.state.uploadProgress,
|
||||
};
|
||||
},
|
||||
sponsor: function () {
|
||||
return this.store.state.sponsor;
|
||||
},
|
||||
},
|
||||
props: {
|
||||
notifications: Array,
|
||||
},
|
||||
created: function () {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
|
|
|
|||
6
dist/css/chunk-vendors.0f1ada3b.css
vendored
Normal file
6
dist/css/chunk-vendors.0f1ada3b.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6
dist/css/chunk-vendors.52eaf30c.css
vendored
6
dist/css/chunk-vendors.52eaf30c.css
vendored
File diff suppressed because one or more lines are too long
1
dist/css/index.307488cf.css
vendored
Normal file
1
dist/css/index.307488cf.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.progress-bar-animated{animation-direction:reverse}.btn.caption{opacity:1}.btn.first{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}code{font-size:87.5%;color:#e83e8c;word-wrap:break-word}.value,input[type=radio],label.btn{white-space:nowrap!important}.text-muted a,.text-muted a:hover{color:#6c757d!important;text-decoration:none}.bg-muted{opacity:.25}.icon[data-v-0f71c17c]{color:#0fdd42}.icon[data-v-60f66a8e]{color:#0fdd42;display:inline-block}.sponsor-button[data-v-60f66a8e]{touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.support-button .solid[data-v-60f66a8e]{display:none}.support-button:hover .solid[data-v-60f66a8e]{display:inline-block}.support-button:hover .outline[data-v-60f66a8e]{display:none}.logo[data-v-59c735a7]{width:85px}.app[data-v-59c735a7]{min-height:100vh}.btn[data-v-a92589b2]{flex-basis:0}.vehicle-soc[data-v-61c611fd]{--height:38px;--thumb-overlap:3px;--thumb-width:3px;--thumb-horizontal-padding:15px;--label-height:26px;position:relative;height:var(--height)}.progress[data-v-61c611fd]{height:100%;font-size:1rem}.progress-bar.bg-muted[data-v-61c611fd]{color:var(--white)}.bg-light[data-v-61c611fd]{color:var(--bs-gray-dark)}.target-label[data-v-61c611fd]{width:3em;margin-left:-1.5em;height:var(--label-height);position:absolute;top:calc(var(--label-height)*-1 + var(--thumb-overlap)*-1);text-align:center;color:var(--bs-gray-dark);font-size:1rem;opacity:1;transition:opacity .2s ease 1s}.target-slider[data-v-61c611fd]{-webkit-appearance:none;position:absolute;top:calc(var(--thumb-overlap)*-1);left:calc(var(--thumb-horizontal-padding)*-1);height:calc(100% + var(--thumb-overlap)*2);width:calc(100% + var(--thumb-horizontal-padding)*2);background:transparent}.target-slider[data-v-61c611fd]:focus{outline:none}.target-slider[data-v-61c611fd]::-webkit-slider-runnable-track{position:relative;background:transparent;border:none;height:100%;cursor:pointer}.target-slider[data-v-61c611fd]::-moz-range-track{background:transparent;border:none;height:100%;cursor:pointer}.target-slider[data-v-61c611fd]::-webkit-slider-thumb{-webkit-appearance:none;position:relative;top:calc(var(--label-height)*-1);height:100%;width:var(--thumb-width);padding:var(--label-height) var(--thumb-horizontal-padding) 0;box-sizing:content-box;background-clip:content-box;background-color:var(--bs-gray-dark);cursor:-webkit-grab;cursor:grab;border:none;opacity:1;-webkit-transition:opacity .2s ease 1s;transition:opacity .2s ease 1s}.target-slider[data-v-61c611fd]::-moz-range-thumb{position:relative;top:calc(var(--label-height)*-1);height:100%;width:var(--thumb-width);padding:var(--label-height) var(--thumb-horizontal-padding) 0;box-sizing:content-box;background-clip:content-box;background-color:var(--bs-gray-dark);cursor:grab;border:none;opacity:1;-moz-transition:opacity .2s ease 1s;transition:opacity .2s ease 1s}.target--max .target-label[data-v-61c611fd],.target--max .target-slider[data-v-61c611fd]::-webkit-slider-thumb{opacity:0}.target--max .target-label[data-v-61c611fd],.target--max .target-slider[data-v-61c611fd]::-moz-range-thumb{opacity:0}.target:hover .target-label[data-v-61c611fd],.target:hover .target-slider[data-v-61c611fd]::-webkit-slider-thumb{opacity:1;transition-delay:0s}.target:hover .target-label[data-v-61c611fd],.target:hover .target-slider[data-v-61c611fd]::-moz-range-thumb{opacity:1;transition-delay:0s}
|
||||
1
dist/css/index.65dbbf5e.css
vendored
1
dist/css/index.65dbbf5e.css
vendored
|
|
@ -1 +0,0 @@
|
|||
.progress-bar-animated{animation-direction:reverse}.btn.caption{opacity:1}.btn.first{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}code{font-size:87.5%;color:#e83e8c;word-wrap:break-word}.value,input[type=radio],label.btn{white-space:nowrap!important}.text-muted a,.text-muted a:hover{color:#6c757d!important;text-decoration:none}.bg-muted{opacity:.25}.fade-enter-active[data-v-a6ded36e],.fade-leave-active[data-v-a6ded36e]{transition:opacity .25s ease-in}.fade-enter[data-v-a6ded36e],.fade-leave-to[data-v-a6ded36e]{opacity:0}.dialog[data-v-a6ded36e]{position:fixed;top:0;left:0;z-index:1050;width:100%;height:100%;overflow:hidden;outline:0}.icon[data-v-a6ded36e]{color:#0fdd42}.text-black a[data-v-a6ded36e]{color:#18191a}.icon[data-v-5f0f38d1]{color:#0fdd42}.text-black a[data-v-5f0f38d1]{color:#18191a}.logo[data-v-8dad761a]{width:85px}.app[data-v-8dad761a]{min-height:100vh}.btn[data-v-139a81de]{flex-basis:0}.vehicle-soc[data-v-2d786089]{--height:38px;--thumb-overlap:3px;--thumb-width:3px;--thumb-horizontal-padding:15px;--label-height:26px;position:relative;height:var(--height)}.progress[data-v-2d786089]{height:100%;font-size:1rem}.progress-bar.bg-muted[data-v-2d786089]{color:var(--white)}.bg-light[data-v-2d786089]{color:var(--dark)}.target-label[data-v-2d786089]{width:3em;margin-left:-1.5em;height:var(--label-height);position:absolute;top:calc(var(--label-height)*-1 + var(--thumb-overlap)*-1);text-align:center;color:var(--dark);font-size:1rem;opacity:1;transition:opacity .2s ease 1s}.target-slider[data-v-2d786089]{-webkit-appearance:none;position:absolute;top:calc(var(--thumb-overlap)*-1);left:calc(var(--thumb-horizontal-padding)*-1);height:calc(100% + var(--thumb-overlap)*2);width:calc(100% + var(--thumb-horizontal-padding)*2);background:transparent}.target-slider[data-v-2d786089]:focus{outline:none}.target-slider[data-v-2d786089]::-webkit-slider-runnable-track{background:transparent;border:none;height:100%;cursor:pointer}.target-slider[data-v-2d786089]::-moz-range-track{background:transparent;border:none;height:100%;cursor:pointer}.target-slider[data-v-2d786089]::-webkit-slider-thumb{-webkit-appearance:none;position:relative;top:calc(var(--label-height)*-1);height:100%;width:var(--thumb-width);padding:var(--label-height) var(--thumb-horizontal-padding) 0;box-sizing:content-box;background-clip:content-box;background-color:var(--dark);cursor:-webkit-grab;cursor:grab;border:none;opacity:1;-webkit-transition:opacity .2s ease 1s;transition:opacity .2s ease 1s}.target-slider[data-v-2d786089]::-moz-range-thumb{position:relative;top:calc(var(--label-height)*-1);height:100%;width:var(--thumb-width);padding:0 var(--thumb-horizontal-padding);box-sizing:content-box;background-clip:content-box;background-color:var(--dark);cursor:grab;border:none;opacity:1;-moz-transition:opacity .2s ease 1s;transition:opacity .2s ease 1s}.target--max .target-label[data-v-2d786089],.target--max .target-slider[data-v-2d786089]::-webkit-slider-thumb{opacity:0}.target--max .target-label[data-v-2d786089],.target--max .target-slider[data-v-2d786089]::-moz-range-thumb{opacity:0}.target:hover .target-label[data-v-2d786089],.target:hover .target-slider[data-v-2d786089]::-webkit-slider-thumb{opacity:1;transition-delay:0s}.target:hover .target-label[data-v-2d786089],.target:hover .target-slider[data-v-2d786089]::-moz-range-thumb{opacity:1;transition-delay:0s}
|
||||
4
dist/index.html
vendored
4
dist/index.html
vendored
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="EV Charge Controller"><meta name="author" content="andig"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="apple-touch-icon" sizes="180x180" href="ico/apple-touch-icon.png?[[.Version]]"><link rel="icon" type="image/png" sizes="32x32" href="ico/favicon-32x32.png?[[.Version]]"><link rel="icon" type="image/png" sizes="16x16" href="ico/favicon-16x16.png?[[.Version]]"><link rel="manifest" href="ico/site.webmanifest"><link rel="mask-icon" href="ico/safari-pinned-tab.svg?[[.Version]]" color="#18191a"><link rel="shortcut icon" href="ico/favicon.ico?[[.Version]]"><meta name="apple-mobile-web-app-title" content="evcc"><meta name="application-name" content="evcc"><meta name="msapplication-TileColor" content="#18191a"><meta name="msapplication-config" content="ico/browserconfig.xml"><meta name="theme-color" content="#18191a"><title>evcc</title><link href="css/chunk-vendors.52eaf30c.css" rel="preload" as="style"><link href="css/index.65dbbf5e.css" rel="preload" as="style"><link href="js/chunk-vendors.35669cb4.js" rel="preload" as="script"><link href="js/index.f51648a0.js" rel="preload" as="script"><link href="css/chunk-vendors.52eaf30c.css" rel="stylesheet"><link href="css/index.65dbbf5e.css" rel="stylesheet"></head><body><script>window.evcc = {
|
||||
<!DOCTYPE html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="EV Charge Controller"><meta name="author" content="andig"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="apple-touch-icon" sizes="180x180" href="ico/apple-touch-icon.png?[[.Version]]"><link rel="icon" type="image/png" sizes="32x32" href="ico/favicon-32x32.png?[[.Version]]"><link rel="icon" type="image/png" sizes="16x16" href="ico/favicon-16x16.png?[[.Version]]"><link rel="manifest" href="ico/site.webmanifest"><link rel="mask-icon" href="ico/safari-pinned-tab.svg?[[.Version]]" color="#18191a"><link rel="shortcut icon" href="ico/favicon.ico?[[.Version]]"><meta name="apple-mobile-web-app-title" content="evcc"><meta name="application-name" content="evcc"><meta name="msapplication-TileColor" content="#18191a"><meta name="msapplication-config" content="ico/browserconfig.xml"><meta name="theme-color" content="#18191a"><title>evcc</title><link href="css/chunk-vendors.0f1ada3b.css" rel="preload" as="style"><link href="css/index.307488cf.css" rel="preload" as="style"><link href="js/chunk-vendors.47c2aa5a.js" rel="preload" as="script"><link href="js/index.ab413d5d.js" rel="preload" as="script"><link href="css/chunk-vendors.0f1ada3b.css" rel="stylesheet"><link href="css/index.307488cf.css" rel="stylesheet"></head><body><script>window.evcc = {
|
||||
version: "[[.Version]]",
|
||||
configured: "[[.Configured]]",
|
||||
};</script><div id="app"></div><div id="toasts"></div><script src="js/chunk-vendors.35669cb4.js"></script><script src="js/index.f51648a0.js"></script></body></html>
|
||||
};</script><div id="app"></div><script src="js/chunk-vendors.47c2aa5a.js"></script><script src="js/index.ab413d5d.js"></script></body></html>
|
||||
73
dist/js/chunk-vendors.35669cb4.js
vendored
73
dist/js/chunk-vendors.35669cb4.js
vendored
File diff suppressed because one or more lines are too long
1
dist/js/chunk-vendors.35669cb4.js.map
vendored
1
dist/js/chunk-vendors.35669cb4.js.map
vendored
File diff suppressed because one or more lines are too long
24
dist/js/chunk-vendors.47c2aa5a.js
vendored
Normal file
24
dist/js/chunk-vendors.47c2aa5a.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/js/chunk-vendors.47c2aa5a.js.map
vendored
Normal file
1
dist/js/chunk-vendors.47c2aa5a.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
dist/js/index.ab413d5d.js
vendored
Normal file
2
dist/js/index.ab413d5d.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/js/index.ab413d5d.js.map
vendored
Normal file
1
dist/js/index.ab413d5d.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
dist/js/index.f51648a0.js
vendored
2
dist/js/index.f51648a0.js
vendored
File diff suppressed because one or more lines are too long
1
dist/js/index.f51648a0.js.map
vendored
1
dist/js/index.f51648a0.js.map
vendored
File diff suppressed because one or more lines are too long
3439
package-lock.json
generated
3439
package-lock.json
generated
File diff suppressed because it is too large
Load diff
21
package.json
21
package.json
|
|
@ -13,21 +13,22 @@
|
|||
"author": "naltatis & andig",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@storybook/addon-actions": "^6.1.21",
|
||||
"@storybook/addon-essentials": "^6.1.21",
|
||||
"@storybook/addon-links": "^6.1.21",
|
||||
"@storybook/vue": "^6.1.21",
|
||||
"@storybook/addon-actions": "^6.2.9",
|
||||
"@storybook/addon-essentials": "^6.2.9",
|
||||
"@storybook/addon-links": "^6.2.9",
|
||||
"@storybook/addon-postcss": "^2.0.0",
|
||||
"@storybook/vue": "^6.2.9",
|
||||
"@vue/cli-service": "^4.5.12",
|
||||
"@vue/component-compiler-utils": "^3.2.0",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
"eslint": "^7.22.0",
|
||||
"eslint": "^7.25.0",
|
||||
"eslint-config-prettier": "^6.15.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-promise": "^4.3.1",
|
||||
"eslint-plugin-standard": "^4.1.0",
|
||||
"eslint-plugin-vue": "^7.7.0",
|
||||
"eslint-plugin-vue": "^7.9.0",
|
||||
"prettier": "^2.2.0",
|
||||
"vue-template-compiler": "^2.6.12"
|
||||
},
|
||||
|
|
@ -41,12 +42,12 @@
|
|||
"repository": "github:andig/evcc",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.35",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"@fortawesome/vue-fontawesome": "^2.0.0",
|
||||
"axios": "^0.21.0",
|
||||
"bootstrap": "^4.6.0",
|
||||
"jquery": "^3.6.0",
|
||||
"popper.js": "^1.16.1",
|
||||
"bootstrap": "^5.0.0-beta3",
|
||||
"canvas-confetti": "^1.4.0",
|
||||
"vue": "^2.6.12",
|
||||
"vue-hot-reload-api": "^2.3.4",
|
||||
"vue-router": "^3.5.1"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue