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