Modales & Capasoverlayscookiegdprprivacydrawer
Cookie Preferences Drawer
Panel lateral para configurar categorías detalladas de cookies técnicas y analíticas.
Vista Previa en Vivo
Uso
Copia y pega este código directamente en tu componente React:
tsx
import { CookiePreferencesDrawer } from 'react-component-kit-ui/overlays';
<CookiePreferencesDrawer title="Cookie Preferences" description="Manage your privacy and data sharing settings." />Instalación Manual
Si no estás usando el paquete npm, crea un archivo nuevo y pega el siguiente código: src/components/CookiePreferencesDrawer.tsx + CookiePreferencesDrawer.css:
CookiePreferencesDrawer.tsx
'use client';
import { useEffect, useRef } from 'react';
import './CookiePreferencesDrawer.css';
/**
* CookiePreferencesDrawer — GDPR/CCPA consent drawer with frosted glass styling and category toggles.
*
* @param {string} title - Header text. Default is 'Privacy Preferences'.
* @param {string} description - Explanation text for user privacy consent.
*/
export interface CookiePreferencesDrawerProps {
title?: string;
description?: string;
}
export function CookiePreferencesDrawer({
title = 'Privacy & Cookie Settings',
description = 'We use cookies and telemetry to improve performance, analyze usage, and customize your experience.',
}: CookiePreferencesDrawerProps) {
const categories = [
{ id: 'necessary', name: 'Strictly Necessary', desc: 'Required for core authentication and security.', locked: true },
{ id: 'analytics', name: 'Performance & Analytics', desc: 'Anonymous traffic data to improve component reliability.', locked: false },
{ id: 'marketing', name: 'Targeted Experience', desc: 'Personalized recommendations based on library interactions.', locked: false },
];
// Ported from the Astro <script>: runs once after mount (DOM logic kept as in the Astro kit).
const mounted = useRef(false);
useEffect(() => {
if (mounted.current) return;
mounted.current = true;
function setupCookieDrawers() {
document.querySelectorAll('[data-cookie-drawer]').forEach((drawer) => {
const dismiss = () => {
(drawer as HTMLElement).style.transform = 'translateY(120%)';
(drawer as HTMLElement).style.opacity = '0';
setTimeout(() => drawer.remove(), 350);
};
drawer.querySelector('[data-cookie-reject]')?.addEventListener('click', dismiss);
drawer.querySelector('[data-cookie-accept]')?.addEventListener('click', dismiss);
});
}
setupCookieDrawers();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<>
<aside className="cookie-drawer" role="dialog" aria-modal="true" aria-label={title} data-cookie-drawer data-rk-5e1b22="">
<div className="cookie-drawer__header" data-rk-5e1b22="">
<div className="cookie-drawer__icon" data-rk-5e1b22="">🍪</div>
<div className="cookie-drawer__titles" data-rk-5e1b22="">
<h4 className="cookie-drawer__title" data-rk-5e1b22="">{title}</h4>
<p className="cookie-drawer__desc" data-rk-5e1b22="">{description}</p>
</div>
</div>
<div className="cookie-drawer__categories" data-rk-5e1b22="">
{categories.map((cat, __i: number) => (
<div key={__i} className="cookie-cat" data-rk-5e1b22="">
<div className="cookie-cat__info" data-rk-5e1b22="">
<span className="cookie-cat__name" data-rk-5e1b22="">{cat.name}</span>
<span className="cookie-cat__desc" data-rk-5e1b22="">{cat.desc}</span>
</div>
<label className="switch" data-rk-5e1b22="">
<input type="checkbox" defaultChecked={cat.locked} disabled={cat.locked} name={cat.id} data-rk-5e1b22="" />
<span className="slider" data-rk-5e1b22=""></span>
</label>
</div>
))}
</div>
<div className="cookie-drawer__actions" data-rk-5e1b22="">
<button type="button" className="btn btn--secondary" data-cookie-reject data-rk-5e1b22="">Reject All</button>
<button type="button" className="btn btn--primary" data-cookie-accept data-rk-5e1b22="">Accept Selected</button>
</div>
</aside>
</>
);
}
export default CookiePreferencesDrawer;CookiePreferencesDrawer.css
/* CookiePreferencesDrawer — ported from astro-component-kit (overlays/CookiePreferencesDrawer.astro) */
.cookie-drawer:where([data-rk-5e1b22]) {
position: fixed;
bottom: 1.5rem;
left: 1.5rem;
right: 1.5rem;
max-width: 520px;
z-index: 100;
margin: 0 auto;
padding: 1.4rem;
background: rgba(12, 12, 16, 0.94);
backdrop-filter: blur(24px);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: var(--r-xl, 24px);
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.7);
font-family: var(--font-sans, system-ui, sans-serif);
transition: transform 0.3s ease, opacity 0.3s ease;
}
.cookie-drawer__header:where([data-rk-5e1b22]) {
display: flex;
gap: 12px;
margin-bottom: 16px;
}
.cookie-drawer__icon:where([data-rk-5e1b22]) {
font-size: 1.8rem;
line-height: 1;
}
.cookie-drawer__title:where([data-rk-5e1b22]) {
font-size: 1rem;
font-weight: 800;
color: var(--c-text-1, #ffffff);
margin: 0 0 4px 0;
}
.cookie-drawer__desc:where([data-rk-5e1b22]) {
font-size: 0.8rem;
color: var(--c-text-2, #a3a3a3);
margin: 0;
line-height: 1.45;
}
.cookie-drawer__categories:where([data-rk-5e1b22]) {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 18px;
padding: 10px 0;
border-top: 1px solid rgba(255, 255, 255, 0.06);
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.cookie-cat:where([data-rk-5e1b22]) {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
}
.cookie-cat__name:where([data-rk-5e1b22]) {
display: block;
font-size: 0.82rem;
font-weight: 700;
color: var(--c-text-1, #ffffff);
}
.cookie-cat__desc:where([data-rk-5e1b22]) {
display: block;
font-size: 0.72rem;
color: var(--c-text-3, #737373);
}
/* Switch toggle */
.switch:where([data-rk-5e1b22]) {
position: relative;
display: inline-block;
width: 38px;
height: 22px;
flex-shrink: 0;
}
.switch:where([data-rk-5e1b22]) input:where([data-rk-5e1b22]) { opacity: 0; width: 0; height: 0; }
.slider:where([data-rk-5e1b22]) {
position: absolute;
cursor: pointer;
inset: 0;
background-color: rgba(255, 255, 255, 0.15);
border-radius: 34px;
transition: 0.25s;
}
.slider:where([data-rk-5e1b22]):before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 3px;
bottom: 3px;
background-color: white;
border-radius: 50%;
transition: 0.25s;
}
input:checked:where([data-rk-5e1b22]) + .slider:where([data-rk-5e1b22]) {
background-color: var(--c-primary-light, #d4a017);
}
input:checked:where([data-rk-5e1b22]) + .slider:where([data-rk-5e1b22]):before {
transform: translateX(16px);
}
input:disabled:where([data-rk-5e1b22]) + .slider:where([data-rk-5e1b22]) {
opacity: 0.6;
cursor: not-allowed;
}
.cookie-drawer__actions:where([data-rk-5e1b22]) {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.btn:where([data-rk-5e1b22]) {
padding: 0.55rem 1.2rem;
font-size: 0.82rem;
font-weight: 700;
border-radius: var(--r-md, 10px);
cursor: pointer;
transition: all 0.2s ease;
}
.btn--secondary:where([data-rk-5e1b22]) {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
color: var(--c-text-2, #a3a3a3);
}
.btn--secondary:hover:where([data-rk-5e1b22]) {
color: var(--c-text-1, #ffffff);
background: rgba(255, 255, 255, 0.1);
}
.btn--primary:where([data-rk-5e1b22]) {
background: linear-gradient(135deg, #d4a017, #b8860b);
border: none;
color: #050505;
box-shadow: 0 4px 14px rgba(184, 134, 11, 0.35);
}
.btn--primary:hover:where([data-rk-5e1b22]) {
transform: translateY(-1px);
box-shadow: 0 6px 20px rgba(184, 134, 11, 0.45);
}Información Rápida
- Categoría
- Modales & Capas
- Nombre de archivo
CookiePreferencesDrawer.tsx- Dependencias
- Ninguna — React + CSS puro
- Etiquetas
- overlayscookiegdprprivacydrawer