feat: add visual admin panel with page builder and settings editor
- Add /admin route with password-protected visual page builder
- Page Builder: manage hero images, standalone albums, subpages, and sections
- Album Picker: browse all shared Immich albums with search and filtering
- Settings Editor: theme, grid, footer, legal, SEO configuration
- YAML service with atomic writes and automatic backups (content/.backups/)
- HMAC-signed admin sessions (24h expiry, HttpOnly cookies)
- API endpoints: /api/admin/{auth,gallery,settings,albums,reload}
- Enable with ADMIN_PASSWORD env var; disabled by default
- invalidateConfigCache() export for hot-reload after saves
This commit is contained in:
54
app/admin/page.tsx
Normal file
54
app/admin/page.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import AdminLogin from './components/AdminLogin';
|
||||
import AdminDashboard from './components/AdminDashboard';
|
||||
import './admin.css';
|
||||
|
||||
export default function AdminPage() {
|
||||
const [authenticated, setAuthenticated] = useState<boolean | null>(null);
|
||||
const [enabled, setEnabled] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
checkAuth();
|
||||
}, []);
|
||||
|
||||
async function checkAuth() {
|
||||
try {
|
||||
const res = await fetch('/api/admin/auth');
|
||||
const data = await res.json();
|
||||
setAuthenticated(data.authenticated);
|
||||
setEnabled(data.enabled);
|
||||
} catch {
|
||||
setAuthenticated(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (authenticated === null) {
|
||||
return (
|
||||
<div className="admin-loading">
|
||||
<div className="admin-spinner" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
return (
|
||||
<div className="admin-disabled">
|
||||
<div className="admin-disabled-card">
|
||||
<h1>Admin Panel</h1>
|
||||
<p>
|
||||
The admin panel is not enabled. Set <code>ADMIN_PASSWORD</code> in your environment
|
||||
variables to activate it.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!authenticated) {
|
||||
return <AdminLogin onSuccess={() => setAuthenticated(true)} />;
|
||||
}
|
||||
|
||||
return <AdminDashboard onLogout={() => setAuthenticated(false)} />;
|
||||
}
|
||||
Reference in New Issue
Block a user