#![allow(
clippy::uninlined_format_args,
clippy::std_instead_of_core,
clippy::unwrap_used
)]
use jugar_probar::{
AccessibilityAudit, AccessibilityConfig, AccessibilityValidator, Color, ContrastAnalysis,
FlashDetector, Severity, MIN_CONTRAST_LARGE, MIN_CONTRAST_NORMAL, MIN_CONTRAST_UI,
};
fn main() {
println!("=== Probar Accessibility Demo ===\n");
demo_color_contrast();
demo_flash_detection();
demo_full_audit();
println!("\n=== Accessibility Demo Complete ===");
}
fn demo_color_contrast() {
println!("--- Demo 1: Color Contrast Analysis ---\n");
println!("WCAG 2.1 AA Minimum Contrast Ratios:");
println!(" Normal text (< 18pt): {:.1}:1", MIN_CONTRAST_NORMAL);
println!(" Large text (>= 18pt): {:.1}:1", MIN_CONTRAST_LARGE);
println!(" UI components: {:.1}:1", MIN_CONTRAST_UI);
println!();
let white = Color::new(255, 255, 255);
let black = Color::new(0, 0, 0);
let dark_blue = Color::new(0, 0, 139);
let light_gray = Color::new(200, 200, 200);
let yellow = Color::new(255, 255, 0);
let pairs = vec![
("Black on White", black, white),
("Dark Blue on White", dark_blue, Color::new(255, 255, 255)),
("Light Gray on White", light_gray, Color::new(255, 255, 255)),
("Yellow on White", yellow, Color::new(255, 255, 255)),
];
println!("Contrast Analysis Results:");
for (name, foreground, background) in &pairs {
let ratio = foreground.contrast_ratio(background);
let passes_normal = foreground.meets_wcag_aa_normal(background);
let passes_large = foreground.meets_wcag_aa_large(background);
let passes_ui = foreground.meets_wcag_aa_ui(background);
println!(" {} (ratio: {:.2}:1)", name, ratio);
println!(
" Normal text: {} | Large text: {} | UI: {}",
pass_fail(passes_normal),
pass_fail(passes_large),
pass_fail(passes_ui)
);
}
println!("\nBatch Analysis with ContrastAnalysis:");
let mut analysis = ContrastAnalysis::empty();
analysis.add_pair(black, white, "Primary text");
analysis.add_pair(dark_blue, Color::new(255, 255, 255), "Link text");
analysis.add_pair(light_gray, Color::new(255, 255, 255), "Disabled text");
println!(" Pairs analyzed: {}", analysis.pairs_analyzed);
println!(" Min ratio: {:.2}:1", analysis.min_ratio);
println!(" Max ratio: {:.2}:1", analysis.max_ratio);
println!(" Avg ratio: {:.2}:1", analysis.avg_ratio);
println!(" Passes WCAG AA: {}", pass_fail(analysis.passes_wcag_aa));
if !analysis.failing_pairs.is_empty() {
println!(" Failing pairs: {}", analysis.failing_pairs.len());
for pair in &analysis.failing_pairs {
println!(" - {} (ratio: {:.2}:1)", pair.context, pair.ratio);
}
}
println!();
}
fn demo_flash_detection() {
println!("--- Demo 2: Flash Detection (Photosensitivity) ---\n");
let detector = FlashDetector::new();
println!("WCAG 2.3.1 'Three Flashes or Below Threshold':");
println!(" Max flash rate: {:.1} Hz", detector.max_flash_rate);
println!(" Max red intensity: {:.1}", detector.max_red_intensity);
println!(" Max flash area: {:.0}%", detector.max_flash_area * 100.0);
println!();
println!("Test 1: Slow transition (safe)");
let result = detector.analyze(
0.3, 0.2, 0.1, 1.0, );
print_flash_result(&result);
println!("\nTest 2: Fast strobing (dangerous)");
let result = detector.analyze(
0.5, 0.3, 0.2, 0.08, );
print_flash_result(&result);
println!("\nTest 3: High red intensity (dangerous)");
let result = detector.analyze(
0.4, 0.95, 0.1, 0.5, );
print_flash_result(&result);
println!("\nTest 4: Large flash area (dangerous)");
let result = detector.analyze(
0.3, 0.2, 0.5, 0.5, );
print_flash_result(&result);
println!();
}
fn demo_full_audit() {
println!("--- Demo 3: Full Accessibility Audit ---\n");
let config = AccessibilityConfig::default();
println!("Audit Configuration (AccessibilityConfig::default()):");
println!(" Check contrast: {}", check_mark(config.check_contrast));
println!(" Check focus: {}", check_mark(config.check_focus));
println!(
" Check reduced motion: {}",
check_mark(config.check_reduced_motion)
);
println!(" Check keyboard: {}", check_mark(config.check_keyboard));
let validator = AccessibilityValidator::with_config(config);
println!("\n--- Audit 1: Good Accessibility ---");
let black = Color::new(0, 0, 0);
let white = Color::new(255, 255, 255);
let audit = validator.audit(
&[(black, white, "Main text")],
true, true, );
print_audit_result(&audit);
println!("\n--- Audit 2: Poor Accessibility ---");
let light_gray = Color::new(180, 180, 180);
let audit = validator.audit(
&[(light_gray, white, "Low contrast text")],
false, false, );
print_audit_result(&audit);
println!();
}
const fn pass_fail(passed: bool) -> &'static str {
if passed {
"PASS"
} else {
"FAIL"
}
}
const fn check_mark(enabled: bool) -> &'static str {
if enabled {
"[x]"
} else {
"[ ]"
}
}
const fn severity_label(severity: &Severity) -> &'static str {
match severity {
Severity::Critical => "CRITICAL",
Severity::Major => "MAJOR",
Severity::Minor => "MINOR",
Severity::Info => "INFO",
}
}
fn print_flash_result(result: &jugar_probar::FlashResult) {
println!(" Flash rate: {:.1} Hz", result.flash_rate);
println!(" Red flash exceeded: {}", result.red_flash_exceeded);
println!(" Flash area: {:.0}%", result.flash_area * 100.0);
println!(" Is safe: {}", if result.is_safe { "YES" } else { "NO" });
if let Some(warning) = &result.warning {
println!(" Warning: {}", warning);
}
}
fn print_audit_result(audit: &AccessibilityAudit) {
println!("Audit Results:");
println!(" Score: {}/100", audit.score);
println!(" Has focus indicators: {}", audit.has_focus_indicators);
println!(
" Respects reduced motion: {}",
audit.respects_reduced_motion
);
println!(" Passes: {}", if audit.passes() { "YES" } else { "NO" });
if !audit.issues.is_empty() {
println!("\nIssues Found ({}):", audit.issues.len());
for issue in &audit.issues {
println!(
" [{}] WCAG {}: {}",
severity_label(&issue.severity),
issue.wcag_code,
issue.description
);
if let Some(fix) = &issue.fix_suggestion {
println!(" Fix: {}", fix);
}
}
}
}