Statistics styling

This commit is contained in:
baldo 2022-05-23 13:23:37 +02:00
parent 6c47c5b178
commit 3ce2ba5013
6 changed files with 198 additions and 19 deletions

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import {RouterLink, RouterView} from "vue-router";
import PageHeader from "@/components/PageHeader.vue";
import PageFooter from "@/components/PageFooter.vue";
import PageHeader from "@/components/page/PageHeader.vue";
import PageFooter from "@/components/page/PageFooter.vue";
</script>
<template>

View file

@ -0,0 +1,113 @@
<script setup lang="ts">
import {computed, defineProps} from "vue";
const {
title,
icon,
variant,
value,
link,
filter,
} = defineProps({
title: {
type: String,
required: true,
},
icon: {
type: String,
required: true,
},
variant: {
type: String,
required: true,
},
value: {
type: Number,
required: true,
},
link: {
type: String,
required: true,
},
filter: {
type: Object,
required: false,
},
});
const linkTarget = computed(() => {
if (filter) {
const json = JSON.stringify(filter);
return `${link}?search=${encodeURIComponent(json)}`;
} else {
return link;
}
});
</script>
<template>
<RouterLink :to="linkTarget" :class="['statistics-card', 'statistics-card-' + variant]">
<i :class="['fa', 'fa-' + icon]" aria-hidden="true" />
<dl>
<dt>{{ title }}</dt>
<dd>{{ value }}</dd>
</dl>
</RouterLink>
</template>
<style lang="scss" scoped>
@import "../../scss/variables";
.statistics-card {
display: flex;
min-height: $statistics-card-height;
margin: $statistics-card-margin;
padding: $statistics-card-padding;
border-radius: $statistics-card-border-radius;
@each $variant, $color in $variant-colors {
&.statistics-card-#{$variant} {
background-color: $color;
color: map-get($variant-text-colors, $variant);
}
}
i {
display: inline-block;
margin-right: $statistics-card-icon-gap;
font-size: $statistics-card-icon-size;
width: 1em;
text-align: center;
}
dl {
position: relative;
flex-grow: 1;
box-sizing: border-box;
height: 100%;
margin: 0;
text-align: right;
dt {
position: absolute;
bottom: 0;
right: 0;
}
dd {
position: absolute;
top: 0;
right: 0;
font-weight: bold;
font-size: $statistics-card-value-font-size;
}
}
}
</style>

View file

@ -35,7 +35,7 @@ refresh();
<style lang="scss" scoped>
@use "sass:math";
@import "../scss/variables";
@import "../../scss/variables";
footer {
position: absolute;

View file

@ -36,7 +36,7 @@ refresh();
</template>
<style lang="scss" scoped>
@import "../scss/variables";
@import "../../scss/variables";
header {
background-color: $nav-bar-background-color;

View file

@ -1,17 +1,34 @@
// Grays
$black: #000000;
$gray-darkest: #222222;
$gray-darker: #333333;
$gray-dark: #444444;
$gray: #666666;
$gray-light: #d6d6d6;
$gray-lighter: #ededed;
$white: #ffffff;
// Colors
$color-primary: #e5287a;
$color-success: #449d44;
$color-warning: #fdbc41;
$color-danger: #c9302c;
$color-info: #009ee0;
$variant-colors: (
primary: #e5287a,
success: #4ba74b,
warning: #fdbc41,
danger: #ef5652,
info: #009ee0,
);
$variant-text-colors: (
// primary: do not use, contrast too low
success: $gray-darkest,
warning: $gray-darkest,
danger: $gray-darkest,
info: $gray-darkest,
);
$variant-color-primary: map-get($variant-colors, primary);
$variant-color-success: map-get($variant-colors, success);
$variant-color-warning: map-get($variant-colors, warning);
$variant-color-danger: map-get($variant-colors, danger);
$variant-color-info: map-get($variant-colors, info);
// Page
$page-background-color: $gray-darkest;
@ -19,7 +36,7 @@ $page-text-color: $gray-lighter;
$page-padding: 0.5em;
// Links
$link-color: $color-warning;
$link-color: $variant-color-warning;
// Navigation
$nav-bar-background-color: $gray-darker;
@ -31,3 +48,12 @@ $nav-header-logo-size: 2em;
$nav-header-logo-margin: 0 0.5em 0 0;
$nav-footer-padding: 0.75em;
// Statistics
$statistics-card-height: 4.5em;
$statistics-card-margin: 0.5em;
$statistics-card-padding: 0.3em 0.5em;
$statistics-card-border-radius: 0.5em;
$statistics-card-icon-size: 4em;
$statistics-card-icon-gap: 0.15em;
$statistics-card-value-font-size: 2.5em;

View file

@ -1,4 +1,5 @@
<script setup lang="ts">
import StatisticsCard from "@/components/admin/StatisticsCard.vue";
import { useStatisticsStore } from "@/stores/statistics";
const statistics = useStatisticsStore();
@ -13,18 +14,57 @@ refresh();
<template>
<main>
<div v-if="statistics.getStatistics">
<h1>Nodes</h1>
<h2>Knotenstatistik</h2>
<div>
Registered: {{ statistics.getStatistics.nodes.registered }}<br />
With VPN-key: {{ statistics.getStatistics.nodes.withVPN }}<br />
With coordinates: {{ statistics.getStatistics.nodes.withCoords }}<br />
Monitoring active: {{ statistics.getStatistics.nodes.monitoring.active }}<br />
Monitoring pending: {{ statistics.getStatistics.nodes.monitoring.pending }}
<div class="statistics">
<StatisticsCard
title="Registrierte Knoten"
icon="circle-o"
variant="info"
:value="statistics.getStatistics.nodes.registered"
link="/admin/nodes"
/>
<StatisticsCard
title="Mit hinterlegtem fastd-Key"
icon="lock"
variant="warning"
:value="statistics.getStatistics.nodes.withVPN"
link="/admin/nodes"
:filter="{hasKey: true}"
/>
<StatisticsCard
title="Mit Koordinaten"
icon="map-marker"
variant="success"
:value="statistics.getStatistics.nodes.withCoords"
link="/admin/nodes"
:filter="{hasCoords: true}"
/>
<StatisticsCard
title="Monitoring aktiv"
icon="heartbeat"
variant="success"
:value="statistics.getStatistics.nodes.monitoring.active"
link="/admin/nodes"
:filter="{monitoringState: 'active'}"
/>
<StatisticsCard
title="Monitoring noch nicht bestätigt"
icon="envelope"
variant="danger"
:value="statistics.getStatistics.nodes.monitoring.pending"
link="/admin/nodes"
:filter="{monitoringState: 'pending'}"
/>
</div>
<button @click="refresh()">Refresh</button>
</div>
</main>
</template>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.statistics {
display: grid;
// TODO: Responsive sizes
grid-template-columns: repeat(auto-fill, minmax(25%, 100%));
}
</style>