/** * Declarative settings schema. Each `SettingsField` describes a single setting * that renders as a labeled form control in the Settings panel. Keep this * independent of Svelte so the same schema can drive future serializers * (export/import settings, URL state, etc.). */ export type FieldKind = 'boolean' | 'select' | 'number' | 'string'; export interface BaseField { kind: K; /** Dot-separated path into AppSettings (e.g. `'map.baseLayer'`). */ path: string; labelKey: string; descriptionKey?: string; } export interface BooleanField extends BaseField<'boolean'> {} export interface NumberField extends BaseField<'number'> { min?: number; max?: number; step?: number; } export interface StringField extends BaseField<'string'> { placeholder?: string; } export interface SelectField extends BaseField<'select'> { options: { value: string; labelKey: string }[]; } export type SettingsField = BooleanField | NumberField | StringField | SelectField; export interface SettingsSection { titleKey: string; fields: SettingsField[]; } export const SETTINGS_SCHEMA: SettingsSection[] = [ { titleKey: 'settings.language', fields: [ { kind: 'select', path: 'locale', labelKey: 'settings.language', options: [ { value: 'ru', labelKey: 'common.yes' }, { value: 'en', labelKey: 'common.yes' }, ], }, ], }, { titleKey: 'settings.map', fields: [ { kind: 'select', path: 'map.baseLayer', labelKey: 'settings.baseLayer', options: [ { value: 'osm', labelKey: 'settings.baseLayer' }, { value: 'satellite', labelKey: 'settings.baseLayer' }, ], }, { kind: 'boolean', path: 'map.showScale', labelKey: 'settings.showScale' }, { kind: 'boolean', path: 'map.showNavigation', labelKey: 'settings.showNavigation' }, ], }, { titleKey: 'settings.units', fields: [ { kind: 'select', path: 'units.system', labelKey: 'settings.units', options: [ { value: 'metric', labelKey: 'settings.metric' }, { value: 'imperial', labelKey: 'settings.imperial' }, ], }, ], }, { titleKey: 'settings.wind', fields: [ { kind: 'boolean', path: 'wind.enabled', labelKey: 'settings.windEnabled' }, { kind: 'number', path: 'wind.step', labelKey: 'settings.windStep', min: 0.25, max: 10, step: 0.25, }, { kind: 'number', path: 'wind.trajectoryStep', labelKey: 'settings.windTrajectoryStep', min: 0.25, max: 5, step: 0.25, }, { kind: 'number', path: 'wind.prefetchIntervalMinutes', labelKey: 'settings.windPrefetchInterval', min: 5, max: 60, step: 5, }, { kind: 'number', path: 'wind.maxFlightDurationHours', labelKey: 'settings.windMaxDuration', min: 1, max: 8, step: 0.5, }, { kind: 'number', path: 'wind.maxRegionDegrees', labelKey: 'settings.windMaxRegion', min: 5, max: 60, step: 5, }, { kind: 'number', path: 'wind.trajectoryMarginDegrees', labelKey: 'settings.windMargin', min: 0.5, max: 5, step: 0.5, }, { kind: 'number', path: 'wind.particleDensity', labelKey: 'settings.windParticleDensity', min: 0.25, max: 3, step: 0.25, }, { kind: 'number', path: 'wind.particleSpeed', labelKey: 'settings.windParticleSpeed', min: 0.25, max: 4, step: 0.25, }, { kind: 'number', path: 'wind.trailPersistence', labelKey: 'settings.windTrailPersistence', min: 0.7, max: 0.98, step: 0.02, }, { kind: 'number', path: 'wind.maxVelocity', labelKey: 'settings.windMaxVelocity', min: 10, max: 80, step: 5, }, ], }, ];