util.rs
⎇
Raw
1//! Formatting + small browser helpers.
2
3use chrono::{DateTime, Utc};
4use leptos::prelude::*;
5
6/// A window event listener that is removed when the current owner is disposed.
7///
8/// Leptos' `window_event_listener` returns a `WindowListenerHandle` with no
9/// `Drop` impl — if the owning component is unmounted without an explicit
10/// `remove()`, the listener keeps firing on `window` and panics by reading
11/// the component's now-disposed signals.
12pub fn owned_window_listener<E: leptos::ev::EventDescriptor + 'static>(
13 event: E,
14 cb: impl Fn(E::EventType) + 'static,
15) where
16 E::EventType: wasm_bindgen::JsCast,
17{
18 let handle = window_event_listener(event, cb);
19 on_cleanup(move || handle.remove());
20}
21
22pub fn format_size(bytes: u64) -> String {
23 const UNITS: [&str; 5] = ["B", "KB", "MB", "GB", "TB"];
24 let mut v = bytes as f64;
25 let mut i = 0;
26 while v >= 1024.0 && i < UNITS.len() - 1 {
27 v /= 1024.0;
28 i += 1;
29 }
30 if i == 0 {
31 format!("{bytes} B")
32 } else {
33 format!("{v:.1} {}", UNITS[i])
34 }
35}
36
37pub fn format_date(rfc3339: &str) -> String {
38 match DateTime::parse_from_rfc3339(rfc3339) {
39 Ok(dt) => dt.with_timezone(&Utc).format("%Y-%m-%d %H:%M").to_string(),
40 Err(_) => rfc3339.to_string(),
41 }
42}
43
44pub fn storage_get(key: &str) -> Option<String> {
45 let w = web_sys::window()?;
46 let storage_opt = w.local_storage().ok()?;
47 let storage = storage_opt.as_ref()?;
48 storage.get_item(key).ok().flatten()
49}
50
51pub fn storage_set(key: &str, value: &str) {
52 if let Some(s) = web_sys::window().and_then(|w| w.local_storage().ok().flatten()) {
53 let _ = s.set_item(key, value);
54 }
55}
56
57#[derive(Clone, Copy, PartialEq, Debug)]
58pub enum ViewMode {
59 Grid,
60 List,
61}
62
63impl ViewMode {
64 const KEY: &'static str = "fbng.view";
65
66 pub fn load() -> Self {
67 match storage_get(Self::KEY).as_deref() {
68 Some("list") => ViewMode::List,
69 _ => ViewMode::Grid,
70 }
71 }
72
73 pub fn save(self) {
74 storage_set(
75 Self::KEY,
76 if self == ViewMode::List {
77 "list"
78 } else {
79 "grid"
80 },
81 );
82 }
83}
84