Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const TaskTabs: React.FC<TaskTabsProps> = ({
}) => {
const selectedWorktree = worktrees.find((wt) => wt.id === selectedWorktreeId);
const canCreatePR = selectedWorktree && !selectedWorktree.isPending;
const hasPR = selectedWorktree && selectedWorktree.prUrl;
const hasPR = selectedWorktree?.prUrl;

return (
<div
Expand All @@ -40,15 +40,27 @@ export const TaskTabs: React.FC<TaskTabsProps> = ({

{onModeChange && <ModeToggle mode={mode} onChange={onModeChange} />}

<div className="flex items-end h-full gap-1">
{worktrees.map((worktree) => (
<WorktreeTab
key={worktree.id}
worktree={worktree}
isSelected={selectedWorktreeId === worktree.id}
onSelect={() => onWorktreeSelect(worktree.id)}
/>
))}
<div className="flex items-end h-full gap-0">
{worktrees.map((worktree, index) => {
const isSelected = selectedWorktreeId === worktree.id;
const prevWorktree = index > 0 ? worktrees[index - 1] : null;
const prevIsSelected = prevWorktree?.id === selectedWorktreeId;
const showDivider =
prevWorktree !== null && !isSelected && !prevIsSelected;

return (
<div key={worktree.id} className="flex items-end">
{showDivider && (
<div className="w-px h-5 bg-neutral-700 self-end mb-1" />
)}
<WorktreeTab
worktree={worktree}
isSelected={isSelected}
onSelect={() => onWorktreeSelect(worktree.id)}
/>
</div>
);
})}
</div>

<AddTaskButton onClick={onAddTask} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ export const WorktreeTabButton: React.FC<WorktreeTabButtonProps> = ({
onClick={onClick}
disabled={isPending}
className={`
flex items-center gap-2 px-3 h-8 rounded-t-md transition-all border-t border-x
flex items-center gap-2 px-3 h-8 rounded-t-md transition-all
${
isSelected
? "bg-neutral-900 text-white border-neutral-700 -mb-px"
: "bg-neutral-800/50 text-neutral-400 hover:text-neutral-200 hover:bg-neutral-800 border-transparent"
? "bg-neutral-900 text-white border-t border-x border-r border-neutral-700 -mb-px"
: "bg-transparent text-neutral-400 hover:text-neutral-200 hover:bg-neutral-800/50"
}
${isPending ? "opacity-70 cursor-wait" : ""}
`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ export function AnimatedBackground({
progress,
modeCount,
}: AnimatedBackgroundProps) {
// Calculate the width of each button (36px = h-9 w-9) + gap (4px = gap-1)
const buttonWidth = 36;
// Calculate the width of each button (32px = h-8 w-8) + gap (4px = gap-1)
const buttonWidth = 32;
const gap = 4;
const totalButtonWidth = buttonWidth + gap;

// Transform progress (0-1) to translateX position
// For 2 modes: 0 -> 0px, 1 -> 40px (buttonWidth + gap)
// For 2 modes: 0 -> 0px, 1 -> 36px (buttonWidth + gap)
const translateX = useTransform(
progress,
[0, modeCount - 1],
Expand All @@ -24,9 +24,8 @@ export function AnimatedBackground({

return (
<motion.div
className="absolute h-9 rounded bg-neutral-800/60"
className="absolute h-8 w-8 rounded-sm bg-neutral-800/40"
style={{
width: buttonWidth,
x: translateX,
}}
initial={false}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Button } from "@superset/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip";
import type { MotionValue } from "framer-motion";
import { modeIcons, modeLabels } from "../../constants";
import { modeIcons } from "../../constants";
import type { SidebarMode } from "../../types";
import { AnimatedBackground } from "../AnimatedBackground";

Expand All @@ -19,7 +17,7 @@ export function ModeNavigation({
scrollProgress,
}: ModeNavigationProps) {
return (
<div className="flex items-center justify-center gap-1 px-2 py-2 border-t border-neutral-800/50 bg-neutral-900/50 backdrop-blur-sm">
<div className="flex items-center justify-center gap-1 px-2 py-2">
<div className="relative flex items-center gap-1">
<AnimatedBackground
progress={scrollProgress}
Expand All @@ -31,24 +29,17 @@ export function ModeNavigation({
const isActive = mode === currentMode;

return (
<Tooltip key={mode}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="sm"
onClick={() => onModeSelect(mode)}
className={`relative z-10 h-9 w-9 rounded transition-colors duration-200 ${isActive
? "text-neutral-100"
: "text-neutral-400 hover:text-neutral-300"
}`}
>
<Icon className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent side="top">
<p className="text-xs">{modeLabels[mode]}</p>
</TooltipContent>
</Tooltip>
<button
key={mode}
type="button"
onClick={() => onModeSelect(mode)}
className={`relative z-10 h-8 w-8 rounded-sm flex items-center justify-center transition-colors duration-150 ${isActive
? "text-neutral-100"
: "text-neutral-600 hover:text-neutral-500"
}`}
>
<Icon className="w-3.5 h-3.5" />
</button>
Comment on lines +32 to +42
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add accessible labels to icon-only buttons.

These buttons lack accessible text for screen readers. Each button must include an aria-label describing its purpose (e.g., "Switch to tasks mode", "Switch to files mode").

Apply this diff to add accessibility:

 <button
 	key={mode}
 	type="button"
+	aria-label={`Switch to ${mode} mode`}
 	onClick={() => onModeSelect(mode)}
 	className={`relative z-10 h-8 w-8 rounded-sm flex items-center justify-center transition-colors duration-150 ${isActive
 		? "text-neutral-100"
 		: "text-neutral-600 hover:text-neutral-500"
 		}`}
 >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button
key={mode}
type="button"
onClick={() => onModeSelect(mode)}
className={`relative z-10 h-8 w-8 rounded-sm flex items-center justify-center transition-colors duration-150 ${isActive
? "text-neutral-100"
: "text-neutral-600 hover:text-neutral-500"
}`}
>
<Icon className="w-3.5 h-3.5" />
</button>
<button
key={mode}
type="button"
aria-label={`Switch to ${mode} mode`}
onClick={() => onModeSelect(mode)}
className={`relative z-10 h-8 w-8 rounded-sm flex items-center justify-center transition-colors duration-150 ${isActive
? "text-neutral-100"
: "text-neutral-600 hover:text-neutral-500"
}`}
>
<Icon className="w-3.5 h-3.5" />
</button>
🤖 Prompt for AI Agents
In
apps/desktop/src/renderer/screens/main/components/Sidebar/components/ModeCarousel/components/ModeNavigation/ModeNavigation.tsx
around lines 32 to 42, the icon-only buttons lack accessible labels; add an
aria-label to each button describing the action (for example construct a label
like `Switch to ${mode} mode` or map mode keys to human-readable strings) and
pass it to the <button> as aria-label={label}; ensure the label is meaningful
for screen readers and update any typing if needed so TypeScript accepts the new
prop.

);
})}
</div>
Expand Down
Loading