//! Formatting + small browser helpers. use chrono::{DateTime, Utc}; pub fn format_size(bytes: u64) -> String { const UNITS: [&str; 5] = ["B", "KB", "MB", "GB", "TB"]; let mut v = bytes as f64; let mut i = 0; while v >= 1024.0 && i < UNITS.len() - 1 { v /= 1024.0; i += 1; } if i == 0 { format!("{bytes} B") } else { format!("{v:.1} {}", UNITS[i]) } } pub fn format_date(rfc3339: &str) -> String { match DateTime::parse_from_rfc3339(rfc3339) { Ok(dt) => dt.with_timezone(&Utc).format("%Y-%m-%d %H:%M").to_string(), Err(_) => rfc3339.to_string(), } } pub fn storage_get(key: &str) -> Option { let w = web_sys::window()?; let storage_opt = w.local_storage().ok()?; let storage = storage_opt.as_ref()?; storage.get_item(key).ok().flatten() } pub fn storage_set(key: &str, value: &str) { if let Some(s) = web_sys::window().and_then(|w| w.local_storage().ok().flatten()) { let _ = s.set_item(key, value); } } #[derive(Clone, Copy, PartialEq, Debug)] pub enum ViewMode { Grid, List, } impl ViewMode { const KEY: &'static str = "fbng.view"; pub fn load() -> Self { match storage_get(Self::KEY).as_deref() { Some("list") => ViewMode::List, _ => ViewMode::Grid, } } pub fn save(self) { storage_set(Self::KEY, if self == ViewMode::List { "list" } else { "grid" }); } }