File size: 3,060 Bytes
6989587
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
from __future__ import annotations

from typing import Any

import streamlit as st


def render_loading_shell(title: str = "Project Kasper", message: str | None = None) -> dict[str, Any]:
    message = message or "We apologize for the very long load times. Sometimes it can take multiple minutes."
    shell = st.empty()
    progress_slot = st.empty()
    status_slot = st.empty()

    shell.markdown(
        f"""
        <style>
        .kasper-loader {{
            border: 1px solid rgba(92, 122, 168, 0.28);
            border-radius: 22px;
            padding: 1.4rem 1.35rem;
            background:
                radial-gradient(circle at top right, rgba(56,132,255,0.16), transparent 30%),
                radial-gradient(circle at bottom left, rgba(88,210,111,0.10), transparent 28%),
                linear-gradient(180deg, rgba(14, 22, 36, 0.98), rgba(9, 15, 27, 0.98));
            box-shadow: 0 12px 32px rgba(0,0,0,0.20);
            margin: 0.4rem 0 1rem 0;
        }}
        .kasper-loader-kicker {{
            letter-spacing: 0.18em;
            text-transform: uppercase;
            font-size: 0.72rem;
            color: #78d99a;
            font-weight: 700;
        }}
        .kasper-loader-title {{
            font-size: 2rem;
            line-height: 1.05;
            font-weight: 800;
            color: #f7fafc;
            margin-top: 0.35rem;
        }}
        .kasper-loader-message {{
            color: #9fb3c8;
            font-size: 0.97rem;
            margin-top: 0.45rem;
        }}
        .kasper-loader-bar {{
            margin-top: 0.95rem;
            width: 100%;
            height: 10px;
            border-radius: 999px;
            overflow: hidden;
            background: rgba(255,255,255,0.08);
            position: relative;
        }}
        .kasper-loader-bar::before {{
            content: "";
            position: absolute;
            inset: 0;
            background: linear-gradient(90deg, #2f75ff 0%, #6fd2ff 45%, #78d99a 100%);
            transform: translateX(-55%);
            animation: kasperSlide 1.4s ease-in-out infinite;
        }}
        @keyframes kasperSlide {{
            0% {{ transform: translateX(-55%); }}
            100% {{ transform: translateX(100%); }}
        }}
        </style>
        <div class="kasper-loader">
            <div class="kasper-loader-kicker">Loading</div>
            <div class="kasper-loader-title">{title}</div>
            <div class="kasper-loader-message">{message}</div>
            <div class="kasper-loader-bar"></div>
        </div>
        """,
        unsafe_allow_html=True,
    )
    progress = progress_slot.progress(0)
    status = status_slot.caption("Preparing page...")

    def update(step_text: str, pct: float) -> None:
        progress.progress(int(max(0, min(100, round(pct * 100)))))
        status_slot.caption(step_text)

    def clear() -> None:
        shell.empty()
        progress_slot.empty()
        status_slot.empty()

    return {"update": update, "clear": clear, "progress": progress, "status": status}