| Numéro du ticket | Titre du ticket | |------------------|-----------------| | #337 | Création d'un composant Select | ## Description de la PR ## Modification du .env ## Check list - [x] Pas de régression - [ ] TU/TI/TF rédigée - [x] TU/TI/TF OK - [x] CHANGELOG modifié Co-authored-by: tristan <tristan@yuno.malio.fr> Reviewed-on: #3 Reviewed-by: Autin <tristan@yuno.malio.fr> Co-authored-by: kevin <kevin@yuno.malio.fr> Co-committed-by: kevin <kevin@yuno.malio.fr>
129 lines
3.1 KiB
Vue
129 lines
3.1 KiB
Vue
<template>
|
|
<div class="flex min-h-screen">
|
|
<aside class="w-72 bg-m-bg p-6 text-white">
|
|
<button
|
|
type="button"
|
|
class="text-xl text-black font-semibold"
|
|
@click="clearSelection"
|
|
>
|
|
Liste des composants
|
|
</button>
|
|
|
|
<nav class="mt-6 flex flex-col gap-2">
|
|
<button
|
|
v-for="item in items"
|
|
:key="item.name"
|
|
type="button"
|
|
class="rounded px-3 py-2 text-left text-black font-bold hover:bg-m-primary hover:text-white"
|
|
:class="selectedName === item.name ? 'bg-m-secondary text-white' : ''"
|
|
@click="selectOrToggle(item.name)"
|
|
>
|
|
{{ item.label }}
|
|
</button>
|
|
</nav>
|
|
</aside>
|
|
|
|
<main class="flex-1 p-6">
|
|
<component
|
|
:is="selectedDemoComponent"
|
|
v-if="selectedDemoComponent"
|
|
/>
|
|
<p
|
|
v-else-if="selectedName"
|
|
class="text-gray-700"
|
|
>
|
|
Page de demo introuvable:
|
|
<code>.playground/pages/composant/{{ selectedDemoFileName }}.vue</code>
|
|
</p>
|
|
<div v-else>
|
|
<h1 class="text-2xl font-semibold text-gray-900">
|
|
Playground composants
|
|
</h1>
|
|
<p class="mt-2 text-gray-600">
|
|
Selectionne un composant dans la liste pour afficher sa page de demo.
|
|
</p>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, ref, watch, shallowRef } from 'vue'
|
|
|
|
type LoadedModule = {
|
|
default: unknown
|
|
}
|
|
|
|
type Item = {
|
|
name: string
|
|
label: string
|
|
}
|
|
|
|
const componentModules = import.meta.glob('../../app/components/malio/*.vue')
|
|
const demoModules = import.meta.glob('./composant/*.vue')
|
|
|
|
const demoByName: Record<string, () => Promise<LoadedModule>> =
|
|
Object.fromEntries(
|
|
Object.entries(demoModules).map(([file, loader]) => {
|
|
const name = file.split('/').pop()?.replace('.vue', '') ?? ''
|
|
return [name.toLowerCase(), loader as () => Promise<LoadedModule>]
|
|
}),
|
|
)
|
|
|
|
const items = computed<Item[]>(() =>
|
|
Object.keys(componentModules).map((file) => {
|
|
const name = file.split('/').pop()?.replace('.vue', '') ?? ''
|
|
return {
|
|
name,
|
|
label: name,
|
|
}
|
|
}),
|
|
)
|
|
|
|
const selectedName = ref('')
|
|
const hasInitializedSelection = ref(false)
|
|
|
|
watch(
|
|
items,
|
|
(val) => {
|
|
if (!hasInitializedSelection.value && val.length > 0) {
|
|
selectedName.value = val[0].name
|
|
hasInitializedSelection.value = true
|
|
}
|
|
},
|
|
{ immediate: true },
|
|
)
|
|
|
|
function selectOrToggle(name: string) {
|
|
selectedName.value = selectedName.value === name ? '' : name
|
|
}
|
|
|
|
function clearSelection() {
|
|
selectedName.value = ''
|
|
}
|
|
|
|
const selectedDemoComponent = shallowRef<unknown>(null)
|
|
|
|
watch(selectedName, async (name) => {
|
|
if (!name) {
|
|
selectedDemoComponent.value = null
|
|
return
|
|
}
|
|
|
|
const loader = demoByName[name.toLowerCase()]
|
|
if (!loader) {
|
|
selectedDemoComponent.value = null
|
|
return
|
|
}
|
|
|
|
const mod = await loader()
|
|
selectedDemoComponent.value = mod.default
|
|
})
|
|
|
|
const selectedDemoFileName = computed(() => {
|
|
const name = selectedName.value
|
|
if (!name) return ''
|
|
return name.charAt(0).toLowerCase() + name.slice(1)
|
|
})
|
|
</script>
|