refactor: improve layout spacing and smooth scrolling in calibration views
This commit is contained in:
@@ -13,7 +13,7 @@ export default function RootLayout({
|
|||||||
<body className="flex flex-col min-h-screen">
|
<body className="flex flex-col min-h-screen">
|
||||||
<AudioProvider>
|
<AudioProvider>
|
||||||
<Header />
|
<Header />
|
||||||
<main className="flex-grow">
|
<main className="flex-grow py-4">
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export default async function HomePage() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-2xl mx-auto py-4 px-4 sm:px-6 lg:px-8">
|
<div className="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<h1 className="text-2xl font-bold text-gray-800 mb-2">Experimente</h1>
|
<h1 className="text-2xl font-bold text-gray-800 mb-2">Experimente</h1>
|
||||||
<p className="text-gray-500 mb-8">
|
<p className="text-gray-500 mb-8">
|
||||||
Wählen Sie ein Experiment aus, um mit der Annotation zu beginnen oder fortzufahren.
|
Wählen Sie ein Experiment aus, um mit der Annotation zu beginnen oder fortzufahren.
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export default function AnnotationPageView({
|
|||||||
loadScores();
|
loadScores();
|
||||||
}, [experimentId]);
|
}, [experimentId]);
|
||||||
|
|
||||||
|
|
||||||
const getAnnotationConfig = (dialectLabel: string) => {
|
const getAnnotationConfig = (dialectLabel: string) => {
|
||||||
switch (viewType) {
|
switch (viewType) {
|
||||||
case 'quality-choice':
|
case 'quality-choice':
|
||||||
@@ -118,6 +119,12 @@ export default function AnnotationPageView({
|
|||||||
const currentEntry = entries[currentIndex];
|
const currentEntry = entries[currentIndex];
|
||||||
const isComplete = entries.every((e) => e.annotation !== null);
|
const isComplete = entries.every((e) => e.annotation !== null);
|
||||||
|
|
||||||
|
// Smooth scroll to top when current entry changes
|
||||||
|
useEffect(() => {
|
||||||
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
}, [currentIndex]);
|
||||||
|
|
||||||
|
|
||||||
const handlePrevious = () => {
|
const handlePrevious = () => {
|
||||||
if (currentIndex > 0) {
|
if (currentIndex > 0) {
|
||||||
setCurrentIndex((i) => i - 1);
|
setCurrentIndex((i) => i - 1);
|
||||||
@@ -245,7 +252,7 @@ export default function AnnotationPageView({
|
|||||||
{/* Main content area */}
|
{/* Main content area */}
|
||||||
<div className="flex-1 flex flex-col overflow-hidden">
|
<div className="flex-1 flex flex-col overflow-hidden">
|
||||||
{/* Top bar */}
|
{/* Top bar */}
|
||||||
<div className="sticky top-0 z-40 bg-white border-b border-gray-200 p-4">
|
<div className="sticky top-0 z-40 bg-white border-b border-gray-200 pb-4 px-4">
|
||||||
<div className="flex items-center justify-between max-w-4xl mx-auto">
|
<div className="flex items-center justify-between max-w-4xl mx-auto">
|
||||||
{/* Toggle and Home buttons */}
|
{/* Toggle and Home buttons */}
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ export default function CalibrationEntryView({
|
|||||||
setSelectedDialect(existingAnswer?.dialectLabel || null);
|
setSelectedDialect(existingAnswer?.dialectLabel || null);
|
||||||
setSelectedConfidence(existingAnswer?.confidence || null);
|
setSelectedConfidence(existingAnswer?.confidence || null);
|
||||||
setFullyPlayed(existingAnswer ? true : false);
|
setFullyPlayed(existingAnswer ? true : false);
|
||||||
|
// Scroll to top when entry changes with smooth animation
|
||||||
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
}, [entry, existingAnswer]);
|
}, [entry, existingAnswer]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -85,79 +87,82 @@ export default function CalibrationEntryView({
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Dialect question */}
|
{/* Questions container */}
|
||||||
<div className="mt-6 mb-4">
|
<div className="mt-6 flex flex-col lg:flex-row gap-6">
|
||||||
<div className="text-sm font-semibold text-gray-700 mb-3">
|
{/* Dialect question */}
|
||||||
Welcher Dialekt ist es?
|
<div className="flex-1">
|
||||||
</div>
|
<div className="text-sm font-semibold text-gray-700 mb-3">
|
||||||
<div className="flex flex-col gap-2">
|
Welcher Dialekt ist es?
|
||||||
{Object.entries(DIALECT_LABELS_WITHOUT_DE).map(([dialectKey, dialectName]) => {
|
</div>
|
||||||
const selected = selectedDialect === dialectKey;
|
<div className="flex flex-col gap-2">
|
||||||
const disabled = !fullyPlayed || isSaving;
|
{Object.entries(DIALECT_LABELS_WITHOUT_DE).map(([dialectKey, dialectName]) => {
|
||||||
return (
|
const selected = selectedDialect === dialectKey;
|
||||||
<button
|
const disabled = !fullyPlayed || isSaving;
|
||||||
key={dialectKey}
|
return (
|
||||||
disabled={disabled}
|
<button
|
||||||
onClick={() => handleDialectChange(dialectKey)}
|
key={dialectKey}
|
||||||
className={`flex items-center gap-3 w-full text-left px-4 py-2.5 rounded-lg border text-sm transition-colors ${
|
disabled={disabled}
|
||||||
disabled
|
onClick={() => handleDialectChange(dialectKey)}
|
||||||
? 'opacity-40 cursor-not-allowed border-gray-200 bg-gray-50 text-gray-500'
|
className={`flex items-center gap-3 w-full text-left px-4 py-2.5 rounded-lg border text-sm transition-colors ${
|
||||||
: selected
|
disabled
|
||||||
? 'border-blue-500 bg-blue-50 text-blue-800 font-medium'
|
? 'opacity-40 cursor-not-allowed border-gray-200 bg-gray-50 text-gray-500'
|
||||||
: 'border-gray-200 hover:border-blue-300 hover:bg-blue-50 text-gray-700'
|
: selected
|
||||||
}`}
|
? 'border-blue-500 bg-blue-50 text-blue-800 font-medium'
|
||||||
>
|
: 'border-gray-200 hover:border-blue-300 hover:bg-blue-50 text-gray-700'
|
||||||
<span
|
|
||||||
className={`flex-shrink-0 w-6 h-6 rounded-full border-2 flex items-center justify-center text-xs font-bold ${
|
|
||||||
selected
|
|
||||||
? 'border-blue-500 bg-blue-500 text-white'
|
|
||||||
: 'border-gray-300 text-gray-400'
|
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{selected ? '✓' : ''}
|
<span
|
||||||
</span>
|
className={`flex-shrink-0 w-6 h-6 rounded-full border-2 flex items-center justify-center text-xs font-bold ${
|
||||||
<span>{dialectName}</span>
|
selected
|
||||||
</button>
|
? 'border-blue-500 bg-blue-500 text-white'
|
||||||
);
|
: 'border-gray-300 text-gray-400'
|
||||||
})}
|
}`}
|
||||||
|
>
|
||||||
|
{selected ? '✓' : ''}
|
||||||
|
</span>
|
||||||
|
<span>{dialectName}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Confidence question */}
|
{/* Confidence question */}
|
||||||
<div className="mt-6">
|
<div className="flex-1">
|
||||||
<div className="text-sm font-semibold text-gray-700 mb-3">
|
<div className="text-sm font-semibold text-gray-700 mb-3">
|
||||||
Wie sicher sind Sie?
|
Wie sicher sind Sie?
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
{CONFIDENCE_OPTIONS.map(({ value, label }) => {
|
{CONFIDENCE_OPTIONS.map(({ value, label }) => {
|
||||||
const selected = selectedConfidence === value;
|
const selected = selectedConfidence === value;
|
||||||
const disabled = !fullyPlayed || isSaving;
|
const disabled = !fullyPlayed || isSaving;
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
key={value}
|
key={value}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={() => handleConfidenceChange(value)}
|
onClick={() => handleConfidenceChange(value)}
|
||||||
className={`flex items-center gap-3 w-full text-left px-4 py-2.5 rounded-lg border text-sm transition-colors ${
|
className={`flex items-center gap-3 w-full text-left px-4 py-2.5 rounded-lg border text-sm transition-colors ${
|
||||||
disabled
|
disabled
|
||||||
? 'opacity-40 cursor-not-allowed border-gray-200 bg-gray-50 text-gray-500'
|
? 'opacity-40 cursor-not-allowed border-gray-200 bg-gray-50 text-gray-500'
|
||||||
: selected
|
: selected
|
||||||
? 'border-blue-500 bg-blue-50 text-blue-800 font-medium'
|
? 'border-blue-500 bg-blue-50 text-blue-800 font-medium'
|
||||||
: 'border-gray-200 hover:border-blue-300 hover:bg-blue-50 text-gray-700'
|
: 'border-gray-200 hover:border-blue-300 hover:bg-blue-50 text-gray-700'
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className={`flex-shrink-0 w-6 h-6 rounded-full border-2 flex items-center justify-center text-xs font-bold ${
|
|
||||||
selected
|
|
||||||
? 'border-blue-500 bg-blue-500 text-white'
|
|
||||||
: 'border-gray-300 text-gray-400'
|
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{selected ? '✓' : ''}
|
<span
|
||||||
</span>
|
className={`flex-shrink-0 w-6 h-6 rounded-full border-2 flex items-center justify-center text-xs font-bold ${
|
||||||
<span>{label}</span>
|
selected
|
||||||
</button>
|
? 'border-blue-500 bg-blue-500 text-white'
|
||||||
);
|
: 'border-gray-300 text-gray-400'
|
||||||
})}
|
}`}
|
||||||
|
>
|
||||||
|
{selected ? '✓' : ''}
|
||||||
|
</span>
|
||||||
|
<span>{label}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function CalibrationInfoView({
|
|||||||
<div className="flex-1 flex items-center justify-center px-4">
|
<div className="flex-1 flex items-center justify-center px-4">
|
||||||
<div className="max-w-2xl w-full">
|
<div className="max-w-2xl w-full">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="text-center mb-12 mt-8">
|
<div className="text-center mb-4">
|
||||||
<h1 className="text-3xl font-bold text-gray-900 mb-2">Kalibrierungsphase</h1>
|
<h1 className="text-3xl font-bold text-gray-900 mb-2">Kalibrierungsphase</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ export default function CalibrationPageView({
|
|||||||
<div className="flex flex-col h-full bg-white">
|
<div className="flex flex-col h-full bg-white">
|
||||||
<div className="flex-1 flex flex-col overflow-hidden">
|
<div className="flex-1 flex flex-col overflow-hidden">
|
||||||
<div className="flex-1 overflow-y-auto">
|
<div className="flex-1 overflow-y-auto">
|
||||||
<div className="max-w-3xl mx-auto py-20 px-4">
|
<div className="max-w-3xl mx-auto px-4">
|
||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
<div className="text-5xl mb-4">🎉</div>
|
<div className="text-5xl mb-4">🎉</div>
|
||||||
<h1 className="text-3xl font-bold text-green-600 mb-3">
|
<h1 className="text-3xl font-bold text-green-600 mb-3">
|
||||||
@@ -210,7 +210,7 @@ export default function CalibrationPageView({
|
|||||||
<div className="flex flex-col h-full bg-white">
|
<div className="flex flex-col h-full bg-white">
|
||||||
<div className="flex-1 flex flex-col overflow-hidden">
|
<div className="flex-1 flex flex-col overflow-hidden">
|
||||||
{/* Header with progress */}
|
{/* Header with progress */}
|
||||||
<div className="sticky top-0 z-50 bg-white border-b border-gray-200 px-6 py-4">
|
<div className="sticky top-0 z-10 bg-white border-b border-gray-200 px-6 pb-4">
|
||||||
<div className="flex items-center justify-between mb-3">
|
<div className="flex items-center justify-between mb-3">
|
||||||
<h1 className="text-xl font-bold text-gray-800">Kalibrierungsphase</h1>
|
<h1 className="text-xl font-bold text-gray-800">Kalibrierungsphase</h1>
|
||||||
<span className="text-sm text-gray-600">
|
<span className="text-sm text-gray-600">
|
||||||
@@ -241,7 +241,7 @@ export default function CalibrationPageView({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Navigation footer */}
|
{/* Navigation footer */}
|
||||||
<div className="sticky bottom-0 bg-white border-t border-gray-200 px-6 py-4 flex gap-3 justify-between">
|
<div className="sticky bottom-0 bg-white border-t border-gray-200 px-6 pt-4 flex gap-3 justify-between">
|
||||||
<button
|
<button
|
||||||
onClick={handlePrevious}
|
onClick={handlePrevious}
|
||||||
disabled={currentIndex === 0 || isPending}
|
disabled={currentIndex === 0 || isPending}
|
||||||
|
|||||||
Reference in New Issue
Block a user