Introduced ActionButton component as a replacement for HTML's button.
This commit is contained in:
parent
d159e22c50
commit
215f70db26
|
@ -41,34 +41,4 @@ a {
|
||||||
outline: 0.1em solid $link-hover-color;
|
outline: 0.1em solid $link-hover-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
|
||||||
padding: $button-padding;
|
|
||||||
border-radius: $button-border-radius;
|
|
||||||
border-width: $button-border-width;
|
|
||||||
border-style: $button-border-style;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
@each $variant, $color in $variant-colors {
|
|
||||||
&.#{$variant} {
|
|
||||||
background-color: map-get($variant-text-colors, $variant);
|
|
||||||
border-color: $color;
|
|
||||||
color: $color;
|
|
||||||
|
|
||||||
&:hover, &:active {
|
|
||||||
background-color: $color;
|
|
||||||
border-color: $color;
|
|
||||||
color: map-get($variant-text-colors, $variant);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
background-color: $color;
|
|
||||||
border-color: $page-background-color;
|
|
||||||
color: map-get($variant-text-colors, $variant);
|
|
||||||
outline: 0.1em solid $color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, defineProps} from "vue";
|
import {computed, defineProps} from "vue";
|
||||||
import type {NodesFilter} from "@/types";
|
import type {ComponentVariant, NodesFilter} from "@/types";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
variant: string;
|
variant: ComponentVariant;
|
||||||
value: number;
|
value: number;
|
||||||
link: string;
|
link: string;
|
||||||
filter?: NodesFilter;
|
filter?: NodesFilter;
|
||||||
|
@ -29,7 +29,7 @@ const linkTarget = computed(() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<RouterLink :to="linkTarget" :class="['statistics-card', 'statistics-card-' + variant]">
|
<RouterLink :to="linkTarget" :class="['statistics-card', 'statistics-card-' + variant]">
|
||||||
<i :class="['fa', 'fa-' + icon]" aria-hidden="true" />
|
<i :class="['fa', 'fa-' + icon]" aria-hidden="true"/>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>{{ title }}</dt>
|
<dt>{{ title }}</dt>
|
||||||
<dd>{{ value }}</dd>
|
<dd>{{ value }}</dd>
|
||||||
|
|
70
frontend/src/components/form/ActionButton.vue
Normal file
70
frontend/src/components/form/ActionButton.vue
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type {ButtonSize, ComponentVariant} from "@/types";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
variant: ComponentVariant;
|
||||||
|
size: ButtonSize;
|
||||||
|
icon: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "click"): void,
|
||||||
|
}>();
|
||||||
|
|
||||||
|
function onClick() {
|
||||||
|
emit("click");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<button :class="[size, variant]" @click="onClick">
|
||||||
|
<i :class="['fa', `fa-${icon}`]" aria-hidden="true"/>
|
||||||
|
<slot></slot>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../scss/variables";
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 0.3em;
|
||||||
|
|
||||||
|
padding: $button-padding;
|
||||||
|
border-radius: $button-border-radius;
|
||||||
|
border-width: $button-border-width;
|
||||||
|
border-style: $button-border-style;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
@each $variant, $color in $variant-colors {
|
||||||
|
&.#{$variant} {
|
||||||
|
background-color: $color;
|
||||||
|
border-color: $color;
|
||||||
|
color: map-get($variant-text-colors, $variant);
|
||||||
|
|
||||||
|
&:hover, &:active {
|
||||||
|
background-color: $page-background-color;
|
||||||
|
border-color: $color;
|
||||||
|
color: $color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background-color: $color;
|
||||||
|
border-color: $page-background-color;
|
||||||
|
color: map-get($variant-text-colors, $variant);
|
||||||
|
outline: $color solid $button-outline-width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $size, $font-size in $button-sizes {
|
||||||
|
&.#{$size} {
|
||||||
|
font-size: $font-size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -17,11 +17,11 @@ $variant-colors: (
|
||||||
info: #0097c4,
|
info: #0097c4,
|
||||||
);
|
);
|
||||||
$variant-text-colors: (
|
$variant-text-colors: (
|
||||||
// primary: do not use, contrast too low
|
primary: $black,
|
||||||
success: $gray-darkest,
|
success: $black,
|
||||||
warning: $gray-darkest,
|
warning: $black,
|
||||||
danger: $gray-darkest,
|
danger: $black,
|
||||||
info: $gray-darkest,
|
info: $black,
|
||||||
);
|
);
|
||||||
|
|
||||||
$variant-color-primary: map-get($variant-colors, primary);
|
$variant-color-primary: map-get($variant-colors, primary);
|
||||||
|
@ -48,10 +48,17 @@ $input-border: 0.1em solid $page-background-color;
|
||||||
$input-border-radius: 0.5em;
|
$input-border-radius: 0.5em;
|
||||||
$input-focus-outline: 0.1em solid $variant-color-info;
|
$input-focus-outline: 0.1em solid $variant-color-info;
|
||||||
|
|
||||||
|
$button-margin: 0.3em;
|
||||||
$button-padding: 0.25em 0.5em;
|
$button-padding: 0.25em 0.5em;
|
||||||
$button-border-radius: $input-border-radius;
|
$button-border-radius: $input-border-radius;
|
||||||
$button-border-width: 0.1em;
|
$button-border-width: 0.15em;
|
||||||
$button-border-style: solid;
|
$button-border-style: solid;
|
||||||
|
$button-outline-width: 0.15em;
|
||||||
|
$button-sizes: (
|
||||||
|
small: 0.8em,
|
||||||
|
medium: 1em,
|
||||||
|
large: 1.15em,
|
||||||
|
);
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
$nav-bar-background-color: $gray-dark;
|
$nav-bar-background-color: $gray-dark;
|
||||||
|
|
|
@ -1 +1,15 @@
|
||||||
export * from "./shared";
|
export * from "./shared";
|
||||||
|
|
||||||
|
export enum ButtonSize {
|
||||||
|
SMALL = "small",
|
||||||
|
MEDIUM = "medium",
|
||||||
|
LARGE = "large",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ComponentVariant {
|
||||||
|
PRIMARY = "primary",
|
||||||
|
SUCCESS = "success",
|
||||||
|
WARNING = "warning",
|
||||||
|
DANGER = "danger",
|
||||||
|
INFO = "info",
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import StatisticsCard from "@/components/admin/StatisticsCard.vue";
|
import StatisticsCard from "@/components/admin/StatisticsCard.vue";
|
||||||
import {useStatisticsStore} from "@/stores/statistics";
|
import {useStatisticsStore} from "@/stores/statistics";
|
||||||
import {MonitoringState} from "@/types";
|
import {ComponentVariant, MonitoringState} from "@/types";
|
||||||
|
|
||||||
const statistics = useStatisticsStore();
|
const statistics = useStatisticsStore();
|
||||||
|
|
||||||
|
@ -20,14 +20,14 @@ refresh();
|
||||||
<StatisticsCard
|
<StatisticsCard
|
||||||
title="Registrierte Knoten"
|
title="Registrierte Knoten"
|
||||||
icon="circle-o"
|
icon="circle-o"
|
||||||
variant="info"
|
:variant="ComponentVariant.INFO"
|
||||||
:value="statistics.getStatistics.nodes.registered"
|
:value="statistics.getStatistics.nodes.registered"
|
||||||
link="/admin/nodes"
|
link="/admin/nodes"
|
||||||
/>
|
/>
|
||||||
<StatisticsCard
|
<StatisticsCard
|
||||||
title="Mit hinterlegtem fastd-Key"
|
title="Mit hinterlegtem fastd-Key"
|
||||||
icon="lock"
|
icon="lock"
|
||||||
variant="warning"
|
:variant="ComponentVariant.WARNING"
|
||||||
:value="statistics.getStatistics.nodes.withVPN"
|
:value="statistics.getStatistics.nodes.withVPN"
|
||||||
link="/admin/nodes"
|
link="/admin/nodes"
|
||||||
:filter="{hasKey: true}"
|
:filter="{hasKey: true}"
|
||||||
|
@ -35,7 +35,7 @@ refresh();
|
||||||
<StatisticsCard
|
<StatisticsCard
|
||||||
title="Mit Koordinaten"
|
title="Mit Koordinaten"
|
||||||
icon="map-marker"
|
icon="map-marker"
|
||||||
variant="success"
|
:variant="ComponentVariant.SUCCESS"
|
||||||
:value="statistics.getStatistics.nodes.withCoords"
|
:value="statistics.getStatistics.nodes.withCoords"
|
||||||
link="/admin/nodes"
|
link="/admin/nodes"
|
||||||
:filter="{hasCoords: true}"
|
:filter="{hasCoords: true}"
|
||||||
|
@ -43,7 +43,7 @@ refresh();
|
||||||
<StatisticsCard
|
<StatisticsCard
|
||||||
title="Monitoring aktiv"
|
title="Monitoring aktiv"
|
||||||
icon="heartbeat"
|
icon="heartbeat"
|
||||||
variant="success"
|
:variant="ComponentVariant.SUCCESS"
|
||||||
:value="statistics.getStatistics.nodes.monitoring.active"
|
:value="statistics.getStatistics.nodes.monitoring.active"
|
||||||
link="/admin/nodes"
|
link="/admin/nodes"
|
||||||
:filter="{monitoringState: MonitoringState.ACTIVE}"
|
:filter="{monitoringState: MonitoringState.ACTIVE}"
|
||||||
|
@ -51,7 +51,7 @@ refresh();
|
||||||
<StatisticsCard
|
<StatisticsCard
|
||||||
title="Monitoring noch nicht bestätigt"
|
title="Monitoring noch nicht bestätigt"
|
||||||
icon="envelope"
|
icon="envelope"
|
||||||
variant="danger"
|
:variant="ComponentVariant.DANGER"
|
||||||
:value="statistics.getStatistics.nodes.monitoring.pending"
|
:value="statistics.getStatistics.nodes.monitoring.pending"
|
||||||
link="/admin/nodes"
|
link="/admin/nodes"
|
||||||
:filter="{monitoringState: MonitoringState.PENDING}"
|
:filter="{monitoringState: MonitoringState.PENDING}"
|
||||||
|
|
|
@ -2,28 +2,14 @@
|
||||||
import {useNodesStore} from "@/stores/nodes";
|
import {useNodesStore} from "@/stores/nodes";
|
||||||
import {onMounted, type PropType, ref, watch} from "vue";
|
import {onMounted, type PropType, ref, watch} from "vue";
|
||||||
import type {DomainSpecificNodeResponse, MAC, NodesFilter, SearchTerm} from "@/types";
|
import type {DomainSpecificNodeResponse, MAC, NodesFilter, SearchTerm} from "@/types";
|
||||||
import {NodeSortField, SortDirection} from "@/types";
|
import {ButtonSize, ComponentVariant, NodeSortField, SortDirection} from "@/types";
|
||||||
import Pager from "@/components/Pager.vue";
|
import Pager from "@/components/Pager.vue";
|
||||||
|
import ActionButton from "@/components/form/ActionButton.vue";
|
||||||
import LoadingContainer from "@/components/LoadingContainer.vue";
|
import LoadingContainer from "@/components/LoadingContainer.vue";
|
||||||
import NodesFilterPanel from "@/components/nodes/NodesFilterPanel.vue";
|
import NodesFilterPanel from "@/components/nodes/NodesFilterPanel.vue";
|
||||||
import {SortTH} from "@/components/table/SortTH.vue";
|
import {SortTH} from "@/components/table/SortTH.vue";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
|
|
||||||
function debug(...args: any[]): void {
|
|
||||||
console.debug("==================================================================");
|
|
||||||
console.debug("AdminNodesVue:", ...args);
|
|
||||||
console.table({
|
|
||||||
filter: JSON.stringify(props.filter),
|
|
||||||
searchTerm: props.searchTerm,
|
|
||||||
sortDirection: props.sortDirection,
|
|
||||||
sortField: props.sortField,
|
|
||||||
});
|
|
||||||
console.debug("==================================================================");
|
|
||||||
console.debug();
|
|
||||||
}
|
|
||||||
|
|
||||||
debug("init page");
|
|
||||||
|
|
||||||
const NODE_PER_PAGE = 50;
|
const NODE_PER_PAGE = 50;
|
||||||
|
|
||||||
// noinspection JSUnusedGlobalSymbols
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
@ -145,18 +131,22 @@ watch(props, async () => {
|
||||||
@changePage="refresh"/>
|
@changePage="refresh"/>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button
|
<ActionButton
|
||||||
v-if="redactFieldsByDefault"
|
v-if="redactFieldsByDefault"
|
||||||
class="warning"
|
:variant="ComponentVariant.WARNING"
|
||||||
|
:size="ButtonSize.SMALL"
|
||||||
|
icon="eye"
|
||||||
@click="redactAllFields(false)">
|
@click="redactAllFields(false)">
|
||||||
Sensible Daten einblenden
|
Sensible Daten einblenden
|
||||||
</button>
|
</ActionButton>
|
||||||
<button
|
<ActionButton
|
||||||
v-if="!redactFieldsByDefault"
|
v-if="!redactFieldsByDefault"
|
||||||
class="success"
|
:variant="ComponentVariant.SUCCESS"
|
||||||
|
:size="ButtonSize.SMALL"
|
||||||
|
icon="eye-slash"
|
||||||
@click="redactAllFields(true)">
|
@click="redactAllFields(true)">
|
||||||
Sensible Daten ausblenden
|
Sensible Daten ausblenden
|
||||||
</button>
|
</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LoadingContainer :loading="loading">
|
<LoadingContainer :loading="loading">
|
||||||
|
|
|
@ -1,12 +1,38 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import ActionButton from "@/components/form/ActionButton.vue";
|
||||||
|
import {ButtonSize, ComponentVariant} from "@/types";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h2>Willkommen!</h2>
|
<h2>Willkommen!</h2>
|
||||||
|
|
||||||
<p>Du hast einen neuen Freifunk Hamburg Router (Knoten), den Du in Betrieb nehmen möchtest? Du hast schon einen Knoten in Betrieb und möchtest seine Daten ändern? Oder Du möchtest einen Knoten, der nicht mehr in Betrieb ist löschen? Dann bist Du hier richtig!</p>
|
<p>Du hast einen neuen Freifunk Hamburg Router (Knoten), den Du in Betrieb nehmen möchtest? Du hast schon einen
|
||||||
|
Knoten in Betrieb und möchtest seine Daten ändern? Oder Du möchtest einen Knoten, der nicht mehr in Betrieb
|
||||||
|
ist löschen? Dann bist Du hier richtig!</p>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<ActionButton
|
||||||
|
:variant="ComponentVariant.INFO"
|
||||||
|
:size="ButtonSize.LARGE"
|
||||||
|
icon="dot-circle-o">
|
||||||
|
Neuen Knoten anmelden
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton
|
||||||
|
:variant="ComponentVariant.PRIMARY"
|
||||||
|
:size="ButtonSize.LARGE"
|
||||||
|
icon="pencil">
|
||||||
|
Knotendaten ändern
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton
|
||||||
|
:variant="ComponentVariant.WARNING"
|
||||||
|
:size="ButtonSize.LARGE"
|
||||||
|
icon="trash">
|
||||||
|
Knoten löschen
|
||||||
|
</ActionButton>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped>
|
||||||
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue