mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-05-16 17:16:19 +00:00
feat: remove project dependency from settings and mcp form modal
This commit is contained in:
@@ -6,13 +6,25 @@ import { useState } from 'react';
|
||||
*/
|
||||
export const useSidebarModals = () => {
|
||||
const [showNewProject, setShowNewProject] = useState(false);
|
||||
const [showSettingsModal, setShowSettingsModal] = useState(false);
|
||||
const [showVersionModal, setShowVersionModal] = useState(false);
|
||||
|
||||
const openNewProject = () => setShowNewProject(true);
|
||||
const closeNewProject = () => setShowNewProject(false);
|
||||
const openSettingsModal = () => setShowSettingsModal(true);
|
||||
const closeSettingsModal = () => setShowSettingsModal(false);
|
||||
const openVersionModal = () => setShowVersionModal(true);
|
||||
const closeVersionModal = () => setShowVersionModal(false);
|
||||
|
||||
return {
|
||||
showNewProject,
|
||||
openNewProject,
|
||||
closeNewProject,
|
||||
showSettingsModal,
|
||||
openSettingsModal,
|
||||
closeSettingsModal,
|
||||
showVersionModal,
|
||||
openVersionModal,
|
||||
closeVersionModal,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PanelRightOpen } from 'lucide-react';
|
||||
import SidebarFooter from './SidebarFooter';
|
||||
import { useSidebarSettings } from '@/components/refactored/sidebar/hooks/useSidebarSettings';
|
||||
import { useSidebarModals } from '@/components/refactored/sidebar/hooks/useSidebarModals';
|
||||
import { useWorkspaces } from '@/components/refactored/sidebar/hooks/useWorkspaces';
|
||||
@@ -8,6 +9,8 @@ import { SidebarWorkspaceList } from '@/components/refactored/sidebar/view/Sideb
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/shared/view/ui';
|
||||
import ProjectCreationWizard from '@/components/project-creation-wizard';
|
||||
import VersionUpgradeModal from '@/components/version-upgrade/view';
|
||||
import Settings from '@/components/settings/view/Settings';
|
||||
|
||||
export function Sidebar() {
|
||||
const { isCollapsed, toggleCollapse, setCollapsed } = useSidebarSettings();
|
||||
@@ -50,7 +53,18 @@ export function Sidebar() {
|
||||
cancelSessionDelete,
|
||||
confirmSessionDelete,
|
||||
} = useWorkspaces();
|
||||
const { showNewProject, openNewProject, closeNewProject } = useSidebarModals();
|
||||
|
||||
const {
|
||||
showNewProject,
|
||||
openNewProject,
|
||||
closeNewProject,
|
||||
showSettingsModal,
|
||||
openSettingsModal,
|
||||
closeSettingsModal,
|
||||
showVersionModal,
|
||||
openVersionModal,
|
||||
closeVersionModal,
|
||||
} = useSidebarModals();
|
||||
|
||||
const handleSessionDeleteRequest = (workspacePath: string, sessionId: string) => {
|
||||
const workspace = workspaces.find(
|
||||
@@ -77,7 +91,7 @@ export function Sidebar() {
|
||||
|
||||
<aside
|
||||
className={cn(
|
||||
"flex flex-col bg-background/80 backdrop-blur-sm transition-all duration-300 border-r border-border h-full",
|
||||
"flex h-full min-h-0 flex-col overflow-hidden border-r border-border bg-background/80 backdrop-blur-sm transition-all duration-300",
|
||||
"fixed inset-y-0 left-0 z-50 md:relative md:z-0", // Make it fixed drawer on mobile, relative on desktop
|
||||
isCollapsed
|
||||
? "-translate-x-full md:translate-x-0 md:w-0 md:opacity-0 md:overflow-hidden md:border-none" // Hide fully on mobile if collapsed
|
||||
@@ -96,34 +110,40 @@ export function Sidebar() {
|
||||
onSearchFilterChange={setSearchFilter}
|
||||
/>
|
||||
{!isCollapsed && (
|
||||
<div className="flex-1 overflow-y-auto overscroll-contain">
|
||||
<SidebarWorkspaceList
|
||||
workspacesCount={workspaces.length}
|
||||
searchFilter={searchFilter}
|
||||
starredWorkspaces={starredWorkspaces}
|
||||
unstarredWorkspaces={unstarredWorkspaces}
|
||||
expandedWorkspaces={expandedWorkspaces}
|
||||
selectedSessionId={selectedSessionId}
|
||||
editingWorkspacePath={editingWorkspacePath}
|
||||
editingWorkspaceName={editingWorkspaceName}
|
||||
isSavingWorkspaceName={isSavingWorkspaceName}
|
||||
editingSessionId={editingSessionId}
|
||||
editingSessionName={editingSessionName}
|
||||
isSavingSessionName={isSavingSessionName}
|
||||
onEditingWorkspaceNameChange={setEditingWorkspaceName}
|
||||
onEditingSessionNameChange={setEditingSessionName}
|
||||
onToggleWorkspace={toggleWorkspace}
|
||||
onToggleWorkspaceStar={toggleWorkspaceStar}
|
||||
onStartWorkspaceRename={startWorkspaceRename}
|
||||
onCancelWorkspaceRename={cancelWorkspaceRename}
|
||||
onSaveWorkspaceRename={saveWorkspaceRename}
|
||||
onStartSessionRename={startSessionRename}
|
||||
onCancelSessionRename={cancelSessionRename}
|
||||
onSaveSessionRename={saveSessionRename}
|
||||
onDeleteWorkspace={requestWorkspaceDelete}
|
||||
onSessionSelect={openSession}
|
||||
onSessionDelete={handleSessionDeleteRequest}
|
||||
onNewSession={openNewSession}
|
||||
<div className="flex min-h-0 flex-1 flex-col">
|
||||
<div className="min-h-0 flex-1 overflow-y-auto overscroll-contain">
|
||||
<SidebarWorkspaceList
|
||||
workspacesCount={workspaces.length}
|
||||
searchFilter={searchFilter}
|
||||
starredWorkspaces={starredWorkspaces}
|
||||
unstarredWorkspaces={unstarredWorkspaces}
|
||||
expandedWorkspaces={expandedWorkspaces}
|
||||
selectedSessionId={selectedSessionId}
|
||||
editingWorkspacePath={editingWorkspacePath}
|
||||
editingWorkspaceName={editingWorkspaceName}
|
||||
isSavingWorkspaceName={isSavingWorkspaceName}
|
||||
editingSessionId={editingSessionId}
|
||||
editingSessionName={editingSessionName}
|
||||
isSavingSessionName={isSavingSessionName}
|
||||
onEditingWorkspaceNameChange={setEditingWorkspaceName}
|
||||
onEditingSessionNameChange={setEditingSessionName}
|
||||
onToggleWorkspace={toggleWorkspace}
|
||||
onToggleWorkspaceStar={toggleWorkspaceStar}
|
||||
onStartWorkspaceRename={startWorkspaceRename}
|
||||
onCancelWorkspaceRename={cancelWorkspaceRename}
|
||||
onSaveWorkspaceRename={saveWorkspaceRename}
|
||||
onStartSessionRename={startSessionRename}
|
||||
onCancelSessionRename={cancelSessionRename}
|
||||
onSaveSessionRename={saveSessionRename}
|
||||
onDeleteWorkspace={requestWorkspaceDelete}
|
||||
onSessionSelect={openSession}
|
||||
onSessionDelete={handleSessionDeleteRequest}
|
||||
onNewSession={openNewSession}
|
||||
/>
|
||||
</div>
|
||||
<SidebarFooter
|
||||
onOpenSettings={openSettingsModal}
|
||||
onOpenVersionModal={openVersionModal}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -161,6 +181,12 @@ export function Sidebar() {
|
||||
onCancelSessionDelete={cancelSessionDelete}
|
||||
onConfirmSessionDelete={confirmSessionDelete}
|
||||
/>
|
||||
<VersionUpgradeModal isOpen={showVersionModal} onClose={closeVersionModal} />
|
||||
<Settings
|
||||
isOpen={showSettingsModal}
|
||||
onClose={closeSettingsModal}
|
||||
initialTab="agents"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
123
src/components/refactored/sidebar/view/SidebarFooter.tsx
Normal file
123
src/components/refactored/sidebar/view/SidebarFooter.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
import { ArrowUpCircle, Settings } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useVersionCheck } from '@/hooks/useVersionCheck';
|
||||
|
||||
const DISCORD_INVITE_URL = 'https://discord.gg/buxwujPNRE';
|
||||
|
||||
function DiscordIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
type SidebarFooterProps = {
|
||||
onOpenSettings: () => void;
|
||||
onOpenVersionModal: () => void;
|
||||
};
|
||||
|
||||
export default function SidebarFooter({ onOpenSettings, onOpenVersionModal }: SidebarFooterProps) {
|
||||
const { t } = useTranslation('sidebar');
|
||||
const { updateAvailable, releaseInfo, latestVersion } = useVersionCheck('siteboon', 'claudecodeui');
|
||||
|
||||
return (
|
||||
<div className="flex-shrink-0" style={{ paddingBottom: 'env(safe-area-inset-bottom, 0)' }}>
|
||||
{updateAvailable && (
|
||||
<>
|
||||
<div className="nav-divider" />
|
||||
|
||||
<div className="hidden px-2 py-1.5 md:block">
|
||||
<button
|
||||
className="group flex w-full items-center gap-2.5 rounded-lg px-2.5 py-2 text-left transition-colors hover:bg-blue-50/80 dark:hover:bg-blue-900/15"
|
||||
onClick={onOpenVersionModal}
|
||||
>
|
||||
<div className="relative flex-shrink-0">
|
||||
<ArrowUpCircle className="h-4 w-4 text-blue-500 dark:text-blue-400" />
|
||||
<span className="absolute -right-0.5 -top-0.5 h-1.5 w-1.5 animate-pulse rounded-full bg-blue-500" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<span className="block truncate text-sm font-medium text-blue-600 dark:text-blue-300">
|
||||
{releaseInfo?.title || (latestVersion ? `v${latestVersion}` : '')}
|
||||
</span>
|
||||
<span className="text-[10px] text-blue-500/70 dark:text-blue-400/60">
|
||||
{t('version.updateAvailable')}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="px-3 py-2 md:hidden">
|
||||
<button
|
||||
className="flex h-11 w-full items-center gap-3 rounded-xl border border-blue-200/60 bg-blue-50/80 px-3.5 transition-all active:scale-[0.98] dark:border-blue-700/40 dark:bg-blue-900/15"
|
||||
onClick={onOpenVersionModal}
|
||||
>
|
||||
<div className="relative flex-shrink-0">
|
||||
<ArrowUpCircle className="w-4.5 h-4.5 text-blue-500 dark:text-blue-400" />
|
||||
<span className="absolute -right-0.5 -top-0.5 h-1.5 w-1.5 animate-pulse rounded-full bg-blue-500" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1 text-left">
|
||||
<span className="block truncate text-sm font-medium text-blue-600 dark:text-blue-300">
|
||||
{releaseInfo?.title || (latestVersion ? `v${latestVersion}` : '')}
|
||||
</span>
|
||||
<span className="text-xs text-blue-500/70 dark:text-blue-400/60">
|
||||
{t('version.updateAvailable')}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="nav-divider" />
|
||||
|
||||
<div className="hidden px-2 pt-1.5 md:block">
|
||||
<a
|
||||
href={DISCORD_INVITE_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex w-full items-center gap-2 rounded-lg px-2.5 py-1.5 text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
|
||||
>
|
||||
<DiscordIcon className="h-3.5 w-3.5" />
|
||||
<span className="text-sm">{t('actions.joinCommunity')}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="hidden px-2 py-1.5 md:block">
|
||||
<button
|
||||
className="flex w-full items-center gap-2 rounded-lg px-2.5 py-1.5 text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
|
||||
onClick={onOpenSettings}
|
||||
>
|
||||
<Settings className="h-3.5 w-3.5" />
|
||||
<span className="text-sm">{t('actions.settings')}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="px-3 pt-3 md:hidden">
|
||||
<a
|
||||
href={DISCORD_INVITE_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex h-12 w-full items-center gap-3.5 rounded-xl bg-muted/40 px-4 transition-all hover:bg-muted/60 active:scale-[0.98]"
|
||||
>
|
||||
<div className="flex h-8 w-8 items-center justify-center rounded-xl bg-background/80">
|
||||
<DiscordIcon className="w-4.5 h-4.5 text-muted-foreground" />
|
||||
</div>
|
||||
<span className="text-base font-medium text-foreground">{t('actions.joinCommunity')}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="px-3 pb-20 pt-2 md:hidden">
|
||||
<button
|
||||
className="flex h-12 w-full items-center gap-3.5 rounded-xl bg-muted/40 px-4 transition-all hover:bg-muted/60 active:scale-[0.98]"
|
||||
onClick={onOpenSettings}
|
||||
>
|
||||
<div className="flex h-8 w-8 items-center justify-center rounded-xl bg-background/80">
|
||||
<Settings className="w-4.5 h-4.5 text-muted-foreground" />
|
||||
</div>
|
||||
<span className="text-base font-medium text-foreground">{t('actions.settings')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user