# Layout & navigation

## Layout, page et routes

Notre application aura deux pages et deux routes :

* Page des tâches
  * &#x20;`Pages/PageTaches.vue`&#x20;
  * route : `'/'`
* Page de paramétrage&#x20;
  * `Pages/PageParams.vue`&#x20;
  * route : `'/params'`

Ces deux pages seront injectées dans un seul *layout* : `layouts/MainLayout.vue`.

Un *layout* est un modèle graphique de page dans lequel on peut injecter une autre page, une autre composant.

#### Travail à réaliser

1. Créer les pages `PageTaches.vue` et `PageParams.vue` en copiant le fichier `pages/Index.vue`
   * Ajouter un `<h1>` dans chaque page afin de les distinguer.&#x20;
2. Appliquer les modifications dans `router/routes.ts` et créer la route `/params`.&#x20;
   * 6 : Changer `Index.vue` en `PageTaches.vue`
   * 7 : Ajout de la nouvelle route `params` pour la page `PageParams.vue`
3. Tester le fonctionnement de l'application et des deux routes
   * Ouvrir la console pour s'assurer qu'il n'y a pas d'erreur
   * Ajouter `params` dans à l'URL de l'application pour tester la page paramètres.

{% tabs %}
{% tab title="routes.ts" %}

```javascript
import { RouteRecordRaw } from 'vue-router'
import MainLayout from 'layouts/MainLayout.vue'
import PageTaches from 'pages/PageTaches.vue'
import PageParams from 'pages/PageParams.vue'
import ErrorNotFound from 'pages/ErrorNotFound.vue'

const routes: RouteRecordRaw[] = [
  {
    path: '/',
    component: MainLayout,
    children: [
      { path: '', component: PageTaches },
      { path: '/params', component: PageParams }
    ]
  },

  // Always leave this as last one,
  // but you can also remove it
  {
    path: '/:catchAll(.*)*',
    component: ErrorNotFound
  }
]

export default routes

```

{% endtab %}

{% tab title="PageTaches.vue" %}

```markup
<template>
  <q-page padding>
    <h1>Tâches</h1>
  </q-page>
</template>

<script setup>

</script>

<style scoped lang="scss">

</style>

```

{% endtab %}

{% tab title="PageParams.vue" %}

```markup
<template>
  <q-page padding>
    <h1>Paramètres</h1>
  </q-page>
</template>

<script setup>

</script>

<style scoped lang="scss">

</style>

```

{% endtab %}
{% endtabs %}

## Menu Latéral

Nous allons maintenant modifier le menu de navigation latéral en y ajoutant les liens vers nos deux pages.

![Objectif une menu avec un seul lien](https://140209345-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M60O5kdEkdIt2ATmwdy%2Fuploads%2FQffT3QKOLgWlgtLjFl5n%2Fmenu-lien.png?alt=media\&token=bd3322c0-baac-4220-9e3d-9104da159ea3)

Le menu de navigation se trouve dans le fichier `layouts/MainLayout.vue` et est contenu dans l'élément `<q-drawer>`, voir ligne 22 du code.

Les liens du menu sont générés par le composant `components/EssentialLink.vue` ligne 34-38

1. Remplacer le composant `<EssentialLink>` par le code ci-dessous. Ce code représente un lien de navigation.

   ```markup
   <q-item clickable>
     <q-item-section avatar>
       <q-icon name="list" />
     </q-item-section>

     <q-item-section>
       <q-item-label>Tâche</q-item-label>
     </q-item-section>
   </q-item>
   ```
2. Comme notre page n'utilise plus le composant `EssentialLink` il y a des erreurs soulevées par ES Lint. Pour les corriger il faut retirer tout ce qui n'est plus utile. Attention les numéros de lignes peuvent varier de 1-2 lignes.
   1. Supprimer son importation dans le JavaScript de `MainLayout.vue` (ligne 54)
   2. Supprimer le tableau des liens `essentialLinks` lignes 56 à 99 de `MainLayout.vue`
   3. Supprimer le fichier du composant `components/EssentialLink.vue`.
3. Votre application doit fonctionner, sans erreurs, et afficher un menu d'un lien, labellisé "Tâches" et décoré d'une icône "listes".

{% code title="layouts/MainLayout.vue" %}

```markup
<template>
  <q-layout view="lHh Lpr lFf">
    <q-header elevated>
      <q-toolbar>
        <q-btn
          flat
          dense
          round
          icon="menu"
          aria-label="Menu"
          @click="toggleLeftDrawer"
        />

        <q-toolbar-title>
          Quasar App
        </q-toolbar-title>

        <div>Quasar v{{ $q.version }}</div>
      </q-toolbar>
    </q-header>

    <q-drawer
      v-model="leftDrawerOpen"
      show-if-above
      bordered
    >
      <q-list>
        <q-item-label
          header
        >
          Essential Links
        </q-item-label>

        <q-item clickable>
          <q-item-section avatar>
            <q-icon name="list" />
          </q-item-section>

          <q-item-section>
            <q-item-label>Tâche</q-item-label>
          </q-item-section>
        </q-item>
      </q-list>
    </q-drawer>

    <q-page-container>
      <router-view />
    </q-page-container>
  </q-layout>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const leftDrawerOpen = ref(false)

const toggleLeftDrawer = () => {
  leftDrawerOpen.value = !leftDrawerOpen.value
}
</script>

```

{% endcode %}

### Analyse de la liste des liens

```markup
<q-list>
  <q-item-label
    header
    class="text-grey-8"
  >
    Essential Links
  </q-item-label>
  <q-item clickable>
    <q-item-section avatar>
      <q-icon name="list" />
    </q-item-section>

    <q-item-section>
      <q-item-label>Tâche</q-item-label>
    </q-item-section>
  </q-item>
</q-list>
```

Cette liste de liens est crée à l'aide de composants Quasar, on les reconnait facilement car ils commencent tous pas `<q-` .

* `<q-list>` : liste d'éléments Quasar.
* `<q-item>` : élément d'une liste Quasar.
  * C'est cet élément qui est cliquable, grâce à l'attribut `clickable`, et qui redirigera l'utilisateur vers la bonne page.
* `<q-item-section>` : section d'un élément de liste.
  * Permet de créer une section pour l’icône et une autre pour le label, texte du lien.
* `<q-icon>` : icône
  * Par défaut, Quasar utilise les icônes **Material Design** de Google :\
    &#x20;<https://material.io/resources/icons/?style=baseline>
  * Pour changer d’icône, trouver son nom et le saisir dans l'attribut `name` de `<q-icon>`
* `<q-item-label>` : label d'un élément de liste, ici le texte du lien.

Ces composants sont détectés et directement ajoutés à votre application par Quasar, donc pas besoin de les importer dans vos pages comme on le ferait pour nos composants.

Tous ces composants sont documentés :

* listes Quasar : <https://quasar.dev/vue-components/list-and-list-items>
* icônes Quasar : <https://quasar.dev/vue-components/icon>

### Création du lien "Paramètres"

![Menu avec les deux liens](https://140209345-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M60O5kdEkdIt2ATmwdy%2Fuploads%2FGtWGeH4uMpwmQyNDUAfN%2Fmenu-deux-liens.png?alt=media\&token=655b9e91-341b-417b-b13e-6ed794caa70e)

Copier et coller le `<q-item>` "Tâches" pour créer celui du lien "Paramètres"

Voici le résultat pour la liste complète des liens

```markup
<q-list>
  <q-item-label
    header
    class="text-grey-8"
  >
    Essential Links
  </q-item-label>
  <q-item clickable>
    <q-item-section avatar>
      <q-icon name="list" />
    </q-item-section>

    <q-item-section>
      <q-item-label>Tâche</q-item-label>
    </q-item-section>
  </q-item>

  <q-item clickable>
    <q-item-section avatar>
      <q-icon name="settings" />
    </q-item-section>

    <q-item-section>
      <q-item-label>Paramètres</q-item-label>
    </q-item-section>
  </q-item>
</q-list>
```

Nos deux liens s'affichent, mais ne nous mènent nulle part ...

### Définir la route avec `to`

Pour qu'un élément cliquable redirige l'utilisateur vers une route on utilise l'attribut `to="/route"`.

Il suffit d'ajouter `to="/"` et `to="/params"` aux `<q-item>` correspondants pour qu'ils nous renvoient au bon endroit.

Parfait, notre menu est fonctionnel et nous permet de naviguer dans notre application.

#### Problème de la route dans la route

Quand on va à la page "Paramètres", le lien "Paramètres" du menu devient bleu, et quand retourne à la page d’accueil, il devient noir. C'est ce qu'on appelle le **lien actif du menu**.

Si vous observez bien, le lien de la page "Tâches", reste toujours bleu quand on change de page.

Le problème est que la route pour les Tâches `"/"` est présente dans la route des paramètres `"/params"` , puis qu'elle commencer par `"/"`.

Pour indiquer à Quasar qu'un lien est actif **uniquement si la route correspond exactement à l'URL**, on ajoute l'attribut **`exact`** à l'élément cliquable.

Pour finaliser notre menu latéral, renommer notre menu en remplaçant `Essential Links` par `Menu de navigation`

* 31 :  `Essential Links` devient `Menu de navigation`
* 34 : Ajout des attributs `to="/"` et `exact` au lien `<q-item>` vers "Tâches"
* 44 : Ajout des attributs `to="/params"` et `exact` au lien `<q-item>` vers "Paramètres"

<pre class="language-markup" data-title="layouts/MainLayout.vue" data-line-numbers><code class="lang-markup">&#x3C;template>
  &#x3C;q-layout view="lHh Lpr lFf">
    &#x3C;q-header elevated>
      &#x3C;q-toolbar>
        &#x3C;q-btn
          flat
          dense
          round
          icon="menu"
          aria-label="Menu"
          @click="toggleLeftDrawer"
        />

        &#x3C;q-toolbar-title>
          Quasar App
        &#x3C;/q-toolbar-title>

        &#x3C;div>Quasar v{{ $q.version }}&#x3C;/div>
      &#x3C;/q-toolbar>
    &#x3C;/q-header>

    &#x3C;q-drawer
      v-model="leftDrawerOpen"
      show-if-above
      bordered
    >
      &#x3C;q-list>
        &#x3C;q-item-label
          header
        >
<strong>          Menu de navigation
</strong>        &#x3C;/q-item-label>

<strong>        &#x3C;q-item clickable to="/" exact>
</strong>          &#x3C;q-item-section avatar>
            &#x3C;q-icon name="list" />
          &#x3C;/q-item-section>

          &#x3C;q-item-section>
            &#x3C;q-item-label>Tâche&#x3C;/q-item-label>
          &#x3C;/q-item-section>
        &#x3C;/q-item>

<strong>        &#x3C;q-item clickable to="/params" exact>
</strong>          &#x3C;q-item-section avatar>
            &#x3C;q-icon name="settings" />
          &#x3C;/q-item-section>

          &#x3C;q-item-section>
            &#x3C;q-item-label>Paramètres&#x3C;/q-item-label>
          &#x3C;/q-item-section>
        &#x3C;/q-item>
      &#x3C;/q-list>
    &#x3C;/q-drawer>

    &#x3C;q-page-container>
      &#x3C;router-view />
    &#x3C;/q-page-container>
  &#x3C;/q-layout>
&#x3C;/template>

&#x3C;script setup lang="ts">
import { ref } from 'vue'

const leftDrawerOpen = ref(false)

const toggleLeftDrawer = () => {
  leftDrawerOpen.value = !leftDrawerOpen.value
}
&#x3C;/script>

</code></pre>

## Footer avec barre de navigation

![](https://140209345-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M60O5kdEkdIt2ATmwdy%2Fuploads%2FISQ5CIP1s37jj3yuMAyI%2Ffooter.png?alt=media\&token=14edaef7-7f1a-4705-a79d-b0113c62656a)

Afin de faciliter la navigation sur les petits écrans, nous allons ajouter un pied de page avec une barre de navigation.

Pour ajouter un pied de page à notre Layout, voir les docs suivantes :

* <https://quasar.dev/layout/header-and-footer>
* <https://quasar.dev/vue-components/tabs>

Il suffit ensuite de récupérer le code des exemples présentés pour les ajouter à notre application comme présenter cette vidéo :

{% embed url="<https://www.youtube.com/watch?v=uAOtuchl1xM>" %}
Créer un pied de page, footer, en s'aidant de la doc en ligne de Quasar
{% endembed %}

Placer le code ci-dessous après la fermeture du composant `</q-page-container>` à la ligne 58.

{% code title="MainLayout.vue " %}

```markup
<q-footer elevated>
  <q-tabs>
    <q-route-tab
      to="/"
      icon="list"
      label="Tâches"
      exact
    />
    <q-route-tab
      to="/params"
      icon="settings"
      label="Paramètres"
      exact
    />
  </q-tabs>
</q-footer>
```

{% endcode %}

## Refactoring des menus

Les codes du menu latéral et du menu du footer se ressemblent beaucoup, et affichent les mêmes informations.

Nous allons donc automatiser la génération des menus en créant :

1. Un tableau d'objets liens (id, libellé, icône, route) dans les données de `MainLayout.vue`
2. Des boucles `v-for` parcourant le tableau de liens dans les menus

{% hint style="danger" %}
Lorsque vous transformer un attribut statique en attribut dynamique, ne pas oublier d'ajouter `":"` devant son nom.

`to="/params"` => `:to="lien.to"`\
`name="settings"` => `:name="lien.icon"`
{% endhint %}

#### Résultat

* Menu latéral
  * 33-34 : Ajout de `v-for` et `:key` pour parcourir le tableau des liens `v-for="lien in liens"`
  * 35 : Ajout de `:` devant `:to` pour le rendre dynamique et affectation de la route du lien parcourus
  * 39 : Même chose qu'à la ligne 39, mais pour le nom de l’icône `:name`&#x20;
  * 43 : Injection du libellé du lien parcourus `{{ lien.libelle }}`&#x20;
* Menu du footer
  * 56-57 : Ajout de `v-for` et `:key` pour parcourir le tableau des liens `v-for="lien in liens"`&#x20;
  * 58: Injection de la route `:to` (pas oublier  `:`)
  * 59 : Injection du nom de l'icône `:icon` (pas oublier `:`)
  * 60: Injection du libellé du lien `:label` (pas oublier `:`)
* Tableau des liens
  * 71 - 82 : Ajout des data et déclaration du tableau des liens. Chaque objet lien possède les propriétés :
    * id&#x20;
    * libelle
    * icone
    * route

<pre class="language-markup" data-title="src/layouts/MainLayout.vue" data-line-numbers><code class="lang-markup">&#x3C;template>
  &#x3C;q-layout view="lHh Lpr lFf">
    &#x3C;q-header elevated>
      &#x3C;q-toolbar>
        &#x3C;q-btn
          flat
          dense
          round
          icon="menu"
          aria-label="Menu"
          @click="toggleLeftDrawer"
        />

        &#x3C;q-toolbar-title>
          Quasar App
        &#x3C;/q-toolbar-title>

        &#x3C;div>Quasar v{{ $q.version }}&#x3C;/div>
      &#x3C;/q-toolbar>
    &#x3C;/q-header>

    &#x3C;q-drawer
      v-model="leftDrawerOpen"
      show-if-above
      bordered
    >
      &#x3C;q-list>
        &#x3C;q-item-label header>
          Menu de navigation
        &#x3C;/q-item-label>

        &#x3C;q-item
<strong>          v-for="(link, index) of menuLinks"
</strong><strong>          :key="index"
</strong><strong>          :to="link.to"
</strong>          clickable
          exact>
          &#x3C;q-item-section avatar>
<strong>            &#x3C;q-icon :name="link.icon" />
</strong>          &#x3C;/q-item-section>

          &#x3C;q-item-section>
<strong>            &#x3C;q-item-label>{{link.label}}&#x3C;/q-item-label>
</strong>          &#x3C;/q-item-section>
        &#x3C;/q-item>
      &#x3C;/q-list>
    &#x3C;/q-drawer>

    &#x3C;q-page-container>
      &#x3C;router-view />
    &#x3C;/q-page-container>

    &#x3C;q-footer elevated>
      &#x3C;q-tabs>
        &#x3C;q-route-tab
<strong>          v-for="(link, index) of menuLinks"
</strong><strong>          :key="index"
</strong><strong>          :to="link.to"
</strong><strong>          :icon="link.icon"
</strong><strong>          :label="link.label"
</strong>          exact
        />
      &#x3C;/q-tabs>
    &#x3C;/q-footer>
  &#x3C;/q-layout>
&#x3C;/template>

&#x3C;script setup lang="ts">
import { ref } from 'vue'

<strong>const menuLinks = ref([
</strong><strong>  {
</strong><strong>    icon: 'list',
</strong><strong>    label: 'Tâches',
</strong><strong>    to: '/'
</strong><strong>  },
</strong><strong>  {
</strong><strong>    icon: 'settings',
</strong><strong>    label: 'Paramètres',
</strong><strong>    to: '/params'
</strong><strong>  }
</strong><strong>])
</strong>
const leftDrawerOpen = ref(false)

const toggleLeftDrawer = () => {
  leftDrawerOpen.value = !leftDrawerOpen.value
}
&#x3C;/script>

</code></pre>

## Affichage responsive des menus

Il n'es pas utile que les deux menus s'affichent en même temps.

Nous allons donc customiser les menus pour que :

* Le menu latéral s'affiche uniquement pour les grands écrans : `>= 768px`
* Le menu du footer s'affiche uniquement pour les petits écrans : `< 767px`

### Menu latéral

Le menu latéral est gérer par le composant `<q-drawer>` : <https://quasar.dev/layout/drawer#QDrawer-API>

Ce composant possède une propriété `breakpoint` qui permet de définir à partir de quelle largeur, en pixel, le menu doit être caché. Nous utiliserons donc cette propriété et lui affecterons la valeur de 767.

{% code title="layouts/MainLayout.vue" %}

```markup
<q-drawer
  :breakpoint="767"
  v-model="leftDrawerOpen"
  show-if-above
  bordered
>
```

{% endcode %}

![](https://140209345-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M60O5kdEkdIt2ATmwdy%2F-M76s6XeuTGQE2i4EaBH%2F-M775FWF4BtD9qT0w-Vb%2FToDo-menu-lateral-768-767.gif?alt=media\&token=ff38d7e5-8d94-402f-b791-be9537a35930)

### Footer

Il faut maintenant masquer le footer pour les écrans `>= 768px`.&#x20;

Nous allons créer un style CSS responsive utilisant les "[médias queries](https://www.alsacreations.com/article/lire/930-css3-media-queries.html)" pour cacher notre footer.

Si on inspecte notre élément footer, comme présenté sur la capture ci-après, on remarque que l'élément `<footer>` possède une classe `q-footer`.

![](https://140209345-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M60O5kdEkdIt2ATmwdy%2F-M76s6XeuTGQE2i4EaBH%2F-M777fbZfxg_LHHMUl5v%2FToDo-footer-inspect.png?alt=media\&token=fc0f3e4c-ae32-45ea-b68d-d61c6266a51d)

Tous les composants Quasar générés possède une classe CSS portant le nom du composant, dans notre cas `<q-footer>` aura la classe `.q-footer`.

{% hint style="info" %}
**Utiliser les classes CSS Qasar pour sélectionner et styler les composants Quasar !**\
\
Dans notre cas il est préférable d'utiliser le sélecteur CSS de classe `.q-footer` que le sélecteur d'élément `footer`.&#x20;

Il sera plus précis et limite la propagation des styles sur les autres éléments HTML de l'application.
{% endhint %}

Ci-après, le code à ajouter à la fin du fichier `MainLayout.vue`  après le script `</script>`.

{% code title="layouts/MainLayout.vue" %}

```markup
<style scoped lang="scss">
  /* Applique les règles de ce bloc uniquement aux écrans >= 768px */
  @media screen and (min-width: 768px) {
    /* Cache les éléments avec la classe CSS q-footer */
    .q-footer {
      display: none;
    }
  }
</style>
```

{% endcode %}

## Personnalisation du layout

Le composant racine d'un layout est `<q-layout>` (voir deuxième ligne du code de `MainLayout.vue)`  , il possède un attribut `view`, qui permet de personnaliser l'affichage de neuf zones.

{% code title="src/layouts/MainLayout.vue | ligne 2" %}

```markup
<q-layout view="lHh Lpr lFf">
```

{% endcode %}

> Mais c'est quoi ce charabia : `"lHh Lpr lFf"` :face\_with\_monocle:&#x20;

Quasar introduit un concept de mise en page unique et génial, qui permet de structurer facilement les layout en modifiant une simple chaine de caractères.

Pour expliquer comment cela fonctionne, imaginez que votre Layout est une matrice 3x3 de conteneurs (représentée en bleu ci-dessous).

* La première rangée de conteneurs est l'en-tête et la dernière rangée serait le pied de page.&#x20;
* La première colonne de conteneurs serait la "gauche" et la dernière colonne serait la "droite".&#x20;
* Le centre de la matrice, sous l'en-tête et au-dessus du pied de page, serait la page ou le conteneur de contenu principal.

Cette matrice de conteneurs ou "QLayout View" peut être représentée par une chaîne de caractères que vous devez fournir à la attribut `view` de `<q-layout>`.&#x20;

Cette chaîne doit contenir exactement 11 caractères (9 zones + 2 espaces), organisés ainsi :

* 3 définissant la ligne d'en-tête
* un espace
* 3 définissant la ligne du milieu
* un espace
* 3 définissant la ligne de bas de page

![](https://140209345-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M60O5kdEkdIt2ATmwdy%2F-M77AZBWyzI7LUShAvmB%2F-M77EHtL_PiHeU8gwrUx%2FToDo-layout-zones.png?alt=media\&token=e12f93c0-5f14-462a-b953-29d95b2cf0f3)

Vous devez donc choisir une lettre par zone pour définir quel élément sera affiché dans cette zone :

* h ou H : header
* l ou L : left
* f ou F : footer
* r ou R : right
* p : page

Les lettre en majuscule afficheront l'élément de de manière fixe. Il sera toujours visible même lors du scroll de l'utilisateur.

### Outils&#x20;

Les outils suivants vous faciliteront la tâche pour personnaliser votre layout :&#x20;

{% embed url="<https://quasar.dev/layout/layout#Understanding-the-%E2%80%9Cview%E2%80%9D-prop>" %}
Documentation et outils pour gérer les layouts
{% endembed %}

{% embed url="<https://quasar.dev/layout-builder>" %}
Application pour customiser rapidement vos layouts
{% endembed %}

### Configuration actuelle

Notre configuration actuelle donne le résultat suivant :

![Layout actuel](https://140209345-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M60O5kdEkdIt2ATmwdy%2F-M77I_xl8rU7XiZ3JP36%2F-M77JOxMFC4drSp0kT9g%2FToDo-layout-zones-actuelles.png?alt=media\&token=45063d86-452b-4ab0-ab51-c6b08c4a75ad)

### Nouvelle configuration

Nous allons modifier notre configuration pour que le `header` et le `footer` s'affichent de manière fixe (lettre en majuscule) au-dessus des autres (`left`, `right`).

![Nouveau layout](https://140209345-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M60O5kdEkdIt2ATmwdy%2F-M77I_xl8rU7XiZ3JP36%2F-M77KZsr2c9xSjV5h9Wj%2FToDo-layout-zones-new.png?alt=media\&token=37e8adcd-0a00-4941-adb4-908b0f369cb2)

{% code title="layouts/MainLayout.vue" %}

```markup
<q-layout view="hHh lpr fFf">
```

{% endcode %}

### Nettoyage du header

Nous allons retirer tout ce qui est inutile dans le `header` (bouton du menu, version Quasar) et centrer le titre.

Pour centrer le texte nous allons utiliser un "helper". Les "helper" sont des classes CSS qui reproduisent les mises en forme courantes : ajouter des marges, changer l'alignement ou la couleur du texte.

Pour centrer le texte, nous utiliserons le "helper" `absolute-center`.&#x20;

Documentation des "helpers" pour le positionnement : <https://quasar.dev/style/positioning>

Notre header simplifié avec titre centré :

{% code title="layouts/MainLayout.vue" %}

```markup
<q-header elevated>
  <q-toolbar>
    <q-toolbar-title class="absolute-center">
      ToDo
    </q-toolbar-title>
  </q-toolbar>
</q-header>
```

{% endcode %}

Comme nous avons supprimer le bouton du menu, nous pouvons également supprimer la méthode `toggleLeftDrawer` qui ne nous est plus utile.

{% code title="MainLayout.vue" lineNumbers="true" %}

```html
<template>
  <q-layout view="hHh lpr fFf">
    <q-header elevated>
      <q-toolbar>
        <q-toolbar-title class="absolute-center">
          ToDo
        </q-toolbar-title>
      </q-toolbar>
    </q-header>

    <q-drawer
      :breakpoint="767"
      v-model="leftDrawerOpen"
      show-if-above
      bordered
    >
      <q-list>
        <q-item-label header>
          Menu de navigation
        </q-item-label>

        <q-item
          v-for="(link, index) of menuLinks"
          :key="index"
          :to="link.to"
          clickable
          exact>
          <q-item-section avatar>
            <q-icon :name="link.icon" />
          </q-item-section>

          <q-item-section>
            <q-item-label>{{link.label}}</q-item-label>
          </q-item-section>
        </q-item>
      </q-list>
    </q-drawer>

    <q-page-container>
      <router-view />
    </q-page-container>

    <q-footer elevated>
      <q-tabs>
        <q-route-tab
          v-for="(link, index) of menuLinks"
          :key="index"
          :to="link.to"
          :icon="link.icon"
          :label="link.label"
          exact
        />
      </q-tabs>
    </q-footer>
  </q-layout>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const menuLinks = ref([
  {
    icon: 'list',
    label: 'Tâches',
    to: '/'
  },
  {
    icon: 'settings',
    label: 'Paramètres',
    to: '/params'
  }
])

const leftDrawerOpen = ref(false)
</script>

<style scoped lang="scss">
  /* Applique les règles de ce bloc uniquement aux écrans >= 768px */
  @media screen and (min-width: 768px) {
    /* Cache les éléments avec la classe CSS q-footer */
    .q-footer {
      display: none;
    }
  }
</style>
```

{% endcode %}

### Palette de couleurs

Pour appliquer une couleur à un texte ou à un arrière-plan, on peut utiliser les classes CSS de la palette de couleurs Quasar :

{% embed url="<https://quasar.dev/style/color-palette>" %}

On peut **modifier la couleur** en appliquant une simple **classe CSS** à un élément :

* Pour la couleur du **texte** avec le préfixe `text-`&#x20;
  * `class="text-red-2"`
* Pour la couleur de **fond** avec le préfixe `bg-`&#x20;
  * `class="bg-red-2"`

### Style du menu latéral

Nous allons finaliser le style de notre menu latéral `<q-drawer>`  :

* Largeur max de 250px : ajouter la propriété `width="250"` à `<q-drawer>`.
* Couleur de fond en bleu foncé, qui est la couleur principale (primary) de notre application.
  * Ajouter `class="bg-primary"`
* Activer le mode sombre (dark) pour la liste. Indique que la cloueur de fond est sombre et active l'utilisation de couleurs claires pour le texte.
  * `<q-list dark>`
* Changer la couleur de "Menu de navigation" en blanc en ajoutant `class="text-white"` au `<q-item-label>`
* Changer la couleur des lien en gris clair.
  * Ajouter `class="text-grey-4"` à `<q-item>`
* Changer la couleur des liens actifs en blanc.
  * Le lien actif d'un menu est identifiable grâce à la classe CSS `q-router-link--exact-active`&#x20;
  * Il faut créer une règle CSS qui ne s'appliquera qu'au lien actif du menu latéral, car cela ne concerne pas le style du lien actif du footer.

{% code title="layouts/MainLayout.vue" %}

```css
/* Lien actif du menu latéral */
.q-drawer .q-router-link--exact-active {
  color: white !important;
}
```

{% endcode %}

### Utilisation du SCSS

Nous allons réécrire la règles CSS si dessus en SCSS.

{% embed url="<https://sass-lang.com/>" %}

Pour pouvoir utiliser le langage SCSS dans un projet Quasar il faut :

* Activer SCSS dans l'assistant de création d'un projet Quasar
* Indiquer que la partie style du fichier .vue utilise le langage SCSS en y ajoutant l'attribut `lang="scss".`

{% code title="layouts/MainLayout.vue" %}

```markup
<style scoped lang="scss">
  /* Applique les règles de ce bloc uniquement aux écrans >= 768px */
  @media screen and (min-width: 768px) {
    /* Cache les éléments avec la classe CSS q-footer */
    .q-footer {
      display: none;
    }
  }

  /* Lien actif du menu latéral */
  .q-drawer {
    .q-router-link--exact-active {
      color: white !important;
    }
  }
</style>
```

{% endcode %}

###

### Couleurs du thème

Le fichier SCSS `src/css/quasar.variables.scss` permet de changer les couleurs du thème.

Nous allons changer la couleur primaire du thème avec un violet, sentez-vous libre de choisir une autre couleur :art: .

```css
$primary   : #7655e3;
```

Afin de définir les couleurs de votre thème, vous pouvez utiliser l'outil suivant et copier le résultat.

{% embed url="<https://quasar.dev/style/theme-builder>" %}

### Résultat final

{% tabs %}
{% tab title="MainLayout.vue" %}
{% code title="layouts/MainLayout.vue" lineNumbers="true" %}

```markup
<template>
  <q-layout view="hHh lpr fFf">
    <q-header elevated>
      <q-toolbar>
        <q-toolbar-title class="absolute-center">
          ToDo
        </q-toolbar-title>
      </q-toolbar>
    </q-header>

    <q-drawer
      :breakpoint="767"
      v-model="leftDrawerOpen"
      show-if-above
      bordered
      :width="250"
      class="bg-primary"
    >
      <q-list dark>
        <q-item-label
          header
          class="text-white">
          Menu de navigation
        </q-item-label>

        <q-item
          v-for="(link, index) of menuLinks"
          :key="index"
          :to="link.to"
          clickable
          exact
          class="text-grey-4">
          <q-item-section avatar>
            <q-icon :name="link.icon" />
          </q-item-section>

          <q-item-section>
            <q-item-label>{{link.label}}</q-item-label>
          </q-item-section>
        </q-item>
      </q-list>
    </q-drawer>

    <q-page-container>
      <router-view />
    </q-page-container>

    <q-footer elevated>
      <q-tabs>
        <q-route-tab
          v-for="(link, index) of menuLinks"
          :key="index"
          :to="link.to"
          :icon="link.icon"
          :label="link.label"
          exact
        />
      </q-tabs>
    </q-footer>
  </q-layout>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const menuLinks = ref([
  {
    icon: 'list',
    label: 'Tâches',
    to: '/'
  },
  {
    icon: 'settings',
    label: 'Paramètres',
    to: '/params'
  }
])

const leftDrawerOpen = ref(false)
</script>

<style scoped lang="scss">
  /* Applique les règles de ce bloc uniquement aux écrans >= 768px */
  @media screen and (min-width: 768px) {
    /* Cache les éléments avec la classe CSS q-footer */
    .q-footer {
      display: none;
    }
  }

  /* Lien actif du menu latéral */
  .q-drawer {
    .q-router-link--exact-active {
      color: white !important;
    }
  }
</style>

```

{% endcode %}
{% endtab %}

{% tab title="quasar.variables.scss" %}
{% code title="src/css/quasar.variables.scss" %}

```css
// Quasar Sass (& SCSS) Variables
// --------------------------------------------------
// To customize the look and feel of this app, you can override
// the Sass/SCSS variables found in Quasar's source Sass/SCSS files.

// Check documentation for full list of Quasar variables

// Your own variables (that are declared here) and Quasar's own
// ones will be available out of the box in your .vue/.scss/.sass files

// It's highly recommended to change the default colors
// to match your app's branding.
// Tip: Use the "Theme Builder" on Quasar's documentation website.

$primary   : #7655e3
$secondary : #26A69A
$accent    : #9C27B0

$dark      : #1D1D1D

$positive  : #21BA45
$negative  : #C10015
$info      : #31CCEC
$warning   : #F2C037

```

{% endcode %}
{% endtab %}
{% endtabs %}

### Télécharger le code complet du chapitre

* Télécharger et extraire l'archive (zip)
* Depuis le terminal :
  * Aller dans le dossier du projet
  * Taper la commande : `npm install`
  * Taper la commande : `quasar dev`

{% file src="<https://140209345-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M60O5kdEkdIt2ATmwdy%2Fuploads%2F8dESnC23NdGoBt6zbH4L%2Fquasar-project.zip?alt=media&token=5cf965ec-67f1-4cf3-adde-60931ec14654>" %}
Code du chapitre
{% endfile %}

###
