web


git clone https://radroots.dev/git/web.git
Log | Files | Refs | Submodules | README | LICENSE

app-init.svelte (3917B)


      1 <script lang="ts">
      2     import {
      3         app_init_has_completed,
      4         app_init_state,
      5         type AppInitStage,
      6     } from "$lib/utils/app";
      7     import { LogoCircle } from "@radroots/apps-lib-pwa";
      8     import { onDestroy, onMount } from "svelte";
      9 
     10     const stage_messages: Record<AppInitStage, string[]> = {
     11         idle: [`Preparing runtime`, `Starting services`, `Allocating memory`],
     12         storage: [
     13             `Opening local storage`,
     14             `Verifying data stores`,
     15             `Syncing storage index`,
     16         ],
     17         download_sql: [
     18             `Fetching SQL runtime`,
     19             `Downloading core engine`,
     20             `Verifying module`,
     21         ],
     22         download_geo: [
     23             `Fetching map data`,
     24             `Downloading geocoder DB`,
     25             `Validating data file`,
     26         ],
     27         database: [
     28             `Preparing database`,
     29             `Applying migrations`,
     30             `Indexing records`,
     31         ],
     32         geocoder: [
     33             `Loading geocoder`,
     34             `Preparing lookup tables`,
     35             `Calibrating index`,
     36         ],
     37         ready: [`Final checks`, `Ready`, `Starting UI`],
     38         error: [`Init error`, `Retrying setup`, `Check connection`],
     39     };
     40 
     41     const bytes_to_mb = (bytes: number): string =>
     42         (bytes / (1024 * 1024)).toFixed(1);
     43 
     44     let show_ui = $state(false);
     45     let message = $state(``);
     46     let message_index = $state(0);
     47     let stage = $state<AppInitStage>(`idle`);
     48     let message_timer_id = $state<number | null>(null);
     49 
     50     let progress_ratio = $state(0);
     51     let progress_text = $state(`0.0 MB`);
     52 
     53     const set_message_for_stage = (next_stage: AppInitStage): void => {
     54         const list = stage_messages[next_stage] ?? stage_messages.idle;
     55         message_index = 0;
     56         message = list[0] ?? ``;
     57     };
     58 
     59     const step_message = (): void => {
     60         const list = stage_messages[stage] ?? stage_messages.idle;
     61         if (list.length <= 1) return;
     62         message_index = (message_index + 1) % list.length;
     63         message = list[message_index] ?? ``;
     64     };
     65 
     66     $effect(() => {
     67         stage = $app_init_state.stage;
     68         set_message_for_stage(stage);
     69     });
     70 
     71     $effect(() => {
     72         const loaded = $app_init_state.loaded_bytes;
     73         const total = $app_init_state.total_bytes;
     74         progress_ratio = total ? Math.min(1, loaded / total) : 0;
     75         const loaded_mb = bytes_to_mb(loaded);
     76         progress_text = total
     77             ? `${loaded_mb} / ${bytes_to_mb(total)} MB`
     78             : `${loaded_mb} MB`;
     79     });
     80 
     81     onMount(() => {
     82         show_ui = !app_init_has_completed();
     83         if (!show_ui) return;
     84         message_timer_id = window.setInterval(() => {
     85             step_message();
     86         }, 4200);
     87     });
     88 
     89     onDestroy(() => {
     90         if (message_timer_id !== null) window.clearInterval(message_timer_id);
     91     });
     92 </script>
     93 
     94 {#if show_ui}
     95     <div
     96         class={`flex flex-col min-h-screen w-full justify-center items-center`}
     97     >
     98         <div class={`flex flex-col justify-center items-center gap-6`}>
     99             <LogoCircle />
    100             <div class={`flex flex-col items-center gap-3`}>
    101                 <p class={`text-sm text-ly0-gl text-center`}>{message}</p>
    102                 <div
    103                     class={`flex flex-col items-center gap-2 w-[72vw] max-w-[22rem]`}
    104                 >
    105                     <div
    106                         class={`w-full h-2 bg-ly0-gl/15 rounded-full overflow-hidden`}
    107                     >
    108                         <div
    109                             class={`h-full bg-ly0-gl/55 rounded-full`}
    110                             style={`width: ${Math.max(progress_ratio * 100, 4)}%`}
    111                         ></div>
    112                     </div>
    113                     <p class={`text-xs text-ly0-gl-label`}>
    114                         {`Downloaded ${progress_text}`}
    115                     </p>
    116                 </div>
    117             </div>
    118         </div>
    119     </div>
    120 {/if}