auto-claude: subtask-5-2 - Add pop-out button to ProjectTabBar component
Changes: - Added pop-out button to SortableProjectTab alongside settings button - Uses ExternalLink icon from lucide-react - Integrated with window store to track popped-out projects - Added translation keys in both English and French - Button disabled when project is already popped out - Calls window.electronAPI.window.popOutProject() IPC channel Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 4.5
parent
2da3f84068
commit
aba2c325b6
@@ -6,6 +6,7 @@ import { Button } from './ui/button';
|
||||
import { SortableProjectTab } from './SortableProjectTab';
|
||||
import { UsageIndicator } from './UsageIndicator';
|
||||
import { AuthStatusIndicator } from './AuthStatusIndicator';
|
||||
import { useWindowStore } from '../stores/window-store';
|
||||
import type { Project } from '../../shared/types';
|
||||
|
||||
interface ProjectTabBarProps {
|
||||
@@ -29,6 +30,22 @@ export function ProjectTabBar({
|
||||
onSettingsClick
|
||||
}: ProjectTabBarProps) {
|
||||
const { t } = useTranslation('common');
|
||||
const { isProjectPoppedOut, setWindowLoading, addPoppedOutProject } = useWindowStore();
|
||||
|
||||
// Handler for popping out a project into a new window
|
||||
const handlePopOutProject = async (projectId: string) => {
|
||||
try {
|
||||
setWindowLoading(projectId, true);
|
||||
const { windowId } = await window.electronAPI.window.popOutProject(projectId);
|
||||
addPoppedOutProject(projectId);
|
||||
console.log(`Project ${projectId} popped out to window ${windowId}`);
|
||||
} catch (error) {
|
||||
console.error('Failed to pop out project:', error);
|
||||
// TODO: Show error notification to user
|
||||
} finally {
|
||||
setWindowLoading(projectId, false);
|
||||
}
|
||||
};
|
||||
|
||||
// Keyboard shortcuts for tab navigation
|
||||
useEffect(() => {
|
||||
@@ -107,6 +124,8 @@ export function ProjectTabBar({
|
||||
}}
|
||||
// Pass control props only for active tab
|
||||
onSettingsClick={isActiveTab ? onSettingsClick : undefined}
|
||||
onPopOutClick={isActiveTab ? () => handlePopOutProject(project.id) : undefined}
|
||||
isPoppedOut={isProjectPoppedOut(project.id)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useSortable } from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Settings2 } from 'lucide-react';
|
||||
import { Settings2, ExternalLink } from 'lucide-react';
|
||||
import { cn } from '../lib/utils';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip';
|
||||
import type { Project } from '../../shared/types';
|
||||
@@ -15,6 +15,8 @@ interface SortableProjectTabProps {
|
||||
onClose: (e: React.MouseEvent) => void;
|
||||
// Optional control props for active tab
|
||||
onSettingsClick?: () => void;
|
||||
onPopOutClick?: () => void;
|
||||
isPoppedOut?: boolean;
|
||||
}
|
||||
|
||||
// Detect if running on macOS for keyboard shortcut display
|
||||
@@ -28,7 +30,9 @@ export function SortableProjectTab({
|
||||
tabIndex,
|
||||
onSelect,
|
||||
onClose,
|
||||
onSettingsClick
|
||||
onSettingsClick,
|
||||
onPopOutClick,
|
||||
isPoppedOut = false
|
||||
}: SortableProjectTabProps) {
|
||||
const { t } = useTranslation('common');
|
||||
// Build tooltip with keyboard shortcut hint (only for tabs 1-9)
|
||||
@@ -112,9 +116,40 @@ export function SortableProjectTab({
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* Active tab controls - settings and archive, always accessible */}
|
||||
{/* Active tab controls - settings, pop-out, always accessible */}
|
||||
{isActive && (
|
||||
<div className="flex items-center gap-0.5 mr-0.5 sm:mr-1 flex-shrink-0">
|
||||
{/* Pop-out icon - responsive sizing */}
|
||||
{onPopOutClick && (
|
||||
<Tooltip delayDuration={200}>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
'h-5 w-5 sm:h-6 sm:w-6 p-0 rounded',
|
||||
'flex items-center justify-center',
|
||||
'text-muted-foreground hover:text-foreground',
|
||||
'hover:bg-muted/50 transition-colors',
|
||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',
|
||||
isPoppedOut && 'opacity-50 cursor-not-allowed'
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (!isPoppedOut) {
|
||||
onPopOutClick();
|
||||
}
|
||||
}}
|
||||
disabled={isPoppedOut}
|
||||
aria-label={t('projectTab.popOutAriaLabel')}
|
||||
>
|
||||
<ExternalLink className="h-3 w-3 sm:h-3.5 sm:w-3.5" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">
|
||||
<span>{t('projectTab.popOut')}</span>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{/* Settings icon - responsive sizing */}
|
||||
{onSettingsClick && (
|
||||
<Tooltip delayDuration={200}>
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
"hideArchivedTasks": "Hide archived tasks",
|
||||
"closeTab": "Close tab",
|
||||
"closeTabAriaLabel": "Close tab (removes project from app)",
|
||||
"addProjectAriaLabel": "Add project"
|
||||
"addProjectAriaLabel": "Add project",
|
||||
"popOut": "Pop out project",
|
||||
"popOutAriaLabel": "Pop out project into separate window"
|
||||
},
|
||||
"accessibility": {
|
||||
"deleteFeatureAriaLabel": "Delete feature",
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
"hideArchivedTasks": "Masquer les tâches archivées",
|
||||
"closeTab": "Fermer l'onglet",
|
||||
"closeTabAriaLabel": "Fermer l'onglet (retire le projet de l'application)",
|
||||
"addProjectAriaLabel": "Ajouter un projet"
|
||||
"addProjectAriaLabel": "Ajouter un projet",
|
||||
"popOut": "Ouvrir dans une fenêtre séparée",
|
||||
"popOutAriaLabel": "Ouvrir le projet dans une fenêtre séparée"
|
||||
},
|
||||
"accessibility": {
|
||||
"deleteFeatureAriaLabel": "Supprimer la fonctionnalité",
|
||||
|
||||
Reference in New Issue
Block a user