feat: add authentication, cloud sync, and GDPR compliance

Authentication & Cloud Sync:
- Add Supabase integration for auth (email/password, Google, GitHub OAuth)
- Add cloud progress sync for logged-in users
- Add account deletion feature with confirmation dialog
- Auth is optional - anonymous users can still use localStorage

UI Improvements:
- Add dark-themed account section in sidebar
- Show user email in header when logged in
- Add signup success feedback message
- Update landing page: remove cloud sync from Coming Soon, add Code Challenges
- Update benefit text to mention optional cloud sync

GDPR Compliance:
- Add Privacy Policy dialog with full GDPR-compliant content
- Add Imprint dialog with legal contact information
- Add footer links for Privacy and Imprint
- All legal content translated to 6 languages (en, de, pl, es, ar, uk)

Files added:
- src/supabase.js - Supabase client with auth and progress sync helpers
- src/auth.js - Authentication logic and form handlers
- supabase-setup.sql - Database schema and RLS policies
This commit is contained in:
2026-01-16 12:37:22 +01:00
parent ea57ce6d28
commit 68407fe12b
12 changed files with 1520 additions and 26 deletions

View File

@@ -6,6 +6,7 @@ import { initI18n, t, getLanguage, setLanguage, applyTranslations } from "./i18n
import { parseHash, updateHash, replaceHash, getShareableUrl, RouteType, navigateTo } from "./helpers/router.js";
import { sections, getSection, getModuleSection, getModulesBySection } from "./config/sections.js";
import { getRandomTemplate } from "./config/playground-templates.js";
import { initAuth } from "./auth.js";
// CodeMirror imports for syntax highlighting
import { EditorState } from "@codemirror/state";
@@ -2423,6 +2424,9 @@ function init() {
// Initialize URL router for shareable links
initRouter();
// Initialize authentication
initAuth(lessonEngine);
// Sidebar controls
elements.menuBtn.addEventListener("click", openSidebar);
elements.closeSidebar.addEventListener("click", closeSidebar);
@@ -2485,6 +2489,31 @@ function init() {
});
elements.copyUrlBtn.addEventListener("click", copyShareUrl);
// Legal dialogs (Privacy & Imprint)
const privacyDialog = document.getElementById("privacy-dialog");
const imprintDialog = document.getElementById("imprint-dialog");
document.querySelectorAll(".privacy-link").forEach((btn) => {
btn.addEventListener("click", () => privacyDialog?.showModal());
});
document.querySelectorAll(".imprint-link").forEach((btn) => {
btn.addEventListener("click", () => imprintDialog?.showModal());
});
document.querySelector(".privacy-dialog-close")?.addEventListener("click", () => {
privacyDialog?.close();
});
document.querySelector(".imprint-dialog-close")?.addEventListener("click", () => {
imprintDialog?.close();
});
privacyDialog?.addEventListener("click", (e) => {
if (e.target === privacyDialog) privacyDialog.close();
});
imprintDialog?.addEventListener("click", (e) => {
if (e.target === imprintDialog) imprintDialog.close();
});
// Settings
elements.disableFeedbackToggle.addEventListener("change", (e) => {
state.userSettings.disableFeedbackErrors = !e.target.checked;
@@ -2567,10 +2596,18 @@ function init() {
// Newsletter form submission
const newsletterForm = document.getElementById("newsletter-form");
const newsletterThanks = document.getElementById("newsletter-thanks");
newsletterForm?.addEventListener("submit", (e) => {
newsletterForm?.addEventListener("submit", async (e) => {
e.preventDefault();
const email = document.getElementById("newsletter-email")?.value;
const emailInput = document.getElementById("newsletter-email");
const email = emailInput?.value;
if (email) {
// Import newsletter helper dynamically to avoid loading Supabase if not needed
try {
const { newsletter } = await import("./supabase.js");
await newsletter.subscribe(email);
} catch (err) {
console.error("Newsletter subscription error:", err);
}
track("newsletter_signup", { email: email });
newsletterForm.classList.add("hidden");
newsletterThanks?.classList.remove("hidden");