import type { ReactNode } from 'react' import { ChevronUp } from 'lucide-react' import { SettingsDropdown } from './SettingsDropdown' import type { IcLoraControlsProps } from './IcLoraSettingsControls' import type { IcLoraAudioMode } from '../hooks/use-ic-lora' // One labelled row: caption on the left, the dropdown on the right. function Row({ label, children }: { label: string; children: ReactNode }) { return (
{label} {children}
) } const triggerValue = (text: string) => ( <> {text} ) // Advanced IC-LoRA controls, in a side panel beside the prompt bar (so they don't push the // Generate button off the bottom row). Reuses the shared IcLoraControlsProps bag. export function IcLoraAdvancedPanel({ icLoraSkipStage2, onIcLoraSkipStage2Change, icLoraUseLoraInStage2, onIcLoraUseLoraInStage2Change, icLoraResolutionOptions, icLoraResolutionKey, onIcLoraResolutionKeyChange, icLoraResolutionFactor, onIcLoraResolutionFactorChange, icLoraAudioMode, onIcLoraAudioModeChange, icLoraFps, onIcLoraFpsChange, advancedIcLoraControls, }: IcLoraControlsProps) { // Advanced-only knobs. (LoRA strength is a regular control — it lives in the bottom bar.) if (!advancedIcLoraControls) return null return (
Advanced onIcLoraSkipStage2Change?.(v === 'skip')} options={[ { value: 'keep', label: 'On (two-stage)' }, { value: 'skip', label: 'Off (stage 1 only)' }, ]} trigger={triggerValue(icLoraSkipStage2 ? 'Off' : 'On')} /> {/* Always shown. Only takes effect when Stage 2 runs (Stage 2 = On); it's a no-op when Stage 2 is skipped, but kept visible for discoverability. */} onIcLoraUseLoraInStage2Change?.(v === 'on')} options={[ { value: 'off', label: 'Off (refine from prompt)' }, { value: 'on', label: 'On (keep effect, source res)' }, ]} trigger={triggerValue(icLoraUseLoraInStage2 ? 'On' : 'Off')} /> {!icLoraSkipStage2 && icLoraUseLoraInStage2 && (icLoraResolutionOptions?.length ?? 0) > 1 && ( onIcLoraResolutionKeyChange?.(v)} options={icLoraResolutionOptions!.map((o) => ({ value: o.key, label: o.label }))} trigger={triggerValue( (icLoraResolutionOptions!.find((o) => o.key === icLoraResolutionKey)?.label ?? 'Original').split(' ')[0], )} /> )} {icLoraSkipStage2 && ( onIcLoraResolutionFactorChange?.(parseFloat(v))} options={[ // 0 is the "source dimensions" sentinel — output matches the input // resolution and the multiplier is ignored (see ic_lora_handler). { value: '0', label: 'Source dimensions' }, { value: '1', label: '1.00 (half)' }, { value: '1.25', label: '1.25' }, { value: '1.5', label: '1.50' }, { value: '1.75', label: '1.75' }, { value: '2', label: '2.00 (native)' }, ]} trigger={triggerValue( icLoraResolutionFactor === 0 ? 'Source' : `×${(icLoraResolutionFactor ?? 2.0).toFixed(2)}`, )} /> )} onIcLoraAudioModeChange?.(v as IcLoraAudioMode)} options={[ { value: 'generated', label: 'Generated' }, { value: 'source', label: 'Source' }, { value: 'off', label: 'Off' }, ]} trigger={triggerValue((icLoraAudioMode ?? 'generated').replace(/^\w/, (c: string) => c.toUpperCase()))} /> onIcLoraFpsChange?.(v === 'source' ? null : parseFloat(v))} options={[ { value: 'source', label: 'Source' }, { value: '24', label: '24 fps' }, { value: '16', label: '16 fps' }, { value: '12', label: '12 fps' }, { value: '8', label: '8 fps' }, ]} trigger={triggerValue(icLoraFps == null ? 'Src' : String(icLoraFps))} />
) }