Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@
## 2026-01-22 - Replacing Text Characters with Semantic Icons
**Learning:** In `AppSidebar.tsx`, a text character "â–¼" was used for the expand/collapse arrow. Screen readers might announce this as "Black Down-Pointing Triangle" or similar, which is distracting. Text characters also don't scale or style as consistently as SVGs.
**Action:** Replace decorative text characters with `CyberIcon` (or proper SVG icons) and add `aria-hidden="true"` to ensure they are treated as visual decoration only.

## 2026-02-01 - Keyboard Visibility for Hover Actions
**Learning:** Buttons hidden with `opacity-0` and shown only on `group-hover:opacity-100` create a "ghost focus" problem for keyboard users. The element receives focus but remains invisible, confusing the user.
**Action:** Always pair `group-hover:opacity-100` with `group-focus-within:opacity-100` to ensure interactive controls become visible when they receive keyboard focus.
28 changes: 21 additions & 7 deletions src/components/goals/GoalsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,26 @@ export function GoalsList({ goals, onEdit, onDelete, onPlan, onStatusChange, onA
</div>
</div>

<div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
<Button variant="ghost" size="sm" onClick={() => onEdit(goal)} className="h-8 w-8 p-0 hover:bg-violet-500/20">
<div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 transition-opacity">
<Button
variant="ghost"
size="sm"
onClick={() => onEdit(goal)}
className="h-8 w-8 p-0 hover:bg-violet-500/20"
aria-label="Editar meta"
title="Editar meta"
>
<CyberIcon name="edit" className="h-4 w-4" />
</Button>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="ghost" size="sm" className="h-8 w-8 p-0 text-destructive hover:text-destructive hover:bg-destructive/10">
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0 text-destructive hover:text-destructive hover:bg-destructive/10"
aria-label="Excluir meta"
title="Excluir meta"
>
<CyberIcon name="trash" className="h-4 w-4" />
</Button>
</AlertDialogTrigger>
Expand Down Expand Up @@ -133,27 +146,27 @@ export function GoalsList({ goals, onEdit, onDelete, onPlan, onStatusChange, onA

<div className="grid grid-cols-3 gap-2">
{goal.status !== "completed" ? (
<Button variant="secondary" size="sm" onClick={() => onStatusChange(goal, "completed")}>
<Button variant="secondary" size="sm" onClick={() => onStatusChange(goal, "completed")} aria-label="Concluir meta">
<CyberIcon name="done" className="h-4 w-4 mr-1" />
<span className="hidden sm:inline">Concluir</span>
<span className="sm:hidden">Ok</span>
</Button>
) : (
<Button variant="outline" size="sm" onClick={() => onStatusChange(goal, "active")}>
<Button variant="outline" size="sm" onClick={() => onStatusChange(goal, "active")} aria-label="Reativar meta">
<CyberIcon name="play" className="h-4 w-4 mr-1" />
<span className="hidden sm:inline">Reativar</span>
<span className="sm:hidden">Ativar</span>
</Button>
)}

{goal.status === "paused" ? (
<Button variant="outline" size="sm" onClick={() => onStatusChange(goal, "active")}>
<Button variant="outline" size="sm" onClick={() => onStatusChange(goal, "active")} aria-label="Retomar meta">
<CyberIcon name="play" className="h-4 w-4 mr-1" />
<span className="hidden sm:inline">Retomar</span>
<span className="sm:hidden">Play</span>
</Button>
) : (
<Button variant="ghost" size="sm" onClick={() => onStatusChange(goal, "paused")}>
<Button variant="ghost" size="sm" onClick={() => onStatusChange(goal, "paused")} aria-label="Pausar meta">
<CyberIcon name="pause" className="h-4 w-4 mr-1" />
<span className="hidden sm:inline">Pausar</span>
<span className="sm:hidden">Pausa</span>
Expand All @@ -165,6 +178,7 @@ export function GoalsList({ goals, onEdit, onDelete, onPlan, onStatusChange, onA
size="sm"
onClick={() => onAddTask(goal)}
className="border-emerald-500/30 hover:bg-emerald-500/10 hover:border-emerald-500/50"
aria-label="Adicionar tarefa à meta"
>
<CyberIcon name="add" className="h-4 w-4 mr-1 text-emerald-400" />
<span className="hidden sm:inline">Tarefa</span>
Expand Down
Loading