feat(ui): enhance timeline sidebar with slide-in animation and responsive layout

- Add slide-in animation to timeline sidebar using framer-motion
- Implement responsive layout adjustments for main content area
- Add proper timeline header with close button
- Fix floating prompt input positioning to accommodate timeline
- Reorder CSS imports for proper style precedence
- Fix animation scaling issue in rotating symbol keyframes

The timeline now slides in from the right with a smooth spring animation
and properly adjusts the main content area width on larger screens.
This commit is contained in:
Mufeed VH
2025-07-02 20:49:56 +05:30
parent 2d73a38222
commit f1377833b3
3 changed files with 59 additions and 23 deletions

View File

@@ -1076,7 +1076,10 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
</motion.div>
{/* Main Content Area */}
<div className="flex-1 overflow-hidden">
<div className={cn(
"flex-1 overflow-hidden transition-all duration-300",
showTimeline && "sm:mr-96"
)}>
{showPreview ? (
// Split pane layout when preview is active
<SplitPane
@@ -1241,14 +1244,19 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
</motion.div>
)}
<FloatingPromptInput
ref={floatingPromptRef}
onSend={handleSendPrompt}
onCancel={handleCancelExecution}
isLoading={isLoading}
disabled={!projectPath}
projectPath={projectPath}
/>
<div className={cn(
"fixed bottom-0 left-0 right-0 transition-all duration-300 z-50",
showTimeline && "sm:right-96"
)}>
<FloatingPromptInput
ref={floatingPromptRef}
onSend={handleSendPrompt}
onCancel={handleCancelExecution}
isLoading={isLoading}
disabled={!projectPath}
projectPath={projectPath}
/>
</div>
{/* Token Counter - positioned under the Send button */}
{totalTokens > 0 && (
@@ -1274,17 +1282,45 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
</ErrorBoundary>
{/* Timeline */}
{showTimeline && effectiveSession && (
<TimelineNavigator
sessionId={effectiveSession.id}
projectId={effectiveSession.project_id}
projectPath={projectPath}
currentMessageIndex={messages.length - 1}
onCheckpointSelect={handleCheckpointSelect}
onFork={handleFork}
refreshVersion={timelineVersion}
/>
)}
<AnimatePresence>
{showTimeline && effectiveSession && (
<motion.div
initial={{ x: "100%" }}
animate={{ x: 0 }}
exit={{ x: "100%" }}
transition={{ type: "spring", damping: 20, stiffness: 300 }}
className="fixed right-0 top-0 h-full w-full sm:w-96 bg-background border-l border-border shadow-xl z-30 overflow-hidden"
>
<div className="h-full flex flex-col">
{/* Timeline Header */}
<div className="flex items-center justify-between p-4 border-b border-border">
<h3 className="text-lg font-semibold">Session Timeline</h3>
<Button
variant="ghost"
size="icon"
onClick={() => setShowTimeline(false)}
className="h-8 w-8"
>
<X className="h-4 w-4" />
</Button>
</div>
{/* Timeline Content */}
<div className="flex-1 overflow-y-auto p-4">
<TimelineNavigator
sessionId={effectiveSession.id}
projectId={effectiveSession.project_id}
projectPath={projectPath}
currentMessageIndex={messages.length - 1}
onCheckpointSelect={handleCheckpointSelect}
onFork={handleFork}
refreshVersion={timelineVersion}
/>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
{/* Fork Dialog */}

View File

@@ -2,8 +2,8 @@ import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { ErrorBoundary } from "./components/ErrorBoundary";
import "./styles.css";
import "./assets/shimmer.css";
import "./styles.css";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>

View File

@@ -423,9 +423,9 @@ button:focus-visible,
/* Rotating symbol animation */
@keyframes rotate-symbol {
0% { content: "◐"; transform: scale(1); }
25% { content: "◓"; transform: scale(10); }
25% { content: "◓"; transform: scale(1); }
50% { content: "◑"; transform: scale(1); }
75% { content: "◒"; transform: scale(10); }
75% { content: "◒"; transform: scale(1); }
100% { content: "◐"; transform: scale(1); }
}