Réaliser un Side Drawer avec Astro et Vue JS
Astro Vue TailwindIntroduction
Dans cet article nous allons implémenter un Side Drawer
avec Astro et Vue JS.
Pour rappel Astro est un framework web ayant pour but de générer une MPA (Multi Page Application) et focus de base le SSG (Static Site Generation).
A l’inverse, Next JS ou Nuxt JS permettent de générer des SPA (Single Page Application) via SSG (Static Site Generation) ou SSR (Server Side Rendering).
Le composant Backdrop Vue JS
Commençons par créer un composant Backdrop
avec Vue JS qui permettra d’obtenir une ombre portée lorsque le Side Drawer
sera ouvert. Nous utiliserons également Tailwind pour simplifier l’écriture du code css.
<!-- src/components/ui/Backdrop.vue -->
<template>
<div class="z-20 fixed inset-0 transition-opacity">
<div class="absolute inset-0 bg-black opacity-70"></div>
</div>
</template>
Pour le moment rien de bien compliqué dans le composant Backdrop
, il n’y a que du code HTML 🙂.
Les nanos stores avec Astro
Ensuite, il va être nécessaire d’avoir un mécanisme qui nous permettre de gérer un état dans notre application Astro
. Pour ce faire, nous allons utiliser les nano stores.
// src/store/drawerStore.ts
import { atom } from "nanostores";
export const isDrawerOpen = atom(false);
Le code est très simple, l’atom dispose d’un état de type boolean
et nous l’initialisons à false
par défaut, pour que notre Drawer
soit fermé.
Le composable Vue JS
Nous allons maintenant créer un composable
avec Vue JS
, qui exploitera le nano store
. Pour rappel, un composable
est une fonction qui peut contenir un état et être réutilisable entre plusieurs composants.
// src/composables/useDrawer.ts
import { useStore } from "@nanostores/vue";
import { isDrawerOpen } from "../store/drawerStore";
export function useDrawer() {
const $isDrawerOpen = useStore(isDrawerOpen);
function openDrawer() {
isDrawerOpen.set(true);
}
function closeDrawer() {
isDrawerOpen.set(false);
}
function toggleDrawer() {
isDrawerOpen.set(!$isDrawerOpen.value);
}
return { isDrawerOpen: $isDrawerOpen, openDrawer, closeDrawer, toggleDrawer };
}
Le composable
est relativement simple, il expose des fonctions permettant d’ouvrir ou fermer le Drawer
tout en mettant l’état du nano store
à jour.
Le composant Drawer Vue JS
Passons maintenant au composant Drawer
, qui utilisera l’ensemble de ce que nous avons précédemment créer.
<!-- src/components/ui/Drawer.vue -->
<template>
<Backdrop v-if="isDrawerOpen" @click="closeDrawer" />
<aside
class="drawer transform top-0 left-0 w-3/4 bg-white fixed h-screen overflow-auto ease-in-out transition-all duration-150 z-30"
:class="{
'translate-x-0': isDrawerOpen,
'-translate-x-full': !isDrawerOpen,
}"
>
<div class="bg-zinc-700 h-16 flex items-center">
<h2 class="ml-4 text-xl text-white">Menu</h2>
</div>
<ul class="ml-8">
<slot />
</ul>
</aside>
</template>
<script lang="ts" setup>
import { useDrawer } from "../../composables/useDrawer";
import Backdrop from "./Backdrop.vue";
const { isDrawerOpen, closeDrawer } = useDrawer();
</script>
Le Backdrop
est caché ou affiché en fonction de l’état du Drawer
. Des classes tailwind sont également utilisées pour animer l’ouverture du Drawer
en fonction de l’état ouvert
ou fermé
.
Vous noterez également que nous avons utilisé l’instruction <slot />
qui permet d’injecter du contenu dynamique à l’intérieur du Drawer
. Nous nous en sevirons pour afficher la liste des liens.
Le composant DrawerLink Vue JS
Afin de pouvoir correctemnet fermer le Drawer
il est nécessaire de définir un nouveau composant que nous allons appeler DrawerLink
.
Le composant utilisera notre composable useDrawer
, afin de pouvoir fermer le Drawer
, lorsque l’utilisateur cliquera sur le lien.
<!-- src/components/ui/DrawerLink.vue -->
<template>
<li class="mt-8 flex" @click="closeDrawer">
<slot />
</li>
</template>
<script lang="ts" setup>
import { useDrawer } from "../../composables/useDrawer";
const { closeDrawer } = useDrawer();
</script>
Un click event est bindé sur la balise <li>
, à l’aide de @click="closeDrawer"
. L’event appelera la fonction closeDrawer
fournie par notre composable.
Un slot est aussi utilisé pour personaliser le contenu du lien. Nous utiliserons dans le composant parant un icône Astro
avec un label.
Le composant Header avec Astro
Pour terminer, créeons notre composant Header
en Astro
afin d’afficher notre Drawer
. Vous remaquerez la directive client:load qui est très importante, c’est grâce à cette instruction que Astro
va contrôler l’hydratation javascript pour nos composants. Sans cette directive Astro
considèrerait nos composants comme du HTML
à 100%.
Nous utiliserons aussi un Array d'objet
pour lister les liens du Drawer
(const links
).
---
// src/components/Header.astro
import { Icon } from "astro-icon";
import Drawer from "./Drawer.vue";
const links = [
{
href: "/",
label: "Accueil",
icon: "mdi:home",
},
{
href: "/articles",
label: "Mes articles",
icon: "mdi:post",
},
];
---
<header>
<Drawer client:load>
{
links.map((link) => (
<DrawerLink client:load>
<div class="mr-4">
<Icon name={link.icon} class="w-6 h-6" />
</div>
<a
class:list={[
{ active: Astro.url.pathname === link.href },
"hover:underline",
"ml-2",
]}
href={link.href}
>
{link.label}
</a>
</DrawerLink>
))
}
</Drawer>
</header>
Nous itérons sur la liste de liens et la tranformons en composants DrawerLink
, grâce à la fonction map
.
La directive class:list
est utilisée pour conditionner le lien actif, en fonction de l’url courante.
Vous noterez également que nous utilisons la librairie astro-icon pour afficher des icônes mdi
.
Voilà, nous arrivons à la fin de l’article, j’espère que cet exemple avec Astro
et Vue JS
vous sera utile 😀.