Update panel

This commit is contained in:
Louis Knight-Webb
2025-06-21 18:00:28 +01:00
parent acd71a88bb
commit 0f4765dcf8
3 changed files with 81 additions and 63 deletions

View File

@@ -6,8 +6,6 @@ import {
Clock,
FileText,
Code,
Maximize2,
Minimize2,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
@@ -22,6 +20,7 @@ import {
} from "@/components/ui/select";
import { makeRequest } from "@/lib/api";
import { getTaskPanelClasses, getBackdropClasses } from "@/lib/responsive-config";
import type {
TaskStatus,
TaskAttempt,
@@ -39,8 +38,6 @@ interface TaskDetailsPanelProps {
projectId: string;
isOpen: boolean;
onClose: () => void;
viewMode: "overlay" | "sideBySide";
onViewModeChange: (mode: "overlay" | "sideBySide") => void;
}
const statusLabels: Record<TaskStatus, string> = {
@@ -153,8 +150,6 @@ export function TaskDetailsPanel({
projectId,
isOpen,
onClose,
viewMode,
onViewModeChange,
}: TaskDetailsPanelProps) {
const [taskAttempts, setTaskAttempts] = useState<TaskAttempt[]>([]);
const [selectedAttempt, setSelectedAttempt] = useState<TaskAttempt | null>(
@@ -342,24 +337,15 @@ export function TaskDetailsPanel({
<>
{isOpen && (
<>
{/* Backdrop - only in overlay mode */}
{viewMode === "overlay" && (
<div
className="fixed inset-0 z-40 bg-background/80 backdrop-blur-sm"
onClick={onClose}
/>
)}
{/* Backdrop - only on smaller screens (overlay mode) */}
<div
className={getBackdropClasses()}
onClick={onClose}
/>
{/* Panel */}
<div
className={`
${
viewMode === "overlay"
? "fixed inset-y-0 right-0 z-50 w-full sm:w-[800px]"
: "w-full sm:w-[800px] h-full relative"
}
bg-background border-l shadow-lg overflow-hidden
`}
className={getTaskPanelClasses()}
>
<div className="flex flex-col h-full">
{/* Header */}
@@ -388,26 +374,6 @@ export function TaskDetailsPanel({
</div>
</div>
<div className="flex items-center gap-1">
<Button
variant="ghost"
size="icon"
onClick={() =>
onViewModeChange(
viewMode === "overlay" ? "sideBySide" : "overlay"
)
}
title={
viewMode === "overlay"
? "Switch to side-by-side view"
: "Switch to overlay view"
}
>
{viewMode === "overlay" ? (
<Maximize2 className="h-4 w-4" />
) : (
<Minimize2 className="h-4 w-4" />
)}
</Button>
<Button variant="ghost" size="icon" onClick={onClose}>
<X className="h-4 w-4" />
</Button>

View File

@@ -0,0 +1,70 @@
/**
* Centralized responsive configuration for TaskDetailsPanel
* Adjust these values to change when the panel switches between overlay and side-by-side modes
*/
// The breakpoint at which we switch from overlay to side-by-side mode
// Change this value to adjust when the panel switches to side-by-side mode:
// 'sm' = 640px, 'md' = 768px, 'lg' = 1024px, 'xl' = 1280px, '2xl' = 1536px
export const PANEL_SIDE_BY_SIDE_BREAKPOINT = "xl" as const;
// Panel widths for different screen sizes (in overlay mode)
export const PANEL_WIDTHS = {
base: "w-full", // < 640px
sm: "sm:w-[560px]", // 640px+
md: "md:w-[600px]", // 768px+
lg: "lg:w-[650px]", // 1024px+ (smaller to start transitioning)
xl: "xl:w-[750px]", // 1280px+
"2xl": "2xl:w-[800px]", // 1536px+ (side-by-side mode)
} as const;
// Generate classes for TaskDetailsPanel
export const getTaskPanelClasses = () => {
const overlayClasses = [
"fixed inset-y-0 right-0 z-50",
PANEL_WIDTHS.base,
PANEL_WIDTHS.sm,
PANEL_WIDTHS.md,
PANEL_WIDTHS.lg,
PANEL_WIDTHS.xl,
].join(" ");
const sideBySideClasses = [
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:relative`,
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:inset-auto`,
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:z-auto`,
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:h-full`,
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:w-[800px]`,
].join(" ");
return `${overlayClasses} ${sideBySideClasses} bg-background border-l shadow-lg overflow-hidden`;
};
// Generate classes for backdrop (only show in overlay mode)
export const getBackdropClasses = () => {
return `fixed inset-0 z-40 bg-background/80 backdrop-blur-sm ${PANEL_SIDE_BY_SIDE_BREAKPOINT}:hidden`;
};
// Generate classes for main container (enable flex layout in side-by-side mode)
export const getMainContainerClasses = (isPanelOpen: boolean) => {
if (!isPanelOpen) return "w-full";
return `w-full ${PANEL_SIDE_BY_SIDE_BREAKPOINT}:flex ${PANEL_SIDE_BY_SIDE_BREAKPOINT}:h-full`;
};
// Generate classes for kanban section
export const getKanbanSectionClasses = (isPanelOpen: boolean) => {
if (!isPanelOpen) return "w-full transition-all duration-300";
const overlayClasses = "w-full opacity-50 pointer-events-none";
const sideBySideClasses = [
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:flex-1`,
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:min-w-0`,
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:h-full`,
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:overflow-y-auto`,
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:opacity-100`,
`${PANEL_SIDE_BY_SIDE_BREAKPOINT}:pointer-events-auto`,
].join(" ");
return `${overlayClasses} ${sideBySideClasses} transition-all duration-300`;
};

View File

@@ -6,6 +6,7 @@ import { ArrowLeft, Plus } from "lucide-react";
import { makeRequest } from "@/lib/api";
import { TaskFormDialog } from "@/components/tasks/TaskFormDialog";
import { useKeyboardShortcuts } from "@/lib/keyboard-shortcuts";
import { getMainContainerClasses, getKanbanSectionClasses } from "@/lib/responsive-config";
import { TaskKanbanBoard } from "@/components/tasks/TaskKanbanBoard";
import { TaskDetailsPanel } from "@/components/tasks/TaskDetailsPanel";
@@ -41,7 +42,6 @@ export function ProjectTasks() {
// Panel state
const [selectedTask, setSelectedTask] = useState<Task | null>(null);
const [isPanelOpen, setIsPanelOpen] = useState(false);
const [viewMode, setViewMode] = useState<"overlay" | "sideBySide">("overlay");
// Define task creation handler
const handleCreateNewTask = () => {
@@ -237,9 +237,7 @@ export function ProjectTasks() {
setSelectedTask(null);
};
const handleViewModeChange = (mode: "overlay" | "sideBySide") => {
setViewMode(mode);
};
const handleDragEnd = async (event: DragEndEvent) => {
const { active, over } = event;
@@ -301,25 +299,11 @@ export function ProjectTasks() {
return (
<div
className={`w-full ${
viewMode === "sideBySide" && isPanelOpen ? "flex h-full" : ""
}`}
className={getMainContainerClasses(isPanelOpen)}
>
{/* Left Column - Kanban Section */}
<div
className={`
${
viewMode === "sideBySide" && isPanelOpen
? "flex-1 min-w-0 h-full overflow-y-auto"
: "w-full"
}
${
viewMode === "overlay" && isPanelOpen
? "opacity-50 pointer-events-none"
: ""
}
transition-all duration-300
`}
className={getKanbanSectionClasses(isPanelOpen)}
>
<div className="space-y-6 max-w-7xl mx-auto">
{/* Header */}
@@ -396,8 +380,6 @@ export function ProjectTasks() {
projectId={projectId!}
isOpen={isPanelOpen}
onClose={handleClosePanel}
viewMode={viewMode}
onViewModeChange={handleViewModeChange}
/>
)}
</div>