Add touch-ready Filament login and admin update tooling

This commit is contained in:
soeren
2026-01-18 15:34:16 +01:00
parent 6f6ea8b24f
commit 30ca8082b3
31 changed files with 1940 additions and 1159 deletions

View File

@@ -1,6 +1,19 @@
<template>
<Head :title="props.galleryHeading" />
<div class="min-h-screen bg-gradient-to-br from-slate-100 via-white to-slate-200 text-slate-900 transition-colors duration-500 dark:from-slate-950 dark:via-slate-900 dark:to-slate-950 dark:text-slate-100">
<div class="relative min-h-screen bg-gradient-to-br from-slate-100 via-white to-slate-200 text-slate-900 transition-colors duration-500 dark:from-slate-950 dark:via-slate-900 dark:to-slate-950 dark:text-slate-100">
<button
type="button"
class="absolute left-2 top-2 z-20 h-10 w-10 opacity-0"
@click="handleAdminHotzoneTap"
aria-label="Admin access"
></button>
<a
v-if="showAdminLink"
href="/admin"
class="fixed left-6 top-6 z-[120] rounded-full border border-slate-200 bg-white/90 px-4 py-2 text-xs font-semibold uppercase tracking-[0.3em] text-slate-700 shadow-lg backdrop-blur transition hover:border-emerald-300 hover:text-emerald-600 dark:border-white/20 dark:bg-white/10 dark:text-white"
>
Admin
</a>
<div class="mx-auto flex w-full max-w-7xl flex-col gap-6 px-2 py-8 sm:px-4 lg:px-6">
<header class="relative rounded-3xl border border-slate-200 bg-white/90 p-6 text-slate-900 shadow-2xl backdrop-blur transition-colors duration-300 dark:border-white/10 dark:bg-white/5 dark:text-white">
<div class="absolute right-4 top-4 z-10 flex items-center gap-3 sm:right-6 sm:top-6">
@@ -156,9 +169,16 @@ const lastRefreshedAt = ref(new Date());
const refreshIntervalMs = ref(5000);
const toastMessage = ref(null);
const toastVariant = ref('info');
const showAdminLink = ref(false);
let toastTimer = null;
let refreshTimer = null;
let aiStatusTimer = null;
let adminTapTimer = null;
let adminHideTimer = null;
let adminTapCount = 0;
const adminTapTarget = 5;
const adminTapWindowMs = 3000;
const adminRevealDurationMs = 15000;
const getImageIdentifier = (image) => image?.id ?? image?.image_id ?? null;
@@ -317,6 +337,32 @@ const handleManualRefresh = () => {
fetchImages({ silent: false });
};
const handleAdminHotzoneTap = () => {
adminTapCount += 1;
if (!adminTapTimer) {
adminTapTimer = setTimeout(() => {
adminTapCount = 0;
adminTapTimer = null;
}, adminTapWindowMs);
}
if (adminTapCount >= adminTapTarget) {
adminTapCount = 0;
if (adminTapTimer) {
clearTimeout(adminTapTimer);
adminTapTimer = null;
}
showAdminLink.value = true;
if (adminHideTimer) {
clearTimeout(adminHideTimer);
}
adminHideTimer = setTimeout(() => {
showAdminLink.value = false;
}, adminRevealDurationMs);
}
};
const showContextMenu = (image) => {
selectedImage.value = image;
currentOverlayComponent.value = 'contextMenu';
@@ -639,5 +685,11 @@ onUnmounted(() => {
if (aiStatusTimer) {
clearInterval(aiStatusTimer);
}
if (adminTapTimer) {
clearTimeout(adminTapTimer);
}
if (adminHideTimer) {
clearTimeout(adminHideTimer);
}
});
</script>