feat: admin panel with SQLite, auth, and calendar-style schedule editor
Complete admin panel for content management: - SQLite database with better-sqlite3, seed script from content.ts - Simple password auth with HMAC-signed cookies (Edge + Node compatible) - 9 section editors: meta, hero, about, team, classes, schedule, pricing, FAQ, contact - Team CRUD with image upload and drag reorder - Schedule editor with Google Calendar-style visual timeline (colored blocks, overlap detection, click-to-add) - All public components refactored to accept data props from DB (with fallback to static content) - Middleware protecting /admin/* and /api/admin/* routes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,16 +1,25 @@
|
||||
import { Users, Layers, MapPin } from "lucide-react";
|
||||
import { siteContent } from "@/data/content";
|
||||
import { SectionHeading } from "@/components/ui/SectionHeading";
|
||||
import { Reveal } from "@/components/ui/Reveal";
|
||||
import type { SiteContent } from "@/types/content";
|
||||
|
||||
const stats = [
|
||||
{ icon: <Users size={22} />, value: "16", label: "тренеров" },
|
||||
{ icon: <Layers size={22} />, value: "6", label: "направлений" },
|
||||
{ icon: <MapPin size={22} />, value: "2", label: "зала в Минске" },
|
||||
];
|
||||
interface AboutStats {
|
||||
trainers: number;
|
||||
classes: number;
|
||||
locations: number;
|
||||
}
|
||||
|
||||
export function About() {
|
||||
const { about } = siteContent;
|
||||
interface AboutProps {
|
||||
data: SiteContent["about"];
|
||||
stats: AboutStats;
|
||||
}
|
||||
|
||||
export function About({ data: about, stats }: AboutProps) {
|
||||
const statItems = [
|
||||
{ icon: <Users size={22} />, value: String(stats.trainers), label: "тренеров" },
|
||||
{ icon: <Layers size={22} />, value: String(stats.classes), label: "направлений" },
|
||||
{ icon: <MapPin size={22} />, value: String(stats.locations), label: "зала в Минске" },
|
||||
];
|
||||
|
||||
return (
|
||||
<section id="about" className="section-glow relative section-padding bg-neutral-100 dark:bg-[#080808]">
|
||||
@@ -33,7 +42,7 @@ export function About() {
|
||||
{/* Stats */}
|
||||
<Reveal>
|
||||
<div className="mx-auto mt-14 grid max-w-3xl grid-cols-3 gap-4 sm:gap-8">
|
||||
{stats.map((stat, i) => (
|
||||
{statItems.map((stat, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="group flex flex-col items-center gap-3 rounded-2xl border border-neutral-200 bg-white/50 p-6 transition-all duration-300 hover:border-gold/30 sm:p-8 dark:border-white/[0.06] dark:bg-white/[0.02] dark:hover:border-gold/20"
|
||||
|
||||
Reference in New Issue
Block a user