Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 0 additions & 69 deletions apps/desktop/src/renderer/components/ZustandExample.tsx

This file was deleted.

6 changes: 2 additions & 4 deletions apps/desktop/src/renderer/screens/main/MainScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { DndProvider } from "react-dnd";
import { dragDropManager } from "../../lib/dnd";
import { AppFrame } from "./components/AppFrame";
import { Background } from "./components/Background";
import { CenterView } from "./components/CenterView";
import { Sidebar } from "./components/Sidebar";
import { TabView } from "./components/TabView";
import { TopBar } from "./components/TopBar";

export function MainScreen() {
Expand All @@ -14,8 +13,7 @@ export function MainScreen() {
<div className="flex flex-col h-full w-full">
<TopBar />
<div className="flex flex-1 overflow-hidden">
<Sidebar />
<CenterView />
<TabView />
</div>
</div>
</AppFrame>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
export function NewTabView() {
return (
<div className="flex-1 h-full flex items-center justify-center bg-background">
<div className="text-center max-w-2xl px-6">
<h1 className="text-4xl font-bold text-foreground mb-4">New Tab</h1>
<p className="text-lg text-muted-foreground mb-8">
Start by selecting an action or creating something new
</p>
<div className="grid grid-cols-2 gap-4 max-w-md mx-auto">
<button
type="button"
className="p-6 border border-border rounded-lg hover:bg-accent hover:border-accent-foreground transition-colors text-left"
>
<div className="text-2xl mb-2">📁</div>
<div className="font-medium text-foreground">Open Project</div>
<div className="text-sm text-muted-foreground">
Browse your files
</div>
</button>
<button
type="button"
className="p-6 border border-border rounded-lg hover:bg-accent hover:border-accent-foreground transition-colors text-left"
>
<div className="text-2xl mb-2">⚡</div>
<div className="font-medium text-foreground">Quick Actions</div>
<div className="text-sm text-muted-foreground">Common tasks</div>
</button>
<button
type="button"
className="p-6 border border-border rounded-lg hover:bg-accent hover:border-accent-foreground transition-colors text-left"
>
<div className="text-2xl mb-2">🔍</div>
<div className="font-medium text-foreground">Search</div>
<div className="text-sm text-muted-foreground">Find anything</div>
</button>
<button
type="button"
className="p-6 border border-border rounded-lg hover:bg-accent hover:border-accent-foreground transition-colors text-left"
>
<div className="text-2xl mb-2">⚙️</div>
<div className="font-medium text-foreground">Settings</div>
<div className="text-sm text-muted-foreground">Configure app</div>
</button>
</div>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { NewTabView } from "./NewTabView";
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { useCallback, useRef, useState } from "react";
import { ModeContent } from "./components/ModeContent";
import { ModeHeader } from "./components/ModeHeader";
import { ModeNavigation } from "./components/ModeNavigation";
import { useModeDetection } from "./hooks/useModeDetection";
import { useScrollProgress } from "./hooks/useScrollProgress";
import { useScrollSnap } from "./hooks/useScrollSnap";
import type { ModeCarouselProps } from "./types";

export function ModeCarousel({
modes,
currentMode,
onModeSelect,
children,
onScrollProgress,
isDragging = false,
}: ModeCarouselProps) {
const isInitialMount = useRef(true);
const currentIndex = modes.findIndex((m) => m === currentMode);
const [scrollContainer, setScrollContainer] = useState<HTMLDivElement | null>(
null,
);

// Use callback ref to get notified when the ref is attached
const scrollContainerRef = useCallback((node: HTMLDivElement | null) => {
if (node) {
setScrollContainer(node);
}
}, []);

// Track scroll progress
const modeProgress = useScrollProgress({
scrollContainer,
currentIndex,
onScrollProgress,
});

// Handle scroll snapping
useScrollSnap({
scrollContainer,
currentIndex,
isInitialMount,
});

// Detect mode changes from scrolling
useModeDetection({
scrollContainer,
modes,
currentMode,
onModeSelect,
isDragging,
});

// If only one mode or no modes, disable carousel
if (modes.length <= 1) {
return (
<div className="flex flex-col flex-1 h-full">
<div className="flex-1 overflow-y-auto">
<ModeHeader mode={currentMode} />
<div className="px-3">{children(currentMode, true)}</div>
</div>
</div>
);
}

return (
<div className="flex flex-col flex-1 h-full">
{/* Carousel content */}
<div
ref={scrollContainerRef}
className="flex-1 overflow-x-scroll overflow-y-hidden"
style={{
scrollSnapType: isDragging ? "none" : "x mandatory",
scrollSnapStop: "always",
scrollBehavior: "smooth",
WebkitOverflowScrolling: "touch",
overscrollBehaviorX: "contain",
scrollbarWidth: "none",
msOverflowStyle: "none",
pointerEvents: isDragging ? "none" : "auto",
}}
>
<div
className="flex h-full"
style={{ width: `${modes.length * 100}%` }}
>
{modes.map((mode) => (
<div
key={mode}
style={{
width: `${100 / modes.length}%`,
}}
>
<ModeContent mode={mode} isActive={mode === currentMode}>
{children(mode, mode === currentMode)}
</ModeContent>
</div>
))}
</div>
</div>

{/* Bottom navigation bar */}
<ModeNavigation
modes={modes}
currentMode={currentMode}
onModeSelect={onModeSelect}
scrollProgress={modeProgress}
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { type MotionValue, motion, useTransform } from "framer-motion";

interface AnimatedBackgroundProps {
progress: MotionValue<number>;
modeCount: number;
}

export function AnimatedBackground({
progress,
modeCount,
}: AnimatedBackgroundProps) {
// Calculate the width of each button (32px = h-8 w-8) + gap (4px = gap-1)
const buttonWidth = 32;
const gap = 4;
const totalButtonWidth = buttonWidth + gap;

// Transform progress (0-1) to translateX position
// For 2 modes: 0 -> 0px, 1 -> 36px (buttonWidth + gap)
const translateX = useTransform(
progress,
[0, modeCount - 1],
[0, (modeCount - 1) * totalButtonWidth],
);

return (
<motion.div
className="absolute h-8 w-8 rounded-sm bg-sidebar-accent"
style={{
x: translateX,
}}
initial={false}
transition={{
type: "spring",
stiffness: 300,
damping: 30,
}}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { AnimatedBackground } from "./AnimatedBackground";
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { ReactNode } from "react";
import type { SidebarMode } from "../../types";
import { ModeHeader } from "../ModeHeader";

interface ModeContentProps {
mode: SidebarMode;
isActive: boolean;
children: ReactNode;
}

export function ModeContent({ mode, children }: ModeContentProps) {
return (
<div
className="overflow-y-auto h-full"
style={{
scrollSnapAlign: "start",
scrollSnapStop: "always",
}}
>
<ModeHeader mode={mode} />
<div className="px-1">{children}</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ModeContent } from "./ModeContent";
Loading
Loading