179 lines
8.9 KiB
JavaScript
179 lines
8.9 KiB
JavaScript
'use client';
|
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
import { Cookie } from 'lucide-react';
|
|
import { useEffect, useState } from 'react';
|
|
import { CONSENT_CATEGORIES } from './categories.js';
|
|
import { useConsentContext } from './ConsentContext.js';
|
|
/**
|
|
* Colours and radius come from CSS custom properties with built-in fallbacks,
|
|
* so the banner looks right with no setup, and re-skinning per client means
|
|
* declaring a few variables — no imports, no props, no specificity fights:
|
|
*
|
|
* ```css
|
|
* :root {
|
|
* --ipal-primary: #16a34a;
|
|
* --ipal-radius: 1rem;
|
|
* }
|
|
* ```
|
|
*
|
|
* Available: --ipal-surface, --ipal-border, --ipal-text, --ipal-text-strong,
|
|
* --ipal-text-muted, --ipal-primary, --ipal-primary-hover, --ipal-primary-text,
|
|
* --ipal-hover, --ipal-radius. Each has a `-dark` counterpart used under
|
|
* Tailwind's `dark:` variant (e.g. --ipal-surface-dark).
|
|
*
|
|
* Layout stays in Tailwind: spacing and flow aren't things a brand changes, and
|
|
* exposing them as tokens would mean re-inventing CSS one variable at a time.
|
|
*/ const surface = 'bg-[var(--ipal-surface,#fff)] dark:bg-[var(--ipal-surface-dark,#171717)]';
|
|
const border = 'border-[var(--ipal-border,#e5e5e5)] dark:border-[var(--ipal-border-dark,#262626)]';
|
|
const radius = 'rounded-[var(--ipal-radius,0.375rem)]';
|
|
const accent = 'text-[var(--ipal-primary,#2563eb)]';
|
|
const defaults = {
|
|
primaryButton: `${radius} px-3 py-1.5 text-sm font-medium bg-[var(--ipal-primary,#2563eb)] text-[var(--ipal-primary-text,#fff)] hover:bg-[var(--ipal-primary-hover,#1d4ed8)]`,
|
|
root: `fixed inset-x-0 bottom-0 z-50 border-t p-4 shadow-lg ${surface} ${border}`,
|
|
secondaryButton: `${radius} px-3 py-1.5 text-sm font-medium text-[var(--ipal-text,#404040)] hover:bg-[var(--ipal-hover,#f5f5f5)] dark:text-[var(--ipal-text-dark,#e5e5e5)] dark:hover:bg-[var(--ipal-hover-dark,#262626)]`
|
|
};
|
|
const bodyText = 'text-[var(--ipal-text,#404040)] dark:text-[var(--ipal-text-dark,#d4d4d4)]';
|
|
const strongText = 'text-[var(--ipal-text-strong,#171717)] dark:text-[var(--ipal-text-strong-dark,#f5f5f5)]';
|
|
const mutedText = 'text-[var(--ipal-text-muted,#737373)] dark:text-[var(--ipal-text-muted-dark,#a3a3a3)]';
|
|
export function CookieBanner({ classNames } = {}) {
|
|
const { acceptAll, decided, rejectAll, savePreferences, state, texts } = useConsentContext();
|
|
const [showSettings, setShowSettings] = useState(false);
|
|
const [choices, setChoices] = useState(state);
|
|
useEffect(()=>{
|
|
setChoices(state);
|
|
}, [
|
|
state
|
|
]);
|
|
if (decided) {
|
|
return null;
|
|
}
|
|
const toggle = (cat)=>{
|
|
if (cat === 'necessary') {
|
|
return;
|
|
}
|
|
setChoices((prev)=>({
|
|
...prev,
|
|
[cat]: !prev[cat]
|
|
}));
|
|
};
|
|
const rootClass = classNames?.root ?? defaults.root;
|
|
const primaryClass = classNames?.primaryButton ?? defaults.primaryButton;
|
|
const secondaryClass = classNames?.secondaryButton ?? defaults.secondaryButton;
|
|
return /*#__PURE__*/ _jsx("div", {
|
|
"aria-label": "Cookie consent",
|
|
className: rootClass,
|
|
"data-ipal": "banner",
|
|
role: "dialog",
|
|
children: /*#__PURE__*/ _jsx("div", {
|
|
className: "mx-auto max-w-4xl",
|
|
children: !showSettings ? /*#__PURE__*/ _jsxs("div", {
|
|
className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
|
|
children: [
|
|
/*#__PURE__*/ _jsxs("div", {
|
|
className: "flex items-start gap-3",
|
|
children: [
|
|
/*#__PURE__*/ _jsx(Cookie, {
|
|
"aria-hidden": "true",
|
|
className: `h-6 w-6 shrink-0 ${accent}`
|
|
}),
|
|
/*#__PURE__*/ _jsxs("p", {
|
|
className: `text-justify text-sm ${bodyText}`,
|
|
children: [
|
|
texts.message,
|
|
texts.privacyLink && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
children: [
|
|
' ',
|
|
/*#__PURE__*/ _jsx("a", {
|
|
className: `${accent} underline hover:no-underline`,
|
|
href: texts.privacyLink.href,
|
|
children: texts.privacyLink.label
|
|
})
|
|
]
|
|
})
|
|
]
|
|
})
|
|
]
|
|
}),
|
|
/*#__PURE__*/ _jsxs("div", {
|
|
className: "flex shrink-0 gap-2",
|
|
children: [
|
|
/*#__PURE__*/ _jsx("button", {
|
|
className: secondaryClass,
|
|
onClick: ()=>setShowSettings(true),
|
|
children: texts.buttons.settings
|
|
}),
|
|
/*#__PURE__*/ _jsx("button", {
|
|
className: secondaryClass,
|
|
onClick: rejectAll,
|
|
children: texts.buttons.reject
|
|
}),
|
|
/*#__PURE__*/ _jsx("button", {
|
|
className: primaryClass,
|
|
onClick: acceptAll,
|
|
children: texts.buttons.acceptAll
|
|
})
|
|
]
|
|
})
|
|
]
|
|
}) : /*#__PURE__*/ _jsxs("div", {
|
|
className: "flex flex-col gap-4",
|
|
children: [
|
|
/*#__PURE__*/ _jsxs("h2", {
|
|
className: `flex items-center gap-2 text-base font-semibold ${strongText}`,
|
|
children: [
|
|
/*#__PURE__*/ _jsx(Cookie, {
|
|
"aria-hidden": "true",
|
|
className: `h-5 w-5 ${accent}`
|
|
}),
|
|
texts.settingsTitle
|
|
]
|
|
}),
|
|
/*#__PURE__*/ _jsx("ul", {
|
|
className: "flex flex-col gap-3",
|
|
children: CONSENT_CATEGORIES.map((cat)=>/*#__PURE__*/ _jsxs("li", {
|
|
className: "flex items-start justify-between gap-4",
|
|
children: [
|
|
/*#__PURE__*/ _jsxs("div", {
|
|
children: [
|
|
/*#__PURE__*/ _jsx("p", {
|
|
className: `text-sm font-medium ${strongText}`,
|
|
children: texts.categories[cat].title
|
|
}),
|
|
/*#__PURE__*/ _jsx("p", {
|
|
className: `text-xs ${mutedText}`,
|
|
children: texts.categories[cat].description
|
|
})
|
|
]
|
|
}),
|
|
/*#__PURE__*/ _jsx("input", {
|
|
checked: cat === 'necessary' ? true : choices[cat],
|
|
className: "mt-1 h-4 w-4 shrink-0 accent-[var(--ipal-primary,#2563eb)]",
|
|
disabled: cat === 'necessary',
|
|
onChange: ()=>toggle(cat),
|
|
type: "checkbox"
|
|
})
|
|
]
|
|
}, cat))
|
|
}),
|
|
/*#__PURE__*/ _jsxs("div", {
|
|
className: "flex justify-end gap-2",
|
|
children: [
|
|
/*#__PURE__*/ _jsx("button", {
|
|
className: secondaryClass,
|
|
onClick: ()=>setShowSettings(false),
|
|
children: texts.buttons.back
|
|
}),
|
|
/*#__PURE__*/ _jsx("button", {
|
|
className: primaryClass,
|
|
onClick: ()=>savePreferences(choices),
|
|
children: texts.buttons.save
|
|
})
|
|
]
|
|
})
|
|
]
|
|
})
|
|
})
|
|
});
|
|
} //# sourceMappingURL=CookieBanner.js.map
|
|
|
|
//# sourceMappingURL=CookieBanner.js.map
|