Append icons in toolbar shows tooltips, exercise page icon adds open exercises badge

This commit is contained in:
2025-08-30 13:39:16 +02:00
parent 052bb7694a
commit cde3c84bc7
5 changed files with 134 additions and 57 deletions

View File

@@ -98,7 +98,7 @@
"nameEn": "Upgrade your privileges",
"exerciseNr": 4,
"descriptionDe": "Jetzt bearbeiten wir unseren eigenen Account. Schreibe hierfür einen >>UPDATE<<-SQL-Befehl, welcher die >>accountRoleId<< auf das Niveau eines >>Admin<< erhöht für deinen Account-Namen.",
"descriptionEn": "Change the privileges of your account"
"descriptionEn": "Now we'll edit our own account. To do this, write an >>UPDATE<< SQL command that elevates the >>accountRoleId<< to the level of >>Admin<< for your account name."
},
{
"uuid": "sql-injection-capture-account",

View File

@@ -2,54 +2,121 @@
import { useAccountStore } from "@/stores/account.store";
import { useBasketStore } from "@/stores/basket.store";
import { useExerciseStore } from "@/stores/exercise.store";
import { ref, watch } from "vue";
const accountStore = useAccountStore();
const basketStore = useBasketStore();
const exerciseStore = useExerciseStore();
const basketItems = ref(0);
exerciseStore.getAllExercises();
watch(
() => basketStore.itemsInBasket,
() => {
basketItems.value = basketStore.itemsInBasket.reduce((tot, item) => {
return tot + item.seats.length;
}, 0);
}
);
</script>
<template>
<v-btn variant="plain" icon="mdi-magnify" to="/search" />
<!-- Global search -->
<v-tooltip :text="$t('misc.search.globalsearch')" location="bottom">
<template #activator="{ props }">
<v-btn v-bind="props" variant="plain" icon="mdi-magnify" to="/search" />
</template>
</v-tooltip>
<!-- Account -->
<v-tooltip :text="$t('account.account')" location="bottom">
<template #activator="{ props }">
<v-btn
v-if="accountStore.userAccountToken == ''"
v-bind="props"
variant="plain"
icon="mdi-account"
to="/account/login"
/>
<v-btn v-else variant="plain" icon="mdi-account-check" to="/account/home" />
<v-btn
v-else
v-bind="props"
variant="plain"
icon="mdi-account-check"
to="/account/home"
/>
</template>
</v-tooltip>
<div>
<!-- Basket -->
<v-tooltip :text="$t('basket.basket')" location="bottom">
<template #activator="{ props }">
<v-badge
v-if="basketItems > 0"
:content="basketItems"
color="error"
offset-x="8"
offset-y="8"
>
<v-btn v-bind="props" variant="plain" icon="mdi-cart" to="/basket" />
</v-badge>
<v-btn
v-else
v-bind="props"
variant="plain"
icon="mdi-cart"
to="/basket"
/>
</template>
</v-tooltip>
<!-- Exercise page -->
<v-tooltip :text="$t('misc.firstStartup.exercises')" location="bottom">
<template #activator="{ props }">
<v-badge
v-if="exerciseStore.exercisePageVisible"
:content="
basketStore.itemsInBasket.reduce((tot, item) => {
return tot + item.seats.length;
exerciseStore.exercises.reduce((tot, exercise) => {
if (exercise.available && !exercise.solved) {
return tot + 1;
} else {
return tot;
}
}, 0)
"
color="error"
offset-x="8"
offset-y="8"
>
<v-btn variant="plain" icon="mdi-cart" to="/basket" />
</v-badge>
</div>
<v-btn
v-if="accountStore.adminPanelVisible"
variant="plain"
icon="mdi-table-cog"
to="/admin"
/>
<v-btn
v-if="exerciseStore.exercisePageVisible"
v-bind="props"
variant="plain"
icon="mdi-book-open-blank-variant"
to="/help"
/>
<v-btn variant="plain" icon="mdi-cog" to="/preferences" />
</v-badge>
</template>
</v-tooltip>
<!-- Admin panel -->
<v-tooltip :text="$t('admin.adminpanel')" location="bottom">
<template #activator="{ props }">
<v-btn
v-if="accountStore.adminPanelVisible"
v-bind="props"
variant="plain"
icon="mdi-table-cog"
to="/admin"
/>
</template>
</v-tooltip>
<v-tooltip :text="$t('preferences.preferences')" location="bottom">
<template #activator="{ props }">
<v-btn v-bind="props" variant="plain" icon="mdi-cog" to="/preferences" />
</template>
</v-tooltip>
</template>

View File

@@ -179,7 +179,8 @@
"selectConfigFile": "Konfigurations-Datei auswählen",
"download": "Konfiguration exportieren",
"upload": "Datei hochladen"
}
},
"preferences": "Einstellungen"
},
"help": {
"scoreBoard": {
@@ -280,7 +281,8 @@
"empty": {
"headline": "So leer hier..."
},
"searchterm": "Suchbegriff"
"searchterm": "Suchbegriff",
"globalsearch": "Globale Suche"
},
"submit": "Absenden",
"content": "Inhalt",
@@ -295,5 +297,8 @@
},
"genre": {
"withoutBand": "ohne Band"
},
"admin": {
"adminpanel": "Admin Panel"
}
}

View File

@@ -181,7 +181,8 @@
"selectConfigFile": "Select config file",
"upload": "Upload file",
"download": "Export config"
}
},
"preferences": "Preferences"
},
"help": {
"scoreBoard": {
@@ -280,7 +281,8 @@
"empty": {
"headline": "So empty here..."
},
"searchterm": "Search term"
"searchterm": "Search term",
"globalsearch": "Global Search"
},
"submit": "Submit",
"content": "Content",
@@ -295,5 +297,8 @@
},
"genre": {
"withoutBand": "without Band"
},
"admin": {
"adminpanel": "Admin Panel"
}
}

View File

@@ -1,24 +1,24 @@
<script setup lang="ts">
import { useConcertStore } from '@/stores/concert.store';
import { useLocationStore } from '@/stores/location.store';
import bandSection from './bandsSection.vue';
import UpcomingConcertsSection from './upcomingConcertsSection.vue';
import TopLocationsSection from './topLocationsSection.vue';
import { usePreferencesStore } from '@/stores/preferences.store';
import welcomeDialog from './welcomeDialog/dialog.vue';
import { ref } from 'vue';
import { useConcertStore } from "@/stores/concert.store";
import { useLocationStore } from "@/stores/location.store";
import bandSection from "./bandsSection.vue";
import UpcomingConcertsSection from "./upcomingConcertsSection.vue";
import TopLocationsSection from "./topLocationsSection.vue";
import { usePreferencesStore } from "@/stores/preferences.store";
import welcomeDialog from "./welcomeDialog/dialog.vue";
import { ref } from "vue";
const concertStore = useConcertStore()
const locationStore = useLocationStore()
const preferencesStore = usePreferencesStore()
const showWelcomeDialog = ref(false)
const concertStore = useConcertStore();
const locationStore = useLocationStore();
const preferencesStore = usePreferencesStore();
const showWelcomeDialog = ref(false);
concertStore.getUpcomingConcerts()
locationStore.getTopLocations()
concertStore.getUpcomingConcerts();
locationStore.getTopLocations();
// First startup
showWelcomeDialog.value = true
if (preferencesStore.firstStartup) {
showWelcomeDialog.value = true;
}
</script>