export type Severity = 'critical' | 'serious' | 'warning' | 'notice'; export interface IssueNode { element: string; selector: string; } export type Grade = 'A' | 'B' | 'C' | 'D' | 'F'; export type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; export type AIProvider = 'none' | 'anthropic' | 'openai' | 'gemini' | 'ollama'; export type ScanSchedule = 'daily' | 'weekly' | 'monthly'; export interface Issue { id: string; rule: string; wcag: string; wcag_level?: string; wcag_standard?: string; severity: Severity; category?: 'wcag' | 'best-practice'; title: string; description: string; element?: string; selector?: string; nodes?: IssueNode[]; count: number; fixed: boolean; ai_fixable: boolean; help_url?: string; } export interface ScanResult { url: string; scanned_at: string; score: number; grade: Grade; issues: Issue[]; passed: number; failed: number; error?: string; } export interface PourPrinciple { score: number; issues: Issue[]; } export interface Report { has_data: boolean; score: number; grade: Grade; scanned_at: string | null; url: string | null; passed?: number; failed?: number; issues: Issue[]; groups: { critical: Issue[]; serious: Issue[]; warning: Issue[]; notice: Issue[]; }; pour: { perceivable: PourPrinciple; operable: PourPrinciple; understandable: PourPrinciple; robust: PourPrinciple; }; summary: { critical: number; serious: number; warnings: number; notices: number; }; } export interface Settings { ai_provider: AIProvider; ai_key_set: boolean; ai_model: string; scan_schedule: ScanSchedule; default_rulesets?: string[]; email_alerts?: boolean; } export interface ScanHistoryEntry { date: string; score: number; grade: Grade; failed: number; } export type ButtonSize = 'small' | 'medium' | 'large'; export interface WidgetConfig { enabled: boolean; color: string; position: Position; features: string[]; hide_powered_by?: boolean; button_size?: ButtonSize; offset_vertical?: number; offset_horizontal?: number; } export interface ScannableUrl { url: string; type: string; label: string; } export interface PassedCheck { id: string; title: string; description: string; help_url?: string; count: number; } export interface PageScanSummary { url: string; title?: string; score: number; grade: Grade; failed: number; passed: number; issues: Issue[]; passed_checks?: PassedCheck[]; scanned_at: string; rulesets?: string[]; /** @deprecated legacy single-value field from before multi-select rulesets */ ruleset?: string; } export interface StatementData { status: 'none' | 'draft' | 'published'; page_id: number; page_url: string; edit_url: string; updated_at: string; basic_info: { org_name: string; website: string; website_name: string; }; efforts: { selected: string[]; additional: string[]; }; conformance: { standard: string; custom_standard: string; level: string; additional_notes: string; }; tech_specs: { browsers: string[]; operating_systems: string[]; assistive_tech: string[]; technology_reliance: string[]; }; feedback: { phone: string; email: string; address: string; response_duration: string; }; } export type MediaAltStatus = 'missing' | 'weak' | 'ok'; export interface MediaScanImage { id: number; url: string; thumb: string; filename: string; title: string; caption: string; alt: string; status: MediaAltStatus; /** User-facing explanation for a 'weak' status; empty for 'missing'/'ok'. */ reason: string; width: number | null; height: number | null; /** File size in bytes, or null if the attached file couldn't be read. */ size: number | null; /** ISO 8601 upload date. */ date: string; } export interface MediaScanResult { scanned: number; missing: number; needs_review: number; images: MediaScanImage[]; /** ISO 8601 timestamp of this scan, or null if the library has never been scanned. */ scanned_at: string | null; } export interface MediaScanStart { total: number; } /** Progress or final payload from a single POST /media-scan/chunk call. */ export type MediaScanChunk = | { done: false; scanned: number; total: number; missing: number; needs_review: number } | ( { done: true } & MediaScanResult );