feat: Curator-Hilfe-System implementiert

- Hilfe-Seite /curator/help mit vollständiger Dokumentation (de/en)
- HelpTooltip-Komponente mit Hover- und Click-Modi
- Tooltips bei allen wichtigen Dashboard-Bereichen:
  * Dashboard-Übersicht
  * Upload-Bereich & Genre-Zuweisung
  * Track-Liste (Suche, Filter, Batch-Edit)
  * Kommentar-Verwaltung
- Prominenter Hilfe-Button im Header
- Umfassende Übersetzungen für alle Hilfe-Texte
- Fix: TypeScript-Fehler in batch route behoben
- Fix: Doppelter Browser-Tooltip entfernt (nur noch custom Tooltip)
This commit is contained in:
Hördle Bot
2025-12-04 01:07:45 +01:00
parent a61caa2d13
commit 65425ac15c
8 changed files with 694 additions and 94 deletions

173
components/HelpTooltip.tsx Normal file
View File

@@ -0,0 +1,173 @@
'use client';
import { useState, useRef, useEffect } from 'react';
interface HelpTooltipProps {
shortText: string; // Text für Hover
longText: string; // Text für Click/Modal
position?: 'top' | 'bottom' | 'left' | 'right';
}
export default function HelpTooltip({ shortText, longText, position = 'top' }: HelpTooltipProps) {
const [showHover, setShowHover] = useState(false);
const [showModal, setShowModal] = useState(false);
const tooltipRef = useRef<HTMLDivElement>(null);
const buttonRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (
tooltipRef.current &&
!tooltipRef.current.contains(event.target as Node) &&
buttonRef.current &&
!buttonRef.current.contains(event.target as Node)
) {
setShowModal(false);
}
}
if (showModal) {
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}
}, [showModal]);
const positionStyles = {
top: { bottom: '100%', left: '50%', transform: 'translateX(-50%)', marginBottom: '0.5rem' },
bottom: { top: '100%', left: '50%', transform: 'translateX(-50%)', marginTop: '0.5rem' },
left: { right: '100%', top: '50%', transform: 'translateY(-50%)', marginRight: '0.5rem' },
right: { left: '100%', top: '50%', transform: 'translateY(-50%)', marginLeft: '0.5rem' },
};
return (
<div style={{ position: 'relative', display: 'inline-block' }}>
<button
ref={buttonRef}
type="button"
onClick={() => setShowModal(!showModal)}
onMouseEnter={() => setShowHover(true)}
onMouseLeave={() => setShowHover(false)}
style={{
background: 'none',
border: 'none',
cursor: 'pointer',
color: '#6b7280',
fontSize: '1rem',
padding: '0.25rem',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '50%',
width: '1.5rem',
height: '1.5rem',
transition: 'background-color 0.2s',
}}
onMouseOver={(e) => {
e.currentTarget.style.backgroundColor = '#f3f4f6';
}}
onMouseOut={(e) => {
e.currentTarget.style.backgroundColor = 'transparent';
}}
aria-label="Help"
>
?
</button>
{/* Hover Tooltip */}
{showHover && !showModal && (
<div
ref={tooltipRef}
style={{
position: 'absolute',
...positionStyles[position],
background: '#1f2937',
color: 'white',
padding: '0.5rem 0.75rem',
borderRadius: '0.375rem',
fontSize: '0.875rem',
whiteSpace: 'normal',
zIndex: 1000,
pointerEvents: 'none',
maxWidth: '250px',
}}
>
{shortText}
<div
style={{
position: 'absolute',
...(position === 'top' && { top: '100%', left: '50%', transform: 'translateX(-50%)', borderLeft: '6px solid transparent', borderRight: '6px solid transparent', borderTop: '6px solid #1f2937' }),
...(position === 'bottom' && { bottom: '100%', left: '50%', transform: 'translateX(-50%)', borderLeft: '6px solid transparent', borderRight: '6px solid transparent', borderBottom: '6px solid #1f2937' }),
...(position === 'left' && { left: '100%', top: '50%', transform: 'translateY(-50%)', borderTop: '6px solid transparent', borderBottom: '6px solid transparent', borderLeft: '6px solid #1f2937' }),
...(position === 'right' && { right: '100%', top: '50%', transform: 'translateY(-50%)', borderTop: '6px solid transparent', borderBottom: '6px solid transparent', borderRight: '6px solid #1f2937' }),
}}
/>
</div>
)}
{/* Modal für detaillierte Informationen */}
{showModal && (
<>
{/* Overlay */}
<div
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'rgba(0, 0, 0, 0.5)',
zIndex: 9998,
}}
onClick={() => setShowModal(false)}
/>
{/* Modal Content */}
<div
ref={tooltipRef}
style={{
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
background: 'white',
padding: '1.5rem',
borderRadius: '0.5rem',
boxShadow: '0 10px 25px rgba(0, 0, 0, 0.2)',
maxWidth: '500px',
width: '90%',
maxHeight: '80vh',
overflowY: 'auto',
zIndex: 9999,
}}
onClick={(e) => e.stopPropagation()}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start', marginBottom: '1rem' }}>
<h3 style={{ margin: 0, fontSize: '1.25rem', fontWeight: 'bold' }}>Hilfe</h3>
<button
type="button"
onClick={() => setShowModal(false)}
style={{
background: 'none',
border: 'none',
fontSize: '1.5rem',
cursor: 'pointer',
color: '#6b7280',
padding: '0',
lineHeight: '1',
}}
aria-label="Close"
>
×
</button>
</div>
<div style={{ fontSize: '0.9rem', lineHeight: '1.6', whiteSpace: 'pre-wrap' }}>
{longText}
</div>
</div>
</>
)}
</div>
);
}