Add complete frontend implementation and Docker deployment setup

- Implement React frontend with TypeScript and Tailwind CSS
- Add scrappbook.de-inspired UI design with photo galleries
- Implement authentication, photo viewing, and download features
- Add Docker Swarm configuration with Traefik reverse proxy
- Set up Drone CI/CD pipeline for automated deployments
- Add monitoring stack with Prometheus and Grafana
- Create comprehensive deployment documentation
- Add simple local development setup with docker-compose.local.yml

Features:
- Password-protected galleries with expiration warnings
- Responsive photo grid with lightbox viewer
- Bulk download functionality
- Hot reload development environment
- Email testing with Mailhog
- Production-ready deployment scripts

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
This commit is contained in:
2025-07-06 20:23:13 +02:00
co-authored by Claude
parent 032bbae50d
commit 6c82958c79
73 changed files with 10611 additions and 2 deletions
@@ -0,0 +1,53 @@
import React from 'react';
import { AlertTriangle, Download } from 'lucide-react';
import Countdown from 'react-countdown';
import { parseISO } from 'date-fns';
interface ExpirationBannerProps {
daysRemaining: number;
expiresAt: string;
}
export const ExpirationBanner: React.FC<ExpirationBannerProps> = ({
daysRemaining,
expiresAt
}) => {
const expirationDate = parseISO(expiresAt);
const countdownRenderer = ({ days, hours, minutes, completed }: any) => {
if (completed) {
return <span>Gallery has expired</span>;
} else {
return (
<span className="font-mono">
{days}d {hours}h {minutes}m
</span>
);
}
};
const getBannerColor = () => {
if (daysRemaining <= 1) return 'bg-red-600';
if (daysRemaining <= 3) return 'bg-amber-600';
return 'bg-amber-500';
};
return (
<div className={`${getBannerColor()} text-white sticky top-0 z-50`}>
<div className="container py-3">
<div className="flex items-center justify-between">
<div className="flex items-center">
<AlertTriangle className="w-5 h-5 mr-2 animate-pulse" />
<span className="font-medium">
Gallery expires in <Countdown date={expirationDate} renderer={countdownRenderer} />
</span>
</div>
<div className="flex items-center text-sm">
<Download className="w-4 h-4 mr-1" />
<span>Download your photos now!</span>
</div>
</div>
</div>
</div>
);
};