Files
CC-Switch/src/components/AppSwitcher.tsx
T
TinsFox f0e8ba1d8f feat: session manger (#867)
* feat: init session manger

* feat: persist selected app to localStorage

- Save app selection when switching providers
- Restore last selected app on page load

* feat: persist current view to localStorage

- Save view selection when switching tabs
- Restore last selected view on page load

* styles: update ui

* feat: Improve macOS Terminal activation and refactor Kitty launch to use  command with user's default shell.

* fix: session view

* feat: toc

* feat: Implement FlexSearch for improved session search functionality.

* feat: Redesign session manager search and filter UI for a more compact and dynamic experience.

* refactor: modularize session manager by extracting components and utility functions into dedicated files.

* feat: Enhance session terminal launching with support for iTerm2, Ghostty, WezTerm, and Alacritty, including UI and custom configuration options.

* feat: Conditionally render terminal selection and resume session buttons only on macOS.
2026-02-02 11:12:30 +08:00

70 lines
1.9 KiB
TypeScript

import type { AppId } from "@/lib/api";
import type { VisibleApps } from "@/types";
import { ProviderIcon } from "@/components/ProviderIcon";
interface AppSwitcherProps {
activeApp: AppId;
onSwitch: (app: AppId) => void;
visibleApps?: VisibleApps;
compact?: boolean;
}
const ALL_APPS: AppId[] = ["claude", "codex", "gemini", "opencode"];
const STORAGE_KEY = "cc-switch-last-app";
export function AppSwitcher({
activeApp,
onSwitch,
visibleApps,
compact,
}: AppSwitcherProps) {
const handleSwitch = (app: AppId) => {
if (app === activeApp) return;
localStorage.setItem(STORAGE_KEY, app);
onSwitch(app);
};
const iconSize = 20;
const appIconName: Record<AppId, string> = {
claude: "claude",
codex: "openai",
gemini: "gemini",
opencode: "opencode",
};
const appDisplayName: Record<AppId, string> = {
claude: "Claude",
codex: "Codex",
gemini: "Gemini",
opencode: "OpenCode",
};
// Filter apps based on visibility settings (default all visible)
const appsToShow = ALL_APPS.filter((app) => {
if (!visibleApps) return true;
return visibleApps[app];
});
return (
<div className="inline-flex bg-muted rounded-xl p-1 gap-1">
{appsToShow.map((app) => (
<button
key={app}
type="button"
onClick={() => handleSwitch(app)}
className={`group inline-flex items-center gap-2 px-3 h-8 rounded-md text-sm font-medium transition-all duration-200 ${
activeApp === app
? "bg-background text-foreground shadow-sm"
: "text-muted-foreground hover:text-foreground hover:bg-background/50"
}`}
>
<ProviderIcon
icon={appIconName[app]}
name={appDisplayName[app]}
size={iconSize}
/>
{!compact && <span>{appDisplayName[app]}</span>}
</button>
))}
</div>
);
}