This commit is contained in:
2026-05-21 15:35:54 +02:00
commit 2d39550bc8
333 changed files with 7768 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title> Downloads </title>
</head>
<body>
<h1> Downloads </h1>
<ul>
<li><a id="https://restaurantcolibri.ca/" href="index.html"> Colibri — Bon pour vrai, prêt quand vous l&apos;êtes. </a></li>
</ul>
</body>
</html>

View File

@@ -0,0 +1 @@
"use strict";(()=>{function e(e){let t=location.href;if(e){let n=new URL(t);if(n.pathname!==e)return n.pathname=e,n.search="",n.href}return t}function t(){return!!(navigator.webdriver||navigator.userAgent.includes("Headless"))}var n,a,r,i,o=(r=()=>{},()=>(r&&(i=r(r=0)),i));(n=()=>{o(),function(){var n;let a=e=>e,r=document,i=r.currentScript;if(t())return;let o=null!=(n=null==i?void 0:i.dataset)?n:{},l=d(o,"view"),s=d(o,"event"),u=d(o,"session"),c=null,p=null,f=!0;function d(e,t){return e[`${t}Endpoint`]||("endpoint"in e?`${e.endpoint}/${t}`:`${null!=i&&i.src.includes("/va/")?"/va":"/_vercel/insights"}/${t}`)}async function h(e){if(e&&!Array.isArray(e))return{p:e};let t=r.querySelectorAll("[data-flag-values]");if(!i||!t.length)return;let n=new URL(i.src),a=n.pathname.split("/"),o=a.pop();return o&&a.push("flags",o),n.pathname=a.join("/"),import(n.href).then(n=>n.gather(t,e))}async function v({type:t,data:n,options:i}){var u;let f=e(p),d=r.referrer,v=a({type:t,url:f,payload:n});if(!1===v||null===v)return;v&&(f=v.url,n=null!=(u=v.payload)?u:n);let w=d.includes(location.host),y={o:f,sv:"0.1.3",sdkn:o.sdkn,sdkv:o.sdkv,ts:Date.now(),...c&&{dp:c},...null!=i&&i.withReferrer&&!w?{r:d}:{},..."event"===t&&n&&{en:n.name,ed:n.data},f:await h(null==i?void 0:i.flags).catch(()=>{})};try{await fetch("pageview"===t?l:s,{method:"POST",keepalive:!0,headers:{"Content-Type":"application/json"},body:JSON.stringify(y)})}catch(g){}}async function w(e={}){return v({type:"pageview",options:{withReferrer:e.withReferrer}})}async function y(e,t,n){return v({type:"event",data:{name:e,data:t},options:{withReferrer:!0,flags:null==n?void 0:n.flags}})}async function g(){await fetch(u,{method:"GET",keepalive:!0}).catch(()=>{})}function m(e){return e.pathname===new URL(k).pathname}function R(e){let t=e?"string"==typeof e?new URL(e,location.origin):new URL(e.href):null;!t||m(t)||t.hash&&m(t)||w()}let k=e(),S=()=>{var e;window.va=function(e,t){"beforeSend"===e?a=t:"event"===e?t&&y(t.name,t.data,t.options):"pageview"===e&&t&&(t.route&&(c=t.route),t.path&&(p=t.path),w({withReferrer:f}),f=!1),"enableCookie"===e&&g()},null==(e=window.vaq)||e.forEach(([e,t])=>{window.va(e,t)})};(()=>{if(window.vai||(window.vai=!0,S(),o.disableAutoTrack))return;w({withReferrer:!0});let t=history.pushState.bind(history);history.pushState=function(...n){t(...n);try{R(n[2]),k=e()}catch(a){}},window.addEventListener("popstate",function(){R(e()),k=e()})})()}()},()=>(a||n((a={exports:{}}).exports,a),a.exports))()})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Commande en ligne — Restaurant Colibri</title>
<meta name="description" content="Commandez en ligne chez Restaurant Colibri. Cuisine fraîche et locale à Québec.">
<link rel="icon" href="../../favicon.ico" sizes="32x32">
<link rel="icon" type="image/png" href="../../images/favicon-192.png" sizes="192x192">
<link rel="apple-touch-icon" href="../../images/apple-touch-icon.png">
<link rel="stylesheet" href="../../styles.css">
<style>.order-page {
min-height: 100vh;
padding-top: 100px;
}
.order-page__header {
text-align: center;
padding: 2rem 1rem 1rem;
}
.order-page__back {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--color-vert);
text-decoration: none;
font-weight: 600;
margin-bottom: 1rem;
}
.order-page__back:hover {
text-decoration: underline;
}
#ueat-order {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem 4rem;
min-height: 600px;
}
</style>
</head>
<body>
<!-- Minimal header with back link -->
<div class="order-page">
<div class="order-page__header">
<a href="../../index.html" class="order-page__back">← Retour au site</a>
<h1 style="font-family: var(--font-serif); color: var(--color-vert); font-size: 2rem;">Commande en ligne</h1>
</div>
<!-- UEAT Integration -->
<div id="ueat-order"></div>
</div>
<script id="ueat-integration" src="https://order.ueat.io/integration/8725227c-800a-4af4-9876-11ab21977bae/fr-CA.js"></script>
<script defer src="../../_vercel/insights/script.js"></script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 902 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,430 @@
/* ============================================
RESTAURANT COLIBRI — JavaScript
============================================ */
document.addEventListener('DOMContentLoaded', () => {
// ===== NAVIGATION — Scroll Effect =====
const nav = document.getElementById('nav');
const handleNavScroll = () => {
if (window.scrollY > 50) {
nav.classList.add('nav--scrolled');
} else {
nav.classList.remove('nav--scrolled');
}
};
window.addEventListener('scroll', handleNavScroll, { passive: true });
handleNavScroll();
// ===== HERO CAROUSEL =====
const heroSlides = document.querySelectorAll('.hero__slide');
const heroDots = document.querySelectorAll('.hero__dot');
const heroPrev = document.getElementById('heroPrev');
const heroNext = document.getElementById('heroNext');
let currentSlide = 0;
let heroInterval = null;
const goToSlide = (index) => {
heroSlides[currentSlide].classList.remove('active');
heroDots[currentSlide].classList.remove('active');
currentSlide = (index + heroSlides.length) % heroSlides.length;
heroSlides[currentSlide].classList.add('active');
heroDots[currentSlide].classList.add('active');
};
const startHeroAutoplay = () => {
heroInterval = setInterval(() => goToSlide(currentSlide + 1), 6000);
};
const resetHeroAutoplay = () => {
clearInterval(heroInterval);
startHeroAutoplay();
};
if (heroSlides.length > 1) {
heroPrev.addEventListener('click', () => {
goToSlide(currentSlide - 1);
resetHeroAutoplay();
});
heroNext.addEventListener('click', () => {
goToSlide(currentSlide + 1);
resetHeroAutoplay();
});
heroDots.forEach(dot => {
dot.addEventListener('click', () => {
goToSlide(parseInt(dot.dataset.slide));
resetHeroAutoplay();
});
});
startHeroAutoplay();
// Touch swipe support
const heroEl = document.querySelector('.hero');
let touchStartX = 0;
let touchEndX = 0;
heroEl.addEventListener('touchstart', (e) => {
touchStartX = e.changedTouches[0].screenX;
}, { passive: true });
heroEl.addEventListener('touchend', (e) => {
touchEndX = e.changedTouches[0].screenX;
const diff = touchStartX - touchEndX;
if (Math.abs(diff) > 50) {
if (diff > 0) {
goToSlide(currentSlide + 1);
} else {
goToSlide(currentSlide - 1);
}
resetHeroAutoplay();
}
}, { passive: true });
}
// ===== MOBILE MENU =====
const burger = document.getElementById('navBurger');
const mobileMenu = document.getElementById('mobileMenu');
const mobileLinks = document.querySelectorAll('.mobile-menu__link, .mobile-menu__cta');
if (burger && mobileMenu) {
burger.addEventListener('click', () => {
burger.classList.toggle('active');
mobileMenu.classList.toggle('active');
document.body.style.overflow = mobileMenu.classList.contains('active') ? 'hidden' : '';
});
mobileLinks.forEach(link => {
link.addEventListener('click', () => {
burger.classList.remove('active');
mobileMenu.classList.remove('active');
document.body.style.overflow = '';
});
});
}
// ===== MENU TABS (with ARIA) =====
const tabs = document.querySelectorAll('.menu__tab');
const contents = document.querySelectorAll('.menu__content');
// Set ARIA roles
const tabList = document.querySelector('.menu__tabs');
if (tabList) tabList.setAttribute('role', 'tablist');
tabs.forEach((tab, i) => {
const target = tab.dataset.tab;
tab.setAttribute('role', 'tab');
tab.setAttribute('aria-controls', `tab-${target}`);
tab.setAttribute('aria-selected', tab.classList.contains('active') ? 'true' : 'false');
tab.id = `tab-btn-${target}`;
});
contents.forEach(content => {
content.setAttribute('role', 'tabpanel');
const id = content.id.replace('tab-', '');
content.setAttribute('aria-labelledby', `tab-btn-${id}`);
});
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const target = tab.dataset.tab;
// Update active tab + ARIA
tabs.forEach(t => {
t.classList.remove('active');
t.setAttribute('aria-selected', 'false');
});
tab.classList.add('active');
tab.setAttribute('aria-selected', 'true');
// Show target content
contents.forEach(content => {
content.classList.remove('active');
content.classList.remove('scrolled-end');
if (content.id === `tab-${target}`) {
content.classList.add('active');
// Reset scroll position & check scroll indicator
const grid = content.querySelector('.menu__grid');
if (grid) {
grid.scrollLeft = 0;
checkScrollEnd(content, grid);
}
}
});
});
});
// ===== SCROLL INDICATOR — fade gradient at end =====
const checkScrollEnd = (contentEl, gridEl) => {
const atEnd = gridEl.scrollLeft + gridEl.clientWidth >= gridEl.scrollWidth - 10;
if (atEnd) {
contentEl.classList.add('scrolled-end');
} else {
contentEl.classList.remove('scrolled-end');
}
};
document.querySelectorAll('.menu__grid').forEach(grid => {
grid.addEventListener('scroll', () => {
const contentEl = grid.closest('.menu__content');
if (contentEl) checkScrollEnd(contentEl, grid);
}, { passive: true });
});
// Initial check for active tab
const activeContent = document.querySelector('.menu__content.active');
if (activeContent) {
const activeGrid = activeContent.querySelector('.menu__grid');
if (activeGrid) checkScrollEnd(activeContent, activeGrid);
}
// ===== DIETARY FILTERS (multi-select) =====
const filterBtns = document.querySelectorAll('.menu__filter');
const filterReset = document.getElementById('filterReset');
const allCards = document.querySelectorAll('.menu-card');
const applyFilters = () => {
// Gather all active filters
const activeFilters = [];
filterBtns.forEach(b => {
if (b.classList.contains('active')) activeFilters.push(b.dataset.filter);
});
// Show/hide reset button
if (filterReset) {
filterReset.classList.toggle('visible', activeFilters.length > 0);
}
// No filters active = show everything
if (activeFilters.length === 0) {
allCards.forEach(card => card.classList.remove('filtered-out'));
} else {
allCards.forEach(card => {
const diet = (card.dataset.diet || '').split(' ').filter(Boolean);
const hasNuts = card.dataset.noix === 'true';
// Card must match ALL active filters (AND logic)
const pass = activeFilters.every(f => {
if (f === 'sg') return diet.includes('sg');
if (f === 'v') return diet.includes('v') || diet.includes('vg');
if (f === 'vg') return diet.includes('vg');
if (f === 'noix') return !hasNuts;
return true;
});
card.classList.toggle('filtered-out', !pass);
});
}
// Empty-state per tab panel
document.querySelectorAll('.menu__content').forEach(panel => {
const grids = panel.querySelectorAll('.menu__grid');
let allHidden = true;
grids.forEach(grid => {
if (grid.querySelectorAll('.menu-card:not(.filtered-out)').length > 0) allHidden = false;
});
let emptyMsg = panel.querySelector('.menu__empty-msg');
if (allHidden && activeFilters.length > 0) {
if (!emptyMsg) {
emptyMsg = document.createElement('p');
emptyMsg.className = 'menu__empty-msg visible';
emptyMsg.textContent = 'Aucun item ne correspond à ces filtres dans cette catégorie.';
panel.appendChild(emptyMsg);
} else {
emptyMsg.classList.add('visible');
}
} else if (emptyMsg) {
emptyMsg.classList.remove('visible');
}
});
};
// Toggle individual filter chips
filterBtns.forEach(btn => {
btn.addEventListener('click', () => {
btn.classList.toggle('active');
applyFilters();
});
});
// Reset all filters
if (filterReset) {
filterReset.addEventListener('click', () => {
filterBtns.forEach(b => b.classList.remove('active'));
applyFilters();
});
}
// ===== SMOOTH SCROLL for anchor links =====
document.querySelectorAll('a[href^="#"]').forEach(link => {
link.addEventListener('click', (e) => {
const targetId = link.getAttribute('href');
if (targetId === '#') return;
const target = document.querySelector(targetId);
if (target) {
e.preventDefault();
const navHeight = window.innerWidth < 768 ? 64 : 80;
const top = target.getBoundingClientRect().top + window.scrollY - navHeight;
window.scrollTo({
top,
behavior: 'smooth'
});
}
});
});
// ===== SCROLL REVEAL ANIMATION =====
const revealElements = document.querySelectorAll(
'.section__header, .menu-card, .value-card, ' +
'.traiteur__visual, .traiteur__content, ' +
'.contact__info, .contact__form, .traiteur__feature'
);
revealElements.forEach(el => {
el.classList.add('reveal');
});
const revealOnScroll = () => {
const windowHeight = window.innerHeight;
document.querySelectorAll('.reveal').forEach(el => {
const elementTop = el.getBoundingClientRect().top;
const revealPoint = windowHeight - 80;
if (elementTop < revealPoint) {
el.classList.add('visible');
}
});
};
window.addEventListener('scroll', revealOnScroll, { passive: true });
revealOnScroll(); // trigger on load
// ===== ACTIVE NAV LINK on scroll =====
const sections = document.querySelectorAll('section[id]');
const navLinks = document.querySelectorAll('.nav__link');
const highlightNav = () => {
const scrollY = window.scrollY + 100;
sections.forEach(section => {
const top = section.offsetTop - 100;
const height = section.offsetHeight;
const id = section.getAttribute('id');
if (scrollY >= top && scrollY < top + height) {
navLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('href') === `#${id}`) {
link.classList.add('active');
}
});
}
});
};
window.addEventListener('scroll', highlightNav, { passive: true });
// ===== CONTACT FORM — FormSubmit.co (AJAX) =====
const contactForm = document.getElementById('contactForm');
if (contactForm) {
const btn = contactForm.querySelector('button[type="submit"]');
const btnOriginalText = btn.textContent;
contactForm.addEventListener('submit', (e) => {
e.preventDefault();
btn.textContent = 'Envoi en cours...';
btn.disabled = true;
const formData = new FormData(contactForm);
fetch(contactForm.action, {
method: 'POST',
body: formData,
headers: { 'Accept': 'application/json' }
})
.then(response => {
if (response.ok) {
// Success
contactForm.reset();
btn.textContent = 'Message envoyé ✓';
btn.style.background = 'var(--color-vert)';
setTimeout(() => {
btn.textContent = btnOriginalText;
btn.disabled = false;
btn.style.background = '';
}, 4000);
} else {
throw new Error('Erreur serveur');
}
})
.catch(() => {
btn.textContent = 'Erreur — Réessayer';
btn.style.background = '#c0392b';
btn.disabled = false;
setTimeout(() => {
btn.textContent = btnOriginalText;
btn.style.background = '';
}, 4000);
});
});
}
// ===== MOBILE STICKY CTA =====
const mobileCta = document.getElementById('mobileCta');
if (mobileCta) {
const heroSection = document.getElementById('hero');
const footerEl = document.querySelector('.footer');
const toggleMobileCta = () => {
if (window.innerWidth > 768) {
mobileCta.classList.remove('visible');
return;
}
const heroBottom = heroSection ? heroSection.offsetTop + heroSection.offsetHeight : 600;
const footerTop = footerEl ? footerEl.offsetTop : Infinity;
const scrollBottom = window.scrollY + window.innerHeight;
// Hide when a section CTA button is visible on screen
const sectionBtns = document.querySelectorAll('.menu__footer .btn, .contact__form .btn');
let sectionCtaVisible = false;
sectionBtns.forEach(btn => {
const rect = btn.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
sectionCtaVisible = true;
}
});
if (window.scrollY > heroBottom && scrollBottom < footerTop + 40 && !sectionCtaVisible) {
mobileCta.classList.add('visible');
} else {
mobileCta.classList.remove('visible');
}
};
window.addEventListener('scroll', toggleMobileCta, { passive: true });
toggleMobileCta();
}
// ===== PARALLAX subtle on hero =====
const heroContent = document.querySelector('.hero__content');
if (heroContent && window.innerWidth > 768) {
window.addEventListener('scroll', () => {
const scrollY = window.scrollY;
if (scrollY < window.innerHeight) {
heroContent.style.transform = `translateY(${scrollY * 0.15}px)`;
heroContent.style.opacity = 1 - (scrollY / (window.innerHeight * 0.8));
}
}, { passive: true });
}
});

File diff suppressed because it is too large Load Diff