Simplify WorkspaceSummary card hover UI with opacity fade and single action button (Vibe Kanban) (#2059)
* All changes are complete. Here's a summary of what was changed: ## Summary of Changes ### `WorkspaceSummary.tsx` 1. **Title truncation**: Replaced `truncate` class with CSS mask gradient that fades to transparent (no ellipsis dots) 2. **Simplified hover actions**: Removed pin and archive buttons, keeping only the "more options" (ListIcon) button 3. **Removed sliding animation**: The action button now uses simple opacity transition (`opacity-0 group-hover:opacity-100`) instead of the sliding animation 4. **Removed unused code**: `handleArchive`, `handlePin` functions and `ArchiveIcon` import removed 5. **Removed unused props**: `onArchive` and `onPin` props removed from interface ### `WorkspacesSidebar.tsx` - Removed `onArchiveWorkspace` and `onPinWorkspace` props from interface and destructuring ### `WorkspacesSidebarContainer.tsx` - Removed `handleArchiveWorkspace` and `handlePinWorkspace` callbacks - Removed unused imports (`useCallback`, `useActions`, `Actions`) All type checks pass. The pin and archive functionality is still accessible through the command bar (more options button). * Cleanup script changes for workspace 262a1c1d-87ae-40f5-a36d-f43758d18fed * Done. Changed `ListIcon` to `DotsThreeIcon` with `weight="bold"` for the more options button. * Done. Changed the icon size from `size-icon-xs` to `size-5` (20px) while keeping the bold weight. * Done. Added the `ArchiveWorkspace` action to the left side of the navbar in `NavbarActionGroups.left`.
This commit is contained in:
committed by
GitHub
parent
5ca8b9852a
commit
4a6e556ed2
@@ -965,7 +965,7 @@ export type NavbarItem = ActionDefinition | typeof NavbarDivider;
|
||||
|
||||
// Navbar action groups define which actions appear in each section
|
||||
export const NavbarActionGroups = {
|
||||
left: [Actions.OpenInOldUI] as ActionDefinition[],
|
||||
left: [Actions.ArchiveWorkspace, Actions.OpenInOldUI] as ActionDefinition[],
|
||||
right: [
|
||||
Actions.ToggleDiffViewMode,
|
||||
Actions.ToggleAllDiffs,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useState, useCallback, useMemo } from 'react';
|
||||
import { useState, useMemo } from 'react';
|
||||
import { useWorkspaceContext } from '@/contexts/WorkspaceContext';
|
||||
import { useActions } from '@/contexts/ActionsContext';
|
||||
import { useScratch } from '@/hooks/useScratch';
|
||||
import { ScratchType, type DraftWorkspaceData } from 'shared/types';
|
||||
import { splitMessageToTitleDescription } from '@/utils/string';
|
||||
@@ -9,7 +8,6 @@ import {
|
||||
usePersistedExpanded,
|
||||
} from '@/stores/useUiPreferencesStore';
|
||||
import { WorkspacesSidebar } from '@/components/ui-new/views/WorkspacesSidebar';
|
||||
import { Actions } from '@/components/ui-new/actions';
|
||||
|
||||
// Fixed UUID for the universal workspace draft (same as in useCreateModeState.ts)
|
||||
const DRAFT_WORKSPACE_ID = '00000000-0000-0000-0000-000000000001';
|
||||
@@ -50,23 +48,6 @@ export function WorkspacesSidebarContainer() {
|
||||
return title || 'New Workspace';
|
||||
}, [draftScratch]);
|
||||
|
||||
// Action handlers for sidebar workspace actions
|
||||
const { executeAction } = useActions();
|
||||
|
||||
const handleArchiveWorkspace = useCallback(
|
||||
(workspaceId: string) => {
|
||||
executeAction(Actions.ArchiveWorkspace, workspaceId);
|
||||
},
|
||||
[executeAction]
|
||||
);
|
||||
|
||||
const handlePinWorkspace = useCallback(
|
||||
(workspaceId: string) => {
|
||||
executeAction(Actions.PinWorkspace, workspaceId);
|
||||
},
|
||||
[executeAction]
|
||||
);
|
||||
|
||||
return (
|
||||
<WorkspacesSidebar
|
||||
workspaces={activeWorkspaces}
|
||||
@@ -76,8 +57,6 @@ export function WorkspacesSidebarContainer() {
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
onAddWorkspace={navigateToCreate}
|
||||
onArchiveWorkspace={handleArchiveWorkspace}
|
||||
onPinWorkspace={handlePinWorkspace}
|
||||
isCreateMode={isCreateMode}
|
||||
draftTitle={persistedDraftTitle}
|
||||
onSelectCreate={navigateToCreate}
|
||||
|
||||
@@ -6,8 +6,7 @@ import {
|
||||
FileIcon,
|
||||
CircleIcon,
|
||||
GitPullRequestIcon,
|
||||
ArchiveIcon,
|
||||
ListIcon,
|
||||
DotsThreeIcon,
|
||||
} from '@phosphor-icons/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -31,8 +30,6 @@ interface WorkspaceSummaryProps {
|
||||
latestProcessStatus?: 'running' | 'completed' | 'failed' | 'killed';
|
||||
prStatus?: 'open' | 'merged' | 'closed' | 'unknown';
|
||||
onClick?: () => void;
|
||||
onArchive?: () => void;
|
||||
onPin?: () => void;
|
||||
className?: string;
|
||||
summary?: boolean;
|
||||
/** Whether this is a draft workspace (shows "Draft" instead of elapsed time) */
|
||||
@@ -55,8 +52,6 @@ export function WorkspaceSummary({
|
||||
latestProcessStatus,
|
||||
prStatus,
|
||||
onClick,
|
||||
onArchive,
|
||||
onPin,
|
||||
className,
|
||||
summary = false,
|
||||
isDraft = false,
|
||||
@@ -74,16 +69,6 @@ export function WorkspaceSummary({
|
||||
});
|
||||
};
|
||||
|
||||
const handleArchive = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
onArchive?.();
|
||||
};
|
||||
|
||||
const handlePin = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
onPin?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -108,7 +93,18 @@ export function WorkspaceSummary({
|
||||
: 'text-low opacity-60 hover:opacity-100 hover:text-normal'
|
||||
)}
|
||||
>
|
||||
<div className={cn('truncate pr-double', !summary && 'text-normal')}>
|
||||
<div
|
||||
className={cn(
|
||||
'overflow-hidden whitespace-nowrap pr-double',
|
||||
!summary && 'text-normal'
|
||||
)}
|
||||
style={{
|
||||
maskImage:
|
||||
'linear-gradient(to right, black calc(100% - 24px), transparent 100%)',
|
||||
WebkitMaskImage:
|
||||
'linear-gradient(to right, black calc(100% - 24px), transparent 100%)',
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</div>
|
||||
{(!summary || isActive) && (
|
||||
@@ -204,55 +200,23 @@ export function WorkspaceSummary({
|
||||
)}
|
||||
</button>
|
||||
|
||||
{/* Right-side hover zone for action overlay */}
|
||||
{/* Right-side hover action - more options only */}
|
||||
{workspaceId && (
|
||||
<div className="absolute right-0 top-0 bottom-0 w-16 group/actions">
|
||||
{/* Sliding action overlay - only appears when hovering this zone */}
|
||||
<div
|
||||
className={cn(
|
||||
'absolute right-0 top-0 bottom-0 flex items-center',
|
||||
'translate-x-full group-hover/actions:translate-x-0',
|
||||
'transition-transform duration-150 ease-out'
|
||||
)}
|
||||
>
|
||||
{/* Gradient fade from transparent to pill background */}
|
||||
<div className="absolute right-0 top-0 bottom-0 flex items-center opacity-0 group-hover:opacity-100">
|
||||
{/* Gradient fade from transparent to background */}
|
||||
<div className="h-full w-6 pointer-events-none bg-gradient-to-r from-transparent to-secondary" />
|
||||
{/* Action pill */}
|
||||
<div className="flex items-center gap-0.5 pr-base h-full bg-secondary">
|
||||
<button
|
||||
onClick={handlePin}
|
||||
onPointerDown={(e) => e.stopPropagation()}
|
||||
className={cn(
|
||||
'p-1.5 rounded-sm transition-colors duration-100',
|
||||
'hover:bg-tertiary',
|
||||
isPinned ? 'text-brand' : 'text-low hover:text-normal'
|
||||
)}
|
||||
title={isPinned ? t('workspaces.unpin') : t('workspaces.pin')}
|
||||
>
|
||||
<PushPinIcon
|
||||
className="size-icon-xs"
|
||||
weight={isPinned ? 'fill' : 'regular'}
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
onClick={handleArchive}
|
||||
onPointerDown={(e) => e.stopPropagation()}
|
||||
className="p-1.5 rounded-sm text-low hover:text-normal hover:bg-tertiary transition-colors duration-100"
|
||||
title={t('workspaces.archive')}
|
||||
>
|
||||
<ArchiveIcon className="size-icon-xs" />
|
||||
</button>
|
||||
{/* Single action button */}
|
||||
<div className="flex items-center pr-base h-full bg-secondary">
|
||||
<button
|
||||
onClick={handleOpenCommandBar}
|
||||
onPointerDown={(e) => e.stopPropagation()}
|
||||
className="p-1.5 rounded-sm text-low hover:text-normal hover:bg-tertiary transition-colors duration-100"
|
||||
className="p-1.5 rounded-sm text-low hover:text-normal hover:bg-tertiary"
|
||||
title={t('workspaces.more')}
|
||||
>
|
||||
<ListIcon className="size-icon-xs" />
|
||||
<DotsThreeIcon className="size-5" weight="bold" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -11,8 +11,6 @@ interface WorkspacesSidebarProps {
|
||||
selectedWorkspaceId: string | null;
|
||||
onSelectWorkspace: (id: string) => void;
|
||||
onAddWorkspace?: () => void;
|
||||
onArchiveWorkspace?: (id: string) => void;
|
||||
onPinWorkspace?: (id: string) => void;
|
||||
searchQuery: string;
|
||||
onSearchChange: (value: string) => void;
|
||||
/** Whether we're in create mode */
|
||||
@@ -33,8 +31,6 @@ export function WorkspacesSidebar({
|
||||
selectedWorkspaceId,
|
||||
onSelectWorkspace,
|
||||
onAddWorkspace,
|
||||
onArchiveWorkspace,
|
||||
onPinWorkspace,
|
||||
searchQuery,
|
||||
onSearchChange,
|
||||
isCreateMode = false,
|
||||
@@ -107,8 +103,6 @@ export function WorkspacesSidebar({
|
||||
latestProcessStatus={workspace.latestProcessStatus}
|
||||
prStatus={workspace.prStatus}
|
||||
onClick={() => onSelectWorkspace(workspace.id)}
|
||||
onArchive={() => onArchiveWorkspace?.(workspace.id)}
|
||||
onPin={() => onPinWorkspace?.(workspace.id)}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
@@ -145,8 +139,6 @@ export function WorkspacesSidebar({
|
||||
latestProcessStatus={workspace.latestProcessStatus}
|
||||
prStatus={workspace.prStatus}
|
||||
onClick={() => onSelectWorkspace(workspace.id)}
|
||||
onArchive={() => onArchiveWorkspace?.(workspace.id)}
|
||||
onPin={() => onPinWorkspace?.(workspace.id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user