Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger-ui

src/components/skeleton.rs

//! Layout-preserving loading placeholders.
//!
//! A skeleton is only honest when it has the SHAPE of what arrives: same
//! table, same columns, so the page does not jump when data lands. Text-only
//! `Loading` stays for small inline waits — skeletons are for the
//! table-shaped ones, where a bare "loading…" collapses the layout twice.
//!
//! Screen readers get the sentence, not the shimmer: the boxes are
//! `aria-hidden` and a single visually-hidden live region speaks instead.

use leptos::prelude::*;

#[component]
pub fn TableSkeleton(
    /// How many placeholder rows to draw — pick the page's usual density, not
    /// a number that implies a count the server has not reported.
    #[prop(default = 5)]
    rows: usize,
    #[prop(default = 4)] cols: usize,
    #[prop(into)] what: String,
) -> impl IntoView {
    view! {
        <p class="vh" role="status">{format!("loading {what}…")}</p>
        <div class="tablewrap" aria-hidden="true">
            <table class="skeleton-table">
                <tbody>
                    {(0..rows).map(|r| view! {
                        <tr>
                            {(0..cols).map(|c| {
                                // Vary the bar widths a little so the block
                                // reads as text-to-come, not as a grid.
                                let w = 45 + ((r * 7 + c * 23) % 45);
                                view! {
                                    <td><span class="skeleton-bar"
                                              style=format!("width:{w}%")></span></td>
                                }
                            }).collect_view()}
                        </tr>
                    }).collect_view()}
                </tbody>
            </table>
        </div>
    }
}