Polish workspace board settings

This commit is contained in:
Neil 2026-05-20 23:00:05 -07:00
parent 8b77dffec2
commit e9a79b8280
3 changed files with 59 additions and 65 deletions

View File

@ -48,8 +48,6 @@ export default function WorkspaceKanbanDrawer({
const updateWorktreesMeta = useAppStore((s) => s.updateWorktreesMeta)
const workspaceStatuses = useAppStore((s) => s.workspaceStatuses)
const setWorkspaceStatuses = useAppStore((s) => s.setWorkspaceStatuses)
const workspaceBoardOpacity = useAppStore((s) => s.workspaceBoardOpacity)
const setWorkspaceBoardOpacity = useAppStore((s) => s.setWorkspaceBoardOpacity)
const workspaceBoardCompact = useAppStore((s) => s.workspaceBoardCompact)
const setWorkspaceBoardCompact = useAppStore((s) => s.setWorkspaceBoardCompact)
const workspaceBoardColumnWidth = useAppStore((s) => s.workspaceBoardColumnWidth)
@ -219,13 +217,6 @@ export default function WorkspaceKanbanDrawer({
onOpenChange(false)
}, [onOpenChange])
const handleOpacityChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
setWorkspaceBoardOpacity(Number(event.target.value) / 100)
},
[setWorkspaceBoardOpacity]
)
const handleRenameStatus = useCallback(
(statusId: string, label: string) => {
const trimmed = label.trim()
@ -341,7 +332,6 @@ export default function WorkspaceKanbanDrawer({
return () => document.removeEventListener('pointerdown', clearSelectionOutsideBoard, true)
}, [clearSelection, open, selectedWorktreeIds.size])
const opacityPercent = Math.round(workspaceBoardOpacity * 100)
const drawerLeft = sidebarOpen ? sidebarWidth : 0
const drawerLeftCss = sidebarOpen
? `var(--workspace-sidebar-live-width, ${sidebarWidth}px)`
@ -361,8 +351,7 @@ export default function WorkspaceKanbanDrawer({
left: drawerLeftCss,
top: 36,
height: 'calc(100% - 36px)',
width: `min(calc(100vw - ${drawerLeftCss}), 1294px)`,
opacity: workspaceBoardOpacity
width: `min(calc(100vw - ${drawerLeftCss}), 1294px)`
} as React.CSSProperties
}
data-workspace-board-compact={workspaceBoardCompact ? 'true' : 'false'}
@ -397,10 +386,8 @@ export default function WorkspaceKanbanDrawer({
<WorkspaceKanbanDrawerHeader
selectedCount={selectedWorktrees.length}
compact={workspaceBoardCompact}
opacityPercent={opacityPercent}
workspaceStatuses={workspaceStatuses}
onCompactChange={setWorkspaceBoardCompact}
onOpacityChange={handleOpacityChange}
onRenameStatus={handleRenameStatus}
onChangeStatusColor={handleChangeStatusColor}
onChangeStatusIcon={handleChangeStatusIcon}

View File

@ -1,8 +1,7 @@
import React from 'react'
import { LayoutList, Rows3, X } from 'lucide-react'
import { X } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { SheetClose, SheetDescription, SheetHeader, SheetTitle } from '@/components/ui/sheet'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import type { WorkspaceStatusDefinition } from '../../../../shared/types'
import SidebarFilter from './SidebarFilter'
import WorkspaceKanbanSettingsMenu from './WorkspaceKanbanSettingsMenu'
@ -10,10 +9,8 @@ import WorkspaceKanbanSettingsMenu from './WorkspaceKanbanSettingsMenu'
type WorkspaceKanbanDrawerHeaderProps = {
selectedCount: number
compact: boolean
opacityPercent: number
workspaceStatuses: readonly WorkspaceStatusDefinition[]
onCompactChange: (compact: boolean) => void
onOpacityChange: (event: React.ChangeEvent<HTMLInputElement>) => void
onRenameStatus: (statusId: string, label: string) => void
onChangeStatusColor: (statusId: string, color: string) => void
onChangeStatusIcon: (statusId: string, icon: string) => void
@ -26,10 +23,8 @@ type WorkspaceKanbanDrawerHeaderProps = {
export default function WorkspaceKanbanDrawerHeader({
selectedCount,
compact,
opacityPercent,
workspaceStatuses,
onCompactChange,
onOpacityChange,
onRenameStatus,
onChangeStatusColor,
onChangeStatusIcon,
@ -38,8 +33,6 @@ export default function WorkspaceKanbanDrawerHeader({
onAddStatus,
onFilterMenuOpenChange
}: WorkspaceKanbanDrawerHeaderProps): React.JSX.Element {
const BoardModeIcon = compact ? Rows3 : LayoutList
return (
<>
<SheetHeader className="border-b border-sidebar-border px-4 py-3 pr-32">
@ -63,27 +56,10 @@ export default function WorkspaceKanbanDrawerHeader({
contentSide="bottom"
onMenuOpenChange={onFilterMenuOpenChange}
/>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
variant={compact ? 'secondary' : 'ghost'}
size="icon-xs"
aria-pressed={compact}
aria-label={compact ? 'Compact workspace cards' : 'Detailed workspace cards'}
onClick={() => onCompactChange(!compact)}
>
<BoardModeIcon className="size-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent side="top" sideOffset={4}>
{compact ? 'Show detailed cards' : 'Show compact cards'}
</TooltipContent>
</Tooltip>
<WorkspaceKanbanSettingsMenu
opacityPercent={opacityPercent}
compact={compact}
workspaceStatuses={workspaceStatuses}
onOpacityChange={onOpacityChange}
onCompactChange={onCompactChange}
onRenameStatus={onRenameStatus}
onChangeStatusColor={onChangeStatusColor}
onChangeStatusIcon={onChangeStatusIcon}

View File

@ -1,5 +1,5 @@
import React from 'react'
import { ArrowDown, ArrowUp, Plus, Settings2, Trash2 } from 'lucide-react'
import { ArrowDown, ArrowUp, LayoutList, Plus, Rows3, Settings, Trash2 } from 'lucide-react'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
@ -8,15 +8,17 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu'
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { cn } from '@/lib/utils'
import type { WorkspaceStatusDefinition } from '../../../../shared/types'
import { getWorkspaceStatusVisualMeta } from './workspace-status'
import WorkspaceStatusAppearancePopover from './WorkspaceStatusAppearancePopover'
type WorkspaceKanbanSettingsMenuProps = {
opacityPercent: number
compact: boolean
workspaceStatuses: readonly WorkspaceStatusDefinition[]
onOpacityChange: (event: React.ChangeEvent<HTMLInputElement>) => void
onCompactChange: (compact: boolean) => void
onRenameStatus: (statusId: string, label: string) => void
onChangeStatusColor: (statusId: string, color: string) => void
onChangeStatusIcon: (statusId: string, icon: string) => void
@ -26,9 +28,9 @@ type WorkspaceKanbanSettingsMenuProps = {
}
export default function WorkspaceKanbanSettingsMenu({
opacityPercent,
compact,
workspaceStatuses,
onOpacityChange,
onCompactChange,
onRenameStatus,
onChangeStatusColor,
onChangeStatusIcon,
@ -38,14 +40,27 @@ export default function WorkspaceKanbanSettingsMenu({
}: WorkspaceKanbanSettingsMenuProps): React.JSX.Element {
return (
<DropdownMenu modal={false}>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon-xs" aria-label="Workspace board settings">
<Settings2 className="size-3.5" />
</Button>
</DropdownMenuTrigger>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon-xs"
aria-label="Workspace board settings"
className="text-muted-foreground"
>
<Settings className="size-3.5" />
</Button>
</DropdownMenuTrigger>
</TooltipTrigger>
<TooltipContent side="top" sideOffset={4}>
Board settings
</TooltipContent>
</Tooltip>
<DropdownMenuContent
align="end"
sideOffset={8}
collisionPadding={8}
className="max-h-[min(80vh,720px)] w-80 overflow-y-auto p-2 scrollbar-sleek"
onInteractOutside={(event) => {
const target = event.target
@ -57,21 +72,37 @@ export default function WorkspaceKanbanSettingsMenu({
}
}}
>
<DropdownMenuLabel>Board opacity</DropdownMenuLabel>
<DropdownMenuLabel>Card density</DropdownMenuLabel>
<div className="px-2 pb-2">
<div className="mb-1 flex items-center justify-between text-[11px] text-muted-foreground">
<span>Pane opacity</span>
<span>{opacityPercent}%</span>
</div>
<input
type="range"
min={20}
max={100}
value={opacityPercent}
onChange={onOpacityChange}
className="h-5 w-full accent-foreground"
aria-label="Workspace board opacity"
/>
<ToggleGroup
type="single"
value={compact ? 'compact' : 'detailed'}
onValueChange={(value) => {
if (value) {
onCompactChange(value === 'compact')
}
}}
variant="outline"
size="sm"
className="h-7 w-full justify-stretch"
>
<ToggleGroupItem
value="detailed"
className="h-7 grow basis-0 gap-1.5 px-1.5 text-[11px] data-[state=on]:bg-foreground/10 data-[state=on]:font-semibold data-[state=on]:text-foreground"
aria-label="Detailed workspace cards"
>
<LayoutList className="size-3.5" />
Detailed
</ToggleGroupItem>
<ToggleGroupItem
value="compact"
className="h-7 grow basis-0 gap-1.5 px-1.5 text-[11px] data-[state=on]:bg-foreground/10 data-[state=on]:font-semibold data-[state=on]:text-foreground"
aria-label="Compact workspace cards"
>
<Rows3 className="size-3.5" />
Compact
</ToggleGroupItem>
</ToggleGroup>
</div>
<DropdownMenuSeparator />
<DropdownMenuLabel>Statuses</DropdownMenuLabel>