Introduced ActionButton component as a replacement for HTML's button.

This commit is contained in:
baldo 2022-08-02 16:31:38 +02:00
parent d159e22c50
commit 215f70db26
8 changed files with 146 additions and 69 deletions

View file

@ -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>

View file

@ -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>

View 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>

View file

@ -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;

View file

@ -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",
}

View file

@ -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}"

View file

@ -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">

View file

@ -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>