import React, { useMemo, useState } from 'react'; import { useAppTranslation } from '@features/localization/renderer'; import { useTheme } from '@renderer/hooks/useTheme'; import { cn } from '@renderer/lib/utils'; import { ChevronRight, Settings2 } from 'lucide-react'; interface OptionalSettingsSectionProps { title: string; description: string; summary?: string[]; defaultOpen?: boolean; className?: string; onOpenChange?: (open: boolean) => void; children: React.ReactNode; } const SUMMARY_PREFIXES_TO_STRIP = ['Provider:', 'Model:', 'Effort:', 'Worktree:']; const MODEL_LABEL_OVERRIDES: Array<[RegExp, string]> = [ [/claude[-\s]?opus[-\s]?4[-\s]?8/i, 'Opus 4.8'], [/claude[-\s]?opus[-\s]?4[-\s]?7/i, 'Opus 4.7'], [/claude[-\s]?opus[-\s]?4[-\s]?6/i, 'Opus 4.6'], [/claude[-\s]?opus[-\s]?4[-\s]?5/i, 'Opus 4.5'], [/claude[-\s]?sonnet[-\s]?4[-\s]?6/i, 'Sonnet 4.6'], [/claude[-\s]?sonnet[-\s]?4[-\s]?5/i, 'Sonnet 4.5'], [/claude[-\s]?haiku[-\s]?4[-\s]?5/i, 'Haiku 4.5'], ]; const SUMMARY_CHIP_REWRITES: Array<[RegExp, string]> = [ [/^Auto-approve tools$/i, 'Tools auto'], [/^Anthropic limited to 200K context$/i, '200K limit'], ]; const toCompactChip = (value: string): string => { let chip = value.trim(); for (const prefix of SUMMARY_PREFIXES_TO_STRIP) { if (chip.toLowerCase().startsWith(prefix.toLowerCase())) { chip = chip.slice(prefix.length).trim(); break; } } for (const [pattern, label] of MODEL_LABEL_OVERRIDES) { if (pattern.test(chip)) { chip = label; break; } } for (const [pattern, label] of SUMMARY_CHIP_REWRITES) { if (pattern.test(chip)) { chip = label; break; } } if (chip.length > 28) { chip = `${chip.slice(0, 27)}…`; } return chip; }; export const OptionalSettingsSection = ({ title, description, summary = [], defaultOpen = false, className, onOpenChange, children, }: OptionalSettingsSectionProps): React.JSX.Element => { const { t } = useAppTranslation('team'); const [isOpen, setIsOpen] = useState(defaultOpen); const { isLight } = useTheme(); const chips = useMemo(() => { const result: string[] = []; const seen = new Set(); for (const raw of summary) { const chip = toCompactChip(raw); if (!chip) continue; const key = chip.toLowerCase(); if (seen.has(key)) continue; seen.add(key); result.push(chip); if (result.length >= 3) break; } return result; }, [summary]); const overflowCount = useMemo(() => { const total = summary.map((value) => value.trim()).filter(Boolean).length; return Math.max(0, total - chips.length); }, [summary, chips.length]); const containerBackground = isLight ? 'color-mix(in srgb, var(--color-surface-overlay) 30%, white 70%)' : 'var(--color-surface-overlay)'; const contentBackground = isLight ? 'color-mix(in srgb, var(--color-surface-overlay) 52%, white 48%)' : 'color-mix(in srgb, var(--color-surface-raised) 88%, black 12%)'; const headerTitleColor = isLight ? 'var(--color-text)' : 'color-mix(in srgb, var(--color-text) 82%, white 18%)'; const headerMutedColor = isLight ? 'color-mix(in srgb, var(--color-text-muted) 58%, var(--color-text) 42%)' : 'color-mix(in srgb, var(--color-text-muted) 52%, white 48%)'; const headerIconColor = isLight ? 'color-mix(in srgb, var(--color-text-muted) 64%, var(--color-text) 36%)' : 'color-mix(in srgb, var(--color-text-muted) 54%, white 46%)'; const handleToggleOpen = (): void => { const nextOpen = !isOpen; setIsOpen(nextOpen); onOpenChange?.(nextOpen); }; return (
{isOpen ? (
{description ? (

{description}

) : null} {children}
) : null}
); };