+layout.svelte (4347B)
1 <script lang="ts"> 2 import { dev, version as kit_version } from "$app/environment"; 3 import { resolve } from "$app/paths"; 4 import { page } from "$app/state"; 5 import { app_init } from "$lib/utils/app"; 6 import { app_cfg } from "$lib/utils/app/config"; 7 import { 8 lc_color_mode, 9 lc_geocode, 10 lc_geop_current, 11 lc_gui_alert, 12 lc_gui_confirm, 13 lc_img_bin, 14 lc_photos_add, 15 lc_photos_upload, 16 } from "$lib/utils/app/handlers"; 17 import { locale, ls } from "$lib/utils/i18n"; 18 import { 19 set_context, 20 theme_key, 21 theme_mode, 22 theme_set, 23 win_h, 24 } from "@radroots/apps-lib"; 25 import { Css, LayoutWindow } from "@radroots/apps-lib-pwa"; 26 import { app_lo } from "@radroots/apps-lib-pwa/stores/app"; 27 import type { LibContext } from "@radroots/apps-lib-pwa/types/context"; 28 import { CFG_APP } from "@radroots/apps-lib-pwa/utils/app"; 29 import { parse_theme_key, parse_theme_mode } from "@radroots/themes"; 30 import { RADROOTS_ASSET_CACHE_NAME, str_cap_words } from "@radroots/utils"; 31 import "css-paint-polyfill"; 32 import { onMount } from "svelte"; 33 import "../app.css"; 34 import type { LayoutProps } from "./$types"; 35 36 type MetaTag = { 37 name: string; 38 content: string; 39 }; 40 41 42 const HEAD_META_TAGS: MetaTag[] = [ 43 { 44 name: "app_version", 45 content: app_cfg.version, 46 }, 47 { 48 name: "app_backup_version", 49 content: app_cfg.backup.version, 50 }, 51 { 52 name: "app_build_id", 53 content: kit_version, 54 }, 55 { 56 name: "app_build_mode", 57 content: dev ? "development" : "production", 58 }, 59 ]; 60 61 let { children }: LayoutProps = $props(); 62 63 const LIB_CONTEXT: LibContext = { 64 ls, 65 locale, 66 lc_color_mode, 67 lc_gui_alert, 68 lc_gui_confirm, 69 lc_geocode, 70 lc_geop_current, 71 lc_img_bin, 72 lc_photos_add, 73 lc_photos_upload, 74 }; 75 76 set_context("lib", LIB_CONTEXT); 77 78 theme_mode.subscribe((_theme_mode) => 79 theme_set(parse_theme_key($theme_key), parse_theme_mode(_theme_mode)), 80 ); 81 82 theme_key.subscribe((_theme_key) => 83 theme_set(parse_theme_key(_theme_key), parse_theme_mode($theme_mode)), 84 ); 85 86 win_h.subscribe((_win_h) => { 87 if (_win_h > CFG_APP.layout.ios1.h) { 88 app_lo.set("ios1"); 89 } else { 90 app_lo.set("ios0"); 91 } 92 }); 93 94 const register_service_worker = async (): Promise<void> => { 95 if (dev) return; 96 if (!("serviceWorker" in navigator)) return; 97 const service_worker_root = resolve("/"); 98 const service_worker_path = service_worker_root.endsWith("/") 99 ? `${service_worker_root}service-worker.js` 100 : `${service_worker_root}/service-worker.js`; 101 try { 102 await navigator.serviceWorker.register(service_worker_path); 103 await navigator.serviceWorker.ready; 104 } catch { 105 return; 106 } 107 }; 108 109 const unregister_service_workers = async (): Promise<void> => { 110 if (!("serviceWorker" in navigator)) return; 111 const registrations = await navigator.serviceWorker.getRegistrations(); 112 await Promise.all(registrations.map((registration) => registration.unregister())); 113 if (!("caches" in globalThis)) return; 114 const cache_names = await caches.keys(); 115 const stale_cache_names = cache_names.filter((name) => name !== RADROOTS_ASSET_CACHE_NAME); 116 await Promise.all(stale_cache_names.map((name) => caches.delete(name))); 117 }; 118 119 onMount(async () => { 120 if (dev) await unregister_service_workers(); 121 await app_init(); 122 await register_service_worker(); 123 }); 124 125 const format_title = (title: string): string => { 126 return str_cap_words(title.replaceAll(`/`, ` `)); 127 }; 128 129 const head_title = $derived(format_title(page.url.pathname)); 130 </script> 131 132 <svelte:head> 133 <title>{`${head_title || "Home"} | Rad Roots`}</title> 134 {#each HEAD_META_TAGS as meta_tag (meta_tag.name)} 135 <meta name={meta_tag.name} content={meta_tag.content} /> 136 {/each} 137 </svelte:head> 138 139 <LayoutWindow> 140 {@render children()} 141 </LayoutWindow> 142 <Css />