Add mobile selection
This commit is contained in:
parent
9b8bbf5ebc
commit
7ce195f518
|
|
@ -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',
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue