| 1 | import { useId } from "react"; |
| 2 | import { useT } from "../lib/i18n"; |
| 3 | import { imageInputHardBlocked, imageInputState, type ImageInputMode } from "../lib/providerImageInput"; |
| 4 | import type { ProviderModelCapabilityView } from "../lib/types"; |
| 5 | |
| 6 | export function ModelImageInputControl({ model, mode, capability, baseURL, fallback, disabled, onChange }: { |
| 7 | model: string; mode: ImageInputMode; capability?: ProviderModelCapabilityView; |
| 8 | baseURL?: string; fallback?: string; disabled: boolean; onChange?: (mode: ImageInputMode) => void; |
| 9 | }) { |
| 10 | const t = useT(); |
| 11 | const groupName = useId(); |
| 12 | const blocked = imageInputHardBlocked(baseURL, model, capability); |
| 13 | const state = blocked ? "unsupported" : imageInputState(mode, capability, fallback); |
| 14 | const status = blocked ? t("settings.imageInputProtocolBadge") |
| 15 | : mode === "on" ? t("settings.imageInputManualOn") |
| 16 | : mode === "off" ? t("settings.imageInputManualOff") |
| 17 | : capability?.automaticSource === "legacy" ? t("settings.imageInputLegacy") |
| 18 | : state === "supported" ? t("settings.imageInputSupported") |
| 19 | : state === "unsupported" ? t("settings.imageInputUnsupported") : t("settings.imageInputUnknown"); |
| 20 | const statusTone = blocked ? "restricted" : mode === "on" || state === "supported" ? "supported" |
| 21 | : mode === "off" || state === "unsupported" ? "unsupported" : "unknown"; |
| 22 | const options: Array<{ value: ImageInputMode; label: string }> = [ |
| 23 | { value: "auto", label: t("settings.imageInputAuto") }, |
| 24 | { value: "on", label: t("settings.imageInputOn") }, |
| 25 | { value: "off", label: t("settings.imageInputOff") }, |
| 26 | ]; |
| 27 | return <div className="provider-image-input"> |
| 28 | <div className="provider-image-input__head"> |
| 29 | <span className="provider-image-input__label">{t("settings.imageInputLabel")}</span> |
| 30 | <div className="set-seg provider-image-input__modes" role="radiogroup" aria-label={t("settings.imageInputModeAria", { model })}> |
| 31 | {options.map((option) => { |
| 32 | const optionDisabled = disabled || !onChange || (blocked && option.value === "on"); |
| 33 | return <label key={option.value} className={`set-seg__btn provider-image-input__mode${mode === option.value ? " set-seg__btn--on" : ""}${optionDisabled ? " provider-image-input__mode--disabled" : ""}`}> |
| 34 | <input className="sr-only" type="radio" name={groupName} value={option.value} checked={mode === option.value} |
| 35 | disabled={optionDisabled} onChange={() => onChange?.(option.value)} /> |
| 36 | <span>{option.label}</span> |
| 37 | </label>; |
| 38 | })} |
| 39 | </div> |
| 40 | </div> |
| 41 | <div className="provider-image-input__meta"> |
| 42 | <span className={`provider-image-input__status provider-image-input__status--${statusTone}`}> |
| 43 | <span className="provider-image-input__status-dot" aria-hidden="true" />{status} |
| 44 | </span> |
| 45 | {(blocked || (mode === "auto" && state === "unknown")) && ( |
| 46 | <span className="provider-image-input__detail">{blocked ? t("settings.imageInputProtocolBlocked") : t("settings.imageInputUnknownHint")}</span> |
| 47 | )} |
| 48 | </div> |
| 49 | </div>; |
| 50 | } |
| 51 |