@ -9,18 +9,31 @@
// according to those terms.
// according to those terms.
-->
-->
<!--
The Login Procedure.
Has multiple states (steps) through the user flow.
-->
< script lang = "ts" >
< script lang = "ts" >
import { Alert , Toggle } from "flowbite-svelte";
import { Alert , Toggle } from "flowbite-svelte";
import { onMount , createEventDispatcher , tick } from "svelte";
import { onMount , createEventDispatcher , tick } from "svelte";
import ng from "../api";
import ng from "../api";
import { emoji_cat , emojis , load_svg } from "../wallet_emojis";
import { emoji_cat , emojis , load_svg } from "../wallet_emojis";
import { PuzzlePiece } from "svelte-heros-v2";
import {
PuzzlePiece,
XCircle,
Backspace,
ArrowPath,
LockOpen,
Key,
CheckCircle,
} from "svelte-heros-v2";
import PasswordInput from "./components/PasswordInput.svelte";
//import Worker from "../worker.js?worker&inline";
//import Worker from "../worker.js?worker&inline";
export let wallet;
export let wallet;
export let for_import = false;
export let for_import = false;
let tauri_platform = import.meta.env.TAURI_PLATFORM;
let tauri_platform = import.meta.env.TAURI_PLATFORM;
let mobile = tauri_platform == "android" || tauri_platform == "ios";
const dispatch = createEventDispatcher();
const dispatch = createEventDispatcher();
@ -46,16 +59,22 @@
}
}
emojis2 = emojis2;
emojis2 = emojis2;
display = 0;
pazzlePage = 0;
selection = [];
selection = [];
error = undefined;
error = undefined;
loaded = true;
loaded = true;
}
}
function letsgo () {
function start_with_pazz le() {
loaded = false;
loaded = false;
step = "pazzle";
step = "pazzle";
unlockWith = "pazzle";
}
function start_with_mnemonic() {
loaded = false;
step = "mnemonic";
unlockWith = "mnemonic";
}
}
let emojis2 = [];
let emojis2 = [];
@ -68,29 +87,32 @@
let pazzle_length = 9;
let pazzle_length = 9;
let display = 0;
let pazzlePage = 0;
let selection = [];
/** The selected emojis by category (one for each pazzle page). First will be the selected of first pazzle page. */
let selection = [].fill(null, 0, pazzle_length);
let pin_code = [];
let pin_code = [];
/** The selected order from the order page. */
let ordered = [];
let ordered = [];
let last_one = {} ;
let shuffle_pin;
let shuffle_pin;
let error;
let error;
let trusted = false;
let trusted = false;
let mnemonic = "";
let unlockWith: "pazzle" | "mnemonic" | undefined;
function order() {
function order() {
step = "order";
step = "order";
ordered = [];
ordered = [];
last_one = {} ;
// In case, this is called by the cancel button, we need to reset the selection.
for (let i = 0; i < pazzle_length ; i ++) {
selection.forEach((emoji) => (emoji.sel = undefined));
last_one[i] = true;
selection = selection;
}
}
}
async function start_pin() {
async function start_pin() {
@ -101,20 +123,19 @@
//console.log(shuffle_pin);
//console.log(shuffle_pin);
}
}
/** Called on selecting emoji in a category. */
function select(val) {
function select(val) {
//console.log(emojis2[display][val]);
//console.log(emojis2[display][val]);
let cat_idx = shuffle.category_indices[display ];
let cat_idx = shuffle.category_indices[pazzlePage ];
let cat = emojis[emoji_cat[cat_idx]];
let cat = emojis[emoji_cat[cat_idx]];
let idx = shuffle.emoji_indices[display][val];
let idx = shuffle.emoji_indices[pazzlePage][val];
//console.log(cat_idx, emoji_cat[cat_idx], idx, cat[idx].code);
selection.push({ cat : cat_idx , index : idx } );
selection[pazzlePage] = { cat : cat_idx , index : idx } ;
//console.log(selection);
if (display == pazzle_length - 1) {
if (pazzlePage == pazzle_length - 1) {
order();
order();
} else {
} else {
display = display + 1;
pazzlePage = pazzlePage + 1;
}
}
}
}
@ -122,20 +143,21 @@
step = "opening";
step = "opening";
let pazzle = [];
let pazzle = [];
for (const emoji of ordered) {
for (const emoji of ordered) {
pazzle.push((emoji.cat < < 4 ) + emoji . index ) ;
pazzle.push((emoji.cat < < 4 ) + emoji . index ) ;
}
}
//console.log(pazzle);
const mnemonic_words = mnemonic.split(" ");
//console.log(wallet);
// open the wallet
// open the wallet
try {
try {
if (tauri_platform) {
if (tauri_platform) {
let opened_wallet = await ng.wallet_open_with_pazzle(
let opened_wallet =
unlockWith === "pazzle"
? await ng.wallet_open_with_pazzle(wallet, pazzle, pin_code)
: await ng.wallet_open_with_mnemonic_words(
wallet,
wallet,
pazzle,
mnemonic_words ,
pin_code
pin_code
);
);
// try {
// try {
@ -172,7 +194,11 @@
myWorker.onmessage = async (msg) => {
myWorker.onmessage = async (msg) => {
//console.log("Message received from worker", msg.data);
//console.log("Message received from worker", msg.data);
if (msg.data.loaded) {
if (msg.data.loaded) {
if (unlockWith === "pazzle") {
myWorker.postMessage({ wallet , pazzle , pin_code } );
myWorker.postMessage({ wallet , pazzle , pin_code } );
} else {
myWorker.postMessage({ wallet , mnemonic_words , pin_code } );
}
//console.log("postMessage");
//console.log("postMessage");
} else if (msg.data.success) {
} else if (msg.data.success) {
//console.log(msg.data);
//console.log(msg.data);
@ -214,23 +240,17 @@
dispatch("cancel");
dispatch("cancel");
}
}
async function pin(val) {
async function on_pin_key(val) {
//console.log(val);
pin_code = [...pin_code, val];
pin_code.push(val);
if (pin_code.length == 4) {
await finish();
}
}
}
async function select_order(val, pos) {
async function select_order(val) {
delete last_one[pos];
//console.log(last_one);
//console.log(val);
ordered.push(val);
ordered.push(val);
val.sel = ordered.length;
val.sel = ordered.length;
selection = selection;
selection = selection;
if (ordered.length == pazzle_length - 1) {
if (ordered.length == pazzle_length - 1) {
let last = selection[Object.keys(last_one)[0]] ;
let last = selection.find((emoji) => !emoji.sel) ;
ordered.push(last);
ordered.push(last);
last.sel = ordered.length;
last.sel = ordered.length;
selection = selection;
selection = selection;
@ -238,11 +258,74 @@
await start_pin();
await start_pin();
}
}
}
}
function go_back() {
if (step === "mnemonic") {
init();
} else if (step === "pazzle") {
// Go to previous pazzle or init page, if on first pazzle.
if (pazzlePage === 0) {
init();
} else {
pazzlePage -= 1;
}
} else if (step === "order") {
if (ordered.length === 0) {
step = "pazzle";
} else {
const last_selected = ordered.pop();
last_selected.sel = null;
ordered = ordered;
selection = selection;
}
} else if (step === "pin") {
if (unlockWith === "mnemonic") {
start_with_mnemonic();
} else if (pin_code.length === 0) {
// Unselect the last two elements.
const to_unselect = ordered.slice(-2);
to_unselect.forEach((val) => {
val.sel = null;
});
ordered = ordered.slice(0, -2);
selection = selection;
step = "order";
} else {
pin_code = pin_code.slice(0, pin_code.length - 1);
}
}
}
let width: number;
let height: number;
const breakPointWidth: number = 530;
const breakPointHeight: number = 900;
let mobile = false;
$: if (width >= breakPointWidth && height >= breakPointHeight) {
mobile = false;
} else {
mobile = true;
}
< / script >
< / script >
{ #if step == "load" }
< div
< div class = " max-w-xl lg:px-8 mx-auto px-4 mt-10" >
class="flex flex-col justify-center h-screen p-4"
< h2 class = "pb-5 text-xl" > How to open your wallet, step by step :< / h2 >
class:min-w-[310px]={ mobile }
class:min-w-[500px]={ ! mobile }
class:max-w-[360px]={ mobile }
class:max-w-[600px]={ ! mobile }
>
{ #if step == "load" }
< div
class="flex flex-col justify-center p-4"
class:min-w-[310px]={ mobile }
class:min-w-[500px]={ ! mobile }
class:max-w-[360px]={ mobile }
class:max-w-[600px]={ ! mobile }
>
< h2 class = "pb-5 text-xl self-start" > How to open your wallet:< / h2 >
< h3 class = "pb-2 text-lg self-start" > By your Pazzle< / h3 >
< ul class = "mb-8 ml-3 space-y-4 text-left list-decimal" >
< ul class = "mb-8 ml-3 space-y-4 text-left list-decimal" >
< li >
< li >
For each one of the 9 categories of images, you will be presented with
For each one of the 9 categories of images, you will be presented with
@ -251,37 +334,48 @@
< / li >
< / li >
< li >
< li >
At each category, only one of the 15 displayed choices is the correct
At each category, only one of the 15 displayed choices is the correct
image that belongs to your pazzle. Find it and tap or click on that one.
image that belongs to your pazzle. Find it and tap or click on that
The 15 images are shuffled too, they will not appear at the same
one. The 15 images are shuffled too, they will not appear at the same
position at each login. On a computer, you can also use the tab key on
position at each login. On a computer, you can also use the tab key on
your keyboard to move to the desired item on the screen, then press the
your keyboard to move to the desired item on the screen, then press
space bar to select each one.
the space bar to select each one.
< / li >
< / li >
< li >
< li >
Once you completed the last category, you will be presented with all the
Once you completed the last category, you will be presented with all
images you have previously selected. Their order is displayed as it w as
the images you have previously selected. Their order is displayed as
when you picked them. But this is not the correct order of the images in
it was when you picked them. But this is not the correct order of the
your pazzle. You now have to order them correctly.
images in your pazzle. You now have to order them correctly.
< / li >
< / li >
< li >
< li >
You must remember which image should be the first one in your pazzle.
You must remember which image should be the first one in your pazzle.
Find it on the screen and click or tap on it. It will be greyed out and
Find it on the screen and click or tap on it. It will be greyed out
the number 1 will appear on top of it.
and the number 1 will appear on top of it.
< / li >
< / li >
< li >
< li >
Move on to the second image of your pazzle (that you memorized). Find it
Move on to the second image of your pazzle (that you memorized). Find
on the screen and tap on it. Repeat this step until you reached the last
it on the screen and tap on it. Repeat this step until you reached the
image.
last image.
< / li >
< / li >
< li >
< li >
Finally, your PIN code will be asked. enter it by clicking or tapping on
Finally, your PIN code will be asked. enter it by clicking or tapping
the digits.
on the digits.
< / li >
< / li >
< / ul >
< / ul >
< / div >
< h3 class = "pb-2 text-lg self-start" >
By your 12 word Mnemonic (passphrase)
< / h3 >
< ul class = "mb-8 ml-3 space-y-4 text-left list-decimal" >
< li >
Enter your twelve word mnemonic in the input field. The words must be
separated by spaces.
< / li >
< li > Enter the PIN code that you chose when you created your wallet.< / li >
< / ul >
< div class = " max-w-xl lg:px-8 mx-auto px-4 text-primary-700" >
< div class = " max-w-xl lg:px-8 mx-auto px-4 text-primary-700" >
{ #if ! loaded }
{ #if ! loaded }
Loading pazzle...
Loading wallet ...
< svg
< svg
class="animate-spin my-4 h-14 w-14 mx-auto"
class="animate-spin my-4 h-14 w-14 mx-auto"
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
@ -304,20 +398,9 @@
/>
/>
< / svg >
< / svg >
{ : else }
{ : else }
< button
<!-- Save wallet? -->
on:click={ letsgo }
class="mt-1 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2"
>
< PuzzlePiece
tabindex="-1"
class="w-8 h-8 mr-2 -ml-1 transition duration-75 group-hover:text-gray-900 dark:group-hover:text-white"
/>
Open my wallet now!
< / button >
{ /if }
< / div >
{ #if for_import }
{ #if for_import }
< div class = " max-w-xl lg:px-8 mx-auto px-4 mb-8" >
< div class = "max-w-xl lg:px-8 mx-auto px-4 mb-8" >
< span class = "text-xl" > Do you trust this device? < / span > < br / >
< span class = "text-xl" > Do you trust this device? < / span > < br / >
< div class = "flex justify-center items-center my-4" >
< div class = "flex justify-center items-center my-4" >
< Toggle class = "" bind:checked = { trusted }
< Toggle class = "" bind:checked = { trusted }
@ -325,26 +408,97 @@
>
>
< / div >
< / div >
< p class = "text-sm" >
< p class = "text-sm" >
If you do, if this device is yours or is used by few trusted persons of
If you do, if this device is yours or is used by few trusted
your family or workplace, and you would like to login again from this
persons of your family or workplace, and you would like to login
device in the future, then you can save your wallet on this device. To
again from this device in the future, then you can save your
the contrary, if this device is public and shared by strangers, do not
wallet on this device. To the contrary, if this device is public
save your wallet here. { #if ! tauri_platform } By selecting this option,
and shared by strangers, do not save your wallet here. { #if ! tauri_platform } By
you agree to save some cookies on your browser.{ /if } < br />
selecting this option, you agree to save some cookies on your
browser.{ /if } < br />
< / p >
< / p >
< / div >
< / div >
{ /if }
{ /if }
{ :else if step == "pazzle" }
< div class = "flex flex-col justify-centerspace-x-12 mt-4 mb-4" >
< button
on:click={ start_with_pazzle }
class="mt-1 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2"
>
< PuzzlePiece
tabindex="-1"
class="w-8 h-8 mr-2 -ml-1 transition duration-75 group-hover:text-gray-900 dark:group-hover:text-white"
/>
Open with Pazzle!
< / button >
< a
on:click={ start_with_mnemonic }
class="mt-1 text-lg px-5 py-2.5 text-center inline-flex items-center mb-2 underline cursor-pointer"
>
Open with Mnemonic instead
< / a >
< button
on:click={ cancel }
class="mt-1 mb-2 bg-red-100 hover:bg-red-100/90 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55"
>< XCircle
tabindex="-1"
class="w-8 h-8 mr-2 -ml-1 transition duration-75 group-hover:text-gray-900 dark:group-hover:text-white"
/>Cancel< /button
>
< / div >
{ /if }
< / div >
< / div >
<!-- The following steps have navigation buttons and fixed layout -->
{ :else if step == "pazzle" || step == "order" || step == "pin" || step == "mnemonic" }
< div
< div
class="h-screen aspect-[3/5] pazzleline"
class="flex flex-col justify-center h-screen p-4 "
class:min-w-[310px]={ mobile }
class:min-w-[310px]={ mobile }
class:min-w-[500px]={ ! mobile }
class:min-w-[500px]={ ! mobile }
class:max-w-[360px]={ mobile }
class:max-w-[360px]={ mobile }
class:max-w-[600px]={ ! mobile }
class:max-w-[600px]={ ! mobile }
>
>
< div class = "mt-auto flex flex-col justify-center" >
<!-- Unlock Screens -->
{ #if step == "mnemonic" }
< form on:submit | preventDefault = { start_pin } >
< label
for="mnemonic-input"
class="block mb-2 text-xl text-gray-900 dark:text-white"
>Your 12 word mnemonic< /label
>
< PasswordInput
id="mnemonic-input"
placeholder="Enter your 12 word mnemonic here separated by spaces"
bind:value={ mnemonic }
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
auto_complete="mnemonic"
/>
< div class = "flex" >
< button
type="submit"
class="mt-1 ml-auto text-white bg-primary-700 disabled:opacity-65 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55"
on:click={ start_pin }
disabled={ mnemonic . split ( " " ). length !== 12 }
>< CheckCircle
tabindex="-1"
class="w-8 h-8 mr-2 -ml-1 transition duration-75 group-hover:text-gray-900 dark:group-hover:text-white"
/>Confirm< /button
>
< / div >
< / form >
{ :else if step == "pazzle" }
< p class = "max-w-xl md:mx-auto lg:max-w-2xl" >
< span class = "text-xl" >
<!-- TODO: Internationalization -->
Select your emoji of category: { emoji_cat [
shuffle.category_indices[pazzlePage]
]}< /span
>
< / p >
{ #each [ 0 , 1 , 2 , 3 , 4 ] as row }
{ #each [ 0 , 1 , 2 , 3 , 4 ] as row }
< div class = "columns-3 gap-0" >
< div class = "columns-3 gap-0" >
{ #each emojis2 [ display ] ? . slice ( 0 + row * 3 , 3 + row * 3 ) || [] as emoji , i }
{ #each emojis2 [ pazzlePage ] ? . slice ( 0 + row * 3 , 3 + row * 3 ) || [] as emoji , i ( pazzlePage + "-" + row + "-" + i ) }
< div
< div
role="button"
role="button"
tabindex="0"
tabindex="0"
@ -357,16 +511,10 @@
{ /each }
{ /each }
< / div >
< / div >
{ /each }
{ /each }
< / div >
{ :else if step == "order" }
{ :else if step == "order" }
< p class = "max-w-xl md:mx-auto lg:max-w-2xl mb-2" >
<!-- console.log(cat_idx, emoji_cat[cat_idx], idx, cat[idx].code); -->
< span class = "text-xl" > Click your emojis in the correct order< / span >
< div
< / p >
class="h-screen aspect-[3/3] pazzleline"
class:min-w-[320px]={ mobile }
class:min-w-[500px]={ ! mobile }
class:max-w-[360px]={ mobile }
class:max-w-[600px]={ ! mobile }
>
{ #each [ 0 , 1 , 2 ] as row }
{ #each [ 0 , 1 , 2 ] as row }
< div class = "columns-3 gap-0" >
< div class = "columns-3 gap-0" >
{ #each selection . slice ( 0 + row * 3 , 3 + row * 3 ) || [] as emoji , i }
{ #each selection . slice ( 0 + row * 3 , 3 + row * 3 ) || [] as emoji , i }
@ -375,19 +523,24 @@
role="button"
role="button"
tabindex="0"
tabindex="0"
class="w-full aspect-square emoji focus:outline-none focus:bg-gray-300"
class="w-full aspect-square emoji focus:outline-none focus:bg-gray-300"
on:click={() => select_order ( emoji , row * 3 + i )}
on:click={() => select_order ( emoji )}
on:keypress={() => select_order ( emoji , row * 3 + i )}
on:keypress={() => select_order ( emoji )}
>
>
< svelte:component
< svelte:component
this={ emojis [ emoji_cat [ emoji . cat ]][ emoji . index ]. svg ? . default }
this={ emojis [ emoji_cat [ emoji . cat ]][ emoji . index ]. svg
?.default}
/>
/>
< / div >
< / div >
{ : else }
{ : else }
< div class = "w-full aspect-square opacity-25 select-none sel-emoji" >
< div
class="w-full aspect-square opacity-25 select-none sel-emoji"
>
< svelte:component
< svelte:component
this={ emojis [ emoji_cat [ emoji . cat ]][ emoji . index ]. svg ? . default }
this={ emojis [ emoji_cat [ emoji . cat ]][ emoji . index ]. svg
?.default}
/>
/>
< span class = "sel drop-shadow-[2px_2px_2px_rgba(255,255,255,1)]"
< span
class="sel drop-shadow-[2px_2px_2px_rgba(255,255,255,1)]"
>{ emoji . sel } < /span
>{ emoji . sel } < /span
>
>
< / div >
< / div >
@ -395,36 +548,73 @@
{ /each }
{ /each }
< / div >
< / div >
{ /each }
{ /each }
< / div >
{ :else if step == "pin" }
{ :else if step == "pin" }
< p class = "flex items-center md:mx-auto lg:max-w-2xl" >
< div class = " max-w-6xl lg:px-8 mx-auto px-3" >
< span class = "text-xl" > Enter your PIN code:< / span >
< p class = "max-w-xl md:mx-auto lg:max-w-2xl" >
< span class = "text-xl min-w-[2em] ml-1 text-left"
< span class = "text-xl" > Enter your PIN code< / span >
>{ #each pin_code as pin_key } *{ /each } < /span
>
< / p >
< / p >
< div class = "w-[295px] mx-auto" >
{ #each [ 0 , 1 , 2 ] as row }
{ #each [ 0 , 1 , 2 ] as row }
< div class = "" >
< div class = "columns-3 flex " >
{ #each shuffle_pin . slice ( 0 + row * 3 , 3 + row * 3 ) as num }
{ #each shuffle_pin . slice ( 0 + row * 3 , 3 + row * 3 ) as num }
< button
< button
tabindex="0"
tabindex="0"
class="m-1 select-none align-bottom text-7xl w-[90px] h-[90px] p-0"
class="m-1 disabled:opacity-15 select-none align-bottom text-7xl p-0 w-full aspect-square border-0"
on:click={ async () => await pin ( num )}
on:click={ async () => await on_pin_key ( num )}
disabled={ pin_code . length >= 4 }
>
>
< span > { num } </ span >
< span > { num } </ span >
< / button >
< / button >
{ /each }
{ /each }
< / div >
< / div >
{ /each }
{ /each }
< div class = "columns-3 flex" >
< div class = "m-1 w-full aspect-square" / >
< button
< button
tabindex="0"
tabindex="0"
class="m-1 select-none mx-auto align-bottom text-7xl w-[90px] h-[90px] p-0"
class="disabled:opacity-15 m-1 select-none align-bottom text-7xl p-0 w-full aspect-square border-0"
on:click={ async () => await pin ( shuffle_pin [ 9 ])}
on:click={ async () => await on_pin_key ( shuffle_pin [ 9 ])}
disabled={ pin_code . length >= 4 }
>
>
< span > { shuffle_pin [ 9 ]} </ span >
< span > { shuffle_pin [ 9 ]} </ span >
< / button >
< / button >
< button
tabindex="0"
class="w-full bg-green-300 hover:bg-green-300/90 disabled:opacity-15 m-1 select-none align-bottom text-7xl p-0 w-full aspect-square border-0"
on:click={ async () => await finish ()}
disabled={ pin_code . length < 4 }
>
< LockOpen
tabindex="-1"
class="w-full h-[50%] transition duration-75 group-hover:text-gray-900 dark:group-hover:text-white"
/>
< / button >
< / div >
{ /if }
< / div >
<!-- Navigation Buttons for pazzle, order pin, mnemonic -->
< div class = "flex justify-between mt-auto" >
< button
on:click={ cancel }
class="mt-1 bg-red-100 hover:bg-red-100/90 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55"
>< XCircle
tabindex="-1"
class="w-8 h-8 mr-2 -ml-1 transition duration-75 group-hover:text-gray-900 dark:group-hover:text-white"
/>Cancel< /button
>
< button
class="mt-1 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55"
on:click={ go_back }
>< Backspace
tabindex="-1"
class="w-8 h-8 mr-2 -ml-1 transition duration-75 group-hover:text-gray-900 dark:group-hover:text-white"
/>Go Back< /button
>
< / div >
< / div >
< / div >
< / div >
{ :else if step == "opening" }
{ :else if step == "opening" }
< div class = " max-w-6xl lg:px-8 mx-auto px-4 text-primary-700" >
< div class = " max-w-6xl lg:px-8 mx-auto px-4 text-primary-700" >
Opening your wallet...< br / >
Opening your wallet...< br / >
Please wait
Please wait
@ -450,9 +640,10 @@
/>
/>
< / svg >
< / svg >
< / div >
< / div >
{ :else if step == "end" }
{ :else if step == "end" }
{ #if error }
{ #if error }
< div class = " max-w-6xl lg:px-8 mx-auto px-4 text-red-800" >
< div class = " max-w-6xl lg:px-8 mx-auto px-4 text-red-800" >
< div class = "mt-auto max-w-6xl lg:px-8" >
An error occurred !
An error occurred !
< svg
< svg
fill="none"
fill="none"
@ -472,8 +663,27 @@
< Alert color = "red" class = "mt-5" >
< Alert color = "red" class = "mt-5" >
{ error }
{ error }
< / Alert >
< / Alert >
< button class = "mt-10 select-none" on:click = { init } > Try again </ button >
< / div >
< button class = "mt-10 ml-5 select-none" on:click = { cancel } > Cancel </ button >
< div class = "flex justify-between mt-auto gap-4" >
< button
class="mt-10 select-none text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55"
on:click={ init }
>
< ArrowPath
tabindex="-1"
class="w-8 h-8 mr-2 -ml-1 transition duration-75 group-hover:text-gray-900 dark:group-hover:text-white"
/>
Try again
< / button >
< button
on:click={ cancel }
class="mt-10 bg-red-100 hover:bg-red-100/90 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55"
>< XCircle
tabindex="-1"
class="w-8 h-8 mr-2 -ml-1 transition duration-75 group-hover:text-gray-900 dark:group-hover:text-white"
/>Cancel< /button
>
< / div >
< / div >
< / div >
{ : else }
{ : else }
< div class = " max-w-6xl lg:px-8 mx-auto px-4 text-green-800" >
< div class = " max-w-6xl lg:px-8 mx-auto px-4 text-green-800" >
@ -495,7 +705,10 @@
< / svg >
< / svg >
< / div >
< / div >
{ /if }
{ /if }
{ /if }
{ /if }
< / div >
< svelte:window bind:innerWidth = { width } bind:innerHeight= { height } />
< style >
< style >
.pazzleline {
.pazzleline {
@ -505,11 +718,16 @@
.sel {
.sel {
position: absolute;
position: absolute;
display: flex;
width: 100%;
width: 100%;
top: 45%;
height: 100%;
top: 0;
left: 0;
left: 0;
font-size: 100px;
font-size: 100px;
font-weight: 700;
font-weight: 700;
justify-content: center;
align-items: center;
padding-top: 25%;
}
}
.sel-emoji {
.sel-emoji {