feat(theme): animate public background with aurora and particles, polish landing pages

Add background_effect (aurora/particles), background_overlay tint and
opacity to the theme manager, rendered site-wide by ThemeVars on every
public page. Polish the home and register pages (hero mascot, live stat
pulse, date pills, photo strip, CTA band, theme-aware register intro,
i18n for home/register section).
This commit is contained in:
openhands committed 2026-09-18 12:44:39 +02:00
1 parent 5923b736fa
commit d131124515
9 files changed
+573 -25

No files matched your search

+52
View File
@@ -12,10 +12,12 @@ import { siteSettings } from "@/lib/services/site-settings";
import { logStaffActivity } from "@/lib/services/staff-activity";
import {
BACKGROUND_DEFAULTS,
BACKGROUND_EFFECTS,
BACKGROUND_POSITIONS,
BACKGROUND_REPEATS,
BACKGROUND_SIZES,
isSafeBackgroundUrl,
OVERLAY_OPACITY_MAX,
} from "@/lib/theme-bg";
import {
type CustomTheme,
@@ -187,6 +189,17 @@ export async function saveBackground(formData: FormData): Promise<void> {
const repeat = String(formData.get("background_repeat") ?? "")
.normalize("NFC")
.trim();
const effect = String(formData.get("background_effect") ?? "")
.normalize("NFC")
.trim();
const overlay = String(formData.get("background_overlay") ?? "")
.normalize("NFC")
.trim();
const overlayOpacity = String(
formData.get("background_overlay_opacity") ?? "",
)
.normalize("NFC")
.trim();
if (image && !isSafeBackgroundUrl(image)) redirect(MANAGER_PATH);
@@ -210,6 +223,22 @@ export async function saveBackground(formData: FormData): Promise<void> {
? repeat
: BACKGROUND_DEFAULTS.background_repeat,
);
await writeSetting(
"background_effect",
(BACKGROUND_EFFECTS as readonly string[]).includes(effect)
? effect
: BACKGROUND_DEFAULTS.background_effect,
);
await writeSetting(
"background_overlay",
/^#[0-9a-fA-F]{3,8}$/.test(overlay) ? overlay : "",
);
await writeSetting(
"background_overlay_opacity",
/^\d{1,2}$/.test(overlayOpacity)
? String(Math.min(parseInt(overlayOpacity, 10), OVERLAY_OPACITY_MAX))
: "0",
);
siteSettings.reload();
revalidatePath("/", "layout");
revalidatePath(MANAGER_PATH);
@@ -344,6 +373,29 @@ export async function getThemeManagerData() {
)
? (backgroundValues.background_repeat as string)
: BACKGROUND_DEFAULTS.background_repeat,
effect: (BACKGROUND_EFFECTS as readonly string[]).includes(
backgroundValues.background_effect ?? "",
)
? (backgroundValues.background_effect as string)
: BACKGROUND_DEFAULTS.background_effect,
overlay: /^#[0-9a-fA-F]{3,8}$/.test(
backgroundValues.background_overlay ?? "",
)
? (backgroundValues.background_overlay as string)
: "",
overlayOpacity: /^\d{1,2}$/.test(
backgroundValues.background_overlay_opacity ?? "",
)
? String(
Math.min(
parseInt(
backgroundValues.background_overlay_opacity as string,
10,
),
OVERLAY_OPACITY_MAX,
),
)
: "0",
},
};
}