import { useId, useState } from 'react' import { useTranslation } from '../../i18n/TranslationContext' import { fs } from '../shared/DialogShell' import { INPUT, LABEL } from '../shared/dialogParts' export interface RoutingDefaults { routing_base_url?: string valhalla_base_url?: string } interface RoutingFieldsProps { defaults: RoutingDefaults onSave: (patch: RoutingDefaults) => Promise onReset: (key: keyof RoutingDefaults) => Promise /** * The phone's hint look. A caller that passes it keeps the phone's own field * styling as well; without it the fields take the desktop editors' look * (eyebrow label, boxed input, faint hint). */ hintClassName?: string } const ROUTERS = [ { key: 'routing_base_url', label: 'settings.routingBase', hint: 'settings.routingBaseHint', placeholder: 'https://osrm.example.org' }, { key: 'valhalla_base_url', label: 'settings.valhallaBase', hint: 'settings.valhallaBaseHint', placeholder: 'https://valhalla.example.org' }, ] as const // The phone screen's look, unchanged: MAdminDefaultUserSettings passes its own hint class. const PHONE = { wrap: 'min-w-0 space-y-1.5', head: 'flex flex-wrap items-baseline gap-x-2 gap-y-1', label: 'text-body font-medium text-content-secondary', reset: 'text-caption text-content-muted underline disabled:opacity-50', input: 'min-h-11 w-full min-w-0 rounded-lg border border-edge bg-surface-input px-3 py-2 text-body text-content focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent disabled:opacity-50', } // The desktop editors' look (shared/dialogParts): an eyebrow over a boxed field. const DESKTOP = { wrap: 'min-w-0', head: 'flex flex-wrap items-baseline justify-between gap-x-2', label: LABEL, reset: 'mb-[5px] rounded-full font-medium text-content-muted underline-offset-2 hover:text-content hover:underline disabled:opacity-50', input: INPUT, } function RoutingUrlField({ router, defaults, onSave, onReset, hintClassName }: RoutingFieldsProps & { router: typeof ROUTERS[number] }) { const { t } = useTranslation() const id = useId() const [draft, setDraft] = useState(null) const [saving, setSaving] = useState(false) const phone = hintClassName !== undefined const look = phone ? PHONE : DESKTOP const saved = defaults[router.key] ?? '' const commit = async () => { if (draft === null) return const value = draft.trim() if (value === saved) { setDraft(null); return } setSaving(true) try { await onSave({ [router.key]: value }) } finally { setDraft(null); setSaving(false) } } const reset = async () => { setSaving(true) try { await onReset(router.key) } finally { setDraft(null); setSaving(false) } } return (
{defaults[router.key] !== undefined && ( )}
setDraft(e.target.value)} onBlur={commit} onKeyDown={e => { if (e.key === 'Enter') e.currentTarget.blur() }} placeholder={router.placeholder} spellCheck={false} autoComplete="off" autoCapitalize="none" aria-describedby={`${id}-hint`} className={look.input} /> {phone ?

{t(router.hint)}

:

{t(router.hint)}

}
) } export default function RoutingInstanceFields(props: RoutingFieldsProps) { const phone = props.hintClassName !== undefined return
{ROUTERS.map(router => )}
}