web


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

+page.svelte (69539B)


      1 <script lang="ts">
      2     import { goto } from "$app/navigation";
      3     import {
      4         datastore,
      5         db,
      6         nostr_keys,
      7         notif,
      8         radroots,
      9         route,
     10     } from "$lib/utils/app";
     11     import { reset_sql_cipher } from "$lib/utils/app/cipher";
     12     import {
     13         cfg_delay,
     14         type AppData,
     15         type ConfigData,
     16     } from "$lib/utils/config";
     17     import { locale, ls } from "$lib/utils/i18n";
     18     import { get_default_nostr_relays } from "$lib/utils/nostr/lib";
     19     import {
     20         carousel_create,
     21         carousel_dec,
     22         carousel_inc,
     23         carousel_init,
     24         el_id,
     25         Fade,
     26         fmt_id,
     27         geop_is_valid,
     28         Glyph,
     29         sleep,
     30         ViewPane,
     31         ViewStack,
     32     } from "@radroots/apps-lib";
     33     import {
     34         ButtonLayoutPair,
     35         CarouselContainer,
     36         CarouselItem,
     37         EntryLine,
     38         EntryWrap,
     39         FarmsAddMap,
     40         LoadSymbol,
     41         LogoCircle,
     42         SelectMenu,
     43     } from "@radroots/apps-lib-pwa";
     44     import { app_lo, app_loading } from "@radroots/apps-lib-pwa/stores/app";
     45     import type { AppConfigRole } from "@radroots/apps-lib-pwa/types/app";
     46     import {
     47         geol_lat_fmt,
     48         geol_lng_fmt,
     49         type GeocoderReverseResult,
     50         type GeolocationPoint,
     51     } from "@radroots/geo";
     52     import { nostr_secret_key_validate } from "@radroots/nostr";
     53     import type { IError } from "@radroots/types-bindings";
     54     import {
     55         err_msg,
     56         form_fields,
     57         handle_err,
     58         type ResultPass,
     59     } from "@radroots/utils";
     60     import { onMount } from "svelte";
     61 
     62     type View = "cfg_key" | "cfg_profile" | "cfg_bootstrap" | "eula";
     63 
     64     const page_carousel: Record<View, { max_index: number }> = {
     65         cfg_key: {
     66             max_index: 2,
     67         },
     68         cfg_profile: {
     69             max_index: 2,
     70         },
     71         cfg_bootstrap: {
     72             max_index: 2,
     73         },
     74         eula: {
     75             max_index: 1,
     76         },
     77     };
     78 
     79     const carousel_cfg_key = carousel_create({
     80         view: "cfg_key",
     81         max_index: page_carousel.cfg_key.max_index,
     82     });
     83 
     84     const carousel_cfg_profile = carousel_create({
     85         view: "cfg_profile",
     86         max_index: page_carousel.cfg_profile.max_index,
     87     });
     88 
     89     const carousel_cfg_bootstrap = carousel_create({
     90         view: "cfg_bootstrap",
     91         max_index: page_carousel.cfg_bootstrap.max_index,
     92     });
     93 
     94     const carousel_eula = carousel_create({
     95         view: "eula",
     96         max_index: page_carousel.eula.max_index,
     97     });
     98 
     99     const view_carousel = {
    100         cfg_key: carousel_cfg_key,
    101         cfg_profile: carousel_cfg_profile,
    102         cfg_bootstrap: carousel_cfg_bootstrap,
    103         eula: carousel_eula,
    104     };
    105 
    106     const carousel_cfg_profile_index = carousel_cfg_profile.index;
    107     const carousel_cfg_bootstrap_index = carousel_cfg_bootstrap.index;
    108 
    109     let view: View = $state("cfg_key");
    110 
    111     type CfgFarmOpt = "yes" | "no";
    112     type CfgBusinessOpt = "yes" | "no";
    113 
    114     let cfg_farm_opt: CfgFarmOpt | undefined = $state(undefined);
    115     let cfg_business_opt: CfgBusinessOpt | undefined = $state(undefined);
    116     type CfgKeyOpt = "nostr_key_gen" | "nostr_key_add";
    117     let cgf_key_opt: CfgKeyOpt | undefined = $state(undefined);
    118 
    119     type CfgKeyStep = "intro" | "choice" | "add_existing";
    120     let cfg_key_step: CfgKeyStep = $state("intro");
    121     let cfg_key_loading = $state(false);
    122 
    123     const cfg_key_step_index = (step: CfgKeyStep): number => {
    124         switch (step) {
    125             case "intro":
    126                 return 0;
    127             case "choice":
    128                 return 1;
    129             case "add_existing":
    130                 return 2;
    131         }
    132     };
    133 
    134     $effect(() => {
    135         console.log(`view `, view);
    136         console.log(`cfg_key_step `, cfg_key_step);
    137     });
    138 
    139     const cfg_key_step_for_index = (index: number): CfgKeyStep => {
    140         if (index <= 0) return "intro";
    141         if (index === 1) return "choice";
    142         return "add_existing";
    143     };
    144 
    145     let nostr_key_add_val = $state(``);
    146 
    147     let profile_name_val = $state(``);
    148     let profile_name_valid = $state(false);
    149     let profile_name_nip05 = $state(true);
    150     let profile_name_loading = $state(false);
    151 
    152     let farm_name_val = $state(``);
    153     let farm_products_val = $state(``);
    154     let farm_map_geop: GeolocationPoint | undefined = $state(undefined);
    155     let farm_map_geoc: GeocoderReverseResult | undefined = $state(undefined);
    156 
    157     const farm_geop_lat = $derived.by(() => {
    158         const farm_map_geop_value = farm_map_geop;
    159         return geop_is_valid(farm_map_geop_value)
    160             ? geol_lat_fmt(farm_map_geop_value.lat, `dms`, $locale, 3)
    161             : ``;
    162     });
    163 
    164     const farm_geop_lng = $derived.by(() => {
    165         const farm_map_geop_value = farm_map_geop;
    166         return geop_is_valid(farm_map_geop_value)
    167             ? geol_lng_fmt(farm_map_geop_value.lng, `dms`, $locale, 3)
    168             : ``;
    169     });
    170 
    171     let is_eula_scrolled = $state(false);
    172     let is_loading_s = $state(false);
    173 
    174     const reset_local_state = (): void => {
    175         cfg_farm_opt = undefined;
    176         cfg_business_opt = undefined;
    177         cgf_key_opt = undefined;
    178         cfg_key_step = "intro";
    179         cfg_key_loading = false;
    180         nostr_key_add_val = ``;
    181         profile_name_val = ``;
    182         profile_name_valid = false;
    183         profile_name_nip05 = true;
    184         profile_name_loading = false;
    185         farm_name_val = ``;
    186         farm_products_val = ``;
    187         farm_map_geop = undefined;
    188         farm_map_geoc = undefined;
    189         is_eula_scrolled = false;
    190         is_loading_s = false;
    191     };
    192 
    193     const cfg_bootstrap_max_index = (): number =>
    194         cfg_farm_opt === "yes" ? page_carousel.cfg_bootstrap.max_index : 0;
    195 
    196     const sync_carousel = (new_view: View, index: number): void => {
    197         const carousel = view_carousel[new_view];
    198         carousel_init(carousel, {
    199             index,
    200             max_index:
    201                 new_view === "cfg_bootstrap"
    202                     ? cfg_bootstrap_max_index()
    203                     : page_carousel[new_view].max_index,
    204         });
    205     };
    206 
    207     const set_cfg_key_step = (step: CfgKeyStep): void => {
    208         cfg_key_step = step;
    209         // @todo confirm why this was breaking the correct... if (step === "choice" && !cgf_key_opt) cgf_key_opt = "nostr_key_gen";
    210         sync_carousel("cfg_key", cfg_key_step_index(step));
    211     };
    212 
    213     onMount(async () => {
    214         try {
    215             await page_init();
    216         } catch (e) {
    217             handle_err(e, `on_mount`);
    218         }
    219     });
    220 
    221     const page_init = async (): Promise<void> => {
    222         reset_local_state();
    223         const nostr_keys_all = await nostr_keys.keys();
    224         if ("results" in nostr_keys_all) {
    225             const confirm = await notif.confirm({
    226                 message: `${$ls(
    227                     `notification.configuration.clear_prior_session`,
    228                 )}`,
    229             });
    230             if (!confirm) {
    231                 await notif.alert(
    232                     `${$ls(
    233                         `notification.configuration.prior_session_pending`,
    234                     )}`,
    235                 );
    236                 return;
    237             }
    238             await page_reset();
    239             return;
    240         }
    241         handle_view(`cfg_key`, { index: 0 });
    242     };
    243 
    244     const page_reset = async (
    245         alert_message?: string,
    246         prevent_loading?: boolean,
    247     ): Promise<void> => {
    248         try {
    249             console.log(`[config] page reset`);
    250             app_loading.set(!prevent_loading);
    251             reset_local_state();
    252             handle_view(`cfg_key`, { index: 0 });
    253             if (alert_message) await notif.alert(alert_message);
    254             await sleep(cfg_delay.load);
    255             await nostr_keys.reset();
    256             await datastore.reset();
    257             await reset_sql_cipher(db.get_store_key());
    258             await db.reinit();
    259         } catch (e) {
    260             handle_err(e, `reset`);
    261         } finally {
    262             app_loading.set(false);
    263         }
    264     };
    265 
    266     const on_scroll_eula = async ({
    267         currentTarget: el,
    268     }: {
    269         currentTarget: EventTarget & HTMLDivElement;
    270     }): Promise<void> => {
    271         const client_h = el?.clientHeight;
    272         const scroll_h = el?.scrollHeight;
    273         const scroll_top = el?.scrollTop;
    274         if (scroll_top + client_h >= scroll_h) is_eula_scrolled = true;
    275     };
    276 
    277     const handle_view = (new_view: View, opts?: { index?: number }): void => {
    278         let next_index = opts?.index ?? 0;
    279         if (new_view === "cfg_key") {
    280             if (opts?.index !== undefined)
    281                 cfg_key_step = cfg_key_step_for_index(opts.index);
    282             else if (view === "cfg_profile")
    283                 cfg_key_step =
    284                     cgf_key_opt === "nostr_key_add" ? "add_existing" : "choice";
    285             if (cfg_key_step === "choice" && !cgf_key_opt)
    286                 cgf_key_opt = "nostr_key_gen";
    287             next_index = cfg_key_step_index(cfg_key_step);
    288         }
    289         view = new_view;
    290         sync_carousel(new_view, next_index);
    291     };
    292 
    293     $effect(() => {
    294         console.log(`cgf_key_opt `, cgf_key_opt);
    295     });
    296 
    297     const handle_config_err = async (
    298         err?: IError<string> | string,
    299     ): Promise<void> => {
    300         console.log(`err `, err);
    301         let message = `${$ls(`error.init.configuration_failure`)}`;
    302         if (typeof err === "string") message = err;
    303         else if (err && "err" in err) message = err.err;
    304         await page_reset(message);
    305     };
    306 
    307     const handle_continue = async (): Promise<void> => {
    308         switch (view) {
    309             case `cfg_key`:
    310                 switch (cfg_key_step) {
    311                     case "intro":
    312                         return set_cfg_key_step("choice");
    313                     case "choice":
    314                         return handle_new_key_or_add();
    315                     case "add_existing":
    316                         return handle_key_add_existing();
    317                 }
    318             case `cfg_profile`:
    319                 switch ($carousel_cfg_profile_index) {
    320                     case 0:
    321                         return handle_setup_profile();
    322                     case 1:
    323                         if (cfg_farm_opt === "no")
    324                             return carousel_inc(view_carousel[view]);
    325                         if (cfg_farm_opt === "yes") return handle_setup_role();
    326                         return;
    327                     case 2:
    328                         if (cfg_farm_opt !== "no") return;
    329                         if (!cfg_business_opt) return;
    330                         return handle_setup_role();
    331                 }
    332             case `cfg_bootstrap`:
    333                 if (cfg_farm_opt === "yes") {
    334                     if ($carousel_cfg_bootstrap_index < 2)
    335                         return carousel_inc(view_carousel[view]);
    336                     return handle_view(`eula`);
    337                 }
    338                 return handle_view(`eula`);
    339         }
    340     };
    341 
    342     const handle_new_key_or_add = async (): Promise<void> => {
    343         console.log(`RUNNING NOSTR KEY SETUP `, cgf_key_opt);
    344         if (cgf_key_opt === `nostr_key_add`)
    345             return set_cfg_key_step("add_existing");
    346         if (cfg_key_loading) return;
    347         cfg_key_loading = true;
    348         try {
    349             console.log(`cfg_key_gen start`, {
    350                 view,
    351                 cfg_key_step,
    352                 cgf_key_opt,
    353             });
    354             const key_created = await create_nostr_key();
    355             console.log(`cfg_key_gen result`, { key_created });
    356             if (!key_created) return;
    357             handle_view(`cfg_profile`);
    358             console.log(`cfg_key_gen view`, { view });
    359         } catch (e) {
    360             console.log(`ERR `, e);
    361             handle_err(e, `handle_new_key_or_add`);
    362         } finally {
    363             cfg_key_loading = false;
    364         }
    365     };
    366 
    367     const create_nostr_key = async (): Promise<boolean> => {
    368         console.log(`cfg_key_gen keystore generate start`);
    369         const keys_nostr_gen = await nostr_keys.generate();
    370         console.log(`keys_nostr_gen `, keys_nostr_gen);
    371         if ("err" in keys_nostr_gen) {
    372             console.log(`cfg_key_gen keystore generate err`, keys_nostr_gen);
    373             await handle_config_err(keys_nostr_gen);
    374             return false;
    375         }
    376         console.log(`cfg_key_gen keystore generate ok`);
    377         const cfg_update = await datastore.update_obj<ConfigData>("cfg_data", {
    378             nostr_public_key: keys_nostr_gen.public_key,
    379         });
    380         console.log(`cfg_update `, cfg_update);
    381         if ("err" in cfg_update) {
    382             console.log(`cfg_key_gen datastore update err`, cfg_update);
    383             await handle_config_err(cfg_update);
    384             return false;
    385         }
    386         console.log(`cfg_key_gen datastore update ok`);
    387         return true;
    388     };
    389 
    390     const add_nostr_key = async (secret_key: string): Promise<boolean> => {
    391         console.log(`cfg_key_add keystore add start`);
    392         const keys_nostr_add = await nostr_keys.add(secret_key);
    393         if ("err" in keys_nostr_add) {
    394             console.log(`cfg_key_add keystore add err`, keys_nostr_add);
    395             await notif.alert(`${$ls(`common.invalid_key`)}`);
    396             return false;
    397         }
    398         console.log(`cfg_key_add keystore add ok`);
    399         const cfg_update = await datastore.update_obj<ConfigData>("cfg_data", {
    400             nostr_public_key: keys_nostr_add.public_key,
    401         });
    402         if ("err" in cfg_update) {
    403             console.log(`cfg_key_add datastore update err`, cfg_update);
    404             await handle_config_err(cfg_update);
    405             return false;
    406         }
    407         console.log(`cfg_key_add datastore update ok`);
    408         return true;
    409     };
    410 
    411     const handle_key_add_existing = async (): Promise<void> => {
    412         if (cfg_key_loading) return;
    413         let loading_set = false;
    414         try {
    415             if (!nostr_key_add_val)
    416                 return void (await notif.alert(
    417                     `${$ls(`icu.enter_a_*`, {
    418                         value: `${$ls(`common.nostr_key`)}`.toLowerCase(),
    419                     })}`,
    420                 ));
    421             const secret_key = nostr_secret_key_validate(nostr_key_add_val);
    422             if (!secret_key)
    423                 return void (await notif.alert(
    424                     `${$ls(`icu.not_a_valid_*`, {
    425                         value: `${$ls(`common.nostr_key`)}`.toLowerCase(),
    426                     })}`,
    427                 ));
    428             cfg_key_loading = true;
    429             loading_set = true;
    430             console.log(`cfg_key_add start`, {
    431                 view,
    432                 cfg_key_step,
    433             });
    434             const key_added = await add_nostr_key(secret_key);
    435             console.log(`cfg_key_add result`, { key_added });
    436             if (!key_added) return;
    437             nostr_key_add_val = ``;
    438             handle_view(`cfg_profile`);
    439             console.log(`cfg_key_add view`, { view });
    440         } catch (e) {
    441             handle_err(e, `handle_key_add_existing`);
    442             return void (await notif.alert(
    443                 `${$ls(`icu.not_a_valid_*`, {
    444                     value: `${$ls(`common.nostr_key`)}`.toLowerCase(),
    445                 })}`,
    446             ));
    447         } finally {
    448             if (loading_set) cfg_key_loading = false;
    449         }
    450     };
    451 
    452     const handle_setup_profile = async (): Promise<void> => {
    453         try {
    454             if (profile_name_loading) return;
    455             //@
    456             const ds_cfg_data = await datastore.get_obj<ConfigData>("cfg_data");
    457             console.log(`ds_cfg_data `, ds_cfg_data);
    458             if ("err" in ds_cfg_data) return handle_config_err();
    459 
    460             const ks_nostr_key = await nostr_keys.read(
    461                 ds_cfg_data.result.nostr_public_key,
    462             );
    463             console.log(`ks_nostr_key `, ks_nostr_key);
    464             if ("err" in ks_nostr_key) return handle_config_err();
    465 
    466             if (profile_name_nip05) {
    467                 if (!profile_name_val)
    468                     return void (await notif.alert(
    469                         `${$ls(`icu.enter_a_*`, {
    470                             value: `${$ls(
    471                                 `common.profile_name`,
    472                             )}`.toLowerCase(),
    473                         })}`,
    474                     ));
    475                 if (!profile_name_valid)
    476                     return void (await notif.alert(
    477                         `${$ls(`error.configuration.profile.name_min_length`)}`,
    478                     ));
    479                 profile_name_loading = true;
    480                 const accounts_req = await radroots.accounts_request({
    481                     profile_name: profile_name_val,
    482                     secret_key: ks_nostr_key.secret_key,
    483                 });
    484                 if ("err" in accounts_req)
    485                     return void (await notif.alert(
    486                         `${$ls(accounts_req.err, {
    487                             default: `${$ls(
    488                                 `error.client.http.request_failure`,
    489                             )}`,
    490                         })}`,
    491                     ));
    492                 const confirm = await notif.confirm({
    493                     message: `${`${$ls(`icu.the_*_is_available`, {
    494                         value: `${$ls(
    495                             `common.profile_name`,
    496                         ).toLowerCase()} "${profile_name_val}"`,
    497                     })}`}. ${`${$ls(`common.would_you_like_to_use_it_q`)}`}`,
    498                     cancel: `${$ls(`common.no`)}`,
    499                     ok: `${$ls(`common.yes`)}`,
    500                 });
    501                 if (!confirm) return;
    502                 const accounts_create = await radroots.accounts_create({
    503                     tok: accounts_req.result,
    504                     secret_key: ks_nostr_key.secret_key,
    505                 });
    506                 if ("err" in accounts_create)
    507                     return void (await notif.alert(
    508                         `${$ls(accounts_create.err, {
    509                             default: `${$ls(
    510                                 `error.client.http.request_failure`,
    511                             )}`,
    512                         })}`,
    513                     ));
    514                 await datastore.update_obj<ConfigData>("cfg_data", {
    515                     nip05_request: true,
    516                     nip05_key: accounts_create.result,
    517                 });
    518             }
    519 
    520             if (!profile_name_val) {
    521                 const confirm =
    522                     await handle_add_profile_without_name_confirmation();
    523                 if (!confirm)
    524                     return void el_id(fmt_id(`nostr:profile`))?.focus();
    525             }
    526 
    527             if (profile_name_val) {
    528                 await datastore.update_obj<ConfigData>("cfg_data", {
    529                     nostr_profile: profile_name_val,
    530                 });
    531             }
    532 
    533             await carousel_inc(view_carousel[view]);
    534         } catch (e) {
    535             handle_err(e, `handle_setup_profile`);
    536         } finally {
    537             profile_name_loading = false;
    538         }
    539     };
    540 
    541     const handle_add_profile_without_name_confirmation =
    542         async (): Promise<boolean> => {
    543             return await notif.confirm({
    544                 message: `${$ls(`notification.init.no_profile_option`)}`,
    545                 cancel: `${$ls(`icu.add_*`, {
    546                     value: `${$ls(`common.profile`)}`,
    547                 })}`,
    548                 ok: `${$ls(`common.continue`)}`,
    549             });
    550         };
    551 
    552     const cfg_role_resolve = (): AppConfigRole => {
    553         if (cfg_farm_opt === "yes") return "farm";
    554         if (cfg_business_opt === "yes") return "business";
    555         return "individual";
    556     };
    557 
    558     const handle_setup_role = async (): Promise<void> => {
    559         const role = cfg_role_resolve();
    560         await datastore.update_obj<ConfigData>("cfg_data", { role });
    561         handle_view(`cfg_bootstrap`);
    562     };
    563 
    564     const handle_back = async (): Promise<void> => {
    565         if (cfg_key_loading) return;
    566         switch (view) {
    567             case `cfg_key`:
    568                 switch (cfg_key_step) {
    569                     case "choice": {
    570                         cgf_key_opt = undefined;
    571                         return set_cfg_key_step("intro");
    572                     }
    573                     case "add_existing": {
    574                         nostr_key_add_val = ``;
    575                         return set_cfg_key_step("choice");
    576                     }
    577                 }
    578             case `cfg_profile`:
    579                 switch ($carousel_cfg_profile_index) {
    580                     case 0: {
    581                         if (!profile_name_val) {
    582                             const confirm =
    583                                 await handle_add_profile_without_name_confirmation();
    584                             if (!confirm)
    585                                 return void el_id(
    586                                     fmt_id(`nostr:profile`),
    587                                 )?.focus();
    588                             return void carousel_inc(view_carousel[view]);
    589                         }
    590                         return handle_view(`cfg_key`);
    591                     }
    592                     case 1:
    593                     case 2:
    594                         return carousel_dec(view_carousel[view]);
    595                 }
    596             case `cfg_bootstrap`:
    597                 if (cfg_farm_opt === "yes" && $carousel_cfg_bootstrap_index > 0)
    598                     return carousel_dec(view_carousel[view]);
    599                 return handle_view(`cfg_profile`, {
    600                     index: cfg_farm_opt === "no" ? 2 : 1,
    601                 });
    602         }
    603     };
    604 
    605     const submit = async (): Promise<void> => {
    606         try {
    607             is_loading_s = true;
    608             const ds_cfg_data = await datastore.get_obj<ConfigData>("cfg_data");
    609             if ("err" in ds_cfg_data) return handle_config_err(ds_cfg_data);
    610             const active_key = ds_cfg_data.result?.nostr_public_key;
    611             if (!active_key)
    612                 return handle_config_err(`${$ls(`error.init.no_active_key`)}`);
    613             const ks_nostr_key = await nostr_keys.read(active_key);
    614             if ("err" in ks_nostr_key) return handle_config_err(ks_nostr_key);
    615             const configure_result = await configure_device(
    616                 active_key,
    617                 ds_cfg_data.result,
    618                 //ds_cfg_data.result.role || "personal",
    619                 //ds_cfg_data.result.nostr_profile,
    620             );
    621             if ("err" in configure_result) {
    622                 return void (await notif.alert(configure_result.err));
    623             } else if (!("pass" in configure_result)) {
    624                 return void (await notif.alert(
    625                     `${$ls(`error.init.configuration_failure`)}`,
    626                 ));
    627             }
    628             const clear_cfg = await datastore.del_obj("cfg_data");
    629             if ("err" in clear_cfg) return handle_config_err(clear_cfg);
    630             goto(`/`);
    631             await notif.notify_init();
    632         } catch (e) {
    633             handle_err(e, `submit`);
    634         } finally {
    635             is_loading_s = false;
    636         }
    637     };
    638 
    639     const configure_device = async (
    640         public_key: string,
    641         config_data: ConfigData,
    642     ): Promise<ResultPass | IError<string>> => {
    643         const profile_type =
    644             config_data.role === `farm` ? `farm` : `individual`;
    645         const nostr_profile_add = await db.nostr_profile_create({
    646             public_key,
    647             profile_type,
    648             name: config_data.nostr_profile
    649                 ? config_data.nostr_profile
    650                 : `${$ls(`common.default`)}`,
    651             display_name: config_data.nostr_profile
    652                 ? config_data.nostr_profile
    653                 : undefined,
    654         });
    655         if ("err" in nostr_profile_add)
    656             return err_msg(
    657                 `${$ls(`error.init.device_configuration_nostr_profile`)}`,
    658             );
    659         for (const url of get_default_nostr_relays()) {
    660             const nostr_relay_add = await db.nostr_relay_create({ url });
    661             if ("err" in nostr_relay_add)
    662                 return err_msg(
    663                     `${$ls(`error.init.device_configuration_nostr_relay`)}`,
    664                 );
    665             const nostr_profile_relay_set = await db.nostr_profile_relay_set({
    666                 nostr_profile: {
    667                     id: nostr_profile_add.result.id,
    668                 },
    669                 nostr_relay: {
    670                     id: nostr_relay_add.result.id,
    671                 },
    672             });
    673             if ("err" in nostr_profile_relay_set)
    674                 return err_msg(
    675                     `${$ls(
    676                         `error.init.device_configuration_nostr_profile_relay`,
    677                     )}`,
    678                 );
    679         }
    680         const set_app_data = await datastore.set_obj<AppData>("app_data", {
    681             active_key: public_key,
    682             role: config_data.role || "individual",
    683             eula_date: new Date().toISOString(),
    684             nip05_key: config_data.nip05_key,
    685         });
    686         if ("err" in set_app_data) return err_msg(set_app_data);
    687         await datastore.del_obj("cfg_data");
    688         return { pass: true };
    689     };
    690 
    691     $effect(() => {
    692         console.log(`view `, view);
    693     });
    694 </script>
    695 
    696 {#if view === "cfg_key" && cfg_key_step !== "intro"}
    697     <Fade basis={{ classes: `z-10 absolute top-8 right-6` }}>
    698         <SelectMenu
    699             basis={{
    700                 layer: 0,
    701                 options: [
    702                     {
    703                         entries: [
    704                             {
    705                                 value: "",
    706                                 label: `${$ls(`common.choose_options`)}`,
    707                                 disabled: true,
    708                             },
    709                             {
    710                                 value: "import",
    711                                 label: `${$ls(`common.import_backup`)}`,
    712                             },
    713                         ],
    714                     },
    715                 ],
    716                 callback: async ({ value }) => {
    717                     if (value === "import")
    718                         return void (await route("/import"));
    719                 },
    720             }}
    721         >
    722             <Glyph
    723                 basis={{
    724                     classes: `text-base text-ly0-gl group-active:text-ly0-gl-a`,
    725                     key: "gear",
    726                 }}
    727             />
    728         </SelectMenu>
    729     </Fade>
    730 {/if}
    731 
    732 <ViewStack
    733     basis={{
    734         active_view: view,
    735     }}
    736 >
    737     <ViewPane basis={{ view: "cfg_key" }}>
    738         <div class={`flex flex-col h-full w-full justify-start items-center`}>
    739             <CarouselContainer
    740                 basis={{
    741                     carousel: carousel_cfg_key,
    742                 }}
    743             >
    744                 <CarouselItem
    745                     basis={{
    746                         classes: `justify-center items-center`,
    747                     }}
    748                 >
    749                     <div
    750                         class={`relative flex flex-col h-full w-full justify-center items-center`}
    751                     >
    752                         <div
    753                             class={`flex flex-row w-full justify-start items-center -translate-y-16`}
    754                         >
    755                             <button
    756                                 class={`flex flex-row w-full justify-center items-center`}
    757                                 onclick={async () => {
    758                                     await goto(`/`);
    759                                 }}
    760                             >
    761                                 <LogoCircle />
    762                             </button>
    763                         </div>
    764                         <div
    765                             class={`absolute bottom-0 left-0 flex flex-col h-[20rem] w-full px-10 gap-2 justify-start items-center`}
    766                         >
    767                             <div
    768                                 class={`flex flex-row w-full justify-start items-center`}
    769                             >
    770                                 <p
    771                                     class={`font-sans font-[400] text-sm text-ly0-gl-label uppercase`}
    772                                 >
    773                                     {`${$ls(`common.configure`)}`}
    774                                 </p>
    775                             </div>
    776                             <div
    777                                 class={`flex flex-col w-full gap-2 justify-start items-center`}
    778                             >
    779                                 <div
    780                                     class={`flex flex-row w-full justify-start items-center`}
    781                                 >
    782                                     <p
    783                                         class={`font-mono font-[400] text-[1.1rem] text-ly0-gl`}
    784                                     >
    785                                         {`${$ls(`notification.init.greeting_header`)}`}
    786                                     </p>
    787                                 </div>
    788                                 <div
    789                                     class={`flex flex-row w-full justify-start items-center`}
    790                                 >
    791                                     <p
    792                                         class={`font-mono font-[400] text-[1.1rem] text-ly0-gl`}
    793                                     >
    794                                         {`${$ls(
    795                                             `notification.init.greeting_subheader`,
    796                                         )}.`}
    797                                     </p>
    798                                 </div>
    799                             </div>
    800                         </div>
    801                     </div>
    802                 </CarouselItem>
    803                 <CarouselItem
    804                     basis={{
    805                         classes: `justify-center items-center`,
    806                     }}
    807                 >
    808                     <div
    809                         class={`flex flex-col h-[16rem] gap-8 w-full justify-start items-center`}
    810                     >
    811                         <div
    812                             class={`flex flex-row w-full justify-center items-center`}
    813                         >
    814                             <p
    815                                 class={`font-sans font-[600] text-ly0-gl text-3xl`}
    816                             >
    817                                 {`${$ls(`icu.configure_*`, {
    818                                     value: `${$ls(`common.device`)}`,
    819                                 })}`}
    820                             </p>
    821                         </div>
    822                         <div
    823                             class={`flex flex-col w-full gap-6 justify-center items-center`}
    824                         >
    825                             <button
    826                                 class={`flex flex-col h-bold_button w-lo_${$app_lo} justify-center items-center rounded-touch ${
    827                                     cgf_key_opt === `nostr_key_gen`
    828                                         ? `ly1-apply-active ly1-raise-apply ly1-ring-apply`
    829                                         : `bg-ly1`
    830                                 } el-re`}
    831                                 onclick={async (ev) => {
    832                                     ev.stopPropagation();
    833                                     cgf_key_opt = `nostr_key_gen`;
    834                                 }}
    835                             >
    836                                 <p
    837                                     class={`font-sans font-[600] text-ly0-gl text-xl`}
    838                                 >
    839                                     {`${$ls(`icu.create_new_*`, {
    840                                         value: `${$ls(
    841                                             `common.keypair`,
    842                                         )}`.toLowerCase(),
    843                                     })}`}
    844                                 </p>
    845                             </button>
    846                             <button
    847                                 class={`flex flex-col h-bold_button w-lo_${$app_lo} justify-center items-center rounded-touch ${
    848                                     cgf_key_opt === `nostr_key_add`
    849                                         ? `ly1-apply-active ly1-raise-apply ly1-ring-apply`
    850                                         : `bg-ly1`
    851                                 } el-re`}
    852                                 onclick={async (ev) => {
    853                                     ev.stopPropagation();
    854                                     cgf_key_opt = `nostr_key_add`;
    855                                 }}
    856                             >
    857                                 <p
    858                                     class={`font-sans font-[600] text-ly0-gl text-xl`}
    859                                 >
    860                                     {`${$ls(`icu.use_existing_*`, {
    861                                         value: `${$ls(
    862                                             `common.keypair`,
    863                                         )}`.toLowerCase(),
    864                                     })}`}
    865                                 </p>
    866                             </button>
    867                         </div>
    868                     </div>
    869                 </CarouselItem>
    870                 <CarouselItem
    871                     basis={{
    872                         classes: `justify-center items-center`,
    873                     }}
    874                 >
    875                     <div
    876                         class={`flex flex-col w-full gap-8 justify-start items-center`}
    877                     >
    878                         <div
    879                             class={`flex flex-col w-full gap-6 justify-center items-center`}
    880                         >
    881                             <p
    882                                 class={`font-sans font-[600] text-ly0-gl text-3xl capitalize`}
    883                             >
    884                                 {`${$ls(`icu.add_existing_*`, {
    885                                     value: `${$ls(`common.key`)}`.toLowerCase(),
    886                                 })}`}
    887                             </p>
    888                             <EntryLine
    889                                 bind:value={nostr_key_add_val}
    890                                 basis={{
    891                                     wrap: {
    892                                         layer: 1,
    893                                         classes: `w-lo_${$app_lo}`,
    894                                         style: `guide`,
    895                                     },
    896                                     el: {
    897                                         classes: `font-sans text-[1.25rem] text-center placeholder:opacity-60`,
    898                                         layer: 1,
    899                                         placeholder: `${$ls(`icu.enter_*`, {
    900                                             value: `${$ls(
    901                                                 `common.nostr_nsec_hex`,
    902                                             )}`,
    903                                         })}`,
    904                                         callback_keydown: async ({
    905                                             key_s,
    906                                             el,
    907                                         }) => {
    908                                             if (key_s) {
    909                                                 el.blur();
    910                                                 handle_continue();
    911                                             }
    912                                         },
    913                                     },
    914                                 }}
    915                             />
    916                         </div>
    917                     </div>
    918                 </CarouselItem>
    919                 <div
    920                     class={`z-10 absolute ios0:bottom-2 bottom-10 left-0 flex flex-col w-full justify-center items-center`}
    921                 >
    922                     <ButtonLayoutPair
    923                         basis={{
    924                             continue: {
    925                                 label: `${$ls(`common.continue`)}`,
    926                                 disabled:
    927                                     cfg_key_loading ||
    928                                     (cfg_key_step === "choice" && !cgf_key_opt),
    929                                 loading: cfg_key_loading,
    930                                 callback: async () => handle_continue(),
    931                             },
    932                             back: {
    933                                 label: `${$ls(`common.back`)}`,
    934                                 visible: cfg_key_step !== "intro",
    935                                 disabled: cfg_key_loading,
    936                                 callback: async () => handle_back(),
    937                             },
    938                         }}
    939                     />
    940                 </div>
    941             </CarouselContainer>
    942         </div>
    943     </ViewPane>
    944 
    945     <ViewPane basis={{ view: "cfg_profile" }}>
    946         <div class={`flex flex-col h-full w-full justify-start items-center`}>
    947             <CarouselContainer
    948                 basis={{
    949                     carousel: carousel_cfg_profile,
    950                 }}
    951             >
    952                 <CarouselItem
    953                     basis={{
    954                         classes: `justify-center items-center`,
    955                     }}
    956                 >
    957                     <div
    958                         class={`flex flex-col h-[16rem] w-full px-4 gap-6 justify-start items-center`}
    959                     >
    960                         <p class={`font-sans font-[600] text-ly0-gl text-3xl`}>
    961                             {`${$ls(`icu.add_*`, {
    962                                 value: `${$ls(`common.profile`)}`,
    963                             })}`}
    964                         </p>
    965                         <div
    966                             class={`flex flex-col w-full gap-4 justify-center items-center`}
    967                         >
    968                             <EntryLine
    969                                 bind:value={profile_name_val}
    970                                 basis={{
    971                                     loading: profile_name_loading,
    972                                     wrap: {
    973                                         layer: 1,
    974                                         classes: `w-lo_${$app_lo}`,
    975                                         style: `guide`,
    976                                     },
    977                                     el: {
    978                                         classes: `font-sans text-[1.25rem] text-center placeholder:opacity-60`,
    979                                         id: fmt_id(`nostr:profile`),
    980                                         layer: 1,
    981                                         placeholder: `${$ls(`icu.enter_*`, {
    982                                             value: `${$ls(
    983                                                 `common.profile_name`,
    984                                             )}`.toLowerCase(),
    985                                         })}`,
    986                                         field: form_fields.profile_name,
    987                                         callback: async ({ pass }) => {
    988                                             profile_name_valid = pass;
    989                                         },
    990                                         callback_keydown: async ({
    991                                             key_s,
    992                                             el,
    993                                         }) => {
    994                                             if (key_s) {
    995                                                 el.blur();
    996                                                 handle_continue();
    997                                             }
    998                                         },
    999                                     },
   1000                                 }}
   1001                             />
   1002                             <div
   1003                                 class={`flex flex-row w-full gap-2 justify-center items-center`}
   1004                             >
   1005                                 <input
   1006                                     type="checkbox"
   1007                                     bind:checked={profile_name_nip05}
   1008                                 />
   1009                                 <button
   1010                                     class={`flex flex-row justify-center items-center`}
   1011                                     onclick={async () => {
   1012                                         profile_name_nip05 =
   1013                                             !profile_name_nip05;
   1014                                     }}
   1015                                 >
   1016                                     <p
   1017                                         class={`font-sans font-[400] text-ly0-gl text-[14px] tracking-wide`}
   1018                                     >
   1019                                         {`${$ls(`common.create`)}`}
   1020                                         <span
   1021                                             class={`font-mono font-[500] tracking-tight px-[3px]`}
   1022                                         >
   1023                                             {`@radroots`}
   1024                                         </span>
   1025                                         {`${$ls(`common.nip05_address`)}`}
   1026                                     </p>
   1027                                 </button>
   1028                             </div>
   1029                         </div>
   1030                     </div>
   1031                 </CarouselItem>
   1032                 <CarouselItem
   1033                     basis={{
   1034                         classes: `justify-center items-center`,
   1035                         role: `button`,
   1036                         tabindex: 0,
   1037                         callback_click: async () => {
   1038                             cfg_farm_opt = undefined;
   1039                             cfg_business_opt = undefined;
   1040                         },
   1041                     }}
   1042                 >
   1043                     <div
   1044                         class={`flex flex-col h-[16rem] w-full gap-10 justify-start items-center`}
   1045                     >
   1046                         <div
   1047                             class={`flex flex-row w-full justify-center items-center`}
   1048                         >
   1049                             <p
   1050                                 class={`font-sans font-[600] text-ly0-gl text-3xl`}
   1051                             >
   1052                                 {`${$ls(`common.setup_for_farmer`)}`}
   1053                             </p>
   1054                         </div>
   1055                         <div
   1056                             class={`flex flex-col w-full gap-5 justify-center items-center`}
   1057                         >
   1058                             <button
   1059                                 class={`flex flex-col h-bold_button w-lo_${$app_lo} justify-center items-center rounded-touch ${
   1060                                     cfg_farm_opt === `yes`
   1061                                         ? `ly1-apply-active ly1-raise-apply ly1-ring-apply`
   1062                                         : `bg-ly1`
   1063                                 } el-re`}
   1064                                 onclick={async (ev) => {
   1065                                     ev.stopPropagation();
   1066                                     cfg_farm_opt = `yes`;
   1067                                 }}
   1068                             >
   1069                                 <p
   1070                                     class={`font-sans font-[600] text-ly0-gl text-xl`}
   1071                                 >
   1072                                     {`${$ls(`common.yes`)}`}
   1073                                 </p>
   1074                             </button>
   1075                             <button
   1076                                 class={`flex flex-col h-bold_button w-lo_${$app_lo} justify-center items-center rounded-touch ${
   1077                                     cfg_farm_opt === `no`
   1078                                         ? `ly1-apply-active ly1-raise-apply ly1-ring-apply`
   1079                                         : `bg-ly1`
   1080                                 } el-re`}
   1081                                 onclick={async (ev) => {
   1082                                     ev.stopPropagation();
   1083                                     cfg_farm_opt = `no`;
   1084                                 }}
   1085                             >
   1086                                 <p
   1087                                     class={`font-sans font-[600] text-ly0-gl text-xl`}
   1088                                 >
   1089                                     {`${$ls(`common.no`)}`}
   1090                                 </p>
   1091                             </button>
   1092                         </div>
   1093                     </div>
   1094                 </CarouselItem>
   1095                 <CarouselItem
   1096                     basis={{
   1097                         classes: `justify-center items-center`,
   1098                         role: `button`,
   1099                         tabindex: 0,
   1100                         callback_click: async () => {
   1101                             cfg_business_opt = undefined;
   1102                         },
   1103                     }}
   1104                 >
   1105                     <div
   1106                         class={`flex flex-col h-[16rem] w-full gap-10 justify-start items-center`}
   1107                     >
   1108                         <div
   1109                             class={`flex flex-row w-full justify-center items-center`}
   1110                         >
   1111                             <p
   1112                                 class={`font-sans font-[600] text-ly0-gl text-3xl`}
   1113                             >
   1114                                 {`${$ls(`common.setup_for_business`)}`}
   1115                             </p>
   1116                         </div>
   1117                         <div
   1118                             class={`flex flex-col w-full gap-5 justify-center items-center`}
   1119                         >
   1120                             <button
   1121                                 class={`flex flex-col h-bold_button w-lo_${$app_lo} justify-center items-center rounded-touch ${
   1122                                     cfg_business_opt === `yes`
   1123                                         ? `ly1-apply-active ly1-raise-apply ly1-ring-apply`
   1124                                         : `bg-ly1`
   1125                                 } el-re`}
   1126                                 onclick={async (ev) => {
   1127                                     ev.stopPropagation();
   1128                                     cfg_business_opt = `yes`;
   1129                                 }}
   1130                             >
   1131                                 <p
   1132                                     class={`font-sans font-[600] text-ly0-gl text-xl`}
   1133                                 >
   1134                                     {`${$ls(`common.yes`)}`}
   1135                                 </p>
   1136                             </button>
   1137                             <button
   1138                                 class={`flex flex-col h-bold_button w-lo_${$app_lo} justify-center items-center rounded-touch ${
   1139                                     cfg_business_opt === `no`
   1140                                         ? `ly1-apply-active ly1-raise-apply ly1-ring-apply`
   1141                                         : `bg-ly1`
   1142                                 } el-re`}
   1143                                 onclick={async (ev) => {
   1144                                     ev.stopPropagation();
   1145                                     cfg_business_opt = `no`;
   1146                                 }}
   1147                             >
   1148                                 <p
   1149                                     class={`font-sans font-[600] text-ly0-gl text-xl`}
   1150                                 >
   1151                                     {`${$ls(`common.no`)}`}
   1152                                 </p>
   1153                             </button>
   1154                         </div>
   1155                     </div>
   1156                 </CarouselItem>
   1157             </CarouselContainer>
   1158             <div
   1159                 class={`absolute ios0:bottom-2 bottom-10 left-0 flex flex-col w-full justify-center items-center`}
   1160             >
   1161                 <ButtonLayoutPair
   1162                     basis={{
   1163                         continue: {
   1164                             label: `${$ls(`common.continue`)}`,
   1165                             disabled:
   1166                                 ($carousel_cfg_profile_index === 1 &&
   1167                                     !cfg_farm_opt) ||
   1168                                 ($carousel_cfg_profile_index === 2 &&
   1169                                     (cfg_farm_opt !== "no" ||
   1170                                         !cfg_business_opt)),
   1171                             callback: async () => handle_continue(),
   1172                         },
   1173                         back: {
   1174                             visible: true,
   1175                             label:
   1176                                 view === "cfg_profile" &&
   1177                                 $carousel_cfg_profile_index === 0 &&
   1178                                 !profile_name_val
   1179                                     ? `${$ls(`common.skip`)}`
   1180                                     : `${$ls(`common.back`)}`,
   1181                             callback: handle_back,
   1182                         },
   1183                     }}
   1184                 />
   1185             </div>
   1186         </div>
   1187     </ViewPane>
   1188 
   1189     <ViewPane basis={{ view: "cfg_bootstrap" }}>
   1190         <div class={`flex flex-col h-full w-full justify-start items-center`}>
   1191             <CarouselContainer
   1192                 basis={{
   1193                     carousel: carousel_cfg_bootstrap,
   1194                 }}
   1195             >
   1196                 {#if cfg_farm_opt === "yes"}
   1197                     <CarouselItem
   1198                         basis={{
   1199                             classes: `justify-center items-center`,
   1200                         }}
   1201                     >
   1202                         <div
   1203                             class={`flex flex-col h-[16rem] w-full px-4 gap-6 justify-start items-center`}
   1204                         >
   1205                             <p
   1206                                 class={`font-sans font-[600] text-ly0-gl text-3xl`}
   1207                             >
   1208                                 {`${$ls(`common.farm_name`)}`}
   1209                             </p>
   1210                             <EntryWrap
   1211                                 basis={{
   1212                                     layer: 1,
   1213                                     classes: `w-lo_${$app_lo}`,
   1214                                     style: `guide`,
   1215                                 }}
   1216                             >
   1217                                 <input
   1218                                     bind:value={farm_name_val}
   1219                                     class={`h-entry_line w-full font-sans text-[1.25rem] text-center placeholder:opacity-60 el-input bg-ly1 text-ly1-gl placeholder:text-ly1-gl_pl caret-ly1-gl el-re`}
   1220                                     placeholder={`${$ls(`common.farm_name`)}`}
   1221                                 />
   1222                             </EntryWrap>
   1223                         </div>
   1224                     </CarouselItem>
   1225                     <CarouselItem
   1226                         basis={{
   1227                             classes: `justify-start items-center`,
   1228                         }}
   1229                     >
   1230                         <FarmsAddMap
   1231                             bind:map_geop={farm_map_geop}
   1232                             bind:map_geoc={farm_map_geoc}
   1233                             {farm_geop_lat}
   1234                             {farm_geop_lng}
   1235                         />
   1236                     </CarouselItem>
   1237                     <CarouselItem
   1238                         basis={{
   1239                             classes: `justify-center items-center`,
   1240                         }}
   1241                     >
   1242                         <div
   1243                             class={`flex flex-col h-[16rem] w-full px-4 gap-6 justify-start items-center`}
   1244                         >
   1245                             <p
   1246                                 class={`font-sans font-[600] text-ly0-gl text-3xl`}
   1247                             >
   1248                                 {`${$ls(`common.products`)}`}
   1249                             </p>
   1250                             <EntryWrap
   1251                                 basis={{
   1252                                     layer: 1,
   1253                                     classes: `w-lo_${$app_lo}`,
   1254                                     style: `guide`,
   1255                                     no_pad: true,
   1256                                 }}
   1257                             >
   1258                                 <textarea
   1259                                     bind:value={farm_products_val}
   1260                                     class={`h-full w-full min-h-[8rem] px-6 py-4 font-sans text-[1.05rem] text-center placeholder:opacity-60 el-input bg-ly1 text-ly1-gl placeholder:text-ly1-gl_pl caret-ly1-gl el-re resize-none`}
   1261                                     placeholder={`${$ls(`common.products`)}`}
   1262                                 ></textarea>
   1263                             </EntryWrap>
   1264                         </div>
   1265                     </CarouselItem>
   1266                 {:else}
   1267                     <CarouselItem
   1268                         basis={{
   1269                             classes: `justify-center items-center`,
   1270                         }}
   1271                     >
   1272                         <div
   1273                             class={`flex flex-col h-[16rem] w-full px-4 gap-6 justify-center items-center`}
   1274                         >
   1275                             <p
   1276                                 class={`font-sans font-[600] text-ly0-gl text-3xl capitalize`}
   1277                             >
   1278                                 {cfg_role_resolve()}
   1279                             </p>
   1280                         </div>
   1281                     </CarouselItem>
   1282                 {/if}
   1283             </CarouselContainer>
   1284             <div
   1285                 class={`absolute ios0:bottom-2 bottom-10 left-0 flex flex-col w-full justify-center items-center`}
   1286             >
   1287                 <ButtonLayoutPair
   1288                     basis={{
   1289                         continue: {
   1290                             label: `${$ls(`common.continue`)}`,
   1291                             callback: async () => handle_continue(),
   1292                         },
   1293                         back: {
   1294                             visible: true,
   1295                             label: `${$ls(`common.back`)}`,
   1296                             callback: handle_back,
   1297                         },
   1298                     }}
   1299                 />
   1300             </div>
   1301         </div>
   1302     </ViewPane>
   1303 
   1304     <ViewPane basis={{ view: "eula" }}>
   1305         <div
   1306             class={`flex flex-col h-full w-full ios0:pt-12 pt-24 justify-start items-center`}
   1307         >
   1308             <CarouselContainer
   1309                 basis={{
   1310                     carousel: carousel_eula,
   1311                     classes: `rounded-2xl scroll-hide`,
   1312                 }}
   1313             >
   1314                 <CarouselItem
   1315                     basis={{
   1316                         classes: `justify-start items-center`,
   1317                     }}
   1318                 >
   1319                     <div
   1320                         class={`flex flex-col h-full w-full px-4 justify-start items-center ${
   1321                             view === `eula` ? `fade-in-long` : ``
   1322                         }`}
   1323                     >
   1324                         <div
   1325                             class={`flex flex-col w-full px-4 gap-4 justify-start items-center`}
   1326                         >
   1327                             <div
   1328                                 class={`flex flex-row w-full ios0:pt-8 justify-center items-center`}
   1329                             >
   1330                                 <p
   1331                                     class={`font-mono font-[600] text-ly0-gl text-2xl`}
   1332                                 >
   1333                                     {`${$ls(`eula.title`)}`}
   1334                                 </p>
   1335                             </div>
   1336                             <div
   1337                                 class={`flex flex-col ios0:h-[26rem] ios1:h-[38rem] w-full gap-6 justify-start items-center overflow-y-scroll scroll-hide`}
   1338                                 onscroll={on_scroll_eula}
   1339                             >
   1340                                 <div
   1341                                     class={`flex flex-col w-full gap-2 justify-start items-start`}
   1342                                 >
   1343                                     <p
   1344                                         class={`font-mono font-[600] text-ly0-gl`}
   1345                                     >
   1346                                         {`**${$ls(`eula.introduction.title`)}**`}
   1347                                     </p>
   1348                                     <p
   1349                                         class={`font-mono font-[500] text-ly0-gl text-sm text-justify break-word`}
   1350                                     >
   1351                                         {`${$ls(`eula.introduction.body`)}`}
   1352                                     </p>
   1353                                 </div>
   1354                                 <div
   1355                                     class={`flex flex-col w-full gap-2 justify-start items-start`}
   1356                                 >
   1357                                     <p
   1358                                         class={`font-mono font-[600] text-ly0-gl`}
   1359                                     >
   1360                                         {`**${$ls(`eula.prohibited_content.title`)}**`}
   1361                                     </p>
   1362                                     <p
   1363                                         class={`font-mono font-[500] text-sm text-ly0-gl text-justify break-word`}
   1364                                     >
   1365                                         {`${$ls(
   1366                                             `eula.prohibited_content.body_0_title`,
   1367                                         )}`}
   1368                                     </p>
   1369                                     <div
   1370                                         class={`flex flex-col w-full justify-start items-start`}
   1371                                     >
   1372                                         {#each [0, 1, 2, 3, 4, 5] as li}
   1373                                             <div
   1374                                                 class={`flex flex-row w-full justify-start items-center`}
   1375                                             >
   1376                                                 <div
   1377                                                     class={`flex flex-row h-full w-8 justify-start items-start`}
   1378                                                 >
   1379                                                     <p
   1380                                                         class={` font-mono font-[500] text-sm text-ly0-gl text-justify break-word`}
   1381                                                     >
   1382                                                         {`*`}
   1383                                                     </p>
   1384                                                 </div>
   1385                                                 <div
   1386                                                     class={`flex flex-row h-full w-full justify-start items-start`}
   1387                                                 >
   1388                                                     <p
   1389                                                         class={`col-span-10 font-mono font-[500] text-sm text-ly0-gl text-justify break-word`}
   1390                                                     >
   1391                                                         {`${$ls(
   1392                                                             `eula.prohibited_content.body_li_0_${li}`,
   1393                                                         )}`}
   1394                                                     </p>
   1395                                                 </div>
   1396                                             </div>
   1397                                         {/each}
   1398                                     </div>
   1399                                 </div>
   1400                                 <div
   1401                                     class={`flex flex-col w-full gap-2 justify-start items-start`}
   1402                                 >
   1403                                     <p
   1404                                         class={`font-mono font-[600] text-ly0-gl`}
   1405                                     >
   1406                                         {`**${$ls(`eula.prohibited_conduct.title`)}**`}
   1407                                     </p>
   1408                                     <div
   1409                                         class={`flex flex-col w-full justify-start items-start`}
   1410                                     >
   1411                                         {#each [0, 1, 2, 3] as li}
   1412                                             <div
   1413                                                 class={`flex flex-row w-full justify-start items-center`}
   1414                                             >
   1415                                                 <div
   1416                                                     class={`flex flex-row h-full w-8 justify-start items-start`}
   1417                                                 >
   1418                                                     <p
   1419                                                         class={` font-mono font-[500] text-sm text-ly0-gl text-justify break-word`}
   1420                                                     >
   1421                                                         {`*`}
   1422                                                     </p>
   1423                                                 </div>
   1424                                                 <div
   1425                                                     class={`flex flex-row h-full w-full justify-start items-start`}
   1426                                                 >
   1427                                                     <p
   1428                                                         class={`col-span-10 font-mono font-[500] text-sm text-ly0-gl text-justify break-word`}
   1429                                                     >
   1430                                                         {`${$ls(
   1431                                                             `eula.prohibited_conduct.body_li_0_${li}`,
   1432                                                         )}`}
   1433                                                     </p>
   1434                                                 </div>
   1435                                             </div>
   1436                                         {/each}
   1437                                     </div>
   1438                                 </div>
   1439                                 <div
   1440                                     class={`flex flex-col w-full gap-2 justify-start items-start`}
   1441                                 >
   1442                                     <p
   1443                                         class={`font-mono font-[600] text-ly0-gl`}
   1444                                     >
   1445                                         {`**${$ls(
   1446                                             `eula.consequences_of_violation.title`,
   1447                                         )}**`}
   1448                                     </p>
   1449                                     <p
   1450                                         class={`font-mono font-[500] text-ly0-gl text-sm text-justify break-word`}
   1451                                     >
   1452                                         {`${$ls(
   1453                                             `eula.consequences_of_violation.body`,
   1454                                         )}`}
   1455                                     </p>
   1456                                 </div>
   1457                                 <div
   1458                                     class={`flex flex-col w-full gap-2 justify-start items-start`}
   1459                                 >
   1460                                     <p
   1461                                         class={`font-mono font-[600] text-ly0-gl`}
   1462                                     >
   1463                                         {`**${$ls(`eula.disclaimer.title`)}**`}
   1464                                     </p>
   1465                                     <p
   1466                                         class={`font-mono font-[500] text-ly0-gl text-sm text-justify break-word`}
   1467                                     >
   1468                                         {`${$ls(`eula.disclaimer.body`)}`}
   1469                                     </p>
   1470                                 </div>
   1471                                 <div
   1472                                     class={`flex flex-col w-full gap-2 justify-start items-start`}
   1473                                 >
   1474                                     <p
   1475                                         class={`font-mono font-[600] text-ly0-gl`}
   1476                                     >
   1477                                         {`**${$ls(`eula.changes.title`)}**`}
   1478                                     </p>
   1479                                     <p
   1480                                         class={`font-mono font-[500] text-ly0-gl text-sm text-justify break-word`}
   1481                                     >
   1482                                         {`${$ls(`eula.changes.body`)}`}
   1483                                     </p>
   1484                                 </div>
   1485                                 <div
   1486                                     class={`flex flex-col w-full gap-2 justify-start items-start`}
   1487                                 >
   1488                                     <p
   1489                                         class={`font-mono font-[600] text-ly0-gl`}
   1490                                     >
   1491                                         {`**${$ls(`eula.contact.title`)}**`}
   1492                                     </p>
   1493                                     <p
   1494                                         class={`font-mono font-[500] text-ly0-gl text-sm text-justify break-word`}
   1495                                     >
   1496                                         {`${$ls(`eula.contact.body`)}`}
   1497                                     </p>
   1498                                 </div>
   1499                                 <div
   1500                                     class={`flex flex-col w-full gap-2 justify-start items-start`}
   1501                                 >
   1502                                     <p
   1503                                         class={`font-mono font-[600] text-ly0-gl`}
   1504                                     >
   1505                                         {`**${$ls(`eula.acceptance_of_terms.title`)}**`}
   1506                                     </p>
   1507                                     <p
   1508                                         class={`font-mono font-[500] text-ly0-gl text-sm text-justify break-word`}
   1509                                     >
   1510                                         {`${$ls(`eula.acceptance_of_terms.body`)}`}
   1511                                     </p>
   1512                                 </div>
   1513                             </div>
   1514                         </div>
   1515                         <div
   1516                             class={`flex flex-row w-full ios0:pt-8 pt-6 justify-center items-center`}
   1517                         >
   1518                             <button
   1519                                 class={`group flex flex-row basis-1/2 gap-4 justify-center items-center ${
   1520                                     is_eula_scrolled ? `` : `opacity-80`
   1521                                 }`}
   1522                                 onclick={async () => {
   1523                                     const confirm = await notif.confirm({
   1524                                         message: `${$ls(
   1525                                             `eula.error.required`,
   1526                                         )}`,
   1527                                         cancel: `${$ls(`common.quit`)}`,
   1528                                     });
   1529 
   1530                                     if (confirm === false)
   1531                                         await page_reset(undefined, true);
   1532                                 }}
   1533                             >
   1534                                 <p
   1535                                     class={`font-mono font-[400] text-sm text-ly0-gl group-active:text-ly0-gl el-re`}
   1536                                 >
   1537                                     {`-`}
   1538                                 </p>
   1539                                 <p
   1540                                     class={`font-mono font-[400] text-sm text-ly0-gl group-active:text-ly0-gl el-re`}
   1541                                 >
   1542                                     {`${`${$ls(`common.disagree`)}`}`}
   1543                                 </p>
   1544                                 <p
   1545                                     class={`font-mono font-[400] text-sm text-ly0-gl group-active:text-ly0-gl el-re`}
   1546                                 >
   1547                                     {`-`}
   1548                                 </p>
   1549                             </button>
   1550                             <button
   1551                                 class={`relative group flex flex-row basis-1/2 gap-4 justify-center items-center el-re ${
   1552                                     is_eula_scrolled ? `` : `opacity-40`
   1553                                 }`}
   1554                                 onclick={async () => {
   1555                                     if (is_eula_scrolled) await submit();
   1556                                 }}
   1557                             >
   1558                                 <p
   1559                                     class={`font-mono font-[400] text-sm text-ly0-gl-hl group-active:text-ly0-gl-hl/80 el-re`}
   1560                                 >
   1561                                     {`-`}
   1562                                 </p>
   1563                                 <p
   1564                                     class={`font-mono font-[400] text-sm text-ly0-gl-hl group-active:text-ly0-gl-hl/80 el-re`}
   1565                                 >
   1566                                     {`${`${$ls(`common.agree`)}`}`}
   1567                                 </p>
   1568                                 <p
   1569                                     class={`font-mono font-[400] text-sm text-ly0-gl-hl group-active:text-ly0-gl-hl/80 el-re`}
   1570                                 >
   1571                                     {`- `}
   1572                                 </p>
   1573                                 {#if is_loading_s}
   1574                                     <div
   1575                                         class={`absolute right-3 flex flex-row justify-start items-center`}
   1576                                     >
   1577                                         <LoadSymbol basis={{ dim: `xs` }} />
   1578                                     </div>
   1579                                 {/if}
   1580                             </button>
   1581                         </div>
   1582                     </div>
   1583                 </CarouselItem>
   1584             </CarouselContainer>
   1585         </div>
   1586     </ViewPane>
   1587 </ViewStack>