mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
feat(desktop): add BrowserAddressBar component
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
25ea37bb3d
commit
bdfedcd2e7
37
desktop/src/components/browser/BrowserAddressBar.test.tsx
Normal file
37
desktop/src/components/browser/BrowserAddressBar.test.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { fireEvent, render, screen } from '@testing-library/react'
|
||||||
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
import '@testing-library/jest-dom'
|
||||||
|
import { BrowserAddressBar } from './BrowserAddressBar'
|
||||||
|
|
||||||
|
const baseProps = {
|
||||||
|
url: 'http://localhost:5173/', canGoBack: false, canGoForward: false,
|
||||||
|
onNavigate: vi.fn(), onBack: vi.fn(), onForward: vi.fn(), onReload: vi.fn(),
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('BrowserAddressBar', () => {
|
||||||
|
it('shows the current url in the input', () => {
|
||||||
|
render(<BrowserAddressBar {...baseProps} />)
|
||||||
|
expect(screen.getByRole('textbox')).toHaveValue('http://localhost:5173/')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('submits the edited url via onNavigate', () => {
|
||||||
|
const onNavigate = vi.fn()
|
||||||
|
render(<BrowserAddressBar {...baseProps} onNavigate={onNavigate} />)
|
||||||
|
const input = screen.getByRole('textbox')
|
||||||
|
fireEvent.change(input, { target: { value: 'http://localhost:3000/x' } })
|
||||||
|
fireEvent.submit(input.closest('form')!)
|
||||||
|
expect(onNavigate).toHaveBeenCalledWith('http://localhost:3000/x')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('disables back when cannot go back', () => {
|
||||||
|
render(<BrowserAddressBar {...baseProps} canGoBack={false} />)
|
||||||
|
expect(screen.getByLabelText('后退')).toBeDisabled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('enables back and fires onBack when canGoBack', () => {
|
||||||
|
const onBack = vi.fn()
|
||||||
|
render(<BrowserAddressBar {...baseProps} canGoBack onBack={onBack} />)
|
||||||
|
fireEvent.click(screen.getByLabelText('后退'))
|
||||||
|
expect(onBack).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
33
desktop/src/components/browser/BrowserAddressBar.tsx
Normal file
33
desktop/src/components/browser/BrowserAddressBar.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { ArrowLeft, ArrowRight, RotateCw } from 'lucide-react'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
url: string
|
||||||
|
canGoBack: boolean
|
||||||
|
canGoForward: boolean
|
||||||
|
onNavigate: (url: string) => void
|
||||||
|
onBack: () => void
|
||||||
|
onForward: () => void
|
||||||
|
onReload: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BrowserAddressBar({ url, canGoBack, canGoForward, onNavigate, onBack, onForward, onReload }: Props) {
|
||||||
|
const [draft, setDraft] = useState(url)
|
||||||
|
useEffect(() => { setDraft(url) }, [url])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-1 px-2 py-1.5 border-b border-[var(--color-border)]">
|
||||||
|
<button aria-label="后退" disabled={!canGoBack} onClick={onBack} className="p-1 disabled:opacity-40"><ArrowLeft size={16} /></button>
|
||||||
|
<button aria-label="前进" disabled={!canGoForward} onClick={onForward} className="p-1 disabled:opacity-40"><ArrowRight size={16} /></button>
|
||||||
|
<button aria-label="刷新" onClick={onReload} className="p-1"><RotateCw size={16} /></button>
|
||||||
|
<form className="flex-1" onSubmit={(e) => { e.preventDefault(); onNavigate(draft.trim()) }}>
|
||||||
|
<input
|
||||||
|
className="w-full rounded-md bg-[var(--color-surface)] px-2 py-1 text-xs text-[var(--color-text-primary)]"
|
||||||
|
value={draft}
|
||||||
|
onChange={(e) => setDraft(e.target.value)}
|
||||||
|
spellCheck={false}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user