feat: migrate website-creator from Next.js+Payload to Astro+Tina CMS
Major changes: - Replace Payload CMS with Tina CMS (self-hosted) - Add Astro DB for consent logging (PDPA compliant) - Update Tailwind v3 to v4 (@tailwindcss/vite plugin) - Add astro-tina-starter template - Rewrite consent template for Astro (ConsentBanner.astro, Astro DB, Nano Stores) - Add install-tina-backend.sh for self-hosted Tina per customer - Rename convert-astro.sh to migrate-tina.sh - Add AGENTS.md template for generated websites - Delete all Payload/Next.js files Technical updates: - Astro DB using defineDb with eq operators for queries - Tailwind v4 with @theme block - Tina CMS local development mode - Proper Astro API routes for consent Research-verified with official documentation (April 2026)
This commit is contained in:
75
skills/website-creator/templates/consent/stores/consent.ts
Normal file
75
skills/website-creator/templates/consent/stores/consent.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { map } from 'nanostores';
|
||||
|
||||
export interface ConsentState {
|
||||
analytics: boolean;
|
||||
marketing: boolean;
|
||||
functional: boolean;
|
||||
hasConsented: boolean;
|
||||
timestamp?: string;
|
||||
}
|
||||
|
||||
export interface ConsentLogData extends ConsentState {
|
||||
ip?: string;
|
||||
userAgent?: string;
|
||||
}
|
||||
|
||||
export const defaultConsent: ConsentState = {
|
||||
analytics: false,
|
||||
marketing: false,
|
||||
functional: false,
|
||||
hasConsented: false,
|
||||
};
|
||||
|
||||
export const consentStore = map<ConsentState>(defaultConsent);
|
||||
export const STORAGE_KEY = 'pdpa_consent';
|
||||
|
||||
export function loadConsent(): ConsentState {
|
||||
if (typeof localStorage === 'undefined') {
|
||||
return defaultConsent;
|
||||
}
|
||||
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
if (stored) {
|
||||
try {
|
||||
const parsed = JSON.parse(stored) as ConsentState;
|
||||
consentStore.set(parsed);
|
||||
return parsed;
|
||||
} catch {
|
||||
return defaultConsent;
|
||||
}
|
||||
}
|
||||
return defaultConsent;
|
||||
}
|
||||
|
||||
export function saveConsentLocally(state: ConsentState): void {
|
||||
if (typeof localStorage === 'undefined') return;
|
||||
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
|
||||
consentStore.set(state);
|
||||
}
|
||||
|
||||
export function hasAnalyticsConsent(): boolean {
|
||||
const state = consentStore.get();
|
||||
return state.hasConsented && state.analytics;
|
||||
}
|
||||
|
||||
export function hasMarketingConsent(): boolean {
|
||||
const state = consentStore.get();
|
||||
return state.hasConsented && state.marketing;
|
||||
}
|
||||
|
||||
export function hasFunctionalConsent(): boolean {
|
||||
const state = consentStore.get();
|
||||
return state.hasConsented;
|
||||
}
|
||||
|
||||
export function resetConsent(): void {
|
||||
if (typeof localStorage === 'undefined') return;
|
||||
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
consentStore.set(defaultConsent);
|
||||
}
|
||||
|
||||
export function hasConsented(): boolean {
|
||||
return consentStore.get().hasConsented;
|
||||
}
|
||||
Reference in New Issue
Block a user