feat: overhaul branch modal design

This commit is contained in:
Sam Chau
2024-09-08 02:25:45 +09:30
parent 15cd66a775
commit 30bc238105
2 changed files with 204 additions and 168 deletions

View File

@@ -13,7 +13,8 @@ import {
GitBranchPlus,
ArrowRightCircle,
Loader,
CloudUpload
CloudUpload,
Search
} from 'lucide-react';
import Tooltip from '../ui/Tooltip';
import Alert from '../ui/Alert';
@@ -27,6 +28,8 @@ const SettingsBranchModal = ({
isDevMode
}) => {
const [branches, setBranches] = useState([]);
const [filteredBranches, setFilteredBranches] = useState([]);
const [searchTerm, setSearchTerm] = useState('');
const [branchOffMode, setBranchOffMode] = useState(null);
const [newBranchName, setNewBranchName] = useState('');
const [validBranchName, setValidBranchName] = useState(true);
@@ -40,6 +43,14 @@ const SettingsBranchModal = ({
}
}, [isOpen]);
useEffect(() => {
setFilteredBranches(
branches.filter(branch =>
branch.name.toLowerCase().includes(searchTerm.toLowerCase())
)
);
}, [branches, searchTerm]);
const fetchBranches = async () => {
try {
const response = await getBranches();
@@ -59,6 +70,7 @@ const SettingsBranchModal = ({
setValidBranchName(true);
setBranchToDelete(null);
setLoadingAction('');
setSearchTerm('');
};
const handleCheckout = async branchName => {
@@ -200,171 +212,191 @@ const SettingsBranchModal = ({
};
return (
<Modal isOpen={isOpen} onClose={onClose} title='Manage Git Branches'>
<div className='space-y-6 text-sm'>
<div className='bg-gray-800 rounded-lg p-4 shadow-inner'>
<h3 className='text-lg font-semibold mb-3 text-gray-100 border-b border-gray-700 pb-2'>
Branches
</h3>
<ul className='space-y-3'>
{branches.map((branch, index) => (
<li
key={index}
className={`flex items-center justify-between p-3 rounded-md transition-all duration-200 ${
branch.name === currentBranch
? 'bg-blue-900/30 border border-blue-500 shadow-md'
: 'bg-gray-700 hover:bg-gray-650'
}`}>
<div className='flex items-center space-x-3'>
<div
className={`w-2 h-2 rounded-full ${
branch.name === currentBranch
? 'bg-blue-400'
: 'bg-gray-400'
}`}></div>
<span
className={`font-medium ${
branch.name === currentBranch
? 'text-blue-200'
: 'text-gray-200'
}`}>
{branch.name || 'Unknown Branch'}
</span>
<span className='text-xs text-gray-400'>
{branch.isLocal && !branch.isRemote
? '(Local)'
: !branch.isLocal && branch.isRemote
? '(Remote)'
: '(Local & Remote)'}
</span>
</div>
<div className='flex items-center space-x-2'>
{branch.name !== currentBranch && (
<Tooltip content='Checkout'>
<button
onClick={() =>
handleCheckout(branch.name)
}
className='p-1.5 bg-blue-500 text-white rounded-md hover:bg-blue-600 hover:scale-105 transition-all duration-200 shadow-sm'
disabled={
loadingAction ===
`checkout-${branch.name}`
}>
{loadingAction ===
`checkout-${branch.name}` ? (
<Loader
size={16}
className='animate-spin'
/>
) : (
<ArrowRightCircle
size={16}
/>
)}
</button>
</Tooltip>
)}
<Tooltip content='Branch Off'>
<button
onClick={() =>
handleBranchOffClick(
branch.name
)
}
className='p-1.5 bg-green-500 text-white rounded-md hover:bg-green-600 hover:scale-105 transition-all duration-200 shadow-sm'
disabled={
loadingAction === 'branchOff'
}>
{loadingAction === 'branchOff' ? (
<Loader
size={16}
className='animate-spin'
/>
) : (
<GitBranchPlus size={16} />
)}
</button>
</Tooltip>
{branch.isLocal &&
!branch.isRemote &&
isDevMode && (
<Tooltip content='Push to Remote'>
<button
onClick={() =>
handlePushToRemote(
branch.name
)
}
className='p-1.5 bg-purple-500 text-white rounded-md hover:bg-purple-600 hover:scale-105 transition-all duration-200 shadow-sm'
disabled={
loadingAction ===
`push-${branch.name}`
}>
{loadingAction ===
`push-${branch.name}` ? (
<Loader
size={16}
className='animate-spin'
/>
) : (
<CloudUpload
size={16}
/>
)}
</button>
</Tooltip>
)}
{(branch.isLocal ||
(branch.isRemote && isDevMode)) &&
branch.name !== currentBranch &&
branch.name.toLowerCase() !==
'stable' && (
<Tooltip content='Delete'>
<button
onClick={() =>
confirmDeleteBranch(
branch.name
)
}
className='p-1.5 bg-red-500 text-white rounded-md hover:bg-red-600 hover:scale-105 transition-all duration-200 shadow-sm'
disabled={
loadingAction ===
`delete-${branch.name}`
}>
{loadingAction ===
`delete-${branch.name}` ? (
<Loader
size={16}
className='animate-spin'
/>
) : (
<Trash2 size={16} />
)}
</button>
</Tooltip>
)}
<Modal
isOpen={isOpen}
onClose={onClose}
title='Manage Git Branches'
size='4xl'>
<div className='space-y-6'>
<div className='bg-gray-100 dark:bg-gray-800 rounded-lg p-4'>
<div className='relative mb-4'>
<input
type='text'
placeholder='Search branches...'
value={searchTerm}
onChange={e => setSearchTerm(e.target.value)}
className='w-full pl-10 pr-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400'
/>
<Search className='absolute left-3 top-2.5 h-5 w-5 text-gray-400 dark:text-gray-500' />
</div>
{branch.isRemote && (
<Tooltip content='View on GitHub'>
<div className='overflow-visible'>
<ul className='space-y-2'>
{filteredBranches.map((branch, index) => (
<li
key={index}
className={`flex items-center justify-between p-4 rounded-lg transition-colors ${
branch.name === currentBranch
? 'bg-blue-100 dark:bg-blue-900/50'
: 'hover:bg-gray-200 dark:hover:bg-gray-700'
}`}>
<div className='flex items-center space-x-3'>
<div
className={`w-3 h-3 rounded-full ${
branch.name === currentBranch
? 'bg-blue-500'
: 'bg-gray-400 dark:bg-gray-500'
}`}></div>
<span
className={`font-medium ${
branch.name === currentBranch
? 'text-blue-700 dark:text-blue-300'
: 'text-gray-700 dark:text-gray-200'
}`}>
{branch.name || 'Unknown Branch'}
</span>
<span className='text-xs text-gray-500 dark:text-gray-400'>
{branch.isLocal && !branch.isRemote
? '(Local)'
: !branch.isLocal &&
branch.isRemote
? '(Remote)'
: '(Local & Remote)'}
</span>
</div>
<div className='flex items-center space-x-2'>
{/* Keep existing buttons with updated styles */}
{branch.name !== currentBranch && (
<Tooltip content='Checkout'>
<button
onClick={() =>
handleCheckout(
branch.name
)
}
className='p-3 text-blue-600 dark:text-blue-400 hover:bg-blue-200 dark:hover:bg-blue-800 rounded-full transition-colors'
disabled={
loadingAction ===
`checkout-${branch.name}`
}>
{loadingAction ===
`checkout-${branch.name}` ? (
<Loader
size={20}
className='animate-spin'
/>
) : (
<ArrowRightCircle
size={20}
/>
)}
</button>
</Tooltip>
)}
<Tooltip content='Branch Off'>
<button
onClick={() =>
handleOpenInGitHub(
handleBranchOffClick(
branch.name
)
}
className='p-1.5 bg-gray-600 text-white rounded-md hover:bg-gray-500 hover:scale-105 transition-all duration-200 shadow-sm'>
<ExternalLink size={16} />
className='p-3 text-green-600 dark:text-green-400 hover:bg-green-200 dark:hover:bg-green-800 rounded-full transition-colors'
disabled={
loadingAction ===
'branchOff'
}>
{loadingAction ===
'branchOff' ? (
<Loader
size={20}
className='animate-spin'
/>
) : (
<GitBranchPlus size={20} />
)}
</button>
</Tooltip>
)}
</div>
</li>
))}
</ul>
{branch.isLocal &&
!branch.isRemote &&
isDevMode && (
<Tooltip content='Push to Remote'>
<button
onClick={() =>
handlePushToRemote(
branch.name
)
}
className='p-3 text-purple-600 dark:text-purple-400 hover:bg-purple-200 dark:hover:bg-purple-800 rounded-full transition-colors'
disabled={
loadingAction ===
`push-${branch.name}`
}>
{loadingAction ===
`push-${branch.name}` ? (
<Loader
size={20}
className='animate-spin'
/>
) : (
<CloudUpload
size={20}
/>
)}
</button>
</Tooltip>
)}
{(branch.isLocal ||
(branch.isRemote && isDevMode)) &&
branch.name !== currentBranch &&
branch.name.toLowerCase() !==
'stable' && (
<Tooltip content='Delete'>
<button
onClick={() =>
confirmDeleteBranch(
branch.name
)
}
className='p-3 text-red-600 dark:text-red-400 hover:bg-red-200 dark:hover:bg-red-800 rounded-full transition-colors'
disabled={
loadingAction ===
`delete-${branch.name}`
}>
{loadingAction ===
`delete-${branch.name}` ? (
<Loader
size={20}
className='animate-spin'
/>
) : (
<Trash2 size={20} />
)}
</button>
</Tooltip>
)}
{branch.isRemote && (
<Tooltip content='View on GitHub'>
<button
onClick={() =>
handleOpenInGitHub(
branch.name
)
}
className='p-3 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-full transition-colors'>
<ExternalLink size={20} />
</button>
</Tooltip>
)}
</div>
</li>
))}
</ul>
</div>
</div>
{branchOffMode && (
<div className='bg-gray-700 p-4 rounded-lg shadow-md'>
<h4 className='text-sm font-semibold mb-2 text-gray-200'>
<div className='bg-gray-100 dark:bg-gray-800 p-4 rounded-lg shadow-md'>
<h4 className='text-lg font-semibold mb-2 text-gray-800 dark:text-gray-200'>
Create New Branch
</h4>
<div className='flex items-center space-x-2'>
@@ -375,11 +407,11 @@ const SettingsBranchModal = ({
validateBranchName(e.target.value)
}
placeholder={`New branch from ${branchOffMode}`}
className={`flex-grow p-2 border rounded bg-gray-800 text-gray-300 focus:ring-2 focus:ring-blue-500 transition-all ${
className={`flex-grow p-2 rounded-lg border ${
!validBranchName
? 'border-red-500'
: 'border-gray-600'
}`}
? 'border-red-500 dark:border-red-400'
: 'border-gray-300 dark:border-gray-600'
} bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400`}
/>
<button
onClick={handleBranchOff}
@@ -388,7 +420,7 @@ const SettingsBranchModal = ({
!validBranchName ||
loadingAction === 'branchOff'
}
className='px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors text-sm font-medium shadow-sm'>
className='px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors text-sm font-medium shadow-sm disabled:opacity-50'>
{loadingAction === 'branchOff'
? 'Creating...'
: 'Create'}
@@ -396,14 +428,13 @@ const SettingsBranchModal = ({
</div>
</div>
)}
{branchToDelete && (
<div className='bg-red-900/30 border border-red-500 rounded-lg p-4 mt-4 text-sm text-gray-200'>
<div className='bg-red-100 dark:bg-red-900/30 border border-red-300 dark:border-red-700 rounded-lg p-4 text-sm text-red-800 dark:text-red-200'>
<p className='mb-3'>
Are you sure you want to delete the branch{' '}
<strong className='text-red-300'>
{branchToDelete}
</strong>
? This action cannot be undone.
<strong>{branchToDelete}</strong>? This action
cannot be undone.
</p>
<div className='flex space-x-4'>
<button
@@ -411,14 +442,14 @@ const SettingsBranchModal = ({
disabled={
loadingAction === `delete-${branchToDelete}`
}
className='px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition-colors text-sm font-medium shadow-sm'>
className='px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors text-sm font-medium shadow-sm disabled:opacity-50'>
{loadingAction === `delete-${branchToDelete}`
? 'Deleting...'
: 'Confirm Delete'}
</button>
<button
onClick={() => setBranchToDelete(null)}
className='px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600 transition-colors text-sm font-medium shadow-sm'>
className='px-4 py-2 bg-gray-300 dark:bg-gray-600 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-400 dark:hover:bg-gray-500 transition-colors text-sm font-medium shadow-sm'>
Cancel
</button>
</div>

View File

@@ -593,7 +593,11 @@ const SettingsPage = () => {
<div className='max-w-4xl mx-auto mt-8 p-6 bg-gray-800 rounded-lg shadow-lg'>
<h2 className='text-xl font-bold mb-4 text-gray-100'>
Git Repository Settings
<span className='ml-4 text-sm text-gray-300 mb-4'>
{isDevMode ? 'Dev Mode: Enabled' : 'Dev Mode: Disabled'}
</span>
</h2>
{!settings && (
<button
onClick={() => setShowLinkModal(true)}
@@ -862,6 +866,7 @@ const SettingsPage = () => {
repoUrl={settings.gitRepo}
currentBranch={status.branch}
onBranchChange={fetchGitStatus}
isDevMode={isDevMode}
/>
)}
{showDiffModal && currentChange && (