7ce4f7efdc
continuous-integration/drone/push Build is passing
- Add Focus Tools dashboard with collapsible help section - Implement Quick Wins page for tasks under 15 minutes - Add Single Task Focus mode to reduce overwhelm - Create Body Doubling page for virtual co-working - Add visual timer, break reminders, and energy tracking - Implement hyperfocus protection alerts - Add ADHD settings panel with customizable options - Include full English and German translations - Fix larger touch targets CSS to not break button layouts - Add Playwright tests for Focus Tools features
298 lines
11 KiB
TypeScript
298 lines
11 KiB
TypeScript
import React from 'react';
|
|
import { useADHDMode, defaultADHDSettings } from '../providers/ADHDModeProvider';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Switch } from '@/components/ui/switch';
|
|
import { Slider } from '@/components/ui/slider';
|
|
import { Label } from '@/components/ui/label';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@/components/ui/select';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Brain,
|
|
Timer,
|
|
Sparkles,
|
|
Coffee,
|
|
Target,
|
|
Battery,
|
|
Zap,
|
|
Shield,
|
|
RotateCcw,
|
|
} from 'lucide-react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { ADHDModeToggle } from '../ADHDModeToggle';
|
|
|
|
export function ADHDSettingsPanel() {
|
|
const { t } = useTranslation();
|
|
const { isEnabled, settings, updateSettings } = useADHDMode();
|
|
|
|
const handleReset = () => {
|
|
updateSettings(defaultADHDSettings);
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Main Toggle */}
|
|
<ADHDModeToggle showLabel={true} />
|
|
|
|
{/* Settings (only shown when enabled) */}
|
|
{isEnabled && (
|
|
<>
|
|
{/* Visual & Interaction Settings */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2 text-lg">
|
|
<Target className="h-5 w-5" />
|
|
{t('adhd.settings.visualTitle')}
|
|
</CardTitle>
|
|
<CardDescription>
|
|
{t('adhd.settings.visualDesc')}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
{/* Reduced Animations */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base">{t('adhd.settings.reducedAnimations')}</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
{t('adhd.settings.reducedAnimationsDesc')}
|
|
</p>
|
|
</div>
|
|
<Switch
|
|
checked={settings.reducedAnimations}
|
|
onCheckedChange={(checked) => updateSettings({ reducedAnimations: checked })}
|
|
/>
|
|
</div>
|
|
|
|
{/* Larger Touch Targets */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base">{t('adhd.settings.largerTargets')}</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
{t('adhd.settings.largerTargetsDesc')}
|
|
</p>
|
|
</div>
|
|
<Switch
|
|
checked={settings.largerTargets}
|
|
onCheckedChange={(checked) => updateSettings({ largerTargets: checked })}
|
|
/>
|
|
</div>
|
|
|
|
{/* Single Task Mode Default */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base">{t('adhd.settings.singleTaskDefault')}</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
{t('adhd.settings.singleTaskDefaultDesc')}
|
|
</p>
|
|
</div>
|
|
<Switch
|
|
checked={settings.singleTaskModeDefault}
|
|
onCheckedChange={(checked) => updateSettings({ singleTaskModeDefault: checked })}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Timer & Focus Settings */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2 text-lg">
|
|
<Timer className="h-5 w-5" />
|
|
{t('adhd.settings.timerTitle')}
|
|
</CardTitle>
|
|
<CardDescription>
|
|
{t('adhd.settings.timerDesc')}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
{/* Visual Timer */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base">{t('adhd.settings.visualTimer')}</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
{t('adhd.settings.visualTimerDesc')}
|
|
</p>
|
|
</div>
|
|
<Switch
|
|
checked={settings.visualTimerEnabled}
|
|
onCheckedChange={(checked) => updateSettings({ visualTimerEnabled: checked })}
|
|
/>
|
|
</div>
|
|
|
|
{/* Hyperfocus Protection */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base flex items-center gap-2">
|
|
<Shield className="h-4 w-4" />
|
|
{t('adhd.settings.hyperfocusProtection')}
|
|
</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
{t('adhd.settings.hyperfocusProtectionDesc')}
|
|
</p>
|
|
</div>
|
|
<Switch
|
|
checked={settings.hyperfocusProtection}
|
|
onCheckedChange={(checked) => updateSettings({ hyperfocusProtection: checked })}
|
|
/>
|
|
</div>
|
|
|
|
{/* Hyperfocus Max Minutes */}
|
|
{settings.hyperfocusProtection && (
|
|
<div className="space-y-3">
|
|
<div className="flex items-center justify-between">
|
|
<Label>{t('adhd.settings.hyperfocusMaxMinutes')}</Label>
|
|
<span className="text-sm text-muted-foreground">
|
|
{settings.hyperfocusMaxMinutes} min
|
|
</span>
|
|
</div>
|
|
<Slider
|
|
value={[settings.hyperfocusMaxMinutes]}
|
|
onValueChange={([value]) => updateSettings({ hyperfocusMaxMinutes: value })}
|
|
min={30}
|
|
max={180}
|
|
step={15}
|
|
className="w-full"
|
|
/>
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Break Reminder Settings */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2 text-lg">
|
|
<Coffee className="h-5 w-5" />
|
|
{t('adhd.settings.breakTitle')}
|
|
</CardTitle>
|
|
<CardDescription>
|
|
{t('adhd.settings.breakDesc')}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
{/* Break Reminder Interval */}
|
|
<div className="space-y-3">
|
|
<div className="flex items-center justify-between">
|
|
<Label>{t('adhd.settings.breakInterval')}</Label>
|
|
<span className="text-sm text-muted-foreground">
|
|
{settings.breakReminderInterval} min
|
|
</span>
|
|
</div>
|
|
<Slider
|
|
value={[settings.breakReminderInterval]}
|
|
onValueChange={([value]) => updateSettings({ breakReminderInterval: value })}
|
|
min={15}
|
|
max={90}
|
|
step={5}
|
|
className="w-full"
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Motivation Settings */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2 text-lg">
|
|
<Sparkles className="h-5 w-5" />
|
|
{t('adhd.settings.motivationTitle')}
|
|
</CardTitle>
|
|
<CardDescription>
|
|
{t('adhd.settings.motivationDesc')}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
{/* Positive Messaging Level */}
|
|
<div className="space-y-2">
|
|
<Label>{t('adhd.settings.messagingLevel')}</Label>
|
|
<Select
|
|
value={settings.positiveMessagingLevel}
|
|
onValueChange={(value: 'minimal' | 'normal' | 'high') =>
|
|
updateSettings({ positiveMessagingLevel: value })
|
|
}
|
|
>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="minimal">{t('adhd.settings.messagingMinimal')}</SelectItem>
|
|
<SelectItem value="normal">{t('adhd.settings.messagingNormal')}</SelectItem>
|
|
<SelectItem value="high">{t('adhd.settings.messagingHigh')}</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<p className="text-xs text-muted-foreground">
|
|
{t('adhd.settings.messagingLevelDesc')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Quick Win Threshold */}
|
|
<div className="space-y-3">
|
|
<div className="flex items-center justify-between">
|
|
<Label className="flex items-center gap-2">
|
|
<Zap className="h-4 w-4 text-yellow-500" />
|
|
{t('adhd.settings.quickWinThreshold')}
|
|
</Label>
|
|
<span className="text-sm text-muted-foreground">
|
|
{settings.quickWinThreshold} min
|
|
</span>
|
|
</div>
|
|
<Slider
|
|
value={[settings.quickWinThreshold]}
|
|
onValueChange={([value]) => updateSettings({ quickWinThreshold: value })}
|
|
min={5}
|
|
max={30}
|
|
step={5}
|
|
className="w-full"
|
|
/>
|
|
<p className="text-xs text-muted-foreground">
|
|
{t('adhd.settings.quickWinThresholdDesc')}
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Energy Check-ins */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2 text-lg">
|
|
<Battery className="h-5 w-5" />
|
|
{t('adhd.settings.energyTitle')}
|
|
</CardTitle>
|
|
<CardDescription>
|
|
{t('adhd.settings.energyDesc')}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base">{t('adhd.settings.energyCheckIns')}</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
{t('adhd.settings.energyCheckInsDesc')}
|
|
</p>
|
|
</div>
|
|
<Switch
|
|
checked={settings.energyCheckInsEnabled}
|
|
onCheckedChange={(checked) => updateSettings({ energyCheckInsEnabled: checked })}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Reset Button */}
|
|
<div className="flex justify-end">
|
|
<Button variant="outline" onClick={handleReset}>
|
|
<RotateCcw className="h-4 w-4 mr-2" />
|
|
{t('adhd.settings.reset')}
|
|
</Button>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|