scraping and improvements

This commit is contained in:
Stefan Hardegger
2025-07-28 13:52:09 +02:00
parent f95d7aa8bb
commit fcad028959
31 changed files with 3788 additions and 118 deletions

View File

@@ -0,0 +1,98 @@
'use client';
import { useState, useRef, useEffect } from 'react';
import Link from 'next/link';
import { ChevronDownIcon } from '@heroicons/react/24/outline';
interface DropdownItem {
href: string;
label: string;
description?: string;
}
interface DropdownProps {
trigger: string;
items: DropdownItem[];
className?: string;
onItemClick?: () => void;
}
export default function Dropdown({ trigger, items, className = '', onItemClick }: DropdownProps) {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
const timeoutRef = useRef<NodeJS.Timeout>();
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setIsOpen(false);
}
};
if (isOpen) {
document.addEventListener('mousedown', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, [isOpen]);
const handleMouseEnter = () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
setIsOpen(true);
};
const handleMouseLeave = () => {
timeoutRef.current = setTimeout(() => {
setIsOpen(false);
}, 150);
};
const handleItemClick = () => {
setIsOpen(false);
onItemClick?.();
};
return (
<div
className={`relative ${className}`}
ref={dropdownRef}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<button
onClick={() => setIsOpen(!isOpen)}
className="theme-text hover:theme-accent transition-colors font-medium flex items-center gap-1"
>
{trigger}
<ChevronDownIcon
className={`h-4 w-4 transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`}
/>
</button>
{isOpen && (
<div className="absolute top-full left-0 mt-1 w-64 theme-card theme-shadow border theme-border rounded-lg py-2 z-50">
{items.map((item, index) => (
<Link
key={index}
href={item.href}
onClick={handleItemClick}
className="block px-4 py-2 theme-text hover:theme-accent transition-colors"
>
<div className="font-medium">{item.label}</div>
{item.description && (
<div className="text-sm theme-text-secondary mt-1">{item.description}</div>
)}
</Link>
))}
</div>
)}
</div>
);
}