npm package: @stratton-cologne/cookie-consent
Description: [![npm version](https://img.shields.io/npm/v/@stratton-cologne/cookie-consent.svg)](https://www.npmjs.com/package/@stratton-cologne/cookie-consent) [![npm downloads (total)](https://img.shields.io/npm/dt/%40stratton-cologne%2Fcookie-consent)](https://www.
Latest version: 1.0.0

# @stratton-cologne/cookie-consent

[![npm version](https://img.shields.io/npm/v/@stratton-cologne/cookie-consent.svg)](https://www.npmjs.com/package/@stratton-cologne/cookie-consent)
[![npm downloads (total)](https://img.shields.io/npm/dt/%40stratton-cologne%2Fcookie-consent)](https://www.npmjs.com/package/@stratton-cologne/cookie-consent)
[![npm downloads (week)](https://img.shields.io/npm/dw/%40stratton-cologne%2Fcookie-consent)](https://www.npmjs.com/package/@stratton-cologne/cookie-consent)
![node >= 18](https://img.shields.io/badge/node-%3E%3D18-brightgreen)
![typescript](https://img.shields.io/badge/TypeScript-ready-blue)
![license: MIT](https://img.shields.io/badge/license-MIT-lightgrey)

Konfigurierbarer Cookie-Consent für **Vue 3 + TypeScript**.  
Kein festes Styling – du stylst im **Consumer** via `data-`-Attribute und eigenen Utilities (z. B. `.text-primary`, `.bg-primary`, `.border-primary`, `.font-primary`, …).

---

## 🚀 Installation

```bash
npm i @stratton-cologne/cookie-consent
```

> Voraussetzung: Vite + Vue 3.

---

## ⚙️ Quickstart

### 1) Plugin registrieren

```ts
// src/main.ts
import { createApp } from "vue";
import App from "./App.vue";
import CookieConsentPlugin from "@stratton-cologne/cookie-consent";

createApp(App).use(CookieConsentPlugin).mount("#app");
```

### 2) Konfiguration anlegen

```ts
// src/consentConfig.ts
import type { CookieConsentConfig } from "@stratton-cologne/cookie-consent";

export const consentConfig: CookieConsentConfig = {
    version: "1.0.0",
    categories: [
        {
            id: "essential",
            label: "Erforderlich",
            description: "Grundfunktionen",
            required: true,
        },
        {
            id: "analytics",
            label: "Analyse",
            description: "anonyme Nutzungsstatistik",
            default: false,
        },
        {
            id: "marketing",
            label: "Marketing",
            description: "personalisierte Inhalte",
        },
    ],
    scripts: [
        // Beispiel: Ads-Stub (liegt im Consumer unter /public/scripts/ads.js)
        {
            id: "ads",
            category: "marketing",
            src: "/scripts/ads.js",
            defer: true,
        },
    ],
};
```

### 3) Banner einhängen

```vue
<!-- src/App.vue -->
<script setup lang="ts">
import { ref } from "vue";
import { CookieConsent } from "@stratton-cologne/cookie-consent";
import { consentConfig } from "./consentConfig";

const showBanner = ref(true);
function onSaved(map: Record<string, boolean>) {
    console.log("Consent gespeichert:", map);
}
</script>

<template>
    <router-view />

    <CookieConsent
        v-model="showBanner"
        :config="consentConfig"
        data-cc="banner"
        title="Cookies & Datenschutz"
        description="Wir verwenden Cookies für Grundfunktionen und zur Verbesserung unseres Angebots."
        policyHref="/datenschutz"
        @saved="onSaved"
    />
</template>
```

---

## 🧩 „Cookie-Einstellungen“ später öffnen

### Variante A (empfohlen): Globaler Helper

Der Banner reagiert auf ein globales Event und öffnet dann direkt die Einstellungen – **ohne** bisherigen Consent zu löschen.

```ts
// Irgendwo im Consumer (z. B. Footer.vue)
import { openConsentEditor } from "@stratton-cologne/cookie-consent";

function openCookies() {
    openConsentEditor();
}
```

```vue
<button type="button" @click="openCookies">Cookie‑Einstellungen</button>
```

### Variante B: Per `ref` auf die gleiche Instanz

```vue
<script setup lang="ts">
import { ref } from "vue";
import { CookieConsent } from "@stratton-cologne/cookie-consent";
import { consentConfig } from "@/consentConfig";

const bannerRef = ref<InstanceType<typeof CookieConsent> | null>(null);
</script>

<template>
    <button @click="bannerRef?.edit()">Cookie‑Einstellungen</button>
    <CookieConsent ref="bannerRef" :config="consentConfig" />
</template>
```

### Zurücksetzen (erneut fragen)

```ts
import { useCookieConsent } from "@stratton-cologne/cookie-consent";
import { consentConfig } from "@/consentConfig";

const { reset } = useCookieConsent(consentConfig);
// …
reset(); // löscht Auswahl → Banner erscheint wieder
```

---

## 🎨 Styling im Consumer

**Keine** festen Styles im Package. Nutze die `data-`-Hooks und **deine** Utilities.

Beispiel-CSS (gekürzt, mobile‑first; Banner fix am Seitenende):

```css
/* src/assets/cookie-consent.css */
[data-cc="container"] {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
    box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.08);
}
[data-cc="container"] .cc-inner {
    max-width: 1280px;
    margin: 0 auto;
    padding: 1rem;
}
[data-cc="title"] {
    font-weight: 600;
    font-size: 1.125rem;
    line-height: 1.5rem;
}
[data-cc="description"] {
    opacity: 0.9;
}
[data-cc="policy-link"] a {
    text-decoration: underline;
}
[data-cc="actions-primary"] {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}
[data-cc^="btn-"] {
    border-radius: 8px;
    padding: 0.5rem 0.875rem;
    font-weight: 500;
}
[data-cc="btn-settings"],
[data-cc="btn-reject"] {
    background: transparent;
    border: 1px solid currentColor;
}
[data-cc="btn-accept"] {
    border: 1px solid transparent;
} /* gib .bg-primary .text-primary im Markup */
[data-cc="settings"] {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid currentColor;
}
[data-cc="category-list"] {
    display: grid;
    gap: 0.75rem;
}
[data-cc="category"] {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
}
```

> Im Markup steuerst du Farben/Fonts einfach selbst, z. B.:
>
> ```html
> <CookieConsent
>     class="bg-secondary text-secondary border-primary font-primary"
>     :config="consentConfig"
> />
> ```

---

## 🧠 Script‑Ladeverhalten

-   Skripte in `config.scripts` werden **nur** geladen, wenn die zugehörige Kategorie erlaubt ist.
-   Doppeltes Laden wird per `data-ccid` verhindert.
-   Optional `when: () => boolean` verwenden (z. B. nur in Produktion).

```ts
scripts: [
    {
        id: "ads",
        category: "marketing",
        src: "/scripts/ads.js",
        defer: true,
        when: () => import.meta.env.PROD,
    },
];
```

### Beispieldatei für den Consumer

Lege folgenden Stub an: **`public/scripts/ads.js`**  
(oder nutze die mitgelieferte Datei aus dieser Unterhaltung)

-   erstellt `window.ADS` mit `ADS.init`, `ADS.pageview`, `ADS.track`, …
-   sendet CustomEvents `ads:ready`, `ads:pageview`, `ads:track`, …
-   idempotent und SPA‑freundlich

---

## 🔄 Verhalten & State

-   Consent wird in `localStorage` unter `@stratton-cologne/cookie-consent:<version>` gespeichert.
-   **Banner‑Sichtbarkeit**: erscheint **nur**, wenn **kein** Consent gespeichert ist.  
    Manuelles Öffnen via `openConsentEditor()`/`edit()` ist jederzeit möglich.
-   **Singleton‑Store** je `storageKey/version`: alle Aufrufe (`useCookieConsent`, Component) teilen sich **denselben** Zustand.

---

## 📡 Events

**Component‑Events**

-   `@saved` – wenn gespeichert wurde, Payload: `Record<string, boolean>`
-   `@navigate:policy` – für Router‑Navigation zur Datenschutzerklärung

**Window‑Events (CustomEvent)**

-   `consent:changed`, `consent:accepted-all`, `consent:rejected-all`
-   **Öffnen**: `consent:open` (wird intern von `openConsentEditor()` gefeuert)

**Ads‑Stub‑Events (optional)**

-   `ads:ready`, `ads:pageview`, `ads:track`, `ads:enabled`, `ads:disabled`

---

## 🧾 Typen

```ts
import type { CookieConsentConfig } from "@stratton-cologne/cookie-consent";
// Weitere Typen: ConsentCategory, ConsentMap, ScriptRegistration, StoredConsent, ...
```

---

## ❗️Troubleshooting

-   **„Werde nach Reload erneut gefragt“** → Prüfe `config.version` (nicht erhöhen), `localStorage` erlaubt, gleiche Origin.
-   **„openConsentEditor nicht gefunden“** → Package auf aktuellen Stand updaten + Neuinstallation.
-   **`/scripts/ads.js` 404** → Datei unter `public/scripts/ads.js` anlegen oder `inline` verwenden.

---

## ✅ TL;DR

1. Plugin registrieren, Config anlegen, Banner in `App.vue` einhängen.
2. Styling im Consumer via Utilities (`.bg-*`, `.text-*`, `.border-*`, `.font-*`).
3. Später öffnen: `openConsentEditor()` oder `ref.edit()`.
4. Reset via `useCookieConsent(consentConfig).reset()`.