UI: Add Light- and Dark-Mode (#3720)
This commit is contained in:
parent
89c908b414
commit
06e688c28b
51 changed files with 14384 additions and 9080 deletions
|
|
@ -1,23 +1,16 @@
|
|||
const { loadConfigFromFile } = require("vite");
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
stories: ["../assets/js/**/*.stories.mdx", "../assets/js/**/*.stories.@(js|jsx|ts|tsx)"],
|
||||
addons: ["@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-postcss"],
|
||||
stories: ["../assets/js/**/*.stories.js"],
|
||||
addons: [
|
||||
"@storybook/addon-links",
|
||||
"@storybook/addon-essentials",
|
||||
"@storybook/addon-interactions",
|
||||
],
|
||||
framework: "@storybook/vue3",
|
||||
core: {
|
||||
builder: "storybook-builder-vite",
|
||||
builder: "@storybook/builder-vite",
|
||||
},
|
||||
staticDirs: ["../assets"],
|
||||
async viteFinal(config, b) {
|
||||
const { config: userConfig } = await loadConfigFromFile(
|
||||
path.resolve(__dirname, "../vite.config.ts")
|
||||
);
|
||||
const vuePlugin = userConfig.plugins.find((p) => p.name === "vite:vue");
|
||||
|
||||
const vuePluginIndex = config.plugins.findIndex((p) => p.name === "vite:vue");
|
||||
config.plugins[vuePluginIndex] = vuePlugin;
|
||||
|
||||
return config;
|
||||
features: {
|
||||
storyStoreV7: true,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
const express = require("express");
|
||||
|
||||
const expressMiddleWare = (router) => {
|
||||
router.post("/update", function (req, res) {
|
||||
res.status(200).send("ok");
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = expressMiddleWare;
|
||||
3
.storybook/preview-head.html
Normal file
3
.storybook/preview-head.html
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<script>
|
||||
window.global = window;
|
||||
</script>
|
||||
|
|
@ -10,16 +10,22 @@ app.use(i18n);
|
|||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
backgrounds: {
|
||||
default: "dark",
|
||||
default: "background",
|
||||
values: [
|
||||
{
|
||||
name: "light",
|
||||
value: "#ffffff",
|
||||
name: "background",
|
||||
value: "var(--evcc-background)",
|
||||
},
|
||||
{
|
||||
name: "dark",
|
||||
value: "#28293e",
|
||||
name: "box",
|
||||
value: "var(--evcc-box)",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ RUN make install-ui
|
|||
COPY assets assets
|
||||
COPY vite.config.js vite.config.js
|
||||
COPY .eslintrc.js .eslintrc.js
|
||||
COPY postcss.config.js postcss.config.js
|
||||
|
||||
RUN make clean ui
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,24 +11,47 @@
|
|||
font-style: normal;
|
||||
}
|
||||
|
||||
/* Bootstrap Breakpoints as Custom Media Queries */
|
||||
@custom-media --sm-and-up (min-width: 576px);
|
||||
@custom-media --md-and-up (min-width: 768px);
|
||||
@custom-media --lg-and-up (min-width: 992px);
|
||||
@custom-media --xl-and-up (min-width: 1200px);
|
||||
@custom-media --xxl-and-up (min-width: 1400px);
|
||||
|
||||
@custom-media --light-mode (prefers-color-scheme: light);
|
||||
@custom-media --dark-mode (prefers-color-scheme: dark);
|
||||
|
||||
:root {
|
||||
--evcc-green: #baffcb;
|
||||
--evcc-dark-green: #0fde41;
|
||||
--evcc-darker-green: #0ba631;
|
||||
--evcc-darkest-green: #076f20;
|
||||
--evcc-yellow: #faf000;
|
||||
--evcc-dark-yellow: #bbb400;
|
||||
--bs-gray-deep: #010322;
|
||||
--bs-gray-dark: #28293e;
|
||||
--bs-gray-medium: #93949e;
|
||||
--bs-gray-light: #b5b6c3;
|
||||
--bs-gray-bright: #f3f3f7;
|
||||
|
||||
--evcc-grid: var(--bs-gray-dark);
|
||||
--evcc-self: var(--evcc-dark-green);
|
||||
--evcc-export: var(--evcc-yellow);
|
||||
--evcc-background: var(--bs-gray-bright);
|
||||
--evcc-box: var(--bs-white);
|
||||
--evcc-default-text: var(--bs-gray-dark);
|
||||
--evcc-gray: var(--bs-gray-medium);
|
||||
|
||||
--evcc-accent1: var(--evcc-dark-yellow);
|
||||
--evcc-accent2: var(--evcc-darker-green);
|
||||
--evcc-accent3: var(--evcc-darkest-green);
|
||||
|
||||
--evcc-transition-slow: 1000ms;
|
||||
--evcc-transition-medium: 500ms;
|
||||
--evcc-transition-fast: 250ms;
|
||||
--evcc-transition-very-fast: 100ms;
|
||||
|
||||
--bs-primary: var(--evcc-dark-green);
|
||||
--bs-primary: var(--evcc-darker-green);
|
||||
--bs-primary-rgb: 58, 186, 44;
|
||||
|
||||
--bs-body-font-size: 14px;
|
||||
|
|
@ -37,6 +60,20 @@
|
|||
"Segoe UI Symbol", "Noto Color Emoji";
|
||||
}
|
||||
|
||||
@media (--dark-mode) {
|
||||
:root {
|
||||
--evcc-grid: var(--bs-gray-medium);
|
||||
--evcc-background: var(--bs-gray-deep);
|
||||
--evcc-box: var(--bs-gray-dark);
|
||||
--evcc-default-text: var(--bs-white);
|
||||
--evcc-gray: var(--bs-gray-light);
|
||||
--evcc-accent1: var(--evcc-yellow);
|
||||
--evcc-accent2: var(--evcc-dark-green);
|
||||
--evcc-accent3: var(--evcc-darker-green);
|
||||
--bs-primary: var(--evcc-dark-green);
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
/* prevents content jump when scrollbar is activate */
|
||||
width: 100vw;
|
||||
|
|
@ -44,7 +81,8 @@ html {
|
|||
}
|
||||
|
||||
body {
|
||||
background-color: var(--evcc-gray-dark);
|
||||
background-color: var(--evcc-background);
|
||||
color: var(--evcc-default-text);
|
||||
}
|
||||
|
||||
h1,
|
||||
|
|
@ -70,7 +108,11 @@ h4 {
|
|||
}
|
||||
|
||||
a {
|
||||
color: var(--evcc-dark-green);
|
||||
color: var(--bs-primary);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--evcc-accent3);
|
||||
}
|
||||
|
||||
/* reverse loading animation */
|
||||
|
|
@ -87,33 +129,50 @@ a {
|
|||
|
||||
.btn-primary,
|
||||
.btn-primary:focus {
|
||||
background-color: var(--bs-gray-dark);
|
||||
border-color: var(--bs-gray-dark);
|
||||
background-color: var(--bs-primary);
|
||||
border-color: var(--bs-primary);
|
||||
color: var(--evcc-background);
|
||||
}
|
||||
|
||||
.btn-primary:hover,
|
||||
.btn-primary:active {
|
||||
background-color: var(--evcc-dark-green);
|
||||
border-color: var(--evcc-dark-green);
|
||||
background-color: var(--evcc-accent3);
|
||||
border-color: var(--evcc-accent3);
|
||||
}
|
||||
.btn-outline-primary,
|
||||
.btn-outline-primary:focus {
|
||||
color: var(--bs-gray-dark);
|
||||
color: var(--bs-primary);
|
||||
background-color: transparent;
|
||||
border-width: 2px;
|
||||
border-color: var(--bs-gray-dark);
|
||||
border-color: var(--bs-primary);
|
||||
}
|
||||
.btn-outline-primary:hover,
|
||||
.btn-outline-primary:active {
|
||||
color: var(--evcc-dark-green);
|
||||
color: var(--evcc-accent3);
|
||||
background-color: transparent;
|
||||
border-width: 2px;
|
||||
border-color: var(--evcc-dark-green);
|
||||
border-color: var(--evcc-accent3);
|
||||
}
|
||||
|
||||
.text-evcc {
|
||||
color: var(--evcc-dark-green);
|
||||
}
|
||||
.text-accent1 {
|
||||
color: var(--evcc-accent1);
|
||||
}
|
||||
.text-accent2 {
|
||||
color: var(--evcc-accent2);
|
||||
}
|
||||
.text-accent3 {
|
||||
color: var(--evcc-accent3);
|
||||
}
|
||||
|
||||
.evcc-default-text {
|
||||
color: var(--evcc-default-text) !important;
|
||||
}
|
||||
.evcc-gray {
|
||||
color: var(--evcc-gray);
|
||||
}
|
||||
.text-grid {
|
||||
color: var(--evcc-grid);
|
||||
}
|
||||
|
|
@ -147,26 +206,39 @@ a {
|
|||
}
|
||||
|
||||
.modal-header {
|
||||
padding-bottom: 1.5rem;
|
||||
padding: 0 0 1rem 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-weight: bold;
|
||||
font-size: 22px;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
border-radius: 1rem;
|
||||
padding: 1rem;
|
||||
padding: 1.25rem;
|
||||
background-color: var(--evcc-box);
|
||||
color: var(--evcc-default-text);
|
||||
}
|
||||
|
||||
@media (--sm-and-up) {
|
||||
.modal-content {
|
||||
padding: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding-top: 1.5rem;
|
||||
padding-bottom: 1.5rem;
|
||||
padding: 1rem 0 0;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding-top: 1.5rem;
|
||||
padding: 1rem 0 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-footer > * {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
|
|
@ -186,3 +258,25 @@ small {
|
|||
.btn-close {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (--dark-mode) {
|
||||
.btn-close {
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 8px var(--bs-gray-light);
|
||||
background-color: var(--evcc-box);
|
||||
}
|
||||
.dropdown-item {
|
||||
color: var(--evcc-default-text);
|
||||
}
|
||||
|
||||
@media (--dark-mode) {
|
||||
.dropdown-menu {
|
||||
box-shadow: 0 0 8px var(--evcc-box);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="evcc - Sonne tanken ☀️🚘" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="evcc" />
|
||||
<meta name="application-name" content="evcc" />
|
||||
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
<link rel="shortcut icon" href="meta/favicon.ico?[[.Version]]" />
|
||||
<meta name="msapplication-TileColor" content="#28293e" />
|
||||
<meta name="msapplication-config" content="meta/browserconfig.xml?[[.Version]]" />
|
||||
<meta name="theme-color" content="#28293e" />
|
||||
<meta name="theme-color" content="#020318" />
|
||||
|
||||
<title>evcc</title>
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -73,3 +73,11 @@ window.app = app.mount("#app");
|
|||
window.setInterval(function () {
|
||||
api.get("health").then(window.app.setOnline).catch(window.app.setOffline);
|
||||
}, 5000);
|
||||
|
||||
const isDarkMode = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
isDarkMode.addEventListener("change", updateThemeColor);
|
||||
function updateThemeColor() {
|
||||
const $el = document.querySelector("meta[name=theme-color]");
|
||||
$el.setAttribute("content", isDarkMode.matches ? "#020318" : "#f3f3f7");
|
||||
}
|
||||
updateThemeColor();
|
||||
|
|
|
|||
|
|
@ -12,11 +12,6 @@ export default {
|
|||
batteryPower: { control: { type: "range", min: -4000, max: 4000, step: 100 } },
|
||||
batterySoC: { control: { type: "range", min: 0, max: 100, step: 1 } },
|
||||
},
|
||||
parameters: {
|
||||
backgrounds: {
|
||||
default: "light",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Template = (args) => ({
|
||||
|
|
|
|||
|
|
@ -19,9 +19,6 @@
|
|||
:valuesInKw="valuesInKw"
|
||||
/>
|
||||
</div>
|
||||
<div class="indicator position-absolute bottom-0 start-50">
|
||||
<shopicon-regular-arrowdown></shopicon-regular-arrowdown>
|
||||
</div>
|
||||
<div class="details" :style="{ height: detailsHeight }">
|
||||
<div ref="detailsInner" class="details-inner row">
|
||||
<div class="col-12 d-flex justify-content-between pt-2 mb-4">
|
||||
|
|
@ -121,7 +118,6 @@
|
|||
|
||||
<script>
|
||||
import "@h2d2/shopicons/es/filled/square";
|
||||
import "@h2d2/shopicons/es/regular/arrowdown";
|
||||
import Visualization from "./Visualization.vue";
|
||||
import EnergyflowEntry from "./EnergyflowEntry.vue";
|
||||
import formatter from "../../mixins/formatter";
|
||||
|
|
@ -204,30 +200,19 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.energyflow {
|
||||
background: var(--bs-white);
|
||||
}
|
||||
.indicator {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) scaleY(1);
|
||||
transition: opacity, transform;
|
||||
transition-duration: var(--evcc-transition-slow);
|
||||
}
|
||||
.energyflow--open .indicator {
|
||||
transform: translateX(-50%) scaleY(-1);
|
||||
}
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.energyflow:hover .indicator {
|
||||
opacity: 0.25;
|
||||
}
|
||||
}
|
||||
.details {
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
transform: scale(0.98);
|
||||
overflow: visible;
|
||||
transition: height;
|
||||
transition: height, opacity, transform;
|
||||
transition-duration: var(--evcc-transition-medium);
|
||||
transition-timing-function: cubic-bezier(0.5, 0.5, 0.5, 1.15);
|
||||
}
|
||||
.energyflow--open .details {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
.color-grid {
|
||||
color: var(--evcc-grid);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="d-flex justify-content-between mb-2 entry" :class="{ 'text-gray-medium': !active }">
|
||||
<div class="d-flex justify-content-between mb-2 entry" :class="{ 'evcc-gray': !active }">
|
||||
<span class="d-flex flex-nowrap">
|
||||
<BatteryIcon v-if="isBattery" :soc="soc" />
|
||||
<component :is="`shopicon-regular-${icon}`" v-else></component>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ export default {
|
|||
opacity: 0;
|
||||
}
|
||||
.label-bar-scale {
|
||||
border: 1px solid var(--bs-gray-medium);
|
||||
border: 1px solid var(--evcc-gray);
|
||||
height: 14px;
|
||||
background: none;
|
||||
display: flex;
|
||||
|
|
@ -64,11 +64,11 @@ export default {
|
|||
border-top: none;
|
||||
}
|
||||
.label-bar-icon {
|
||||
background-color: white;
|
||||
background-color: var(--evcc-background);
|
||||
transform: scale(1);
|
||||
color: var(--bs-gray-dark);
|
||||
color: var(--evcc-default-text);
|
||||
border-radius: 0;
|
||||
border: 0.25rem solid white;
|
||||
border: 0.25rem solid var(--evcc-background);
|
||||
transition-property: background-color, transform, border-radius, border;
|
||||
/* will be overwritten by parent component to avoid initial transition */
|
||||
transition-duration: 0s;
|
||||
|
|
@ -82,7 +82,7 @@ export default {
|
|||
margin-top: 12px;
|
||||
}
|
||||
.label-bar--hide-icon .label-bar-icon {
|
||||
background-color: var(--bs-gray-dark);
|
||||
background-color: var(--evcc-default-text);
|
||||
transform: scale(0.1666666);
|
||||
border-radius: 100%;
|
||||
border-width: 1.5rem;
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ export default {
|
|||
margin-right: 1.2rem;
|
||||
}
|
||||
.label-scale-name {
|
||||
color: var(--bs-gray-medium);
|
||||
color: var(--evcc-gray);
|
||||
flex-basis: 1.2rem;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
|
|
@ -218,6 +218,11 @@ export default {
|
|||
background-color: var(--evcc-grid);
|
||||
color: var(--bs-white);
|
||||
}
|
||||
@media (--dark-mode) {
|
||||
.grid-import {
|
||||
color: var(--bs-dark);
|
||||
}
|
||||
}
|
||||
.self-consumption {
|
||||
background-color: var(--evcc-self);
|
||||
color: var(--bs-dark);
|
||||
|
|
|
|||
|
|
@ -46,8 +46,4 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.footer {
|
||||
color: var(--bs-white);
|
||||
}
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="root" :class="{ 'root--dark': onDark }">
|
||||
<div class="root">
|
||||
<div class="mb-2 label">{{ label }}</div>
|
||||
<slot>
|
||||
<h3 class="value m-0">
|
||||
|
|
@ -19,7 +19,6 @@ export default {
|
|||
label: String,
|
||||
value: String,
|
||||
extraValue: String,
|
||||
onDark: Boolean,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -29,19 +28,14 @@ export default {
|
|||
}
|
||||
.label {
|
||||
text-transform: uppercase;
|
||||
color: var(--bs-gray-medium);
|
||||
color: var(--evcc-gray);
|
||||
font-size: 14px;
|
||||
}
|
||||
.value {
|
||||
font-size: 18px;
|
||||
}
|
||||
.extraValue {
|
||||
color: var(--bs-gray-medium);
|
||||
color: var(--evcc-gray);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.root--dark .extraValue,
|
||||
.root--dark .label {
|
||||
color: var(--bs-gray-light);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<template>
|
||||
<div class="loadpoint bg-white p-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div class="loadpoint pt-4 pb-2 px-3 px-sm-4 mx-2 mx-sm-0">
|
||||
<div class="d-block d-sm-flex justify-content-between align-items-center mb-3">
|
||||
<h3 class="mb-3 me-2 text-truncate">
|
||||
{{ title || $t("main.loadpoint.fallbackName") }}
|
||||
</h3>
|
||||
<div class="mb-3 d-flex align-items-center">
|
||||
<Mode :mode="mode" @updated="setTargetMode" />
|
||||
<Mode class="w-100 w-sm-auto" :mode="mode" @updated="setTargetMode" />
|
||||
<button v-if="$hiddenFeatures" class="btn btn-link text-gray p-0 flex-shrink-0">
|
||||
<shopicon-filled-options size="s"></shopicon-filled-options>
|
||||
</button>
|
||||
|
|
@ -64,6 +64,7 @@
|
|||
${fmtShortDurationUnit(chargeDurationInterpolated)}`"
|
||||
/>
|
||||
</div>
|
||||
<hr class="divider" />
|
||||
<Vehicle
|
||||
v-bind="vehicle"
|
||||
@target-soc-updated="setTargetSoC"
|
||||
|
|
@ -214,7 +215,8 @@ export default {
|
|||
<style scoped>
|
||||
.loadpoint {
|
||||
border-radius: 2rem;
|
||||
color: var(--bs-gray-dark);
|
||||
color: var(--evcc-default-text);
|
||||
background: var(--evcc-box);
|
||||
}
|
||||
|
||||
.details > div {
|
||||
|
|
@ -230,4 +232,18 @@ export default {
|
|||
.opacity-transiton {
|
||||
transition: opacity var(--evcc-transition-slow) ease-in;
|
||||
}
|
||||
.divider {
|
||||
border: none;
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-color: var(--evcc-gray);
|
||||
background: none;
|
||||
opacity: 0.5;
|
||||
margin: 0 -1rem;
|
||||
}
|
||||
@media (--sm-and-up) {
|
||||
.divider {
|
||||
margin: 0 -1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<button
|
||||
v-for="(loadpoint, index) in loadpoints"
|
||||
:key="index"
|
||||
class="btn btn-sm btn-link p-0 mx-1 indicator d-flex justify-content-center align-items-center text-white"
|
||||
class="btn btn-sm btn-link p-0 mx-1 indicator d-flex justify-content-center align-items-center evcc-default-text"
|
||||
:class="{ 'indicator--selected': selected(index) }"
|
||||
@click="scrollTo(index)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<path
|
||||
d="M13.082 29.071a12.384 12.384 0 01-9-3.42 12.192 12.192 0 01-3.54-9.12v-.64a15.394 15.394 0 011.47-6.83 10.825 10.825 0 014.17-4.64 11.64 11.64 0 016.15-1.63 10.45 10.45 0 018.21 3.26c2 2.194 3 5.297 3 9.31v2.76H7.382a6.348 6.348 0 002 4 5.997 5.997 0 004.16 1.49 7.305 7.305 0 006.1-2.84l3.31 3.73a10 10 0 01-4.13 3.39 13.309 13.309 0 01-5.74 1.18zm-.77-20.84a4.216 4.216 0 00-3.26 1.37 7.141 7.141 0 00-1.6 3.91h9.39v-.55a5.005 5.005 0 00-1.22-3.49 4.304 4.304 0 00-3.31-1.24zM36.452 20.331l4.7-17.09h7l-8.48 25.36h-6.44l-8.52-25.36h7l4.74 17.09zM85.542 23.611a4.444 4.444 0 003-1 3.638 3.638 0 001.22-2.75h6.32a8.668 8.668 0 01-1.4 4.73 9.145 9.145 0 01-3.79 3.3 11.736 11.736 0 01-5.29 1.19 10.912 10.912 0 01-8.54-3.46c-2.087-2.3-3.13-5.483-3.13-9.55v-.45c0-3.9 1.033-7.016 3.1-9.35a10.868 10.868 0 018.51-3.5c2.791-.134 5.524.84 7.6 2.71a9.626 9.626 0 012.9 7.21h-6.3a4.663 4.663 0 00-1.2-3.22 4.005 4.005 0 00-3.08-1.24 4.068 4.068 0 00-3.56 1.73c-.8 1.15-1.2 3-1.2 5.6v.7c0 2.61.39 4.49 1.19 5.63a4.092 4.092 0 003.65 1.72zM110.422 23.611a4.454 4.454 0 003-1 3.63 3.63 0 001.21-2.75h6.33a8.668 8.668 0 01-1.4 4.73 9.143 9.143 0 01-3.73 3.3 11.76 11.76 0 01-5.29 1.18 10.912 10.912 0 01-8.54-3.46c-2.087-2.3-3.13-5.483-3.13-9.55v-.45c0-3.9 1.033-7.016 3.1-9.35a10.85 10.85 0 018.57-3.49 10.575 10.575 0 017.6 2.71 9.598 9.598 0 012.91 7.21h-6.33a4.651 4.651 0 00-1.21-3.22 4.492 4.492 0 00-6.64.49c-.8 1.15-1.21 3-1.21 5.6v.7c0 2.607.4 4.484 1.2 5.63a4.09 4.09 0 003.56 1.72z"
|
||||
fill="#fff"
|
||||
class="letter"
|
||||
fill-rule="nonzero"
|
||||
/>
|
||||
<path
|
||||
|
|
@ -26,3 +27,13 @@ export default {
|
|||
name: "Logo",
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.letter {
|
||||
fill: #18191a;
|
||||
}
|
||||
@media (--dark-mode) {
|
||||
.letter {
|
||||
fill: var(--bs-white);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export default {
|
|||
argTypes: {
|
||||
mode: { control: { type: "inline-radio" }, options: ["off", "now", "minpv", "pv"] },
|
||||
},
|
||||
parameters: { backgrounds: { default: "box" } },
|
||||
};
|
||||
|
||||
const Template = (args) => ({
|
||||
|
|
|
|||
|
|
@ -1,27 +1,14 @@
|
|||
<template>
|
||||
<div v-if="$hiddenFeatures" class="mode-group border d-inline-flex" role="group">
|
||||
<button
|
||||
v-for="m in ['fast', 'cheap']"
|
||||
:key="m"
|
||||
type="button"
|
||||
class="btn"
|
||||
:class="{ active: isActive(m) }"
|
||||
@click="setTargetMode(m)"
|
||||
>
|
||||
{{ $t(`main.mode.${m}`) }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="mode-group border d-inline-flex" role="group">
|
||||
<div class="mode-group border d-inline-flex" role="group">
|
||||
<button
|
||||
v-for="m in modes"
|
||||
:key="m"
|
||||
type="button"
|
||||
class="btn"
|
||||
class="btn flex-grow-1 flex-shrink-1"
|
||||
:class="{ active: isActive(m) }"
|
||||
@click="setTargetMode(m)"
|
||||
>
|
||||
<span class="d-inline d-sm-none"> {{ $t(`main.mode.${m}Short`) }} </span>
|
||||
<span class="d-none d-sm-inline"> {{ $t(`main.mode.${m}Long`) }} </span>
|
||||
{{ $t(`main.mode.${m}`) }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -35,30 +22,23 @@ export default {
|
|||
emits: ["updated"],
|
||||
data() {
|
||||
return {
|
||||
modes: ["off", "now", "minpv", "pv"],
|
||||
modes: ["off", "minpv", "pv", "now"],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
isActive: function (mode) {
|
||||
return this.mode === this.mapToOldModes(mode);
|
||||
return this.mode === mode;
|
||||
},
|
||||
setTargetMode: function (mode) {
|
||||
this.$emit("updated", this.mapToOldModes(mode));
|
||||
},
|
||||
mapToOldModes: function (mode) {
|
||||
const mapping = { fast: "now", cheap: "pv" };
|
||||
return mapping[mode] || mode;
|
||||
this.$emit("updated", mode);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
<style scoped>
|
||||
.mode-group {
|
||||
border: 2px solid var(--bs-gray-medium);
|
||||
background-color: var(--bs-white);
|
||||
border: 2px solid var(--evcc-default-text);
|
||||
border-radius: 20px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
|
@ -69,10 +49,14 @@ export default {
|
|||
white-space: nowrap;
|
||||
border-radius: 18px;
|
||||
padding: 0.1em 0.8em;
|
||||
color: var(--evcc-default-text);
|
||||
}
|
||||
.btn:hover {
|
||||
color: var(--evcc-gray);
|
||||
}
|
||||
.btn.active {
|
||||
background: var(--bs-gray-dark);
|
||||
color: var(--bs-white);
|
||||
color: var(--evcc-background);
|
||||
background: var(--evcc-default-text);
|
||||
}
|
||||
.btn-group {
|
||||
border-radius: 16px;
|
||||
|
|
|
|||
|
|
@ -4,11 +4,7 @@ export default {
|
|||
title: "Main/Phases",
|
||||
component: Phases,
|
||||
argTypes: {},
|
||||
parameters: {
|
||||
backgrounds: {
|
||||
default: "light",
|
||||
},
|
||||
},
|
||||
parameters: { backgrounds: { default: "box" } },
|
||||
};
|
||||
|
||||
const Template = (args, { argTypes }) => ({
|
||||
|
|
|
|||
|
|
@ -46,13 +46,18 @@ export default {
|
|||
width: 73px;
|
||||
}
|
||||
.phase {
|
||||
background-color: var(--bs-gray-200);
|
||||
background-color: var(--bs-gray-bright);
|
||||
height: 4px;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
border-radius: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
@media (--dark-mode) {
|
||||
.phase {
|
||||
background-color: var(--bs-gray-bright);
|
||||
}
|
||||
}
|
||||
.phase.inactive {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-link pe-0 text-decoration-none text-white text-nowrap d-flex align-items-end"
|
||||
class="btn btn-link pe-0 text-decoration-none evcc-default-text text-nowrap d-flex align-items-end"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#savingsModal"
|
||||
>
|
||||
|
|
@ -31,18 +31,7 @@
|
|||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">
|
||||
<span class="text-nowrap">
|
||||
{{
|
||||
$t("footer.savings.modalTitlePartOne", {
|
||||
total: fmtKw(totalCharged * 1000, true, false),
|
||||
})
|
||||
}}
|
||||
·
|
||||
</span>
|
||||
{{ " " }}
|
||||
<span class="text-nowrap">
|
||||
{{ $t("footer.savings.modalTitlePartTwo", { percent }) }}
|
||||
</span>
|
||||
{{ $t("footer.savings.modalTitle") }}
|
||||
</h5>
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -51,108 +40,66 @@
|
|||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div class="modal-body py-4">
|
||||
<div class="chart-container mb-3">
|
||||
<div
|
||||
class="chart-legend d-flex flex-wrap justify-content-between mb-1"
|
||||
>
|
||||
<div
|
||||
class="text-nowrap"
|
||||
:class="{ 'text-gray-medium': noData }"
|
||||
>
|
||||
<shopicon-filled-square
|
||||
class="text-evcc d-inline-block"
|
||||
:class="{ 'text-gray-medium': noData }"
|
||||
></shopicon-filled-square>
|
||||
{{
|
||||
$t("footer.savings.modalChartSelf", {
|
||||
self: fmtKw(
|
||||
selfConsumptionCharged * 1000,
|
||||
true,
|
||||
false
|
||||
),
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
<div
|
||||
class="text-nowrap"
|
||||
:class="{ 'text-gray-medium': noData }"
|
||||
>
|
||||
{{
|
||||
$t("footer.savings.modalChartGrid", {
|
||||
grid: fmtKw(gridCharged * 1000, true, false),
|
||||
})
|
||||
}}
|
||||
<shopicon-filled-square
|
||||
class="text-grid d-inline-block"
|
||||
:class="{ 'text-gray-medium': noData }"
|
||||
></shopicon-filled-square>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="chart d-flex justify-content-stretch mb-1 rounded overflow-hidden"
|
||||
>
|
||||
<div
|
||||
v-if="!noData"
|
||||
class="chart-item chart-item--self d-flex justify-content-center align-items-center text-white flex-shrink-1"
|
||||
:style="{ width: `${percent}%` }"
|
||||
>
|
||||
<span class="text-truncate"> {{ percent }}% </span>
|
||||
</div>
|
||||
<div
|
||||
v-if="!noData"
|
||||
class="chart-item chart-item--grid d-flex justify-content-center align-items-center text-white flex-shrink-1"
|
||||
:style="{ width: `${100 - percent}%` }"
|
||||
>
|
||||
<span class="text-truncate"> {{ 100 - percent }}% </span>
|
||||
</div>
|
||||
<div
|
||||
v-if="noData"
|
||||
class="chart-item chart-item--no-data d-flex justify-content-center align-items-center text-white w-100"
|
||||
>
|
||||
<span>{{ $t("footer.savings.modalNoData") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-3">
|
||||
{{ $t("footer.savings.modalSavingsPrice") }}:
|
||||
<strong>{{ fmtPricePerKWh(effectivePrice, currency) }}</strong>
|
||||
<br />
|
||||
{{ $t("footer.savings.modalSavingsTotal") }}:
|
||||
<strong>{{ fmtMoney(amount, currency) }}</strong>
|
||||
</p>
|
||||
|
||||
<p class="small text-muted mb-3">
|
||||
<a
|
||||
href="https://docs.evcc.io/docs/guides/setup/#ersparnisberechnung"
|
||||
target="_blank"
|
||||
class="small"
|
||||
>
|
||||
{{ $t("footer.savings.modalExplaination") }}</a
|
||||
>:
|
||||
<span class="text-nowrap">
|
||||
{{
|
||||
$t("footer.savings.modalExplainationGrid", {
|
||||
gridPrice: fmtPricePerKWh(gridPrice, currency),
|
||||
})
|
||||
}}</span
|
||||
>,
|
||||
<span class="text-nowrap">
|
||||
{{
|
||||
$t("footer.savings.modalExplainationFeedIn", {
|
||||
feedInPrice: fmtPricePerKWh(feedInPrice, currency),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<br />
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
{{
|
||||
$t("footer.savings.modalServerStart", {
|
||||
$t("footer.savings.sinceServerStart", {
|
||||
since: fmtTimeAgo(secondsSinceStart()),
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
|
||||
<hr class="mb-4" />
|
||||
<div class="d-block d-lg-flex mb-4">
|
||||
<SavingsTile
|
||||
class="text-accent1"
|
||||
icon="sun"
|
||||
:title="$t('footer.savings.percentTitle')"
|
||||
:value="percent"
|
||||
unit="%"
|
||||
:sub1="
|
||||
$t('footer.savings.percentSelf', {
|
||||
self: fmtKw(selfConsumptionCharged * 1000, true, false),
|
||||
})
|
||||
"
|
||||
:sub2="
|
||||
$t('footer.savings.percentGrid', {
|
||||
grid: fmtKw(gridCharged * 1000, true, false),
|
||||
})
|
||||
"
|
||||
/>
|
||||
|
||||
<SavingsTile
|
||||
class="text-accent2"
|
||||
icon="receivepayment"
|
||||
:title="$t('footer.savings.priceTitle')"
|
||||
:value="effectivePriceFormatted.value"
|
||||
:unit="effectivePriceFormatted.unit"
|
||||
:sub1="
|
||||
$t('footer.savings.priceFeedIn', {
|
||||
feedInPrice: fmtPricePerKWh(feedInPrice, currency),
|
||||
})
|
||||
"
|
||||
:sub2="
|
||||
$t('footer.savings.priceGrid', {
|
||||
gridPrice: fmtPricePerKWh(gridPrice, currency),
|
||||
})
|
||||
"
|
||||
/>
|
||||
|
||||
<SavingsTile
|
||||
class="text-accent3"
|
||||
icon="coinjar"
|
||||
:title="$t('footer.savings.savingsTitle')"
|
||||
:value="fmtMoney(amount, currency)"
|
||||
:unit="fmtCurrencySymbol(currency)"
|
||||
:sub1="$t('footer.savings.savingsComparedToGrid')"
|
||||
:sub2="
|
||||
$t('footer.savings.savingsTotalEnergy', {
|
||||
total: fmtKw(totalCharged * 1000, true, false),
|
||||
})
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Sponsor :sponsor="sponsor" />
|
||||
</div>
|
||||
|
|
@ -166,12 +113,11 @@
|
|||
<script>
|
||||
import formatter from "../mixins/formatter";
|
||||
import Sponsor from "./Sponsor.vue";
|
||||
import "@h2d2/shopicons/es/filled/square";
|
||||
import "@h2d2/shopicons/es/regular/sun";
|
||||
import SavingsTile from "./SavingsTile.vue";
|
||||
|
||||
export default {
|
||||
name: "Savings",
|
||||
components: { Sponsor },
|
||||
components: { Sponsor, SavingsTile },
|
||||
mixins: [formatter],
|
||||
props: {
|
||||
selfConsumptionPercent: Number,
|
||||
|
|
@ -190,8 +136,11 @@ export default {
|
|||
percent() {
|
||||
return Math.round(this.selfConsumptionPercent) || 0;
|
||||
},
|
||||
noData() {
|
||||
return this.totalCharged === 0;
|
||||
effectivePriceFormatted() {
|
||||
const [value, unit] = this.fmtPricePerKWh(this.effectivePrice, this.currency).split(
|
||||
" "
|
||||
);
|
||||
return { value, unit };
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -202,28 +151,6 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
/* make modal a bottom drawer on small screens */
|
||||
@media (max-width: 575px) {
|
||||
.modal-dialog.modal-dialog-centered {
|
||||
align-items: flex-end;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.modal.fade .modal-dialog {
|
||||
transition: transform var(--evcc-transition-medium) ease;
|
||||
transform: translate(0, 150px);
|
||||
}
|
||||
.modal.show .modal-dialog {
|
||||
transform: none;
|
||||
}
|
||||
.modal-dialog-scrollable {
|
||||
height: calc(100% - 0.5rem);
|
||||
}
|
||||
.modal-content {
|
||||
border-end-end-radius: 0;
|
||||
border-end-start-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.chart {
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
|
@ -243,4 +170,7 @@ export default {
|
|||
transition-duration: var(--evcc-transition-medium);
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
.tile-icon {
|
||||
width: 70px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
60
assets/js/components/SavingsTile.vue
Normal file
60
assets/js/components/SavingsTile.vue
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<div class="flex-grow-1 d-flex mb-4 mb-lg-0 align-items-center align-items-lg-start">
|
||||
<shopicon-regular-sun v-if="icon === 'sun'" class="tile-icon"></shopicon-regular-sun>
|
||||
<shopicon-regular-coinjar
|
||||
v-if="icon === 'coinjar'"
|
||||
class="tile-icon"
|
||||
></shopicon-regular-coinjar>
|
||||
<shopicon-regular-receivepayment
|
||||
v-if="icon === 'receivepayment'"
|
||||
class="tile-icon"
|
||||
></shopicon-regular-receivepayment>
|
||||
<div class="ms-3 d-flex flex-grow-1 d-lg-block align-items-center justify-content-between">
|
||||
<div>
|
||||
<p class="my-0 fw-bold">{{ title }}</p>
|
||||
<strong class="d-flex align-items-baseline lh-sm">
|
||||
<span class="fs-1">{{ value }}</span>
|
||||
<span class="ms-1 unit">{{ unit }}</span>
|
||||
</strong>
|
||||
</div>
|
||||
<small
|
||||
class="d-block mt-0 ms-3 ms-lg-0 text-end text-lg-start flex-grow-1 flex-shrink-1"
|
||||
>
|
||||
{{ sub1 }} <br />
|
||||
{{ sub2 }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import "@h2d2/shopicons/es/regular/coinjar";
|
||||
import "@h2d2/shopicons/es/regular/sun";
|
||||
import "@h2d2/shopicons/es/regular/receivepayment";
|
||||
|
||||
export default {
|
||||
name: "SavingsTile",
|
||||
props: {
|
||||
title: String,
|
||||
icon: String,
|
||||
value: String,
|
||||
unit: String,
|
||||
sub1: String,
|
||||
sub2: String,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.tile-icon {
|
||||
width: 40px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
@media (--lg-and-up) {
|
||||
.tile-icon {
|
||||
width: 70px;
|
||||
}
|
||||
}
|
||||
.unit {
|
||||
font-size: var(--bs-body-font-size);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
</div>
|
||||
<Energyflow v-bind="energyflow" />
|
||||
</div>
|
||||
<div class="d-flex flex-column justify-content-between content-area pt-4">
|
||||
<div class="d-flex flex-column justify-content-between content-area">
|
||||
<Loadpoints class="mt-1 mt-sm-2 flex-grow-1" :loadpoints="loadpoints" />
|
||||
<Vehicles v-if="$hiddenFeatures" />
|
||||
<Footer v-bind="footer"></Footer>
|
||||
|
|
@ -137,8 +137,6 @@ export default {
|
|||
min-height: 100vh;
|
||||
}
|
||||
.content-area {
|
||||
background-color: var(--bs-gray-dark);
|
||||
color: var(--bs-white);
|
||||
flex-grow: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,18 @@
|
|||
<p class="mb-3">
|
||||
{{ $t("footer.sponsor.thanks", { sponsor }) }}
|
||||
</p>
|
||||
<div class="d-flex justify-content-center align-items-center flex-column">
|
||||
<div
|
||||
class="d-flex justify-content-center align-items-center flex-column flex-lg-row align-items-lg-baseline justify-content-lg-start"
|
||||
>
|
||||
<button
|
||||
ref="confetti"
|
||||
class="btn btn btn-outline-primary mb-2 confetti-button bg-evcc w-75 rounded"
|
||||
class="btn btn btn-outline-primary mb-2 confetti-button bg-evcc rounded"
|
||||
@click="surprise"
|
||||
>
|
||||
<shopicon-regular-heart class="me-1 d-inline-block"></shopicon-regular-heart>
|
||||
<shopicon-regular-stars class="me-1 d-inline-block"></shopicon-regular-stars>
|
||||
{{ $t("footer.sponsor.confetti") }}
|
||||
</button>
|
||||
<a href="https://evcc.io/sticker" target="_blank" class="small text-muted">
|
||||
<a href="https://evcc.io/sticker" target="_blank" class="small text-muted ms-lg-3">
|
||||
{{ $t("footer.sponsor.sticker") }}
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -21,16 +23,18 @@
|
|||
<p class="mb-3">
|
||||
{{ $t("footer.sponsor.supportUs") }}
|
||||
</p>
|
||||
<div class="d-flex justify-content-center align-items-center flex-column">
|
||||
<div
|
||||
class="d-flex justify-content-center align-items-center flex-column flex-lg-row align-items-lg-baseline justify-content-lg-start"
|
||||
>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://github.com/sponsors/andig"
|
||||
class="btn btn-outline-primary mb-2 w-75"
|
||||
class="btn btn-outline-primary mb-3 become-sponsor"
|
||||
>
|
||||
<shopicon-regular-heart class="me-1 d-inline-block"></shopicon-regular-heart>
|
||||
{{ $t("footer.sponsor.becomeSponsor") }}
|
||||
</a>
|
||||
<div class="small text-muted text-center">
|
||||
<div class="small text-muted text-center ms-lg-3">
|
||||
{{ $t("footer.sponsor.confettiPromise") }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -40,7 +44,7 @@
|
|||
<script>
|
||||
import confetti from "canvas-confetti";
|
||||
import "@h2d2/shopicons/es/regular/heart";
|
||||
import "@h2d2/shopicons/es/filled/heart";
|
||||
import "@h2d2/shopicons/es/regular/stars";
|
||||
|
||||
export default {
|
||||
name: "Sponsor",
|
||||
|
|
@ -90,4 +94,20 @@ export default {
|
|||
touch-action: none;
|
||||
user-select: none;
|
||||
}
|
||||
.confetti-button,
|
||||
.become-sponsor {
|
||||
width: 100%;
|
||||
}
|
||||
@media (--sm-and-up) {
|
||||
.confetti-button,
|
||||
.become-sponsor {
|
||||
width: 75%;
|
||||
}
|
||||
}
|
||||
@media (--lg-and-up) {
|
||||
.confetti-button,
|
||||
.become-sponsor {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
<template>
|
||||
<div>
|
||||
<LabelAndValue class="flex-grow-1" :label="$t('main.targetCharge.title')" on-dark>
|
||||
<LabelAndValue
|
||||
class="root flex-grow-1"
|
||||
:label="$t('main.targetCharge.title')"
|
||||
:class="disabled ? 'opacity-0' : 'opacity-1'"
|
||||
>
|
||||
<button
|
||||
class="btn btn-link p-0 value text-end"
|
||||
:class="buttonIsEnabled ? 'text-white' : 'text-gray-light'"
|
||||
class="btn btn-link p-0 value text-center"
|
||||
:class="targetChargeEnabled ? 'evcc-default-text' : 'text-gray-light'"
|
||||
data-bs-toggle="modal"
|
||||
:data-bs-target="`#${modalId}`"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<strong v-if="targetChargeEnabled">{{ targetTimeLabel() }}</strong>
|
||||
<span v-else>{{ $t("main.targetCharge.setTargetTime") }}</span>
|
||||
|
|
@ -142,9 +147,6 @@ export default {
|
|||
targetChargeEnabled: function () {
|
||||
return this.targetTime;
|
||||
},
|
||||
buttonIsEnabled: function () {
|
||||
return this.targetChargeEnabled && !this.disabled;
|
||||
},
|
||||
selectedTargetTimeValid: function () {
|
||||
const now = new Date();
|
||||
return now < this.selectedTargetTime;
|
||||
|
|
@ -253,7 +255,9 @@ export default {
|
|||
font-size: 18px;
|
||||
line-height: 1.2;
|
||||
border: none;
|
||||
transition: color var(--evcc-transition-medium) linear;
|
||||
}
|
||||
.root {
|
||||
transition: opacity var(--evcc-transition-medium) linear;
|
||||
}
|
||||
.value:hover {
|
||||
color: var(--bs-color-white);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<LabelAndValue class="flex-grow-1" :label="$t('main.vehicle.targetSoC')" :on-dark="true">
|
||||
<LabelAndValue class="flex-grow-1" :label="$t('main.vehicle.targetSoC')">
|
||||
<h3 class="value m-0">
|
||||
<label class="d-inline-block position-relative">
|
||||
<select :value="targetSoc" class="custom-select" @change="change">
|
||||
|
|
@ -48,7 +48,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
change: function (e) {
|
||||
return this.$emit("target-soc-updated", e.target.value);
|
||||
return this.$emit("target-soc-updated", parseInt(e.target.value, 10));
|
||||
},
|
||||
estimatedRange: function (soc) {
|
||||
if (this.rangePerSoc) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
aria-controls="navbarNavAltMarkup"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
class="btn btn-sm btn-outline-secondary position-relative"
|
||||
class="btn btn-sm btn-outline-secondary position-relative border-0 menu-button"
|
||||
>
|
||||
<span
|
||||
v-if="logoutCount > 0"
|
||||
|
|
@ -102,3 +102,8 @@ export default {
|
|||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.menu-button {
|
||||
margin-right: -0.7rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Vehicle from "./Vehicle.vue";
|
|||
export default {
|
||||
title: "Main/Vehicle",
|
||||
component: Vehicle,
|
||||
parameters: { backgrounds: { default: "box" } },
|
||||
};
|
||||
|
||||
const Template = (args) => ({
|
||||
|
|
@ -11,6 +12,7 @@ const Template = (args) => ({
|
|||
},
|
||||
components: { Vehicle },
|
||||
template: '<Vehicle v-bind="args"></Vehicle>',
|
||||
parameters: { backgrounds: { default: "box" } },
|
||||
});
|
||||
|
||||
export const Base = Template.bind({});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="vehicle p-4 pb-3">
|
||||
<div class="vehicle pt-4">
|
||||
<VehicleTitle v-bind="vehicleTitleProps" />
|
||||
<VehicleStatus v-if="!parked" v-bind="vehicleStatus" class="mb-2" />
|
||||
<VehicleSoc
|
||||
|
|
@ -13,23 +13,22 @@
|
|||
<LabelAndValue
|
||||
class="flex-grow-1 text-start"
|
||||
:label="$t('main.vehicle.vehicleSoC')"
|
||||
:value="`${vehicleSoC || '--'} %`"
|
||||
:value="vehicleSoC ? `${vehicleSoC}%` : '--'"
|
||||
:extraValue="vehicleRange ? `${vehicleRange} km` : null"
|
||||
on-dark
|
||||
/>
|
||||
<TargetSoCSelect
|
||||
class="flex-grow-1 text-center"
|
||||
:target-soc="displayTargetSoC"
|
||||
:range-per-soc="rangePerSoC"
|
||||
@target-soc-updated="targetSocUpdated"
|
||||
/>
|
||||
<TargetCharge
|
||||
class="flex-grow-1 text-end target-charge"
|
||||
class="flex-grow-1 text-center target-charge"
|
||||
v-bind="targetCharge"
|
||||
:disabled="targetChargeDisabled"
|
||||
@target-time-updated="setTargetTime"
|
||||
@target-time-removed="removeTargetTime"
|
||||
/>
|
||||
<TargetSoCSelect
|
||||
class="flex-grow-1 text-end"
|
||||
:target-soc="displayTargetSoC"
|
||||
:range-per-soc="rangePerSoC"
|
||||
@target-soc-updated="targetSocUpdated"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="$hiddenFeatures" class="d-flex justify-content-start">
|
||||
<small>vor 5 Stunden</small>
|
||||
|
|
@ -132,11 +131,6 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.vehicle {
|
||||
background-color: var(--bs-gray-dark);
|
||||
border-radius: 1rem;
|
||||
color: var(--bs-white);
|
||||
}
|
||||
.car-icon {
|
||||
width: 1.75rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,21 +101,23 @@ export default {
|
|||
e.stopPropagation();
|
||||
},
|
||||
changeTargetSoCEnd: function (e) {
|
||||
const value = parseInt(e.target.value, 10);
|
||||
// value changed
|
||||
if (e.target.value !== this.targetSoC) {
|
||||
this.$emit("target-soc-updated", e.target.value);
|
||||
if (value !== this.targetSoC) {
|
||||
this.$emit("target-soc-updated", value);
|
||||
}
|
||||
},
|
||||
movedTargetSoC: function (e) {
|
||||
let value = parseInt(e.target.value, 10);
|
||||
e.stopPropagation();
|
||||
const minTargetSoC = 20;
|
||||
if (e.target.value < minTargetSoC) {
|
||||
if (value < minTargetSoC) {
|
||||
e.target.value = minTargetSoC;
|
||||
this.selectedTargetSoC = e.target.value;
|
||||
this.selectedTargetSoC = value;
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
this.selectedTargetSoC = e.target.value;
|
||||
this.selectedTargetSoC = value;
|
||||
|
||||
this.$emit("target-soc-drag", this.selectedTargetSoC);
|
||||
return true;
|
||||
|
|
@ -135,9 +137,10 @@ export default {
|
|||
.progress {
|
||||
height: 100%;
|
||||
font-size: 1rem;
|
||||
background: var(--evcc-background);
|
||||
}
|
||||
.progress-bar.bg-muted {
|
||||
color: var(--white);
|
||||
opacity: 0.5;
|
||||
}
|
||||
.bg-light {
|
||||
color: var(--bs-gray-dark);
|
||||
|
|
@ -179,7 +182,7 @@ export default {
|
|||
border: none;
|
||||
opacity: 1;
|
||||
border-radius: var(--thumb-overlap);
|
||||
box-shadow: 0 0 6px var(--bs-gray-dark);
|
||||
box-shadow: 0 0 6px var(--evcc-background);
|
||||
pointer-events: auto;
|
||||
}
|
||||
.target-slider::-moz-range-thumb {
|
||||
|
|
@ -191,7 +194,7 @@ export default {
|
|||
border: none;
|
||||
opacity: 1;
|
||||
border-radius: var(--thumb-overlap);
|
||||
box-shadow: 0 0 6px var(--bs-gray-dark);
|
||||
box-shadow: 0 0 6px var(--evcc-background);
|
||||
pointer-events: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="d-block text-gray-light">{{ message }} </div>
|
||||
<div class="d-block evcc-gray">{{ message }} </div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
></shopicon-regular-cablecharge>
|
||||
<span class="flex-grow-1 text-truncate"> {{ name }} </span>
|
||||
</h4>
|
||||
<button v-if="$hiddenFeatures" class="btn btn-link text-white p-0 flex-shrink-0">
|
||||
<button v-if="$hiddenFeatures" class="btn btn-link evcc-default-text p-0 flex-shrink-0">
|
||||
<shopicon-filled-options size="s"></shopicon-filled-options>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<div class="container px-4 mb-3 mb-sm-4 d-flex justify-content-start align-items-center">
|
||||
<h2 class="m-0">{{ $t("main.vehicles") }}</h2>
|
||||
<button
|
||||
class="btn btn-link d-flex text-white p-2 ms-1 refresh"
|
||||
class="btn btn-link d-flex evcc-default-text p-2 ms-1 refresh"
|
||||
:class="{
|
||||
'refresh--in-progress': refreshing,
|
||||
}"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
v-if="commit"
|
||||
:href="githubHashUrl"
|
||||
target="_blank"
|
||||
class="btn btn-link ps-0 text-decoration-none text-white text-nowrap d-flex align-items-end"
|
||||
class="btn btn-link ps-0 text-decoration-none evcc-default-text text-nowrap d-flex align-items-end"
|
||||
>
|
||||
<Logo class="logo me-2" />
|
||||
v{{ installed }}
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
href="#"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#updateModal"
|
||||
class="btn btn-link ps-0 text-decoration-none text-white text-nowrap d-flex align-items-end"
|
||||
class="btn btn-link ps-0 text-decoration-none evcc-default-text text-nowrap d-flex align-items-end"
|
||||
>
|
||||
<shopicon-regular-gift class="me-2 text-evcc"></shopicon-regular-gift>
|
||||
v{{ installed }}
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
v-else
|
||||
:href="releaseNotesUrl(installed)"
|
||||
target="_blank"
|
||||
class="btn btn-link text-white ps-0 text-decoration-none text-nowrap d-flex align-items-end"
|
||||
class="btn btn-link evcc-default-text ps-0 text-decoration-none text-nowrap d-flex align-items-end"
|
||||
>
|
||||
<Logo class="logo me-2" />
|
||||
v{{ installed }}
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
import WaitingDots from "./WaitingDots.vue";
|
||||
|
||||
export default {
|
||||
title: "Main/WaitingDots",
|
||||
component: WaitingDots,
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
const Template = (args, { argTypes }) => ({
|
||||
props: Object.keys(argTypes),
|
||||
components: { WaitingDots },
|
||||
template: '<WaitingDots v-bind="$props"></WaitingDots>',
|
||||
});
|
||||
|
||||
export const HorizontalUp = Template.bind({});
|
||||
HorizontalUp.args = {
|
||||
orientation: "horizontal",
|
||||
direction: "up",
|
||||
};
|
||||
export const HorizontalDown = Template.bind({});
|
||||
HorizontalDown.args = {
|
||||
orientation: "horizontal",
|
||||
direction: "down",
|
||||
};
|
||||
export const VerticalUp = Template.bind({});
|
||||
VerticalUp.args = {
|
||||
orientation: "vertical",
|
||||
direction: "up",
|
||||
};
|
||||
export const VerticalDown = Template.bind({});
|
||||
VerticalDown.args = {
|
||||
orientation: "vertical",
|
||||
direction: "down",
|
||||
};
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
<template>
|
||||
<div class="root position-relative" :class="`direction-${direction}`">
|
||||
<shopicon-filled-options class="dots dots-back"></shopicon-filled-options
|
||||
><shopicon-filled-options
|
||||
class="dots dots-front position-absolute start-0 top-0"
|
||||
></shopicon-filled-options>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import "@h2d2/shopicons/es/filled/options";
|
||||
|
||||
export default {
|
||||
name: "WaitingDots",
|
||||
props: {
|
||||
direction: { type: String, default: "up" },
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dots {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
}
|
||||
.dots-front,
|
||||
.dots-back {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dots-back {
|
||||
opacity: 0.25;
|
||||
}
|
||||
.dots-front {
|
||||
opacity: 1;
|
||||
}
|
||||
.direction-up .dots-front {
|
||||
animation: dots-vertical 2s infinite normal steps(4, jump-none);
|
||||
}
|
||||
.direction-down .dots-front {
|
||||
animation: dots-vertical 2s infinite reverse steps(4, jump-none);
|
||||
}
|
||||
|
||||
@keyframes dots-vertical {
|
||||
25% {
|
||||
clip-path: inset(100% 0 0 0);
|
||||
}
|
||||
75% {
|
||||
clip-path: inset(0 0 0 0);
|
||||
}
|
||||
}
|
||||
|
||||
.root ::v-deep(svg) {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -25,26 +25,26 @@ export default {
|
|||
savings: {
|
||||
footerShort: "{percent}% Sonne",
|
||||
footerLong: "{percent}% Sonnenenergie",
|
||||
modalTitlePartOne: "{total} kWh geladen",
|
||||
modalTitlePartTwo: "{percent}% Sonne",
|
||||
modalChartGrid: "Netz {grid} kWh",
|
||||
modalChartSelf: "Sonne {self} kWh",
|
||||
modalSavingsPrice: "Effektiver Energiepreis",
|
||||
modalSavingsTotal: "Ersparnis gegenüber Netzbezug",
|
||||
modalExplaination: "Berechnung",
|
||||
modalExplainationGrid: "Netz {gridPrice}",
|
||||
modalExplainationFeedIn: "Einspeisung {feedInPrice}",
|
||||
modalServerStart: "Seit Serverstart {since}.",
|
||||
modalNoData: "noch nicht geladen",
|
||||
modalTitle: "Auswertung Ladeenergie",
|
||||
sinceServerStart: "Seit Serverstart {since}.",
|
||||
percentTitle: "Sonnenenergie",
|
||||
percentSelf: "{self} kWh Sonne",
|
||||
percentGrid: "{grid} kWh Netz",
|
||||
priceTitle: "Energiepreis",
|
||||
priceFeedIn: "{feedInPrice} Einpeisung",
|
||||
priceGrid: "{gridPrice} Netz",
|
||||
savingsTitle: "Ersparnis",
|
||||
savingsComparedToGrid: "gegenüber Netzbezug",
|
||||
savingsTotalEnergy: "{total} kWh geladen",
|
||||
},
|
||||
sponsor: {
|
||||
thanks: "Danke für deine Unterstützung, {sponsor}! Das hilft uns bei der Weiterentwicklung.",
|
||||
confetti: "Lust auf etwas Sponsor-Konfetti?",
|
||||
confetti: "Lust auf Konfetti?",
|
||||
supportUs:
|
||||
"Wir möchten effizientes Zuhause-Laden zum Standard für möglichst viele Menschen machen. Helfe uns indem du die Weiterentwicklung und Pflege des Projekts unterstützt.",
|
||||
"Unsere Mission: Sonne tanken zum Standard machen. Hilf uns und unterstütze evcc finanziell.",
|
||||
sticker: "...oder evcc Sticker?",
|
||||
confettiPromise: "Es gibt auch Sticker und digitales Konfetti ;)",
|
||||
becomeSponsor: "Werde jetzt GitHub Sponsor",
|
||||
becomeSponsor: "Sponsor werden",
|
||||
},
|
||||
},
|
||||
notifications: {
|
||||
|
|
@ -65,16 +65,10 @@ export default {
|
|||
pvExport: "Einspeisung",
|
||||
},
|
||||
mode: {
|
||||
offShort: "Aus",
|
||||
offLong: "Aus",
|
||||
nowShort: "Sofort",
|
||||
nowLong: "Sofort",
|
||||
minpvShort: "Min",
|
||||
minpvLong: "Min + PV",
|
||||
pvShort: "PV",
|
||||
pvLong: "PV",
|
||||
fast: "Schnell",
|
||||
cheap: "Günstig",
|
||||
off: "Aus",
|
||||
minpv: "Min+PV",
|
||||
pv: "PV",
|
||||
now: "Schnell",
|
||||
},
|
||||
loadpoint: {
|
||||
fallbackName: "Ladepunkt",
|
||||
|
|
|
|||
|
|
@ -25,26 +25,26 @@ export default {
|
|||
savings: {
|
||||
footerShort: "{percent}% solar",
|
||||
footerLong: "{percent}% solar energy",
|
||||
modalTitlePartOne: "{total} kWh charged",
|
||||
modalTitlePartTwo: "{percent}% solar",
|
||||
modalChartGrid: "Grid {grid} kWh",
|
||||
modalChartSelf: "Solar {self} kWh",
|
||||
modalSavingsPrice: "Effective energy price",
|
||||
modalSavingsTotal: "Savings compared to grid",
|
||||
modalExplaination: "Calculation",
|
||||
modalExplainationGrid: "grid tariff {gridPrice}",
|
||||
modalExplainationFeedIn: "feed-in rate {feedInPrice}",
|
||||
modalServerStart: "since server start {since}.",
|
||||
modalNoData: "nothing charged yet",
|
||||
modalTitle: "Charge Energy Overview",
|
||||
sinceServerStart: "Since server start {since}.",
|
||||
percentTitle: "Solar Energy",
|
||||
percentSelf: "{self} kWh solar",
|
||||
percentGrid: "{grid} kWh grid",
|
||||
priceTitle: "Energy Price",
|
||||
priceFeedIn: "{feedInPrice} feed-in",
|
||||
priceGrid: "{gridPrice} grid",
|
||||
savingsTitle: "Savings",
|
||||
savingsComparedToGrid: "compared to grid",
|
||||
savingsTotalEnergy: "{total} kWh charged",
|
||||
},
|
||||
sponsor: {
|
||||
thanks: "Thanks for your support, {sponsor}! It helps us with the further development.",
|
||||
confetti: "Ready for some sponsor confetti?",
|
||||
confetti: "Ready for confetti?",
|
||||
supportUs:
|
||||
"We want to make efficient home charging the standard for as many people as possible. Help us by supporting the further development and maintenance of the project.",
|
||||
"Our mission: Make solar charging the standard. Help us and support evcc financially.",
|
||||
sticker: "...or evcc stickers?",
|
||||
confettiPromise: "There will be stickers and digital confetti ;)",
|
||||
becomeSponsor: "Become a GitHub Sponsor",
|
||||
becomeSponsor: "Become a Sponsor",
|
||||
},
|
||||
},
|
||||
notifications: {
|
||||
|
|
@ -65,16 +65,10 @@ export default {
|
|||
pvExport: "Grid export",
|
||||
},
|
||||
mode: {
|
||||
offShort: "Stop",
|
||||
offLong: "Stop",
|
||||
nowShort: "Now",
|
||||
nowLong: "Now",
|
||||
minpvShort: "Min",
|
||||
minpvLong: "Min + PV",
|
||||
pvShort: "PV",
|
||||
pvLong: "PV",
|
||||
fast: "Fast",
|
||||
cheap: "Cheap",
|
||||
off: "Off",
|
||||
minpv: "Min+PV",
|
||||
pv: "PV",
|
||||
now: "Fast",
|
||||
},
|
||||
loadpoint: {
|
||||
fallbackName: "Loadpoint",
|
||||
|
|
|
|||
|
|
@ -46,13 +46,10 @@ export default {
|
|||
pvExport: "Grid export",
|
||||
},
|
||||
mode: {
|
||||
title: "Modalità",
|
||||
stop: "Stop",
|
||||
minpv: "Min+FV",
|
||||
pv: "FV",
|
||||
now: "Ora",
|
||||
minpvShort: "Min",
|
||||
minpvLong: "Min + FV",
|
||||
pvShort: "FV",
|
||||
pvLong: "Solo FV",
|
||||
},
|
||||
loadpoint: {
|
||||
fallbackName: "Punto di carica",
|
||||
|
|
|
|||
|
|
@ -24,26 +24,26 @@ export default {
|
|||
savings: {
|
||||
footerShort: "{percent}% saulės",
|
||||
footerLong: "{percent}% saulės energija",
|
||||
modalTitlePartOne: "{total} kWh įkrauta",
|
||||
modalTitlePartTwo: "{percent}% saulės",
|
||||
modalChartGrid: "Energija iš tinklo {grid} kWh",
|
||||
modalChartSelf: "Saulės energija {self} kWh",
|
||||
modalSavingsPrice: "Faktinė energijos kaina",
|
||||
modalSavingsTotal: "Sutaupyta, palyginus su tinklu",
|
||||
modalExplaination: "Skaičiavimas",
|
||||
modalExplainationGrid: "kaina iš tinklo {gridPrice}",
|
||||
modalExplainationFeedIn: "kompensavimas už patiektą į tinklą energiją {feedInPrice}",
|
||||
modalServerStart: "nuo EVCC starto {since}.",
|
||||
modalNoData: "įkrovimo duomenų dar nėra",
|
||||
modalTitle: "Įkrovimo energijos apžvalga",
|
||||
sinceServerStart: "nuo evcc starto {since}.",
|
||||
percentTitle: "Saulės energija",
|
||||
percentSelf: "{self} kWh saulės",
|
||||
percentGrid: "{grid} kWh tinklas",
|
||||
priceTitle: "Energijos kaina",
|
||||
priceFeedIn: "{feedInPrice} eksporto",
|
||||
priceGrid: "{gridPrice} tinklo",
|
||||
savingsTitle: "Sutaupyta",
|
||||
savingsComparedToGrid: "palyginus su tinklu",
|
||||
savingsTotalEnergy: "{total} kWh įkrauta",
|
||||
},
|
||||
sponsor: {
|
||||
thanks: "Ačiū, kad mus remiate {sponsor}! Taip prisidedate prie projekto vystymo.",
|
||||
confetti: "Ar pasiruošę priimti rėmėjo konfeti?",
|
||||
confetti: "Norite konfeti?",
|
||||
supportUs:
|
||||
"Norime, kad efektyvesnis elektromobilių įkrovimas saulės energija taptų pasiekiamas kuo daugiau žmonių. Remdami prisidedate prie nuolatinio projekto vystymo ir techninio palaikymo.",
|
||||
sticker: "... ar EVCC lipdukų?",
|
||||
"Mūsų misija: Siekiame, kad įkrovimas saulės energija taptų standartu. Padėkite mums ir paremkite evcc finansiškai.",
|
||||
sticker: "... ar evcc lipdukų?",
|
||||
confettiPromise: "Gausite lipdukų ir skaitmeninių konfeti ;)",
|
||||
becomeSponsor: "Pradėkite GitHub rėmimą!",
|
||||
becomeSponsor: "Tapkite rėmėju",
|
||||
},
|
||||
},
|
||||
notifications: {
|
||||
|
|
@ -64,16 +64,10 @@ export default {
|
|||
pvExport: "Tinklo eksportas",
|
||||
},
|
||||
mode: {
|
||||
offShort: "Stop",
|
||||
offLong: "Stop",
|
||||
nowShort: "Dabar",
|
||||
nowLong: "Dabar",
|
||||
minpvShort: "Min",
|
||||
minpvLong: "Min + PV",
|
||||
pvShort: "PV",
|
||||
pvLong: "PV",
|
||||
fast: "Greitai",
|
||||
cheap: "Pigiai",
|
||||
off: "Stop",
|
||||
minpv: "Min+PV",
|
||||
pv: "PV",
|
||||
now: "Greitas",
|
||||
},
|
||||
loadpoint: {
|
||||
fallbackName: "Įkroviklis",
|
||||
|
|
|
|||
|
|
@ -128,7 +128,15 @@ export default {
|
|||
return new Intl.NumberFormat(this.$i18n.locale, {
|
||||
style: "currency",
|
||||
currency,
|
||||
}).format(amout);
|
||||
currencyDisplay: "code",
|
||||
})
|
||||
.format(amout)
|
||||
.replace(currency, "")
|
||||
.trim();
|
||||
},
|
||||
fmtCurrencySymbol: function (currency = "EUR") {
|
||||
const symbols = { EUR: "€", USD: "$" };
|
||||
return symbols[currency] || currency;
|
||||
},
|
||||
fmtPricePerKWh: function (amout = 0, currency = "EUR") {
|
||||
let unit = currency;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,5 @@ export default {
|
|||
<style scoped>
|
||||
.app {
|
||||
min-height: 100vh;
|
||||
background-color: white;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
93
dist/assets/index.969c8832.js
vendored
93
dist/assets/index.969c8832.js
vendored
File diff suppressed because one or more lines are too long
93
dist/assets/index.f2e7fb95.js
vendored
Normal file
93
dist/assets/index.f2e7fb95.js
vendored
Normal file
File diff suppressed because one or more lines are too long
8
dist/index.html
vendored
8
dist/index.html
vendored
|
|
@ -5,7 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="evcc - Sonne tanken ☀️🚘" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="evcc" />
|
||||
<meta name="application-name" content="evcc" />
|
||||
|
||||
|
|
@ -17,11 +17,11 @@
|
|||
<link rel="shortcut icon" href="meta/favicon.ico?[[.Version]]" />
|
||||
<meta name="msapplication-TileColor" content="#28293e" />
|
||||
<meta name="msapplication-config" content="meta/browserconfig.xml?[[.Version]]" />
|
||||
<meta name="theme-color" content="#28293e" />
|
||||
<meta name="theme-color" content="#020318" />
|
||||
|
||||
<title>evcc</title>
|
||||
<script type="module" crossorigin src="./assets/index.969c8832.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.dca955c6.css">
|
||||
<script type="module" crossorigin src="./assets/index.f2e7fb95.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.49c54bb1.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
|
|
|||
22259
package-lock.json
generated
22259
package-lock.json
generated
File diff suppressed because it is too large
Load diff
21
package.json
21
package.json
|
|
@ -6,9 +6,9 @@
|
|||
"build": "vite build",
|
||||
"test": "",
|
||||
"lint": "prettier assets './**/*.{yml,yaml}' --write && eslint assets/**/*.js assets/**/*.vue --fix",
|
||||
"build-storybook": "build-storybook",
|
||||
"dev": "vite",
|
||||
"storybook": "start-storybook -p 6006"
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"build-storybook": "build-storybook"
|
||||
},
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
|
|
@ -26,10 +26,13 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.2",
|
||||
"@storybook/addon-actions": "^6.5.0-alpha.38",
|
||||
"@storybook/addon-essentials": "^6.5.0-alpha.38",
|
||||
"@storybook/addon-links": "^6.5.0-alpha.38",
|
||||
"@storybook/vue3": "^6.5.0-alpha.38",
|
||||
"@storybook/addon-actions": "^6.5.9",
|
||||
"@storybook/addon-essentials": "^6.5.9",
|
||||
"@storybook/addon-interactions": "^6.5.9",
|
||||
"@storybook/addon-links": "^6.5.9",
|
||||
"@storybook/builder-vite": "^0.1.37",
|
||||
"@storybook/testing-library": "^0.0.13",
|
||||
"@storybook/vue3": "^6.5.9",
|
||||
"@vue/compiler-sfc": "^3.2.30",
|
||||
"@vue/eslint-config-standard": "^6.1.0",
|
||||
"babel-loader": "^8.2.3",
|
||||
|
|
@ -42,9 +45,11 @@
|
|||
"eslint-plugin-standard": "^5.0.0",
|
||||
"eslint-plugin-storybook": "^0.5.6",
|
||||
"eslint-plugin-vue": "^7.20.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"postcss-custom-media": "^8.0.2",
|
||||
"prettier": "^2.5.1",
|
||||
"storybook-builder-vite": "^0.1.15",
|
||||
"vite": "^2.7.13"
|
||||
"vite": "^2.7.13",
|
||||
"vue-loader": "^16.8.3"
|
||||
},
|
||||
"engines": {
|
||||
"npm": ">=8.0.0",
|
||||
|
|
|
|||
5
postcss.config.js
Normal file
5
postcss.config.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
const postcssCustomMedia = require("postcss-custom-media");
|
||||
|
||||
module.exports = {
|
||||
plugins: [postcssCustomMedia()],
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue