Files
hapi/web/src/components/NewSession/DirectorySection.tsx
T

88 lines
3.8 KiB
TypeScript

import type { KeyboardEvent as ReactKeyboardEvent } from 'react'
import type { Suggestion } from '@/hooks/useActiveSuggestions'
import { Autocomplete } from '@/components/ChatInput/Autocomplete'
import { FloatingOverlay } from '@/components/ChatInput/FloatingOverlay'
import { useTranslation } from '@/lib/use-translation'
export function DirectorySection(props: {
directory: string
suggestions: readonly Suggestion[]
selectedIndex: number
isDisabled: boolean
recentPaths: string[]
statusMessage?: string | null
statusTone?: 'warning' | 'error' | null
onDirectoryChange: (value: string) => void
onDirectoryFocus: () => void
onDirectoryBlur: () => void
onDirectoryKeyDown: (event: ReactKeyboardEvent<HTMLInputElement>) => void
onSuggestionSelect: (index: number) => void
onPathClick: (path: string) => void
}) {
const { t } = useTranslation()
return (
<div className="flex flex-col gap-1.5 px-3 py-3">
<label className="text-xs font-medium text-[var(--app-hint)]">
{t('newSession.directory')}
</label>
<div className="relative">
<input
type="text"
placeholder={t('newSession.placeholder')}
value={props.directory}
onChange={(event) => props.onDirectoryChange(event.target.value)}
onKeyDown={props.onDirectoryKeyDown}
onFocus={props.onDirectoryFocus}
onBlur={props.onDirectoryBlur}
disabled={props.isDisabled}
className="w-full rounded-md border border-[var(--app-border)] bg-[var(--app-bg)] p-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--app-link)] disabled:opacity-50"
/>
{props.suggestions.length > 0 && (
<div className="absolute top-full left-0 right-0 z-10 mt-1">
<FloatingOverlay maxHeight={200}>
<Autocomplete
suggestions={props.suggestions}
selectedIndex={props.selectedIndex}
onSelect={props.onSuggestionSelect}
/>
</FloatingOverlay>
</div>
)}
</div>
{props.recentPaths.length > 0 && (
<div className="flex flex-col gap-1 mt-1">
<span className="text-xs text-[var(--app-hint)]">{t('newSession.recent')}:</span>
<div className="flex flex-wrap gap-1">
{props.recentPaths.map((path) => (
<button
key={path}
type="button"
onClick={() => props.onPathClick(path)}
disabled={props.isDisabled}
className="rounded bg-[var(--app-subtle-bg)] px-2 py-1 text-xs text-[var(--app-fg)] hover:bg-[var(--app-secondary-bg)] transition-colors truncate max-w-[200px] disabled:opacity-50"
title={path}
>
{path}
</button>
))}
</div>
</div>
)}
{props.statusMessage ? (
<div
className={`mt-1 rounded-md px-2 py-1 text-xs ${
props.statusTone === 'error'
? 'bg-red-50 text-red-600 dark:bg-red-900/20 dark:text-red-400'
: 'bg-amber-500/10 text-[var(--app-hint)]'
}`}
>
{props.statusMessage}
</div>
) : null}
</div>
)
}