Agenda Moderne - Bootstrap 5

🏷️ Extraits de code HTML 📅 27/03/2026 08:00:00 👤 Mezgani said
Bootstrap Bootstrap5 Agenda Planning Html Css

Template Bootstrap 5 d'agenda avec design moderne, sections organisees et style clair pour planning et evenements.

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8" />
  <meta name="copyright" content="MEZGANI Said" />
  <meta name="author" content="AngularForAll" />
  <meta name="robots" content="noindex, nofollow" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Snippet Agenda Style Bootstrap 5 01 | AngularForAll</title>
<!-- Bootstrap 5 CSS -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
  <!-- Bootstrap Icons -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
  
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      background: linear-gradient(145deg, #f5f7fa 0%, #e9ecf2 100%);
      min-height: 100vh;
      padding: 24px;
      color: #1e293b;
    }

    /* Container principal */
    .agenda-container {
      max-width: 1400px;
      margin: 0 auto;
    }

    /* Header */
    .agenda-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 28px;
      flex-wrap: wrap;
      gap: 16px;
    }

    .header-left h1 {
      font-size: 2.2rem;
      font-weight: 700;
      margin: 0;
      background: linear-gradient(135deg, #2563eb, #7c3aed);
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;
    }

    .header-left p {
      color: #64748b;
      margin: 4px 0 0;
      font-size: 0.95rem;
    }

    .header-right {
      display: flex;
      align-items: center;
      gap: 12px;
    }

    .date-picker {
      background: white;
      padding: 10px 18px;
      border-radius: 40px;
      display: flex;
      align-items: center;
      gap: 12px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.04);
    }

    .date-picker i {
      color: #64748b;
    }

    .nav-btn {
      width: 44px;
      height: 44px;
      border-radius: 50%;
      background: white;
      border: none;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #1e293b;
      box-shadow: 0 4px 12px rgba(0,0,0,0.04);
      transition: all 0.2s;
      cursor: pointer;
    }

    .nav-btn:hover {
      background: #2563eb;
      color: white;
      box-shadow: 0 8px 20px rgba(37, 99, 235, 0.2);
    }

    .add-btn {
      background: #2563eb;
      color: white;
      border: none;
      padding: 12px 24px;
      border-radius: 40px;
      font-weight: 500;
      display: flex;
      align-items: center;
      gap: 8px;
      box-shadow: 0 8px 20px rgba(37, 99, 235, 0.25);
      transition: all 0.2s;
      cursor: pointer;
    }

    .add-btn:hover {
      background: #1d4ed8;
      transform: translateY(-2px);
      box-shadow: 0 12px 25px rgba(37, 99, 235, 0.3);
    }

    /* Vue actuelle (mois/année) */
    .current-view {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 24px;
    }

    .current-view h2 {
      font-size: 1.6rem;
      font-weight: 600;
      margin: 0;
      color: #0f172a;
    }

    .view-toggle {
      display: flex;
      gap: 8px;
      background: white;
      padding: 6px;
      border-radius: 40px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.04);
    }

    .view-toggle button {
      padding: 8px 20px;
      border: none;
      background: transparent;
      border-radius: 30px;
      font-weight: 500;
      color: #64748b;
      transition: all 0.2s;
      cursor: pointer;
    }

    .view-toggle button.active {
      background: #2563eb;
      color: white;
    }

    /* Grille principale */
    .agenda-grid {
      display: grid;
      grid-template-columns: 1fr 360px;
      gap: 24px;
    }

    @media (max-width: 992px) {
      .agenda-grid {
        grid-template-columns: 1fr;
      }
    }

    /* Calendrier */
    .calendar-card {
      background: white;
      border-radius: 28px;
      padding: 24px;
      box-shadow: 0 20px 40px -12px rgba(0,0,0,0.08);
    }

    .weekdays {
      display: grid;
      grid-template-columns: repeat(7, 1fr);
      text-align: center;
      margin-bottom: 16px;
    }

    .weekday {
      font-weight: 600;
      color: #64748b;
      font-size: 0.85rem;
      text-transform: uppercase;
      letter-spacing: 0.5px;
      padding: 8px 0;
    }

    .calendar-days {
      display: grid;
      grid-template-columns: repeat(7, 1fr);
      gap: 6px;
    }

    .calendar-day {
      aspect-ratio: 1;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      border-radius: 16px;
      font-weight: 500;
      font-size: 0.95rem;
      transition: all 0.2s;
      cursor: pointer;
      position: relative;
      background: #fafbfc;
    }

    .calendar-day:hover {
      background: #eef2ff;
    }

    .calendar-day.other-month {
      color: #94a3b8;
      opacity: 0.6;
    }

    .calendar-day.today {
      background: #2563eb;
      color: white;
      box-shadow: 0 6px 15px rgba(37, 99, 235, 0.3);
    }

    .calendar-day.has-events::after {
      content: '';
      position: absolute;
      bottom: 6px;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: #2563eb;
    }

    .calendar-day.today.has-events::after {
      background: white;
    }

    /* Sidebar - Événements du jour */
    .events-sidebar {
      background: white;
      border-radius: 28px;
      padding: 24px;
      box-shadow: 0 20px 40px -12px rgba(0,0,0,0.08);
    }

    .sidebar-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 20px;
    }

    .sidebar-header h3 {
      font-size: 1.25rem;
      font-weight: 600;
      margin: 0;
    }

    .selected-date-badge {
      background: #eef2ff;
      color: #2563eb;
      padding: 6px 14px;
      border-radius: 30px;
      font-size: 0.9rem;
      font-weight: 500;
    }

    .events-list {
      display: flex;
      flex-direction: column;
      gap: 16px;
    }

    .event-item {
      display: flex;
      gap: 14px;
      padding: 14px;
      background: #fafbfc;
      border-radius: 18px;
      transition: all 0.2s;
      cursor: pointer;
    }

    .event-item:hover {
      background: #eef2ff;
      transform: translateX(4px);
    }

    .event-color {
      width: 4px;
      border-radius: 8px;
      background: #2563eb;
    }

    .event-content {
      flex: 1;
    }

    .event-title {
      font-weight: 600;
      margin-bottom: 6px;
      color: #0f172a;
    }

    .event-time {
      font-size: 0.85rem;
      color: #64748b;
      display: flex;
      align-items: center;
      gap: 6px;
      margin-bottom: 4px;
    }

    .event-location {
      font-size: 0.8rem;
      color: #94a3b8;
      display: flex;
      align-items: center;
      gap: 6px;
    }

    .no-events {
      text-align: center;
      padding: 40px 20px;
      color: #94a3b8;
    }

    .no-events i {
      font-size: 3rem;
      margin-bottom: 16px;
      opacity: 0.5;
    }

    /* Événements à venir */
    .upcoming-section {
      margin-top: 24px;
    }

    .section-title {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 16px;
    }

    .section-title h4 {
      font-size: 1.1rem;
      font-weight: 600;
      margin: 0;
      color: #0f172a;
    }

    .section-title a {
      color: #2563eb;
      font-size: 0.9rem;
      text-decoration: none;
      font-weight: 500;
    }

    .upcoming-events {
      display: flex;
      flex-direction: column;
      gap: 12px;
    }

    .upcoming-item {
      display: flex;
      align-items: center;
      gap: 14px;
      padding: 12px 0;
      border-bottom: 1px solid #e2e8f0;
    }

    .upcoming-item:last-child {
      border-bottom: none;
    }

    .upcoming-date {
      width: 50px;
      height: 50px;
      background: #f1f5f9;
      border-radius: 14px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      font-weight: 600;
    }

    .upcoming-date .day {
      font-size: 1.2rem;
      color: #0f172a;
      line-height: 1.2;
    }

    .upcoming-date .month {
      font-size: 0.7rem;
      color: #64748b;
      text-transform: uppercase;
    }

    .upcoming-info {
      flex: 1;
    }

    .upcoming-info .title {
      font-weight: 600;
      color: #0f172a;
      margin-bottom: 4px;
    }

    .upcoming-info .time {
      font-size: 0.8rem;
      color: #64748b;
    }

    /* Responsive */
    @media (max-width: 640px) {
      body { padding: 16px; }
      .agenda-header { flex-direction: column; align-items: flex-start; }
      .header-right { width: 100%; justify-content: space-between; }
      .calendar-card { padding: 16px; }
      .calendar-day { font-size: 0.8rem; }
    }
  </style>
</head>
<body>

<div class="agenda-container">
  
  <!-- Header -->
  <div class="agenda-header">
    <div class="header-left">
      <h1>Agenda</h1>
      <p>Gérez vos rendez-vous et événements</p>
    </div>
    <div class="header-right">
      <div class="date-picker">
        <i class="bi bi-calendar3"></i>
        <span id="currentDateDisplay">Novembre 2024</span>
      </div>
      <button class="nav-btn" onclick="previousMonth()">
        <i class="bi bi-chevron-left"></i>
      </button>
      <button class="nav-btn" onclick="nextMonth()">
        <i class="bi bi-chevron-right"></i>
      </button>
      <button class="add-btn" onclick="addNewEvent()">
        <i class="bi bi-plus-lg"></i>
        Nouvel événement
      </button>
    </div>
  </div>

  <!-- Vue actuelle -->
  <div class="current-view">
    <h2 id="monthYearDisplay">Novembre 2024</h2>
    <div class="view-toggle">
      <button class="active" onclick="setView('month')">Mois</button>
      <button onclick="setView('week')">Semaine</button>
      <button onclick="setView('day')">Jour</button>
    </div>
  </div>

  <!-- Grille principale -->
  <div class="agenda-grid">
    
    <!-- Calendrier -->
    <div class="calendar-card">
      <div class="weekdays" id="weekdays">
        <!-- Jours de la semaine injectés par JS -->
      </div>
      <div class="calendar-days" id="calendarDays">
        <!-- Jours du calendrier injectés par JS -->
      </div>
    </div>

    <!-- Sidebar -->
    <div class="events-sidebar">
      <div class="sidebar-header">
        <h3>Événements du jour</h3>
        <span class="selected-date-badge" id="selectedDateBadge">Aujourd'hui</span>
      </div>
      
      <div class="events-list" id="dailyEventsList">
        <!-- Événements du jour sélectionné -->
      </div>

      <!-- Événements à venir -->
      <div class="upcoming-section">
        <div class="section-title">
          <h4>À venir</h4>
          <a href="#">Voir tout</a>
        </div>
        <div class="upcoming-events" id="upcomingEvents">
          <!-- Événements à venir injectés par JS -->
        </div>
      </div>
    </div>
  </div>
</div>

<script>
  // ===== DONNÉES =====
  let currentDate = new Date();
  let currentMonth = currentDate.getMonth();
  let currentYear = currentDate.getFullYear();
  let selectedDate = new Date();
  
  // Événements de démonstration
  const events = [
    { id: 1, title: 'Réunion design', date: '2024-11-15', time: '10:00', location: 'Salle visio', color: '#2563eb' },
    { id: 2, title: 'Déjeuner client', date: '2024-11-15', time: '12:30', location: 'Le Gourmet', color: '#10b981' },
    { id: 3, title: 'Présentation projet', date: '2024-11-18', time: '14:00', location: 'Salle comité', color: '#7c3aed' },
    { id: 4, title: 'Workshop UX', date: '2024-11-20', time: '09:00', location: 'Studio créa', color: '#f59e0b' },
    { id: 5, title: 'Revue de code', date: '2024-11-22', time: '16:30', location: 'En ligne', color: '#ef4444' },
    { id: 6, title: 'Call équipe', date: '2024-11-25', time: '11:00', location: 'Teams', color: '#2563eb' },
  ];

  // Jours de la semaine en français
  const weekdaysFR = ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'];
  const monthsFR = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];

  // ===== INITIALISATION =====
  function init() {
    renderWeekdays();
    renderCalendar();
    updateMonthYearDisplay();
    updateCurrentDateDisplay();
    renderDailyEvents();
    renderUpcomingEvents();
  }

  // ===== RENDU DES JOURS DE LA SEMAINE =====
  function renderWeekdays() {
    const weekdaysContainer = document.getElementById('weekdays');
    weekdaysContainer.innerHTML = weekdaysFR.map(day => 
      `<div class="weekday">${day}</div>`
    ).join('');
  }

  // ===== RENDU DU CALENDRIER =====
  function renderCalendar() {
    const calendarDays = document.getElementById('calendarDays');
    const firstDay = new Date(currentYear, currentMonth, 1);
    const lastDay = new Date(currentYear, currentMonth + 1, 0);
    
    // Ajuster pour commencer le lundi (getDay() retourne 0 pour dimanche)
    let startDay = firstDay.getDay() - 1;
    if (startDay < 0) startDay = 6;
    
    const totalDays = startDay + lastDay.getDate();
    const rows = Math.ceil(totalDays / 7);
    
    let html = '';
    let dayCount = 0;
    
    for (let i = 0; i < rows * 7; i++) {
      if (i < startDay) {
        // Jours du mois précédent
        const prevMonthDate = new Date(currentYear, currentMonth, 1 - (startDay - i));
        html += renderCalendarDay(prevMonthDate, true);
      } else if (dayCount < lastDay.getDate()) {
        dayCount++;
        const date = new Date(currentYear, currentMonth, dayCount);
        html += renderCalendarDay(date, false);
      } else {
        // Jours du mois suivant
        const nextMonthDate = new Date(currentYear, currentMonth + 1, dayCount - lastDay.getDate() + 1);
        html += renderCalendarDay(nextMonthDate, true);
      }
    }
    
    calendarDays.innerHTML = html;
  }

  function renderCalendarDay(date, isOtherMonth) {
    const day = date.getDate();
    const dateStr = formatDate(date);
    const isToday = isSameDay(date, new Date());
    const isSelected = isSameDay(date, selectedDate);
    const hasEvents = events.some(e => e.date === dateStr);
    
    let classes = 'calendar-day';
    if (isOtherMonth) classes += ' other-month';
    if (isToday) classes += ' today';
    if (hasEvents) classes += ' has-events';
    if (isSelected) classes += ' selected';
    
    return `<div class="${classes}" onclick="selectDate('${dateStr}')" style="${isSelected ? 'background: #2563eb; color: white;' : ''}">${day}</div>`;
  }

  // ===== SÉLECTION D'UNE DATE =====
  function selectDate(dateStr) {
    selectedDate = new Date(dateStr);
    renderCalendar();
    updateSelectedDateBadge();
    renderDailyEvents();
  }

  // ===== MISE À JOUR DU BADGE DE DATE SÉLECTIONNÉE =====
  function updateSelectedDateBadge() {
    const badge = document.getElementById('selectedDateBadge');
    const today = new Date();
    
    if (isSameDay(selectedDate, today)) {
      badge.textContent = 'Aujourd\'hui';
    } else {
      badge.textContent = `${selectedDate.getDate()} ${monthsFR[selectedDate.getMonth()].substring(0, 3)}`;
    }
  }

  // ===== RENDU DES ÉVÉNEMENTS DU JOUR =====
  function renderDailyEvents() {
    const container = document.getElementById('dailyEventsList');
    const dateStr = formatDate(selectedDate);
    const dailyEvents = events.filter(e => e.date === dateStr);
    
    if (dailyEvents.length === 0) {
      container.innerHTML = `
        <div class="no-events">
          <i class="bi bi-calendar-check"></i>
          <p>Aucun événement ce jour</p>
        </div>
      `;
      return;
    }
    
    dailyEvents.sort((a, b) => a.time.localeCompare(b.time));
    
    container.innerHTML = dailyEvents.map(event => `
      <div class="event-item" onclick="editEvent(${event.id})">
        <div class="event-color" style="background: ${event.color};"></div>
        <div class="event-content">
          <div class="event-title">${event.title}</div>
          <div class="event-time">
            <i class="bi bi-clock"></i>
            ${event.time}
          </div>
          <div class="event-location">
            <i class="bi bi-geo-alt"></i>
            ${event.location}
          </div>
        </div>
      </div>
    `).join('');
  }

  // ===== RENDU DES ÉVÉNEMENTS À VENIR =====
  function renderUpcomingEvents() {
    const container = document.getElementById('upcomingEvents');
    const today = new Date();
    const todayStr = formatDate(today);
    
    const upcoming = events
      .filter(e => e.date >= todayStr)
      .sort((a, b) => a.date.localeCompare(b.date))
      .slice(0, 3);
    
    container.innerHTML = upcoming.map(event => {
      const eventDate = new Date(event.date);
      return `
        <div class="upcoming-item" onclick="selectDate('${event.date}')">
          <div class="upcoming-date">
            <span class="day">${eventDate.getDate()}</span>
            <span class="month">${monthsFR[eventDate.getMonth()].substring(0, 3)}</span>
          </div>
          <div class="upcoming-info">
            <div class="title">${event.title}</div>
            <div class="time">${event.time} · ${event.location}</div>
          </div>
        </div>
      `;
    }).join('');
  }

  // ===== NAVIGATION =====
  function previousMonth() {
    currentMonth--;
    if (currentMonth < 0) {
      currentMonth = 11;
      currentYear--;
    }
    renderCalendar();
    updateMonthYearDisplay();
  }

  function nextMonth() {
    currentMonth++;
    if (currentMonth > 11) {
      currentMonth = 0;
      currentYear++;
    }
    renderCalendar();
    updateMonthYearDisplay();
  }

  function updateMonthYearDisplay() {
    document.getElementById('monthYearDisplay').textContent = 
      `${monthsFR[currentMonth]} ${currentYear}`;
  }

  function updateCurrentDateDisplay() {
    const today = new Date();
    document.getElementById('currentDateDisplay').textContent = 
      `${monthsFR[today.getMonth()]} ${today.getFullYear()}`;
  }

  // ===== CHANGEMENT DE VUE =====
  function setView(view) {
    document.querySelectorAll('.view-toggle button').forEach(btn => {
      btn.classList.remove('active');
    });
    event.target.classList.add('active');
    
    // Simulation de changement de vue (pour démonstration)
    console.log(`Vue changée pour: ${view}`);
  }

  // ===== ACTIONS SUR LES ÉVÉNEMENTS =====
  function addNewEvent() {
    alert('✨ Formulaire de création d\'événement\n\n(Fonctionnalité de démonstration)');
  }

  function editEvent(eventId) {
    const event = events.find(e => e.id === eventId);
    alert(`✏️ Modification de l'événement:\n\n${event.title}\n${event.time} · ${event.location}`);
  }

  // ===== UTILITAIRES =====
  function formatDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  }

  function isSameDay(date1, date2) {
    return date1.getFullYear() === date2.getFullYear() &&
           date1.getMonth() === date2.getMonth() &&
           date1.getDate() === date2.getDate();
  }

  // ===== DÉMARRAGE =====
  init();

  console.log('✅ Agenda moderne - Prêt !');
</script>

</body>
</html>

Ouvrir cet aperçu dans un nouvel onglet du navigateur

🔗 Ouvrir dans le navigateur