fix(i18n): update consent banner on locale switch

Use next-intl translations instead of reading NEXT_LOCALE cookie once, so banner text updates immediately when switching languages.

fix(activity-feed): make loading UI match dark theme

Avoid the white loading card on hard reload by using the same dark styling as the normal feed.

Co-authored-by: dennis <dennis@konkol.net>
This commit is contained in:
Cursor Agent
2026-01-14 16:00:05 +00:00
parent e115a23485
commit 9082bd256a
2 changed files with 17 additions and 38 deletions

View File

@@ -1553,16 +1553,16 @@ export default function ActivityFeed() {
<motion.div <motion.div
initial={false} initial={false}
animate={{ scale: 1, opacity: 1 }} animate={{ scale: 1, opacity: 1 }}
className="pointer-events-auto bg-white/80 backdrop-blur-2xl border border-white/60 rounded-2xl shadow-xl overflow-hidden w-full" className="pointer-events-auto bg-black/95 backdrop-blur-2xl border border-white/10 rounded-2xl shadow-2xl overflow-hidden w-full"
> >
<div className="w-full px-4 py-3 flex items-center justify-between"> <div className="w-full px-4 py-3 flex items-center justify-between">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="relative"> <div className="relative">
<Activity size={18} className="text-stone-900" /> <Activity size={18} className="text-white" />
</div> </div>
<div className="text-left"> <div className="text-left">
<h3 className="text-sm font-bold text-stone-900">Live Activity</h3> <h3 className="text-sm font-bold text-white">Live Activity</h3>
<p className="text-[10px] text-stone-500">Loading...</p> <p className="text-[10px] text-white/50">Loading...</p>
</div> </div>
</div> </div>
<div className="flex items-center gap-2"></div> <div className="flex items-center gap-2"></div>

View File

@@ -1,49 +1,28 @@
"use client"; "use client";
import React, { useMemo, useState } from "react"; import React, { useState } from "react";
import { useConsent, type ConsentState } from "./ConsentProvider"; import { useConsent, type ConsentState } from "./ConsentProvider";
import { useTranslations } from "next-intl";
export default function ConsentBanner() { export default function ConsentBanner() {
const { consent, setConsent } = useConsent(); const { consent, setConsent } = useConsent();
const [draft, setDraft] = useState<ConsentState>({ analytics: false, chat: false }); const [draft, setDraft] = useState<ConsentState>({ analytics: false, chat: false });
const [minimized, setMinimized] = useState(false); const [minimized, setMinimized] = useState(false);
const t = useTranslations("consent");
const locale = useMemo(() => {
if (typeof document === "undefined") return "en";
const match = document.cookie
.split(";")
.map((c) => c.trim())
.find((c) => c.startsWith("NEXT_LOCALE="));
if (!match) return "en";
return decodeURIComponent(match.split("=").slice(1).join("=")) || "en";
}, []);
const shouldShow = consent === null; const shouldShow = consent === null;
if (!shouldShow) return null; if (!shouldShow) return null;
const s = locale === "de" const s = {
? { title: t("title"),
title: "Datenschutz-Einstellungen", description: t("description"),
description: essential: t("essential"),
"Wir nutzen optionale Dienste (Analytics und Chat), um die Seite zu verbessern. Du kannst deine Auswahl jederzeit ändern.", analytics: t("analytics"),
essential: "Essentiell", chat: t("chat"),
analytics: "Analytics", acceptAll: t("acceptAll"),
chat: "Chatbot", acceptSelected: t("acceptSelected"),
acceptAll: "Alles akzeptieren", rejectAll: t("rejectAll"),
acceptSelected: "Auswahl akzeptieren", };
rejectAll: "Alles ablehnen",
}
: {
title: "Privacy settings",
description:
"We use optional services (analytics and chat) to improve the site. You can change your choice anytime.",
essential: "Essential",
analytics: "Analytics",
chat: "Chatbot",
acceptAll: "Accept all",
acceptSelected: "Accept selected",
rejectAll: "Reject all",
};
if (minimized) { if (minimized) {
return ( return (