| import { useState } from 'react'; | |
| import { EXAMPLE_QUERIES } from '../constants'; | |
| interface QueryInputProps { | |
| onSearch: (query: string, intent?: string) => void; | |
| disabled: boolean; | |
| } | |
| export default function QueryInput({ onSearch, disabled }: QueryInputProps) { | |
| const [query, setQuery] = useState(''); | |
| const [intent, setIntent] = useState(''); | |
| const [showIntent, setShowIntent] = useState(false); | |
| function handleSubmit(e: React.FormEvent) { | |
| e.preventDefault(); | |
| const trimmed = query.trim(); | |
| if (trimmed) onSearch(trimmed, intent.trim() || undefined); | |
| } | |
| function handleExample(q: string, exIntent?: string) { | |
| setQuery(q); | |
| if (exIntent) { | |
| setIntent(exIntent); | |
| setShowIntent(true); | |
| } else { | |
| setIntent(''); | |
| setShowIntent(false); | |
| } | |
| onSearch(q, exIntent); | |
| } | |
| return ( | |
| <div style={{ marginBottom: '1.5rem' }}> | |
| <form onSubmit={handleSubmit} style={{ display: 'flex', gap: '0.5rem' }}> | |
| <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: '0.35rem' }}> | |
| <input | |
| type="text" | |
| value={query} | |
| onChange={e => setQuery(e.target.value)} | |
| disabled={disabled} | |
| placeholder={disabled ? 'Loading browser models\u2026' : 'Enter a search query\u2026'} | |
| style={{ | |
| width: '100%', | |
| padding: '0.6rem 0.9rem', | |
| fontSize: '1rem', | |
| fontFamily: 'system-ui, -apple-system, sans-serif', | |
| border: '1px solid var(--input-border)', | |
| borderRadius: '6px', | |
| background: disabled ? 'var(--bg-section)' : 'var(--bg-input)', | |
| color: disabled ? 'var(--text-muted)' : 'var(--text)', | |
| outline: 'none', | |
| transition: 'border-color 0.15s', | |
| }} | |
| onFocus={e => { if (!disabled) e.target.style.borderColor = '#4285F4'; }} | |
| onBlur={e => { e.target.style.borderColor = ''; }} | |
| /> | |
| {showIntent && ( | |
| <input | |
| type="text" | |
| value={intent} | |
| onChange={e => setIntent(e.target.value)} | |
| disabled={disabled} | |
| placeholder="Intent: background context to disambiguate (e.g. 'web page load times')" | |
| style={{ | |
| width: '100%', | |
| padding: '0.45rem 0.9rem', | |
| fontSize: '0.85rem', | |
| fontFamily: 'system-ui, -apple-system, sans-serif', | |
| border: '1px solid var(--input-border)', | |
| borderRadius: '6px', | |
| background: disabled ? 'var(--bg-section)' : 'var(--bg-input)', | |
| color: disabled ? 'var(--text-muted)' : 'var(--text-secondary)', | |
| outline: 'none', | |
| transition: 'border-color 0.15s', | |
| }} | |
| onFocus={e => { if (!disabled) e.target.style.borderColor = '#f57f17'; }} | |
| onBlur={e => { e.target.style.borderColor = ''; }} | |
| /> | |
| )} | |
| </div> | |
| <button | |
| type="submit" | |
| disabled={disabled || !query.trim()} | |
| style={{ | |
| padding: '0.6rem 1.2rem', | |
| fontSize: '1rem', | |
| fontFamily: 'system-ui, -apple-system, sans-serif', | |
| background: disabled || !query.trim() ? 'var(--border)' : '#4285F4', | |
| color: '#fff', | |
| border: 'none', | |
| borderRadius: '6px', | |
| cursor: disabled || !query.trim() ? 'not-allowed' : 'pointer', | |
| transition: 'background 0.15s', | |
| fontWeight: 600, | |
| alignSelf: 'flex-start', | |
| height: '2.5rem', | |
| }} | |
| > | |
| Search | |
| </button> | |
| </form> | |
| <div style={{ marginTop: '0.5rem', display: 'flex', gap: '0.4rem', flexWrap: 'wrap', alignItems: 'center' }}> | |
| {!showIntent && ( | |
| <button | |
| onClick={() => setShowIntent(true)} | |
| disabled={disabled} | |
| style={{ | |
| padding: '0.2rem 0.5rem', | |
| fontSize: '0.75rem', | |
| fontFamily: 'system-ui, -apple-system, sans-serif', | |
| background: 'none', | |
| color: disabled ? 'var(--text-muted)' : '#f57f17', | |
| border: '1px solid #f57f1740', | |
| borderRadius: '4px', | |
| cursor: disabled ? 'not-allowed' : 'pointer', | |
| }} | |
| > | |
| + Add intent | |
| </button> | |
| )} | |
| {showIntent && !intent.trim() && ( | |
| <button | |
| onClick={() => { setShowIntent(false); setIntent(''); }} | |
| style={{ | |
| padding: '0.2rem 0.5rem', | |
| fontSize: '0.75rem', | |
| fontFamily: 'system-ui, -apple-system, sans-serif', | |
| background: 'none', | |
| color: 'var(--text-muted)', | |
| border: '1px solid var(--border)', | |
| borderRadius: '4px', | |
| cursor: 'pointer', | |
| }} | |
| > | |
| Hide intent | |
| </button> | |
| )} | |
| <span style={{ fontSize: '0.8rem', color: 'var(--text-secondary)', fontFamily: 'system-ui, -apple-system, sans-serif' }}> | |
| Demo queries: | |
| </span> | |
| {EXAMPLE_QUERIES.map(ex => ( | |
| <button | |
| key={ex.query} | |
| onClick={() => handleExample(ex.query, ex.intent)} | |
| disabled={disabled} | |
| title={ex.intent ? `Intent: ${ex.intent}` : undefined} | |
| style={{ | |
| padding: '0.25rem 0.6rem', | |
| fontSize: '0.8rem', | |
| fontFamily: 'system-ui, -apple-system, sans-serif', | |
| background: 'var(--example-bg)', | |
| color: disabled ? 'var(--text-muted)' : '#4285F4', | |
| border: `1px solid ${ex.intent ? '#f57f1740' : 'var(--example-border)'}`, | |
| borderRadius: '4px', | |
| cursor: disabled ? 'not-allowed' : 'pointer', | |
| }} | |
| > | |
| {ex.query}{ex.intent ? ' *' : ''} | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| ); | |
| } | |