cognitive-load: add tooltips to advanced features

- Added optional tooltip prop to AdvancedFilters component
- Added tooltips to LibraryPage view mode toggles (Grid/List)
- Added tooltip to LibraryPage sort button
- Added context-aware tooltip to LibraryPage bulk mode button
- Tooltips explain functionality and improve discoverability
- Action 10.4.1.2 complete
This commit is contained in:
senke 2026-01-16 02:22:41 +01:00
parent e2b03341b2
commit 7ab4e03ded
3 changed files with 102 additions and 63 deletions

View file

@ -3586,12 +3586,18 @@ Critical path dependencies:
- **Result**: Tooltip component is ready to use, no dependency needed
- **Rollback**: N/A (component already exists)
- [ ] **Action 10.4.1.2**: Add tooltips to advanced features
- [x] **Action 10.4.1.2**: Add tooltips to advanced features
- **Scope**: Advanced UI elements - Add tooltips explaining usage
- **Dependencies**: Action 10.4.1.1 complete
- **Dependencies**: Action 10.4.1.1 complete
- **Risk**: LOW 🔒
- **Validation**: Tooltips appear on hover
- **Rollback**: Remove tooltips
- **Validation**: ✅ Tooltips added to advanced features:
- **AdvancedFilters component**: Added optional `tooltip` prop to explain what advanced filters are
- **LibraryPage view mode toggles**: Added tooltips to Grid and List view buttons explaining each view type
- **LibraryPage sort button**: Added tooltip explaining sorting functionality
- **LibraryPage bulk mode button**: Added tooltip explaining bulk selection mode (context-aware: different text when active vs inactive)
- **Tooltips use**: Tooltip component from `@/components/ui/tooltip` with hover trigger
- **Result**: Advanced features now have helpful tooltips that appear on hover, improving discoverability and reducing cognitive load
- **Rollback**: Remove tooltip props and Tooltip wrappers
- [ ] **Action 10.4.1.3**: Create onboarding flow for new users (optional)
- **Scope**: `apps/web/src/components/Onboarding.tsx` (create) - Guide new users through features

View file

@ -2,6 +2,7 @@ import * as React from 'react';
import { ChevronDown, ChevronUp, Filter } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Collapsible } from './ui/collapsible';
import { Tooltip } from './ui/tooltip';
export interface AdvancedFiltersProps {
/**
@ -46,6 +47,12 @@ export interface AdvancedFiltersProps {
* @default true
*/
showIcon?: boolean;
/**
* Tooltip text to explain what advanced filters are
* If provided, wraps the trigger in a Tooltip component
*/
tooltip?: string;
}
/**
@ -87,6 +94,7 @@ export function AdvancedFilters({
className,
contentClassName,
showIcon = true,
tooltip,
}: AdvancedFiltersProps) {
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
@ -103,16 +111,26 @@ export function AdvancedFilters({
const ChevronIcon = isOpen ? ChevronUp : ChevronDown;
const triggerContent = (
<div className="flex items-center gap-2">
{showIcon && <Filter className="w-4 h-4" />}
<span>{label}</span>
<ChevronIcon className="w-4 h-4 ml-auto" />
</div>
);
const collapsibleTrigger = tooltip ? (
<Tooltip content={tooltip} position="top">
{triggerContent}
</Tooltip>
) : (
triggerContent
);
return (
<div className={cn('w-full', className)}>
<Collapsible
trigger={
<div className="flex items-center gap-2">
{showIcon && <Filter className="w-4 h-4" />}
<span>{label}</span>
<ChevronIcon className="w-4 h-4 ml-auto" />
</div>
}
trigger={collapsibleTrigger}
open={isOpen}
onOpenChange={handleToggle}
defaultOpen={defaultOpen}

View file

@ -54,6 +54,7 @@ import { ConfirmationDialog } from '@/components/ui/confirmation-dialog';
import { LoadingState } from '@/components/ui/LoadingState';
import { Sidebar } from '@/components/ui/Sidebar';
import { BulkModeBanner } from '@/components/BulkModeBanner';
import { Tooltip } from '@/components/ui/tooltip';
import { logger } from '@/utils/logger';
import { parseApiError } from '@/utils/apiErrorHandler';
import { cn } from '@/lib/utils';
@ -370,49 +371,61 @@ export default function LibraryPagePremium() {
</Button>
</>
)}
<Button
variant={isBulkMode ? 'default' : 'outline'}
onClick={() => {
setIsBulkMode(!isBulkMode);
setSelectedTracks(new Set());
}}
size="sm"
<Tooltip
content={
isBulkMode
? 'Annuler la sélection multiple'
: 'Activer le mode sélection multiple pour modifier plusieurs pistes à la fois'
}
>
{isBulkMode ? (
<>
<X className="mr-2 h-4 w-4" />
Annuler
</>
) : (
<>
<CheckSquare className="mr-2 h-4 w-4" />
Sélection
</>
)}
</Button>
<Button
variant={isBulkMode ? 'default' : 'outline'}
onClick={() => {
setIsBulkMode(!isBulkMode);
setSelectedTracks(new Set());
}}
size="sm"
>
{isBulkMode ? (
<>
<X className="mr-2 h-4 w-4" />
Annuler
</>
) : (
<>
<CheckSquare className="mr-2 h-4 w-4" />
Sélection
</>
)}
</Button>
</Tooltip>
<div className="flex items-center border border-white/10 rounded-lg overflow-hidden">
<button
onClick={() => setViewMode('grid')}
className={cn(
'p-2 transition-colors cursor-pointer hover:bg-white/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-kodo-void',
viewMode === 'grid'
? 'bg-kodo-cyan/20 text-kodo-cyan'
: 'text-kodo-secondary hover:text-white',
)}
>
<Grid3x3 className="w-4 h-4" />
</button>
<button
onClick={() => setViewMode('list')}
className={cn(
'p-2 transition-colors border-l border-white/10 cursor-pointer hover:bg-white/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-kodo-void',
viewMode === 'list'
? 'bg-kodo-cyan/20 text-kodo-cyan'
: 'text-kodo-secondary hover:text-white',
)}
>
<List className="w-4 h-4" />
</button>
<Tooltip content="Vue en grille - Affiche les pistes sous forme de cartes visuelles">
<button
onClick={() => setViewMode('grid')}
className={cn(
'p-2 transition-colors cursor-pointer hover:bg-white/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-kodo-void',
viewMode === 'grid'
? 'bg-kodo-cyan/20 text-kodo-cyan'
: 'text-kodo-secondary hover:text-white',
)}
>
<Grid3x3 className="w-4 h-4" />
</button>
</Tooltip>
<Tooltip content="Vue en liste - Affiche les pistes avec plus de détails et métadonnées">
<button
onClick={() => setViewMode('list')}
className={cn(
'p-2 transition-colors border-l border-white/10 cursor-pointer hover:bg-white/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-kodo-void',
viewMode === 'list'
? 'bg-kodo-cyan/20 text-kodo-cyan'
: 'text-kodo-secondary hover:text-white',
)}
>
<List className="w-4 h-4" />
</button>
</Tooltip>
</div>
<Button onClick={handleOpenUpload} size="sm">
<Upload className="mr-2 h-4 w-4" />
@ -485,17 +498,19 @@ export default function LibraryPagePremium() {
</label>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm" className="w-full justify-between">
<span className="flex items-center gap-2">
<ArrowUpDown className="h-4 w-4" />
{sortBy === 'created_at'
? 'Date'
: sortBy === 'title'
? 'Titre'
: 'Popularité'}
{sortOrder === 'asc' ? ' ↑' : ' ↓'}
</span>
</Button>
<Tooltip content="Trier les pistes par date, titre ou popularité">
<Button variant="outline" size="sm" className="w-full justify-between">
<span className="flex items-center gap-2">
<ArrowUpDown className="h-4 w-4" />
{sortBy === 'created_at'
? 'Date'
: sortBy === 'title'
? 'Titre'
: 'Popularité'}
{sortOrder === 'asc' ? ' ↑' : ' ↓'}
</span>
</Button>
</Tooltip>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>Trier par</DropdownMenuLabel>