resizes the col widths on app resize

This commit is contained in:
2026-06-16 08:11:10 +02:00
parent 299ae17d80
commit bd466e84a8
3 changed files with 28 additions and 24 deletions

View File

@@ -130,12 +130,22 @@ export function App(): React.ReactElement {
toast('Discarded changes', path)
}
const [gitW, setGitW] = useState(() => loadNum('helder.gitW', 232))
const [treeW, setTreeW] = useState(() => loadNum('helder.treeW', 244))
const [rightW, setRightW] = useState(() => loadNum('helder.rightW', 444))
useEffect(() => saveNum('helder.gitW', gitW), [gitW])
useEffect(() => saveNum('helder.treeW', treeW), [treeW])
useEffect(() => saveNum('helder.rightW', rightW), [rightW])
// Columns are proportional — Source Control 10%, Explorer 10%, Editor 40%
// (flex:1, takes the remainder), Right column 40% — and re-apply on resize.
// Dragging a splitter still adjusts them until the next window resize.
const [gitW, setGitW] = useState(() => Math.round(window.innerWidth * 0.1))
const [treeW, setTreeW] = useState(() => Math.round(window.innerWidth * 0.1))
const [rightW, setRightW] = useState(() => Math.round(window.innerWidth * 0.4))
useEffect(() => {
function applyProportions(): void {
const w = window.innerWidth
setGitW(Math.round(w * 0.1))
setTreeW(Math.round(w * 0.1))
setRightW(Math.round(w * 0.4))
}
window.addEventListener('resize', applyProportions)
return () => window.removeEventListener('resize', applyProportions)
}, [])
// Seed explorer expansion from the tree's `open` flags once per opened project.
const seededRoot = useRef<string | null | undefined>(undefined)
@@ -373,7 +383,11 @@ export function App(): React.ReactElement {
cursor={cursor} selection={selection} setCursor={setCursor} setSelection={setSelection}
bufferText={bufferText(active)} onEdit={onEdit} />
</div>
<Splitter onDelta={(dx) => setRightW((w) => clamp(w - dx, 280, 780))} />
<Splitter onDelta={(dx) => setRightW((w) => {
// grow until the editor would drop below ~280px (rather than a fixed cap)
const max = Math.max(280, window.innerWidth - gitW - treeW - 280)
return clamp(w - dx, 280, max)
})} />
{/* keyed by root so the PTYs respawn in the new cwd when the project switches */}
{proj.ready && <RightColumn key={proj.root ?? 'none'} width={rightW} />}

View File

@@ -114,13 +114,9 @@ export function GitPanel({ branch, changes, staged, committed, commitMsg, setCom
<div className="commit-box">
<textarea className="commit-input" rows={1} value={commitMsg} spellCheck={false}
placeholder="Message (⌘↵ to commit)"
placeholder={stagedList.length ? `Message — ⇧↵ to commit ${stagedList.length}` : 'Message (stage a file to commit)'}
onChange={(e) => setCommitMsg(e.target.value)}
onKeyDown={(e) => { if ((e.metaKey || e.ctrlKey) && e.key === 'Enter' && canCommit) { e.preventDefault(); onCommit() } }} />
<button className="commit-btn" disabled={!canCommit} onClick={onCommit}
title={canCommit ? 'Commit staged changes' : 'Stage files and write a message to commit'}>
{Icon.check()}<span>Commit{stagedList.length ? ' ' + stagedList.length : ''}</span>
</button>
onKeyDown={(e) => { if (e.key === 'Enter' && (e.shiftKey || e.metaKey || e.ctrlKey) && canCommit) { e.preventDefault(); onCommit() } }} />
</div>
<div className="git-body">

View File

@@ -65,25 +65,19 @@ describe('Pass on to Agent', () => {
})
describe('Stage + commit', () => {
it('stages a file, commits with a message, and toasts', async () => {
it('stages a file and commits via Shift+Enter (no commit button)', async () => {
const c = renderApp()
const row = await waitFor(() => {
const r = find(c, '.git-row', 'UserController.php')
if (!r) throw new Error('git not ready')
return r
})
const stageBtn = row.querySelector<HTMLButtonElement>('button[title="Stage changes"]')!
fireEvent.click(stageBtn)
// commit button reflects the staged count once a file is staged
await waitFor(() => expect(find(c, '.commit-btn', 'Commit')?.textContent).toMatch(/Commit\s*\d/))
fireEvent.click(row.querySelector<HTMLButtonElement>('button[title="Stage changes"]')!)
// the commit button is intentionally gone — committing is keyboard-only
expect(c.querySelector('.commit-btn')).toBeNull()
const msg = c.querySelector<HTMLTextAreaElement>('.commit-input')!
fireEvent.change(msg, { target: { value: 'wire up balance' } })
const commitBtn = find(c, '.commit-btn', 'Commit') as HTMLButtonElement
expect(commitBtn.disabled).toBe(false)
fireEvent.click(commitBtn)
fireEvent.keyDown(msg, { key: 'Enter', shiftKey: true })
await waitFor(() => expect(find(c, '.toast', 'Committed')).toBeTruthy())
})
})