|
| 1 | +--- |
| 2 | +export interface Props { |
| 3 | + lang: 'es' | 'en'; |
| 4 | +} |
| 5 | +const { lang } = Astro.props; |
| 6 | +
|
| 7 | +const t = { |
| 8 | + es: { |
| 9 | + intro: 'Uso cookies analíticas para saber qué contenidos funcionan y mejorar la web. Nada de publicidad ni de terceros.', |
| 10 | + more: 'Más información', |
| 11 | + href: '/es/legal/#cookies', |
| 12 | + accept: 'Aceptar', |
| 13 | + reject: 'Solo esenciales', |
| 14 | + label: 'Aviso de cookies', |
| 15 | + }, |
| 16 | + en: { |
| 17 | + intro: 'I use analytics cookies to see what works and improve the site. No ads, no third parties.', |
| 18 | + more: 'Learn more', |
| 19 | + href: '/legal/#cookies', |
| 20 | + accept: 'Accept', |
| 21 | + reject: 'Only essential', |
| 22 | + label: 'Cookie notice', |
| 23 | + }, |
| 24 | +}[lang]; |
| 25 | +--- |
| 26 | + |
| 27 | +<aside |
| 28 | + class="cookie-banner" |
| 29 | + role="dialog" |
| 30 | + aria-label={t.label} |
| 31 | + aria-live="polite" |
| 32 | + hidden |
| 33 | + data-cookie-banner |
| 34 | +> |
| 35 | + <div class="cookie-banner-inner"> |
| 36 | + <p class="cookie-banner-copy"> |
| 37 | + {t.intro} |
| 38 | + <a href={t.href} class="cookie-banner-link">{t.more}</a> |
| 39 | + </p> |
| 40 | + <div class="cookie-banner-actions"> |
| 41 | + <button type="button" class="cookie-banner-btn cookie-banner-btn-ghost" data-cookie-reject> |
| 42 | + {t.reject} |
| 43 | + </button> |
| 44 | + <button type="button" class="cookie-banner-btn cookie-banner-btn-primary" data-cookie-accept> |
| 45 | + {t.accept} |
| 46 | + </button> |
| 47 | + </div> |
| 48 | + </div> |
| 49 | +</aside> |
| 50 | + |
| 51 | +<script is:inline> |
| 52 | + (function () { |
| 53 | + var banner = document.querySelector('[data-cookie-banner]'); |
| 54 | + if (!banner) return; |
| 55 | + |
| 56 | + var stored = null; |
| 57 | + try { |
| 58 | + stored = localStorage.getItem('cookie-consent'); |
| 59 | + } catch (e) {} |
| 60 | + |
| 61 | + if (!stored) { |
| 62 | + banner.hidden = false; |
| 63 | + // Delay adding the visible class so CSS transition kicks in. |
| 64 | + requestAnimationFrame(function () { |
| 65 | + banner.classList.add('is-visible'); |
| 66 | + }); |
| 67 | + } |
| 68 | + |
| 69 | + function persist(value) { |
| 70 | + try { |
| 71 | + localStorage.setItem('cookie-consent', value); |
| 72 | + } catch (e) {} |
| 73 | + } |
| 74 | + |
| 75 | + function close() { |
| 76 | + banner.classList.remove('is-visible'); |
| 77 | + // Wait for the transition to finish before hiding entirely. |
| 78 | + setTimeout(function () { |
| 79 | + banner.hidden = true; |
| 80 | + }, 260); |
| 81 | + } |
| 82 | + |
| 83 | + var accept = banner.querySelector('[data-cookie-accept]'); |
| 84 | + var reject = banner.querySelector('[data-cookie-reject]'); |
| 85 | + |
| 86 | + if (accept) { |
| 87 | + accept.addEventListener('click', function () { |
| 88 | + persist('granted'); |
| 89 | + if (typeof gtag === 'function') { |
| 90 | + gtag('consent', 'update', { analytics_storage: 'granted' }); |
| 91 | + } |
| 92 | + close(); |
| 93 | + }); |
| 94 | + } |
| 95 | + if (reject) { |
| 96 | + reject.addEventListener('click', function () { |
| 97 | + persist('denied'); |
| 98 | + if (typeof gtag === 'function') { |
| 99 | + gtag('consent', 'update', { analytics_storage: 'denied' }); |
| 100 | + } |
| 101 | + close(); |
| 102 | + }); |
| 103 | + } |
| 104 | + })(); |
| 105 | +</script> |
| 106 | + |
| 107 | +<style> |
| 108 | + .cookie-banner { |
| 109 | + position: fixed; |
| 110 | + left: 50%; |
| 111 | + bottom: 1.25rem; |
| 112 | + transform: translate(-50%, 130%); |
| 113 | + z-index: var(--z-toast); |
| 114 | + width: min(calc(100vw - 2rem), 44rem); |
| 115 | + padding: 1rem 1.25rem; |
| 116 | + background: color-mix(in oklch, var(--surface-raised) 92%, transparent); |
| 117 | + border: 1px solid var(--stroke-medium); |
| 118 | + border-radius: var(--radius-lg); |
| 119 | + box-shadow: 0 30px 80px -20px oklch(0 0 0 / 0.7); |
| 120 | + backdrop-filter: saturate(140%) blur(16px); |
| 121 | + -webkit-backdrop-filter: saturate(140%) blur(16px); |
| 122 | + opacity: 0; |
| 123 | + transition: transform 320ms var(--ease-out-quart), opacity 320ms var(--ease-out-quart); |
| 124 | + } |
| 125 | + |
| 126 | + .cookie-banner.is-visible { |
| 127 | + transform: translate(-50%, 0); |
| 128 | + opacity: 1; |
| 129 | + } |
| 130 | + |
| 131 | + .cookie-banner-inner { |
| 132 | + display: flex; |
| 133 | + flex-direction: column; |
| 134 | + gap: 0.85rem; |
| 135 | + align-items: flex-start; |
| 136 | + } |
| 137 | + |
| 138 | + @media (min-width: 720px) { |
| 139 | + .cookie-banner-inner { |
| 140 | + flex-direction: row; |
| 141 | + align-items: center; |
| 142 | + gap: 1.25rem; |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + .cookie-banner-copy { |
| 147 | + flex: 1; |
| 148 | + color: var(--ink-body); |
| 149 | + font-family: var(--font-body); |
| 150 | + font-size: 0.85rem; |
| 151 | + line-height: 1.5; |
| 152 | + margin: 0; |
| 153 | + } |
| 154 | + |
| 155 | + .cookie-banner-link { |
| 156 | + color: var(--ink-primary); |
| 157 | + text-decoration: underline; |
| 158 | + text-decoration-color: var(--crimson); |
| 159 | + text-underline-offset: 3px; |
| 160 | + transition: color var(--dur-fast); |
| 161 | + white-space: nowrap; |
| 162 | + margin-left: 0.25rem; |
| 163 | + } |
| 164 | + |
| 165 | + .cookie-banner-link:hover { color: var(--crimson); } |
| 166 | + |
| 167 | + .cookie-banner-actions { |
| 168 | + display: flex; |
| 169 | + align-items: center; |
| 170 | + gap: 0.5rem; |
| 171 | + flex-shrink: 0; |
| 172 | + flex-wrap: wrap; |
| 173 | + } |
| 174 | + |
| 175 | + .cookie-banner-btn { |
| 176 | + display: inline-flex; |
| 177 | + align-items: center; |
| 178 | + justify-content: center; |
| 179 | + padding: 0.6rem 1rem; |
| 180 | + border-radius: var(--radius-pill); |
| 181 | + font-family: var(--font-body); |
| 182 | + font-weight: 600; |
| 183 | + font-size: 0.8rem; |
| 184 | + line-height: 1; |
| 185 | + cursor: pointer; |
| 186 | + border: 1px solid transparent; |
| 187 | + transition: background-color var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast), transform var(--dur-fast); |
| 188 | + white-space: nowrap; |
| 189 | + } |
| 190 | + |
| 191 | + .cookie-banner-btn-primary { |
| 192 | + background: var(--crimson); |
| 193 | + color: var(--ink-primary); |
| 194 | + } |
| 195 | + |
| 196 | + .cookie-banner-btn-primary:hover { |
| 197 | + background: var(--crimson-hot); |
| 198 | + } |
| 199 | + |
| 200 | + .cookie-banner-btn-ghost { |
| 201 | + background: transparent; |
| 202 | + color: var(--ink-primary); |
| 203 | + border-color: var(--stroke-medium); |
| 204 | + } |
| 205 | + |
| 206 | + .cookie-banner-btn-ghost:hover { |
| 207 | + background: color-mix(in oklch, var(--surface-lifted) 60%, transparent); |
| 208 | + border-color: var(--stroke-strong); |
| 209 | + } |
| 210 | +</style> |
0 commit comments