diff --git a/apps/desktop/src/renderer/components/ZustandExample.tsx b/apps/desktop/src/renderer/components/ZustandExample.tsx
deleted file mode 100644
index 81feb9fc12f..00000000000
--- a/apps/desktop/src/renderer/components/ZustandExample.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { useCount, useExampleStore, useText } from "renderer/stores";
-
-/**
- * Example component demonstrating Zustand usage patterns
- *
- * This component shows:
- * 1. Using selector hooks for optimized re-renders
- * 2. Accessing actions from the store
- * 3. Direct store access for multiple values
- */
-export function ZustandExample() {
- // Optimized selectors - only re-renders when specific values change
- const count = useCount();
- const text = useText();
-
- // Access actions directly from the store
- const increment = useExampleStore((state) => state.increment);
- const decrement = useExampleStore((state) => state.decrement);
- const setText = useExampleStore((state) => state.setText);
- const reset = useExampleStore((state) => state.reset);
-
- return (
-
-
Zustand Example
-
- {/* Counter Example */}
-
-
Counter: {count}
-
-
-
-
-
-
- {/* Text Input Example */}
-
-
Text: {text}
-
setText(e.target.value)}
- placeholder="Type something..."
- className="px-3 py-2 border rounded w-full"
- />
-
-
- {/* Reset Button */}
-
-
- );
-}
diff --git a/apps/desktop/src/renderer/screens/main/MainScreen.tsx b/apps/desktop/src/renderer/screens/main/MainScreen.tsx
index 2dda1f70557..b483bb29383 100644
--- a/apps/desktop/src/renderer/screens/main/MainScreen.tsx
+++ b/apps/desktop/src/renderer/screens/main/MainScreen.tsx
@@ -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() {
@@ -14,8 +13,7 @@ export function MainScreen() {
diff --git a/apps/desktop/src/renderer/screens/main/components/AppFrame/AppFrame.tsx b/apps/desktop/src/renderer/screens/main/components/AppFrame.tsx
similarity index 100%
rename from apps/desktop/src/renderer/screens/main/components/AppFrame/AppFrame.tsx
rename to apps/desktop/src/renderer/screens/main/components/AppFrame.tsx
diff --git a/apps/desktop/src/renderer/screens/main/components/AppFrame/index.ts b/apps/desktop/src/renderer/screens/main/components/AppFrame/index.ts
deleted file mode 100644
index 6187d8854af..00000000000
--- a/apps/desktop/src/renderer/screens/main/components/AppFrame/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { AppFrame } from "./AppFrame";
diff --git a/apps/desktop/src/renderer/screens/main/components/Background/Background.tsx b/apps/desktop/src/renderer/screens/main/components/Background.tsx
similarity index 100%
rename from apps/desktop/src/renderer/screens/main/components/Background/Background.tsx
rename to apps/desktop/src/renderer/screens/main/components/Background.tsx
diff --git a/apps/desktop/src/renderer/screens/main/components/Background/index.ts b/apps/desktop/src/renderer/screens/main/components/Background/index.ts
deleted file mode 100644
index 776ec8df708..00000000000
--- a/apps/desktop/src/renderer/screens/main/components/Background/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Background } from "./Background";
diff --git a/apps/desktop/src/renderer/screens/main/components/CenterView/index.ts b/apps/desktop/src/renderer/screens/main/components/CenterView/index.ts
deleted file mode 100644
index a30ea67832d..00000000000
--- a/apps/desktop/src/renderer/screens/main/components/CenterView/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { CenterView } from "./CenterView";
diff --git a/apps/desktop/src/renderer/screens/main/components/Sidebar/index.tsx b/apps/desktop/src/renderer/screens/main/components/Sidebar/index.tsx
deleted file mode 100644
index 98519f47cf0..00000000000
--- a/apps/desktop/src/renderer/screens/main/components/Sidebar/index.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { motion } from "framer-motion";
-import { useSidebarStore } from "renderer/stores";
-
-export function Sidebar() {
- const { isSidebarOpen } = useSidebarStore();
-
- return (
-
-
-
-
-
-
-
- );
-}
diff --git a/apps/desktop/src/renderer/screens/main/components/CenterView/CenterView.tsx b/apps/desktop/src/renderer/screens/main/components/TabView/CenterView.tsx
similarity index 100%
rename from apps/desktop/src/renderer/screens/main/components/CenterView/CenterView.tsx
rename to apps/desktop/src/renderer/screens/main/components/TabView/CenterView.tsx
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/NewTabView.tsx b/apps/desktop/src/renderer/screens/main/components/TabView/NewTabView.tsx
new file mode 100644
index 00000000000..576bff135ce
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/NewTabView.tsx
@@ -0,0 +1,48 @@
+export function NewTabView() {
+ return (
+
+
+
New Tab
+
+ Start by selecting an action or creating something new
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/AnimatedBackground.tsx b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/AnimatedBackground.tsx
new file mode 100644
index 00000000000..4d47b11a2c0
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/AnimatedBackground.tsx
@@ -0,0 +1,39 @@
+import { type MotionValue, motion, useTransform } from "framer-motion";
+
+interface AnimatedBackgroundProps {
+ progress: MotionValue;
+ 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 (
+
+ );
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/ModeContent.tsx b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/ModeContent.tsx
new file mode 100644
index 00000000000..758b3a90cc2
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/ModeContent.tsx
@@ -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 (
+
+ );
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/ModeHeader.tsx b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/ModeHeader.tsx
new file mode 100644
index 00000000000..4be166e86b2
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/ModeHeader.tsx
@@ -0,0 +1,16 @@
+import { modeLabels } from "./constants";
+import type { SidebarMode } from "./types";
+
+interface ModeHeaderProps {
+ mode: SidebarMode;
+}
+
+export function ModeHeader({ mode }: ModeHeaderProps) {
+ return (
+
+
+ {modeLabels[mode]}
+
+
+ );
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/ModeNavigation.tsx b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/ModeNavigation.tsx
new file mode 100644
index 00000000000..e1b31261ae7
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/ModeNavigation.tsx
@@ -0,0 +1,51 @@
+import type { MotionValue } from "framer-motion";
+import { modeIcons, modeLabels } from "./constants";
+import type { SidebarMode } from "./types";
+import { AnimatedBackground } from "./AnimatedBackground";
+
+interface ModeNavigationProps {
+ modes: SidebarMode[];
+ currentMode: SidebarMode;
+ onModeSelect: (mode: SidebarMode) => void;
+ scrollProgress: MotionValue;
+}
+
+export function ModeNavigation({
+ modes,
+ currentMode,
+ onModeSelect,
+ scrollProgress,
+}: ModeNavigationProps) {
+ return (
+
+
+
+
+ {modes.map((mode) => {
+ const Icon = modeIcons[mode];
+ const isActive = mode === currentMode;
+ const label = modeLabels[mode];
+
+ return (
+
+ );
+ })}
+
+
+ );
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/constants.ts b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/constants.ts
new file mode 100644
index 00000000000..f047d29afeb
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/constants.ts
@@ -0,0 +1,12 @@
+import { GitBranch, LayoutList } from "lucide-react";
+import type { SidebarMode } from "./types";
+
+export const modeIcons: Record = {
+ tabs: LayoutList,
+ changes: GitBranch,
+};
+
+export const modeLabels: Record = {
+ tabs: "Tabs",
+ changes: "Changes",
+};
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/hooks/useModeDetection.ts b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/hooks/useModeDetection.ts
new file mode 100644
index 00000000000..3303712c26f
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/hooks/useModeDetection.ts
@@ -0,0 +1,66 @@
+import { useEffect } from "react";
+import type { SidebarMode } from "../types";
+
+interface UseModeDetectionOptions {
+ scrollContainer: HTMLDivElement | null;
+ modes: SidebarMode[];
+ currentMode: SidebarMode;
+ onModeSelect: (mode: SidebarMode) => void;
+ isDragging?: boolean;
+}
+
+export function useModeDetection({
+ scrollContainer,
+ modes,
+ currentMode,
+ onModeSelect,
+ isDragging = false,
+}: UseModeDetectionOptions) {
+ // Detect when user finishes scrolling and update current mode
+ useEffect(() => {
+ if (!scrollContainer || isDragging) return;
+
+ let scrollEndTimer: NodeJS.Timeout | undefined;
+
+ const handleScroll = () => {
+ // Clear existing timeout
+ if (scrollEndTimer) {
+ clearTimeout(scrollEndTimer);
+ }
+
+ // Wait for scroll to settle before updating mode (reduces jitter)
+ scrollEndTimer = setTimeout(() => {
+ const finalScrollLeft = scrollContainer.scrollLeft;
+ const finalContainerWidth = scrollContainer.offsetWidth;
+
+ // Calculate which mode we're closest to and snap to it
+ const finalIndex = Math.round(finalScrollLeft / finalContainerWidth);
+
+ if (finalIndex >= 0 && finalIndex < modes.length && modes[finalIndex]) {
+ // Snap to the nearest mode
+ const targetScrollX = finalIndex * finalContainerWidth;
+ if (Math.abs(finalScrollLeft - targetScrollX) > 5) {
+ scrollContainer.scrollTo({
+ left: targetScrollX,
+ behavior: "smooth",
+ });
+ }
+
+ // Update mode if it changed
+ if (modes[finalIndex] !== currentMode) {
+ onModeSelect(modes[finalIndex]);
+ }
+ }
+ }, 150);
+ };
+
+ scrollContainer.addEventListener("scroll", handleScroll, { passive: true });
+
+ return () => {
+ scrollContainer.removeEventListener("scroll", handleScroll);
+ if (scrollEndTimer) {
+ clearTimeout(scrollEndTimer);
+ }
+ };
+ }, [modes, currentMode, onModeSelect, scrollContainer, isDragging]);
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/hooks/useScrollProgress.ts b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/hooks/useScrollProgress.ts
new file mode 100644
index 00000000000..6b53d9264a3
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/hooks/useScrollProgress.ts
@@ -0,0 +1,60 @@
+import { type MotionValue, useMotionValue } from "framer-motion";
+import { useEffect } from "react";
+
+interface UseScrollProgressOptions {
+ scrollContainer: HTMLDivElement | null;
+ currentIndex: number;
+ onScrollProgress?: (progress: MotionValue) => void;
+}
+
+export function useScrollProgress({
+ scrollContainer,
+ currentIndex,
+ onScrollProgress,
+}: UseScrollProgressOptions) {
+ const initialProgress = currentIndex >= 0 ? currentIndex : 0;
+ const modeProgress = useMotionValue(initialProgress);
+
+ // Track scroll position and update motion value
+ useEffect(() => {
+ if (!scrollContainer) return;
+
+ let rafId: number | undefined;
+
+ const updateProgress = () => {
+ const scrollLeft = scrollContainer.scrollLeft;
+ const containerWidth = scrollContainer.offsetWidth;
+ const progress = scrollLeft / containerWidth;
+ modeProgress.set(progress);
+ };
+
+ const handleScroll = () => {
+ // Use requestAnimationFrame for smooth updates
+ if (rafId !== undefined) {
+ cancelAnimationFrame(rafId);
+ }
+ rafId = requestAnimationFrame(updateProgress);
+ };
+
+ scrollContainer.addEventListener("scroll", handleScroll, { passive: true });
+
+ // Initial value
+ updateProgress();
+
+ return () => {
+ scrollContainer.removeEventListener("scroll", handleScroll);
+ if (rafId !== undefined) {
+ cancelAnimationFrame(rafId);
+ }
+ };
+ }, [scrollContainer, modeProgress]);
+
+ // Expose scroll progress to parent
+ useEffect(() => {
+ if (onScrollProgress) {
+ onScrollProgress(modeProgress);
+ }
+ }, [onScrollProgress, modeProgress]);
+
+ return modeProgress;
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/hooks/useScrollSnap.ts b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/hooks/useScrollSnap.ts
new file mode 100644
index 00000000000..a6c17eb9a7d
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/hooks/useScrollSnap.ts
@@ -0,0 +1,31 @@
+import { useEffect } from "react";
+
+interface UseScrollSnapOptions {
+ scrollContainer: HTMLDivElement | null;
+ currentIndex: number;
+ isInitialMount: React.MutableRefObject;
+}
+
+export function useScrollSnap({
+ scrollContainer,
+ currentIndex,
+ isInitialMount,
+}: UseScrollSnapOptions) {
+ // Scroll to current mode when it changes externally
+ useEffect(() => {
+ if (!scrollContainer || currentIndex < 0) return;
+
+ const targetScrollX = currentIndex * scrollContainer.offsetWidth;
+
+ // Only scroll if we're not already at the target position
+ if (Math.abs(scrollContainer.scrollLeft - targetScrollX) > 5) {
+ scrollContainer.scrollTo({
+ left: targetScrollX,
+ behavior: isInitialMount.current ? "auto" : "smooth",
+ });
+ }
+
+ // Mark that initial mount is complete
+ isInitialMount.current = false;
+ }, [currentIndex, scrollContainer, isInitialMount]);
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/index.tsx b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/index.tsx
new file mode 100644
index 00000000000..3eb29b4fe4d
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/index.tsx
@@ -0,0 +1,106 @@
+import { useCallback, useRef, useState } from "react";
+import { ModeContent } from "./ModeContent";
+import { ModeHeader } from "./ModeHeader";
+import { ModeNavigation } from "./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.indexOf(currentMode);
+ const [scrollContainer, setScrollContainer] = useState(
+ null,
+ );
+
+ const scrollContainerRef = useCallback((node: HTMLDivElement | null) => {
+ if (node) {
+ setScrollContainer(node);
+ }
+ }, []);
+
+ const modeProgress = useScrollProgress({
+ scrollContainer,
+ currentIndex,
+ onScrollProgress,
+ });
+
+ useScrollSnap({
+ scrollContainer,
+ currentIndex,
+ isInitialMount,
+ });
+
+ useModeDetection({
+ scrollContainer,
+ modes,
+ currentMode,
+ onModeSelect,
+ isDragging,
+ });
+
+ if (modes.length <= 1) {
+ return (
+
+
+
+
{children(currentMode, true)}
+
+
+ );
+ }
+
+ return (
+
+ {/* Carousel content */}
+
+
+ {modes.map((mode) => (
+
+
+ {children(mode, mode === currentMode)}
+
+
+ ))}
+
+
+
+ {/* Bottom navigation bar */}
+
+
+ );
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/types.ts b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/types.ts
new file mode 100644
index 00000000000..35d9d4bf0b1
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/ModeCarousel/types.ts
@@ -0,0 +1,14 @@
+import type { MotionValue } from "framer-motion";
+import type { ReactNode } from "react";
+import type { SidebarMode } from "renderer/stores/sidebar-state";
+
+export type { SidebarMode };
+
+export interface ModeCarouselProps {
+ modes: SidebarMode[];
+ currentMode: SidebarMode;
+ onModeSelect: (mode: SidebarMode) => void;
+ children: (mode: SidebarMode, isActive: boolean) => ReactNode;
+ onScrollProgress?: (progress: MotionValue) => void;
+ isDragging?: boolean;
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/index.tsx b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/index.tsx
new file mode 100644
index 00000000000..bcdb756af4a
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/Sidebar/index.tsx
@@ -0,0 +1,75 @@
+import { motion } from "framer-motion";
+import { useSidebarStore } from "renderer/stores";
+import { SidebarMode } from "renderer/stores/sidebar-state";
+import { ModeCarousel } from "./ModeCarousel";
+
+export function Sidebar() {
+ const { isSidebarOpen, currentMode, setMode } = useSidebarStore();
+
+ const modes: SidebarMode[] = [SidebarMode.Tabs, SidebarMode.Changes];
+
+ return (
+
+
+
+ {(mode) => {
+ if (mode === "changes") {
+ return (
+
+ Changes view coming soon...
+
+ );
+ }
+
+ // Tabs mode
+ return (
+
+ );
+ }}
+
+
+
+ );
+}
diff --git a/apps/desktop/src/renderer/screens/main/components/TabView/index.tsx b/apps/desktop/src/renderer/screens/main/components/TabView/index.tsx
new file mode 100644
index 00000000000..54bb07c0dc6
--- /dev/null
+++ b/apps/desktop/src/renderer/screens/main/components/TabView/index.tsx
@@ -0,0 +1,24 @@
+import { useTabsStore } from "renderer/stores/tabs";
+import { CenterView } from "./CenterView";
+import { NewTabView } from "./NewTabView";
+import { Sidebar } from "./Sidebar";
+
+export function TabView() {
+ const { tabs, activeTabId } = useTabsStore();
+ const activeTab = tabs.find((tab) => tab.id === activeTabId);
+
+ if (activeTab?.isNew) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+ );
+}
diff --git a/apps/desktop/src/renderer/stores/example-store.ts b/apps/desktop/src/renderer/stores/example-store.ts
deleted file mode 100644
index 38567b35339..00000000000
--- a/apps/desktop/src/renderer/stores/example-store.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { create } from "zustand";
-import { devtools } from "zustand/middleware";
-
-/**
- * Example store demonstrating Zustand usage patterns
- *
- * Features:
- * - TypeScript type safety
- * - DevTools integration for debugging
- * - Optional persistence (commented out by default)
- */
-
-interface ExampleState {
- // State
- count: number;
- text: string;
-
- // Actions
- increment: () => void;
- decrement: () => void;
- setText: (text: string) => void;
- reset: () => void;
-}
-
-const initialState = {
- count: 0,
- text: "",
-};
-
-export const useExampleStore = create()(
- devtools(
- // Uncomment persist middleware if you need localStorage persistence
- // persist(
- (set) => ({
- ...initialState,
-
- increment: () => set((state) => ({ count: state.count + 1 })),
- decrement: () => set((state) => ({ count: state.count - 1 })),
- setText: (text: string) => set({ text }),
- reset: () => set(initialState),
- }),
- // {
- // name: "example-store", // localStorage key
- // }
- // ),
- {
- name: "ExampleStore", // DevTools name
- },
- ),
-);
-
-// Selectors for optimized re-renders
-export const useCount = () => useExampleStore((state) => state.count);
-export const useText = () => useExampleStore((state) => state.text);
diff --git a/apps/desktop/src/renderer/stores/sidebar-state.ts b/apps/desktop/src/renderer/stores/sidebar-state.ts
index 36c276a8dc7..751ed257097 100644
--- a/apps/desktop/src/renderer/stores/sidebar-state.ts
+++ b/apps/desktop/src/renderer/stores/sidebar-state.ts
@@ -1,16 +1,24 @@
import { create } from "zustand";
import { devtools } from "zustand/middleware";
+export enum SidebarMode {
+ Tabs = "tabs",
+ Changes = "changes",
+}
+
interface SidebarState {
isSidebarOpen: boolean;
+ currentMode: SidebarMode;
toggleSidebar: () => void;
setSidebarOpen: (open: boolean) => void;
+ setMode: (mode: SidebarMode) => void;
}
export const useSidebarStore = create()(
devtools(
(set) => ({
isSidebarOpen: true,
+ currentMode: "tabs",
toggleSidebar: () => {
set((state) => ({ isSidebarOpen: !state.isSidebarOpen }));
@@ -19,6 +27,10 @@ export const useSidebarStore = create()(
setSidebarOpen: (open) => {
set({ isSidebarOpen: open });
},
+
+ setMode: (mode) => {
+ set({ currentMode: mode });
+ },
}),
{ name: "SidebarStore" },
),
diff --git a/apps/desktop/src/renderer/stores/tabs.ts b/apps/desktop/src/renderer/stores/tabs.ts
index e1dc5fe8cf4..050237a7a8f 100644
--- a/apps/desktop/src/renderer/stores/tabs.ts
+++ b/apps/desktop/src/renderer/stores/tabs.ts
@@ -4,6 +4,7 @@ import { devtools } from "zustand/middleware";
export interface Tab {
id: string;
title: string;
+ isNew?: boolean;
}
interface TabsState {
@@ -14,11 +15,13 @@ interface TabsState {
removeTab: (id: string) => void;
setActiveTab: (id: string) => void;
reorderTabs: (startIndex: number, endIndex: number) => void;
+ markTabAsUsed: (id: string) => void;
}
const createNewTab = (): Tab => ({
id: `tab-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`,
title: "New Tab",
+ isNew: true,
});
export const useTabsStore = create()(
@@ -65,6 +68,14 @@ export const useTabsStore = create()(
return { tabs };
});
},
+
+ markTabAsUsed: (id) => {
+ set((state) => ({
+ tabs: state.tabs.map((tab) =>
+ tab.id === id ? { ...tab, isNew: false } : tab,
+ ),
+ }));
+ },
}),
{ name: "TabsStore" },
),
diff --git a/apps/old-desktop/src/renderer/screens/main/components/Sidebar/components/WorktreeList/components/WorktreeItem/WorktreeItemArborist.tsx b/apps/old-desktop/src/renderer/screens/main/components/Sidebar/components/WorktreeList/components/WorktreeItem/WorktreeItemArborist.tsx
index 64d423ca5f0..c7c99702df3 100644
--- a/apps/old-desktop/src/renderer/screens/main/components/Sidebar/components/WorktreeList/components/WorktreeItem/WorktreeItemArborist.tsx
+++ b/apps/old-desktop/src/renderer/screens/main/components/Sidebar/components/WorktreeList/components/WorktreeItem/WorktreeItemArborist.tsx
@@ -37,9 +37,7 @@ interface WorktreeItemProps {
}
// Convert Tab[] to react-arborist format
-function convertTabsToTreeData(
- tabs: Tab[],
-): Array<{
+function convertTabsToTreeData(tabs: Tab[]): Array<{
id: string;
name: string;
tab: Tab;
diff --git a/packages/ui/src/components/dropdown-menu.tsx b/packages/ui/src/components/dropdown-menu.tsx
index 43d40d3794c..7efd658e3fb 100644
--- a/packages/ui/src/components/dropdown-menu.tsx
+++ b/packages/ui/src/components/dropdown-menu.tsx
@@ -5,256 +5,256 @@ import type * as React from "react";
import { cn } from "../lib/utils";
function DropdownMenu({
- modal = false,
- ...props
+ modal = false,
+ ...props
}: React.ComponentProps) {
- return (
-
- );
+ return (
+
+ );
}
function DropdownMenuPortal({
- ...props
+ ...props
}: React.ComponentProps) {
- return (
-
- );
+ return (
+
+ );
}
function DropdownMenuTrigger({
- ...props
+ ...props
}: React.ComponentProps) {
- return (
-
- );
+ return (
+
+ );
}
function DropdownMenuContent({
- className,
- sideOffset = 4,
- ...props
+ className,
+ sideOffset = 4,
+ ...props
}: React.ComponentProps) {
- return (
-
- );
+ return (
+
+ );
}
function DropdownMenuGroup({
- ...props
+ ...props
}: React.ComponentProps) {
- return (
-
- );
+ return (
+
+ );
}
function DropdownMenuItem({
- className,
- inset,
- variant = "default",
- ...props
+ className,
+ inset,
+ variant = "default",
+ ...props
}: React.ComponentProps & {
- inset?: boolean;
- variant?: "default" | "destructive";
+ inset?: boolean;
+ variant?: "default" | "destructive";
}) {
- return (
-
- );
+ return (
+
+ );
}
function DropdownMenuCheckboxItem({
- className,
- children,
- checked,
- ...props
+ className,
+ children,
+ checked,
+ ...props
}: React.ComponentProps) {
- return (
-
-
-
-
-
-
- {children}
-
- );
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
}
function DropdownMenuRadioGroup({
- ...props
+ ...props
}: React.ComponentProps) {
- return (
-
- );
+ return (
+
+ );
}
function DropdownMenuRadioItem({
- className,
- children,
- ...props
+ className,
+ children,
+ ...props
}: React.ComponentProps) {
- return (
-
-
-
-
-
-
- {children}
-
- );
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
}
function DropdownMenuLabel({
- className,
- inset,
- ...props
+ className,
+ inset,
+ ...props
}: React.ComponentProps & {
- inset?: boolean;
+ inset?: boolean;
}) {
- return (
-
- );
+ return (
+
+ );
}
function DropdownMenuSeparator({
- className,
- ...props
+ className,
+ ...props
}: React.ComponentProps) {
- return (
-
- );
+ return (
+
+ );
}
function DropdownMenuShortcut({
- className,
- ...props
+ className,
+ ...props
}: React.ComponentProps<"span">) {
- return (
-
- );
+ return (
+
+ );
}
function DropdownMenuSub({
- ...props
+ ...props
}: React.ComponentProps) {
- return ;
+ return ;
}
function DropdownMenuSubTrigger({
- className,
- inset,
- children,
- ...props
+ className,
+ inset,
+ children,
+ ...props
}: React.ComponentProps & {
- inset?: boolean;
+ inset?: boolean;
}) {
- return (
-
- {children}
-
-
- );
+ return (
+
+ {children}
+
+
+ );
}
function DropdownMenuSubContent({
- className,
- ...props
+ className,
+ ...props
}: React.ComponentProps) {
- return (
-
- );
+ return (
+
+ );
}
export {
- DropdownMenu,
- DropdownMenuPortal,
- DropdownMenuTrigger,
- DropdownMenuContent,
- DropdownMenuGroup,
- DropdownMenuLabel,
- DropdownMenuItem,
- DropdownMenuCheckboxItem,
- DropdownMenuRadioGroup,
- DropdownMenuRadioItem,
- DropdownMenuSeparator,
- DropdownMenuShortcut,
- DropdownMenuSub,
- DropdownMenuSubTrigger,
- DropdownMenuSubContent,
+ DropdownMenu,
+ DropdownMenuPortal,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuLabel,
+ DropdownMenuItem,
+ DropdownMenuCheckboxItem,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubTrigger,
+ DropdownMenuSubContent,
};
diff --git a/packages/ui/src/components/select.tsx b/packages/ui/src/components/select.tsx
index 205251792d5..3498c2b21d8 100644
--- a/packages/ui/src/components/select.tsx
+++ b/packages/ui/src/components/select.tsx
@@ -1,7 +1,11 @@
"use client";
import * as SelectPrimitive from "@radix-ui/react-select";
-import { HiMiniCheck, HiMiniChevronDown, HiMiniChevronUp } from "react-icons/hi2";
+import {
+ HiMiniCheck,
+ HiMiniChevronDown,
+ HiMiniChevronUp,
+} from "react-icons/hi2";
import type * as React from "react";
import { cn } from "../lib/utils";