Odysseus — Deep Research Report

Guide complet de développement du panneau latéral de navigation Notion

463.0s Duration
3 Rounds
7 Queries
23 URLs Analyzed
deepseek-v4-pro Model
searxng Search

Difficulté : Avancé
Temps de développement estimé : 40 à 60 heures (selon le stack et les intégrations)
Prérequis techniques : React (ou framework moderne), gestion d’état (Redux/Zustand), CSS-in-JS ou SCSS, bibliothèque de drag & drop comme dnd-kit, connaissance des design tokens pour thèmes clair/foncé.

Ce guide vous donne toutes les clés pour reproduire à l’identique le menu de navigation gauche de Notion, en couvrant chaque composant visuel, chaque interaction utilisateur et chaque règle d’affichage conditionnelle. Il s’appuie directement sur la documentation officielle12 et les meilleures pratiques UX3 pour garantir une expérience fluide et fidèle.


Quick Guide (Raccourci pour développeurs)

  1. Créer un conteneur fixe de 240 px de large, 100 vh de hauteur, fond sombre.
  2. Ajouter l’en-tête du workspace (avatar + nom), avec un menu déroulant contextuel.
  3. Empiler les 5 onglets principaux : Home, Chat (si IA activée), Meetings (si plan payant), Inbox (avec badge), Search (déclenche Quick Find).
  4. Structurer les sections repliables titrées : Recents, Favorites (drag & drop autorisé), Agents, Shared (avec sous-niveaux Teamspaces), Private, Notion apps.
  5. Placer les liens utilitaires fixes (My Tasks, Library, Marketplace, Help, Trash) au-dessus du pied.
  6. Ajouter un pied sticky contenant le bouton “+ New” (ouvre un menu de création) et “New Chat” (si IA).
  7. Gérer la réduction de la sidebar à 56 px (mode icônes seules) via un hamburger, avec infobulles au survol.
  8. Conditionner l’affichage des onglets Chat, Meetings, Agents et New Chat selon les droits utilisateur.
  9. Implémenter le drag & drop uniquement sur la section Favorites, avec persistance immédiate.
  10. Sauvegarder localement les préférences (sections dépliées, ordre des favoris, mode réduit).
  11. Appliquer les design tokens pour supporter les thèmes clair et foncé.

Prérequis

Avant de commencer, assurez-vous de maîtriser les concepts suivants :


Step 1: Mise en place du conteneur et du style de base

Spécifications UI

Le panneau latéral est un élément aside (ou nav) avec les propriétés suivantes :

.sidebar {
  width: 240px;
  min-width: 240px;
  height: 100vh;
  position: fixed;
  left: 0;
  top: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overflow-x: hidden;
  background-color: var(--sidebar-bg);
  color: var(--sidebar-text);
  border-right: 1px solid var(--border-color);
  box-shadow: 0 0 8px rgba(0,0,0,0.05);
  transition: width 0.25s ease, min-width 0.25s ease;
}

.sidebar.collapsed {
  width: 56px;
  min-width: 56px;
}

Utilisez des variables CSS pour les couleurs afin d’assurer la compatibilité avec un thème sombre/clair. Par exemple : - --sidebar-bg: #f7f6f3; (clair), --sidebar-bg: #191919; (sombre) - --sidebar-text: #37352f; (clair), --sidebar-text: #d3d3d3; (sombre) - --accent: #2383e2;

La hauteur pleine écran est gérée par height: 100vh. Le défilement vertical interne permet aux très longs contenus de rester accessibles.

Tip: Pour éviter un double défilement avec le contenu principal, appliquez overflow: hidden sur body lorsque la sidebar est en mode off‑canvas sur mobile.


Step 2: En-tête du workspace

Composant WorkspaceHeader

Affichez un avatar rond (32×32 px) et le nom du workspace. Le nom est tronqué avec text-overflow: ellipsis si nécessaire.

<button className="workspace-header" onClick={toggleMenu}>
  <img src={workspace.icon} alt="" className="workspace-avatar" />
  <span className="workspace-name">{workspace.name}</span>
  <ChevronDownIcon />
</button>

L’interaction : - Un clic ouvre un panneau contextuel aligné sous l’en-tête, affichant : “Changer de workspace”, “Paramètres du workspace”, “Notifications”, etc. - Le menu se ferme au clic extérieur ou sur un élément.

UX : cet en-tête ancre l’identité du workspace courant et donne un accès rapide aux réglages globaux.

Warning: Ne pas utiliser position: absolute pour le menu flottant sans avoir un conteneur parent position: relative. Une alternative est d’utiliser un portal React pour éviter les débordements de la sidebar.


Step 3: Onglets de navigation primaires

Cinq éléments empilés verticalement, chacun composé d’une icône (16 px) et d’un libellé (font-size 14 px, graisse normale). L’onglet actif reçoit un fond légèrement plus clair et une barre verticale gauche de 3 px.

Structure d’un onglet :

<NavItem
  icon={<HomeIcon />}
  label="Home"
  to="/home"
  active={currentRoute === '/home'}
/>

Comportements spécifiques :

Onglet Icône Rendu conditionnel Action
Home 🏠 Toujours affiché Navigation vers /home
Chat 💬 userPlan.aiEnabled === true Navigation vers l’interface IA, affiche éventuellement un indicateur de conversation active
Meetings 📅 userPlan.includesMeetings === true Filtre les pages avec blocs de type réunion
Inbox 🔔 Toujours affiché Ouvre une modale latérale listant les notifications ; badge non‑lu mis à jour en temps réel
Search 🔍 Toujours affiché Déclenche Cmd/Ctrl+K en appelant la fonction openQuickFind()

Détail de l’Inbox : - La propriété unreadCount est récupérée via polling ou WebSocket. - Le badge est un petit cercle rouge avec le nombre, affiché seulement si unreadCount > 0. - Au clic, une modale s’ouvre. L’utilisateur peut marquer tout comme lu, ce qui réinitialise le badge.

Tip: Pour reproduire exactement le comportement Notion, le clic sur Search ne navigue pas mais active une modale superposée avec un champ de saisie autofocusé. Implémentez QuickFindModal indépendamment.


Step 4: Sections de pages repliables

Chaque section est un composant générique SidebarSection avec : - un en-tête cliquable (chevron animé + titre en majuscules 12 px, lettre-spacing 0.5 px) ; - une liste d’items SidebarItem.

L’ordre des sections est imposé : Recents, Favorites, Agents, Shared, Private, Notion apps. Elles sont empilées dans l’ordre vertical.

4.1 Section Recents

4.2 Section Favorites

Implémentation du drag & drop :

<DndContext onDragEnd={handleDragEnd}>
  <SortableContext items={favorites}>
    {favorites.map(page => (
      <SortableItem key={page.id} id={page.id}>
        <SidebarItem page={page} />
      </SortableItem>
    ))}
  </SortableContext>
</DndContext>

Warning: Seule la section Favorites doit accepter le réordonnancement. Toute autre tentative de glisser un élément doit être ignorée pour coller au comportement original.

4.3 Section Agents

4.4 Section Shared

Modèle de données :

interface SharedSection {
  teamspaces: Array<{
    id: string;
    name: string;
    pages: Page[];
    collapsed: boolean;
  }>;
  directSharedPages: Page[];
}

4.5 Section Private

4.6 Section Notion apps

Comportements communs : - Survol : fond plus clair var(--hover-bg), curseur pointer. - Clic : navigue vers la page ; l’élément prend l’état actif (surlignage). - Clic droit : menu contextuel natif (Ouvrir dans un nouvel onglet, Dupliquer, etc.). - Réduction/extension : le chevron pivote de 90° à l’état replié avec une transition transform 0.2s ease. L’état est sauvegardé localement par utilisateur.

Tip: Stockez l’état collapsed de chaque section dans un objet userPreferences.sectionsState. Utilisez localStorage pour une persistance instantanée, tout en synchronisant de temps en temps avec le backend.


Step 5: Liens utilitaires

Une série de boutons simples, sans chevron ni sous-section, placés dans une div séparée au-dessus du pied.

Liste fixe dans l’ordre : 1. My Tasks 2. Library 3. Marketplace 4. Help 5. Trash

Ces liens ne supportent ni le drag, ni le réordonnancement. Leur comportement est un simple history.push ou window.location. La corbeille (Trash) pointe vers une page dédiée. L’icône de chaque lien est une illustration spécifique (fournie par le set d’icônes Notion).


Step 6: Pied d’actions rapides

Deux boutons always‑visible en bas de la barre, positionnés en sticky :

.sidebar-footer {
  position: sticky;
  bottom: 0;
  background: var(--sidebar-bg);
  padding: 12px 16px;
  border-top: 1px solid var(--border-color);
  margin-top: auto;
}

Bouton “+ New” : - Bouton principal, largeur pleine, couleur d’accentuation var(--accent). - Icône “+” à gauche. - onClick → ouvre un menu flottant (portal) proposant : Page, Base de données, Calendrier, Import, etc. - La sélection déclenche la création et l’ouverture de l’élément. - Le menu se ferme au clic extérieur ou après sélection.

Bouton “New Chat” : - Bouton secondaire avec une icône de bulle. - Visible uniquement si userPlan.aiEnabled === true2. - onClick → bascule l’onglet Chat et démarre une nouvelle conversation IA.

Tip: Associez un raccourci clavier Cmd/Ctrl + N pour l’action “+ New” et affichez le raccourci dans une infobulle au survol.


Step 7: Interactions avancées et dynamiques

Mode réduit (icônes seules)

Un bouton hamburger (ou un raccourci Cmd/Ctrl + \) réduit la sidebar à 56 px. Pendant la transition, les libellés disparaissent en fondu (opacity: 0). Les sections deviennent inaccessibles directement ; au survol d’une icône, un tooltip affiche le nom complet, et un clic sur une section ouvre un popover listant ses items.

<button onClick={toggleCollapsed} className="collapse-btn">
  <HamburgerIcon />
</button>

Recherche unifiée (Quick Find)

Le composant QuickFindModal s’affiche en overlay, centré, avec un champ de saisie autofocusé. La frappe filtre en temps réel les résultats (pages, bases de données, commentaires). Implémentez un système de recherche côté client pour la vitesse.

Badge Inbox en temps réel

Abonnez-vous à un flux de notifications (WebSocket) ou faites du polling toutes les 30 secondes. Mettez à jour l’état global unreadCount ; le badge se met à jour réactivement.

Drag & drop dans les Favorites (rappel)

Utilisez exclusivement dnd-kit et les événements onDragEnd pour sauvegarder le nouvel ordre via l’API Notion ou un store local immédiat.


Step 8: Affichage conditionnel selon le plan utilisateur

Pour respecter les capacités du compte, créez un hook useUserPermissions() qui retourne :

{
  planType: 'free' | 'plus' | 'business' | 'enterprise';
  aiEnabled: boolean;
  meetingsEnabled: boolean;
  agentsActive: boolean;
}

Appliquez ces conditions dans le rendu : - Onglet Chat → aiEnabled - Onglet Meetings → planType !== 'free' - Section Agents → agentsActive - Bouton New Chat → aiEnabled

Si une condition n’est pas remplie, le composant correspondant n’est pas rendu (pas simplement masqué en CSS, pour éviter les trous dans la mise en page).

Warning: Ne jamais se baser uniquement sur le cache local pour ces permissions ; vérifiez-les au chargement et après chaque changement de plan.


Step 9: Accessibilité et responsive design

Respectez les critères WCAG AA : - Tous les items sont focusables (tabIndex), l’ordre de tabulation suit l’ordre visuel. - Rôles ARIA : navigation sur le conteneur, list et listitem sur les sections, button pour les actions. - En mode réduit, utilisez l’attribut aria-label sur les icônes et des tooltips pilotés par aria-describedby. - Contraste suffisant entre le texte et le fond dans les deux thèmes.

Pour le responsive (écrans < 768 px), remplacez la sidebar fixe par un bouton hamburger qui déclenche un tiroir off‑canvas coulissant depuis la gauche. L’implémentation de cette version mobile sort du cadre de ce guide centré sur la reproduction exacte de la sidebar desktop, mais prévoyez une architecture qui facilite ce basculement.


Step 10: Test et validation UX

Testez les scénarios suivants pour garantir la conformité avec Notion :


Erreurs courantes

  1. Oublier de conditionner l’affichage des onglets Meetings et Chat → les utilisateurs sur plan gratuit verront des onglets inactifs ou manquants, ce qui nuit à l’expérience.
  2. Permettre le drag sur d’autres sections que Favorites → le comportement n’est pas authentique et peut provoquer des suppressions accidentelles.
  3. Ne pas persister l’état des sections pliées/dépliées → à chaque rechargement, l’utilisateur devra tout réorganiser, ce qui frustre.
  4. Ne pas animer la rotation du chevron ou la réduction de la sidebar → l’absence de transition donne une impression de bug.
  5. Stocker l’ordre des favoris uniquement en local sans le synchro serveur → en cas de changement d’appareil, les favoris seront perdus. Implémentez une sauvegarde côté backend via l’API Notion.
  6. Mettre le bouton Search sous forme de champ texte dans la sidebar → Notion utilise un bouton déclenchant une modale, ce qui économise l’espace et garde l’interface propre.
  7. Utiliser des tailles de police ou des espacements différents → respectez scrupuleusement les 14 px pour les libellés, 12 px pour les titres de section, et les marges internes de 8-12 px pour une reproduction fidèle.
  8. Négliger la gestion du thème → sans variables CSS, le basculement clair/foncé cassera l’apparence. Prévoir dès le départ les deux jeux de couleurs.

Conclusion

Ce guide vous a fourni l’ensemble des spécifications UI, des modèles d’interaction et des conditions métier nécessaires pour reproduire la barre de navigation gauche de Notion. En suivant les étapes détaillées, vous disposerez d’une sidebar réactive, personnalisée et fidèle à l’original, capable de s’adapter au plan de l’utilisateur et à ses préférences. La clé du succès réside dans une attention méticuleuse aux détails : chaque pixel, chaque transition et chaque condition d’affichage compte pour offrir une expérience utilisateur identique à celle que des millions d’utilisateurs connaissent.

Sources utilisées :

Opens a new chat with this report as context.