chore: remove dead code, unused CSS, unused components, and clean up git tracking

- Remove storage/logs/ and prod.log from git tracking; add to .gitignore
- Remove unused AvatarCarousel and ArticleSlider components
- Remove unused SkeletonTable export from ui.tsx
- Remove unused ChevronDown import from admin layout
- Remove 13 unused CSS classes (icon-base, nav-*, navigation-icon*, .app.dark,
  text-body, transition-base, card-base, admin-info-grid, .coin.*)
- Remove duplicate translation keys (openMenu/closeMenu in en.json)
- Fix admin-bans to use Prisma-generated bans_type enum
- Create shared AdminPageHeader component and formatDate utility
- Add logger and generateRequestId for structured logging
- All 58 tests pass, typecheck clean, build succeeds
This commit is contained in:
openhands committed 2026-07-08 13:27:01 +02:00
1 parent c5db7f5156
commit fc57fb06d1
18 files changed
+40 -2551

No files matched your search

-116
View File
@@ -1,116 +0,0 @@
"use client";
import { useState, useRef, useCallback } from "react";
import { avatarImageUrl } from "@/lib/format";
interface AvatarCarouselProps {
figures: string[];
imager: string;
onSelect: (figure: string) => void;
initialIndex?: number;
}
export function AvatarCarousel({
figures,
imager,
onSelect,
initialIndex = 0,
}: AvatarCarouselProps) {
const [currentIndex, setCurrentIndex] = useState(initialIndex);
const [direction, setDirection] = useState(0);
const isAnimating = useRef(false);
const prevIndexRef = useRef(initialIndex);
const navigate = useCallback((dir: number) => {
if (isAnimating.current || figures.length <= 1) return;
isAnimating.current = true;
setDirection(dir);
prevIndexRef.current = currentIndex;
setCurrentIndex((prev) => (prev + dir + figures.length) % figures.length);
setTimeout(() => { isAnimating.current = false; }, 300);
}, [currentIndex, figures.length]);
const goToIndex = useCallback((index: number) => {
if (isAnimating.current) return;
isAnimating.current = true;
const dir = index > currentIndex ? 1 : -1;
setDirection(dir);
prevIndexRef.current = currentIndex;
setCurrentIndex(index);
setTimeout(() => { isAnimating.current = false; }, 300);
}, [currentIndex]);
return (
<div className="relative w-full max-w-sm mx-auto" role="region" aria-label="Avatar selection">
<div className="relative overflow-hidden rounded-2xl bg-white p-4 shadow-xl dark:bg-gray-800">
<div className="transition-transform duration-300 ease-out" style={{ transform: `translateX(${direction * 100}%)` }}>
{figures.map((figure, idx) => (
<div
key={figure}
className="relative w-full h-48 flex items-center justify-center"
style={{
position: "absolute",
left: `${idx * 100}%`,
top: 0,
transition: "transform 300ms ease-out",
transform: `translateX(${(currentIndex - prevIndexRef.current) * -100}%)`,
}}
>
<div className="relative w-48 h-64">
<img
src={avatarImageUrl(imager, figure, { headOnly: false, direction: 2 })}
alt={`Avatar ${idx + 1}`}
className="w-full h-full object-contain"
loading="lazy"
/>
</div>
</div>
))}
</div>
</div>
<div className="flex justify-center gap-3 mt-4">
<button
type="button"
onClick={() => navigate(-1)}
disabled={isAnimating.current || figures.length <= 1}
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/80 dark:bg-gray-800/80 text-gray-700 dark:text-gray-300 shadow-md hover:scale-105 transition-transform disabled:opacity-50 disabled:cursor-not-allowed"
aria-label="Previous avatar"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
</button>
<div className="flex items-center gap-2">
{figures.map((_, idx) => (
<button
key={idx}
type="button"
onClick={() => goToIndex(idx)}
disabled={isAnimating.current}
className={`w-2.5 h-2.5 rounded-full transition-all ${
idx === currentIndex
? "bg-[#eeb425] scale-125"
: "bg-gray-400 hover:bg-gray-500 dark:bg-gray-600 dark:hover:bg-gray-500"
}`}
aria-label={`Select avatar ${idx + 1}`}
/>
))}
</div>
<button
type="button"
onClick={() => navigate(1)}
disabled={isAnimating.current || figures.length <= 1}
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/80 dark:bg-gray-800/80 text-gray-700 dark:text-gray-300 shadow-md hover:scale-105 transition-transform disabled:opacity-50 disabled:cursor-not-allowed"
aria-label="Next avatar"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
</div>
);
}