Complete Astro migration - PDPA compliant website

- Migrated all pages from Next.js to Astro
- Added PDPA-compliant Privacy Policy (Thai)
- Added PDPA-compliant Terms & Conditions (Thai)
- Added Cookie Policy with disclosure (Thai)
- Implemented cookie consent banner (client-side)
- Integrated Umami Analytics placeholder
- Blog system with 3 posts
- Optimized Docker configuration for production
- Static site build (184KB, 11 pages)
- Ready for Easypanel deployment

Backup: /Users/kunthawatgreethong/Gitea/dealplustech-backup-nextjs-20260309.tar.gz
This commit is contained in:
Kunthawat Greethong
2026-03-09 18:28:01 +07:00
parent 668f69048f
commit 6402d885f9
6183 changed files with 463899 additions and 1913 deletions

View File

@@ -0,0 +1,13 @@
import type { CookieBannerConfig } from "../types/config.js";
/**
* DEFAULT_CONFIG
* ---------------------------------------------------------
* Fallback values ONLY.
*
* These are used:
* - when the user omits a value
* - during internal normalisation
*
* User-provided config ALWAYS takes priority.
*/
export declare const DEFAULT_CONFIG: CookieBannerConfig;

View File

@@ -0,0 +1,40 @@
/**
* DEFAULT_CONFIG
* ---------------------------------------------------------
* Fallback values ONLY.
*
* These are used:
* - when the user omits a value
* - during internal normalisation
*
* User-provided config ALWAYS takes priority.
*/
export const DEFAULT_CONFIG = {
siteName: "This website",
policyUrl: "/privacy",
consent: {
enabled: true,
// Number of days consent remains valid
days: 30,
// Must match runtime + frontend API
storageKey: "astro-consent"
},
categories: {
essential: {
label: "Essential",
description: "Required for the website to function correctly",
enabled: true,
readonly: true
},
analytics: {
label: "Analytics",
description: "Helps us understand how visitors use the site",
enabled: false
},
marketing: {
label: "Marketing",
description: "Used to deliver personalised ads",
enabled: false
}
}
};

View File

@@ -0,0 +1,7 @@
import type { CookieBannerConfig } from "../types/config.js";
/**
* Safely loads the user config file and merges it with defaults.
* User values always override defaults.
* Cache-busted to ensure updates are picked up during dev.
*/
export declare function loadUserConfig(projectRoot: string): Promise<CookieBannerConfig>;

View File

@@ -0,0 +1,65 @@
import * as fs from "node:fs";
import * as path from "node:path";
import { pathToFileURL } from "node:url";
import { DEFAULT_CONFIG } from "./defaults.js";
/**
* Safely loads the user config file and merges it with defaults.
* User values always override defaults.
* Cache-busted to ensure updates are picked up during dev.
*/
export async function loadUserConfig(projectRoot) {
const configPath = path.join(projectRoot, "src", "astro-consent", "config.ts");
let userConfig = {};
try {
const stat = fs.statSync(configPath);
const cacheBuster = `?v=${stat.mtimeMs}`;
const imported = await import(
/* @vite-ignore */
pathToFileURL(configPath).href + cacheBuster);
userConfig = imported?.default ?? {};
}
catch (err) {
console.warn("[astro-consent] Failed to load user config, falling back to defaults");
}
return {
siteName: userConfig.siteName ?? DEFAULT_CONFIG.siteName,
policyUrl: userConfig.policyUrl ?? DEFAULT_CONFIG.policyUrl,
consent: {
enabled: userConfig.consent?.enabled ??
DEFAULT_CONFIG.consent.enabled,
days: userConfig.consent?.days ??
DEFAULT_CONFIG.consent.days,
storageKey: userConfig.consent?.storageKey ??
DEFAULT_CONFIG.consent.storageKey
},
categories: mergeCategories(userConfig.categories, DEFAULT_CONFIG.categories)
};
}
/**
* Merge category config safely.
* - Defaults are preserved
* - User overrides win
* - Custom categories are supported
*/
function mergeCategories(userCategories, defaultCategories) {
const merged = {};
// Start with defaults
for (const key of Object.keys(defaultCategories)) {
merged[key] = {
...defaultCategories[key],
...(userCategories?.[key] ?? {})
};
}
// Add user-defined custom categories safely
if (userCategories) {
for (const key of Object.keys(userCategories)) {
if (!merged[key]) {
merged[key] = {
...userCategories[key],
enabled: userCategories[key].enabled ?? false
};
}
}
}
return merged;
}