diff --git a/content/en/donate-2026.html b/content/en/donate-2026.html new file mode 100644 index 000000000..f3e684815 --- /dev/null +++ b/content/en/donate-2026.html @@ -0,0 +1,9 @@ +--- +title: Support Let's Encrypt +slug: donate-2026 +type: page +layout: donate-2026 +no_donate_footer: true +useContainer: false +lastmod: 2026-06-05 +--- diff --git a/data/donate-2026.json b/data/donate-2026.json new file mode 100644 index 000000000..2c96b8f8c --- /dev/null +++ b/data/donate-2026.json @@ -0,0 +1,37 @@ +{ + "items": [ + { + "id": "item-1", + "eyebrow": "Donate $40+ [PLACEHOLDER]", + "title": "Item One [PLACEHOLDER]", + "description": "Replace this description with the actual merch item details.", + "images": [ + { "thumb": "/images/donate-2024/thumbs/Thumbnail-Donate-2024-Gift-Puzzle-1.png", "full": "/images/donate-2024/Selections/Puzzle/Donate-2024-Gift-Puzzle-1.png" }, + { "thumb": "/images/donate-2024/thumbs/Thumbnail-Donate-2024-Gift-Puzzle-2.jpg", "full": "/images/donate-2024/Selections/Puzzle/Donate-2024-Gift-Puzzle-2.png" }, + { "thumb": "/images/donate-2024/thumbs/Thumbnail-Donate-2024-Gift-Puzzle-3.png", "full": "/images/donate-2024/Selections/Puzzle/Donate-2024-Gift-Puzzle-3.png" } + ] + }, + { + "id": "item-2", + "eyebrow": "Donate $40+ [PLACEHOLDER]", + "title": "Item Two [PLACEHOLDER]", + "description": "Replace this description with the actual merch item details.", + "images": [ + { "thumb": "/images/donate-2024/thumbs/Thumbnail-Donate-2024-Gift-Print-1.jpg", "full": "/images/donate-2024/Selections/Poster/Donate-2024-Gift-Print-1.png" }, + { "thumb": "/images/donate-2024/thumbs/Thumbnail-Donate-2024-Gift-Print-2.jpg", "full": "/images/donate-2024/Selections/Poster/Donate-2024-Gift-Print-2.png" }, + { "thumb": "/images/donate-2024/thumbs/Thumbnail-Donate-2024-Gift-Print-3.jpg", "full": "/images/donate-2024/Selections/Poster/Donate-2024-Gift-Print-3.png" } + ] + }, + { + "id": "item-3", + "eyebrow": "Donate $40+ [PLACEHOLDER]", + "title": "Item Three [PLACEHOLDER]", + "description": "Replace this description with the actual merch item details.", + "images": [ + { "thumb": "/images/donate-2024/thumbs/Thumbnail-Donate-2024-Gift-Shirt-1.jpg", "full": "/images/donate-2024/Selections/Tee/Donate-2024-Gift-Shirt-1.png" }, + { "thumb": "/images/donate-2024/thumbs/Thumbnail-Donate-2024-Gift-Shirt-2.jpg", "full": "/images/donate-2024/Selections/Tee/Donate-2024-Gift-Shirt-2.png" }, + { "thumb": "/images/donate-2024/thumbs/Thumbnail-Donate-2024-Gift-Shirt-3.jpg", "full": "/images/donate-2024/Selections/Tee/Donate-2024-Gift-Shirt-3.png" } + ] + } + ] +} diff --git a/i18n/en.toml b/i18n/en.toml index 3ada28eb5..f4f6f2153 100644 --- a/i18n/en.toml +++ b/i18n/en.toml @@ -549,3 +549,14 @@ other = "We are able to accept most cryptocurrency donations {{ .cryptoLink }}." [donate_page_crypto_link_text] other = "here" + +# ── Donate 2026 Campaign ────────────────────────────────── + +[donate_2026_hero_title] +other = "Encryption for Everybody." + +[donate_2026_hero_body] +other = "For over a decade, Let's Encrypt has provided billions of free TLS certificates. Each one made possible thanks to the generosity of people like you. Donate today to help us continue this work, and we'll say thanks with a gift of your choosing." + +[donate_2026_cta_button] +other = "Donate Now" diff --git a/themes/le-2025/assets/css/donate-2026.css b/themes/le-2025/assets/css/donate-2026.css new file mode 100644 index 000000000..6728b54b2 --- /dev/null +++ b/themes/le-2025/assets/css/donate-2026.css @@ -0,0 +1,43 @@ +/* ── Donate 2026 Campaign ──────────────────────────────── */ +@utility donate-2026-item { + @apply flex flex-col md:flex-row gap-6 pb-10 border-b border-gray-200; + + &:last-child { + @apply border-b-0; + } +} +@utility donate-2026-carousel { + @apply w-full md:w-48 flex-shrink-0; +} +@utility donate-2026-carousel-img { + @apply hidden w-full rounded-lg bg-white object-contain cursor-zoom-in; + + &.active { + @apply block; + } +} +@utility donate-2026-carousel-prev { + @apply w-8 h-8 bg-gray-200 rounded text-center font-bold text-base leading-8 hover:bg-gray-300 select-none; +} +@utility donate-2026-carousel-next { + @apply w-8 h-8 bg-gray-200 rounded text-center font-bold text-base leading-8 hover:bg-gray-300 select-none; +} +@utility donate-2026-eyebrow { + @apply uppercase tracking-wider text-sm font-bold text-le-yellow mb-2; +} +@utility donate-2026-lightbox { + @apply hidden fixed inset-0 z-[999] bg-black/70 items-center justify-center; + + &.active { + @apply flex; + } +} +@utility donate-2026-sticky-cta { + @apply fixed bottom-0 left-0 w-full z-[1000] lg:hidden; + transform: translateY(100%); + transition: transform 0.2s ease-in-out; + + &.visible { + transform: translateY(0); + } +} diff --git a/themes/le-2025/assets/css/le-2025-theme-input.css b/themes/le-2025/assets/css/le-2025-theme-input.css index f5384b05b..32e15b8e5 100644 --- a/themes/le-2025/assets/css/le-2025-theme-input.css +++ b/themes/le-2025/assets/css/le-2025-theme-input.css @@ -673,3 +673,5 @@ .prose-content .pull-quote-right blockquote { @apply mt-0 pt-0 border-0 pl-0; } + +@import "./donate-2026.css"; diff --git a/themes/le-2025/assets/js/donate-2026.js b/themes/le-2025/assets/js/donate-2026.js new file mode 100644 index 000000000..00e5ed2aa --- /dev/null +++ b/themes/le-2025/assets/js/donate-2026.js @@ -0,0 +1,97 @@ +const Donate2026 = { + init() { + const page = document.getElementById('donate-2026-page'); + if (!page) return; + + this.initCarousels(); + this.initLightbox(); + this.initStickyCTA(); + }, + + initCarousels() { + document.querySelectorAll('.donate-2026-carousel').forEach(carousel => { + const images = carousel.querySelectorAll('.donate-2026-carousel-img'); + const prevBtn = carousel.querySelector('.donate-2026-carousel-prev'); + const nextBtn = carousel.querySelector('.donate-2026-carousel-next'); + const counter = carousel.querySelector('.donate-2026-carousel-counter'); + if (images.length <= 1) return; + + let current = 0; + + const show = (index) => { + images[current].classList.remove('active'); + current = (index + images.length) % images.length; + images[current].classList.add('active'); + if (counter) counter.textContent = `${current + 1} / ${images.length}`; + }; + + prevBtn.addEventListener('click', () => show(current - 1)); + nextBtn.addEventListener('click', () => show(current + 1)); + + images.forEach(img => { + img.addEventListener('click', () => { + const fullSrc = img.getAttribute('data-full'); + if (fullSrc) this.openLightbox(fullSrc); + }); + }); + }); + }, + + initLightbox() { + const lightbox = document.getElementById('donate-2026-lightbox'); + const lightboxImg = document.getElementById('donate-2026-lightbox-img'); + if (!lightbox || !lightboxImg) return; + + lightbox.addEventListener('click', (e) => { + if (e.target === lightboxImg) return; + this.closeLightbox(); + }); + + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && lightbox.getAttribute('aria-hidden') === 'false') { + this.closeLightbox(); + } + }); + }, + + openLightbox(src) { + const lightbox = document.getElementById('donate-2026-lightbox'); + const lightboxImg = document.getElementById('donate-2026-lightbox-img'); + lightboxImg.src = src; + lightbox.setAttribute('aria-hidden', 'false'); + lightbox.classList.add('active'); + document.body.style.overflow = 'hidden'; + }, + + closeLightbox() { + const lightbox = document.getElementById('donate-2026-lightbox'); + lightbox.setAttribute('aria-hidden', 'true'); + lightbox.classList.remove('active'); + document.body.style.overflow = ''; + }, + + initStickyCTA() { + const cta = document.getElementById('donate-2026-sticky-cta'); + const anchor = document.getElementById('donate-2026-form-anchor'); + if (!cta || !anchor) return; + + const update = () => { + const rect = anchor.getBoundingClientRect(); + const formVisible = rect.top >= -100 && rect.top <= window.innerHeight + 100; + cta.classList.toggle('visible', !formVisible); + }; + + cta.querySelector('a').addEventListener('click', (e) => { + e.preventDefault(); + anchor.scrollIntoView({ behavior: 'smooth' }); + }); + + document.addEventListener('scroll', update, { passive: true }); + window.addEventListener('resize', update); + update(); + } +}; + +document.addEventListener('DOMContentLoaded', () => { + Donate2026.init(); +}); diff --git a/themes/le-2025/layouts/page/donate-2026.html b/themes/le-2025/layouts/page/donate-2026.html new file mode 100644 index 000000000..e63c71326 --- /dev/null +++ b/themes/le-2025/layouts/page/donate-2026.html @@ -0,0 +1,48 @@ +{{ define "main" }} +
{{ T "donate_2026_hero_body" }}
+{{ .description }}
+