Add mobile selection

This commit is contained in:
Christian Cueni 2022-10-24 13:31:15 +02:00
parent 9b8bbf5ebc
commit 7ce195f518
5 changed files with 73 additions and 32 deletions

View File

@ -5,6 +5,7 @@ import { computed } from "vue";
interface DropdownSelectable { interface DropdownSelectable {
id: number | string; id: number | string;
name: string; name: string;
iconName?: string;
} }
// https://stackoverflow.com/questions/64775876/vue-3-pass-reactive-object-to-component-with-two-way-binding // https://stackoverflow.com/questions/64775876/vue-3-pass-reactive-object-to-component-with-two-way-binding
@ -40,8 +41,11 @@ const dropdownSelected = computed({
<Listbox v-model="dropdownSelected" as="div"> <Listbox v-model="dropdownSelected" as="div">
<div class="mt-1 relative w-full"> <div class="mt-1 relative w-full">
<ListboxButton <ListboxButton
class="bg-white relative w-full border pl-5 pr-10 py-3 text-left cursor-default font-bold" class="bg-white relative w-full border pl-5 pr-10 py-3 text-left cursor-default font-bold flex flex-row items-center"
> >
<span v-if="dropdownSelected.iconName" class="mr-4">
<component :is="dropdownSelected.iconName"></component>
</span>
<span class="block truncate">{{ dropdownSelected.name }}</span> <span class="block truncate">{{ dropdownSelected.name }}</span>
<span <span
class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none" class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none"
@ -70,7 +74,11 @@ const dropdownSelected = computed({
active ? 'text-white bg-blue-900' : 'text-black', active ? 'text-white bg-blue-900' : 'text-black',
'cursor-default select-none relative py-2 pl-3 pr-9', 'cursor-default select-none relative py-2 pl-3 pr-9',
]" ]"
class="flex flex-row items-center"
> >
<span v-if="item.iconName" class="mr-4">
<component :is="item.iconName"></component>
</span>
<span <span
:class="[ :class="[
dropdownSelected ? 'font-semibold' : 'font-normal', dropdownSelected ? 'font-semibold' : 'font-normal',

View File

@ -2,10 +2,10 @@
import CompetenceProgress from "@/components/competences/CompetenceProgress.vue"; import CompetenceProgress from "@/components/competences/CompetenceProgress.vue";
import PerformanceCriteriaRow from "@/components/competences/PerformanceCriteriaRow.vue"; import PerformanceCriteriaRow from "@/components/competences/PerformanceCriteriaRow.vue";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue"; import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import {useCompetenceStore} from "@/stores/competence"; import { useCompetenceStore } from "@/stores/competence";
import _ from "lodash"; import _ from "lodash";
import * as log from "loglevel"; import * as log from "loglevel";
import {computed} from "vue"; import { computed } from "vue";
log.debug("CompetenceIndexPage created"); log.debug("CompetenceIndexPage created");
@ -133,7 +133,10 @@ const countStatus = computed(() => {
<it-icon-arrow-right></it-icon-arrow-right> <it-icon-arrow-right></it-icon-arrow-right>
</router-link> </router-link>
</div> </div>
<div v-if="failedCriteria.length > 0" class="bg-white px-8 py-4 lg:py-8 l mb-4 lg:mb-8"> <div
v-if="failedCriteria.length > 0"
class="bg-white px-8 py-4 lg:py-8 l mb-4 lg:mb-8"
>
<div class="border-b flex flex-row items-center pb-4 mb-4"> <div class="border-b flex flex-row items-center pb-4 mb-4">
<it-icon-smiley-thinking class="w-11 h-11 mr-5"></it-icon-smiley-thinking> <it-icon-smiley-thinking class="w-11 h-11 mr-5"></it-icon-smiley-thinking>
<h3>«Das muss ich nochmals anschauen»</h3> <h3>«Das muss ich nochmals anschauen»</h3>

View File

@ -9,15 +9,44 @@ import {computed, ref} from "vue";
log.debug("CompetencesMainView created"); log.debug("CompetencesMainView created");
const competenceStore = useCompetenceStore(); interface MenuItem {
id: CourseCompletionStatus;
name: string;
iconName: string;
}
const activeState: Ref<CourseCompletionStatus> = ref("fail"); const competenceStore = useCompetenceStore();
const shownCriteria = computed(() => { const shownCriteria = computed(() => {
return competenceStore.flatPerformanceCriteria.filter((criteria) => { return competenceStore.flatPerformanceCriteria.filter((criteria) => {
return criteria.completion_status === activeState.value; return criteria.completion_status === activeMenuItem.value.id;
}); });
}); });
const mobileMenuItems: MenuItem[] = [
{
id: "fail",
name: "«Das muss ich nochmals anschauen»",
iconName: "it-icon-smiley-thinking",
},
{
id: "success",
name: "«Ja, ich kann das»",
iconName: "it-icon-smiley-happy",
},
{
id: "unknown",
name: "Nicht eingeschätzt",
iconName: "it-icon-smiley-neutral",
},
];
const activeMenuItem: Ref<MenuItem> = ref(mobileMenuItems[0]);
function updateActiveState(status: CourseCompletionStatus) {
activeMenuItem.value =
mobileMenuItems.find((item) => status === item.id) || mobileMenuItems[0];
}
</script> </script>
<template> <template>
@ -38,32 +67,30 @@ const shownCriteria = computed(() => {
class="w-full lg:w-96 mt-4 lg:mt-0" class="w-full lg:w-96 mt-4 lg:mt-0"
:items="competenceStore.availableCircles" :items="competenceStore.availableCircles"
></ItDropdownSelect> ></ItDropdownSelect>
<div class="lg:hidden w-full">
<ItDropdownSelect
v-model="activeMenuItem"
class="w-full lg:w-96 mt-4 lg:mt-0"
:items="mobileMenuItems"
></ItDropdownSelect>
</div>
</div> </div>
<div class="bg-white p-8"> <div class="bg-white p-8">
<div class="border-b flex flex-col lg:flex-row lg:items-center pb-4 mb-4"> <div
class="border-b flex flex-col lg:flex-row lg:items-center pb-4 mb-4 hidden lg:block"
>
<button <button
:class="{ 'bg-gray-200': activeState === 'fail' }" v-for="item in mobileMenuItems"
:key="item.id"
:class="{
'bg-gray-200': activeMenuItem.id === item.id,
'mr-6': item.id !== 'unknown',
}"
class="flex flex-row items-center py-4 px-2 mr-6" class="flex flex-row items-center py-4 px-2 mr-6"
@click="activeState = 'fail'" @click="updateActiveState(item.id)"
> >
<span class="inline-block mr-2">«Das muss ich nochmals anschauen»</span> <span class="inline-block mr-2">{{ item.name }}</span>
<span><it-icon-smiley-thinking></it-icon-smiley-thinking></span> <component :is="item.iconName"></component>
</button>
<button
:class="{ 'bg-gray-200': activeState === 'success' }"
class="flex flex-row items-center py-4 px-2 mr-6"
@click="activeState = 'success'"
>
<span class="inline-block mr-2">«Ja, ich kann das»</span>
<span><it-icon-smiley-happy></it-icon-smiley-happy></span>
</button>
<button
:class="{ 'bg-gray-200': activeState === 'unknown' }"
class="flex flex-row items-center py-4 px-2"
@click="activeState = 'unknown'"
>
<span class="inline-block mr-2">Nicht eingeschätzt</span>
<span><it-icon-smiley-neutral></it-icon-smiley-neutral></span>
</button> </button>
</div> </div>
<ul class="mb-6"> <ul class="mb-6">

View File

@ -68,7 +68,7 @@ const createContinueUrl = (learningPath: LearningPath): [string, boolean] => {
</button> </button>
</div> </div>
<LearningPathDiagram <LearningPathDiagram
class="mx-auto max-w-[1920px] max-h-[380px] w-full" class="mx-auto max-w-[1920px] max-h-[380px] w-full px-4"
identifier="mainVisualization" identifier="mainVisualization"
:vertical="false" :vertical="false"
></LearningPathDiagram> ></LearningPathDiagram>

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import {useMediaLibraryStore} from "@/stores/mediaLibrary"; import { useMediaLibraryStore } from "@/stores/mediaLibrary";
import * as log from "loglevel"; import * as log from "loglevel";
import {onMounted} from "vue"; import { onMounted } from "vue";
log.debug("MediaLibraryView created"); log.debug("MediaLibraryView created");
@ -25,7 +25,10 @@ onMounted(async () => {
<template> <template>
<div class="bg-gray-200"> <div class="bg-gray-200">
<nav class="px-6 py-4 border-b bg-white"> <nav class="px-6 py-4 border-b bg-white">
<ul v-if="mediaLibraryStore.mediaLibraryPage" class="overflow-auto whitespace-nowrap scrollbar"> <ul
v-if="mediaLibraryStore.mediaLibraryPage"
class="overflow-auto whitespace-nowrap scrollbar"
>
<li class="lg:ml-12 inline-block"> <li class="lg:ml-12 inline-block">
<router-link :to="mediaLibraryStore.mediaLibraryPage.frontend_url"> <router-link :to="mediaLibraryStore.mediaLibraryPage.frontend_url">
Übersicht Übersicht