diff options
| author | Adam Soltys <[email protected]> | 2023-02-06 16:40:14 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2023-02-06 16:40:19 -0800 |
| commit | 66740dea41f2772d46e1b13b91ef0e7b1a68bfff (patch) | |
| tree | 2ff8926078222020c05252e64da6ae5e9c9cbbef /src/components | |
| parent | 916f331e0e9a051830ce988639bb2149788e8228 (diff) | |
| download | coinos-ui-66740dea41f2772d46e1b13b91ef0e7b1a68bfff.tar.gz coinos-ui-66740dea41f2772d46e1b13b91ef0e7b1a68bfff.zip | |
new pinpad component
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/Feed.svelte | 4 | ||||
| -rw-r--r-- | src/components/Password.svelte | 6 | ||||
| -rw-r--r-- | src/components/Pin.svelte | 26 | ||||
| -rw-r--r-- | src/components/Pinpad.svelte | 81 | ||||
| -rw-r--r-- | src/components/RegisterOrLogin.svelte | 203 | ||||
| -rw-r--r-- | src/components/index.js | 1 |
6 files changed, 193 insertions, 128 deletions
diff --git a/src/components/Feed.svelte b/src/components/Feed.svelte index ab757fa1..7de087a7 100644 --- a/src/components/Feed.svelte +++ b/src/components/Feed.svelte @@ -4,7 +4,7 @@ import { Event } from '$comp'; import { browser } from '$app/environment'; import VirtualScroll from 'svelte-virtual-scroll-list'; - import { failure } from '$lib/utils'; + import { fail } from '$lib/utils'; import { sign, send } from '$lib/nostr'; export let events; @@ -34,7 +34,7 @@ events = events; } catch (e) { console.log(e, e.stack); - failure('Problem posting event'); + fail('Problem posting event'); } }; diff --git a/src/components/Password.svelte b/src/components/Password.svelte index fd39441c..a84c0b16 100644 --- a/src/components/Password.svelte +++ b/src/components/Password.svelte @@ -1,6 +1,6 @@ <script> import { Icon } from '$comp'; - import { focus, failure, post } from '$lib/utils'; + import { focus, fail, post } from '$lib/utils'; import { password as pw, passwordPrompt } from '$lib/store'; export let user; @@ -17,7 +17,7 @@ $passwordPrompt = false; $pw = password; } catch (e) { - failure('Invalid password, try again'); + fail('Invalid password, try again'); } }; </script> @@ -51,7 +51,7 @@ <button type="button" on:click={() => (revealPassword = !revealPassword)} - class="absolute right-5 top-5" + class="absolute right-5 top-6" > <Icon icon={revealPassword ? 'eye' : 'eye-off'} /> </button> diff --git a/src/components/Pin.svelte b/src/components/Pin.svelte index 7225ac37..0db831ff 100644 --- a/src/components/Pin.svelte +++ b/src/components/Pin.svelte @@ -1,24 +1,28 @@ <script> + import { t } from '$lib/translations'; import { focus } from '$lib/utils'; - import { pin } from '$lib/store'; + import { Pinpad } from '$comp'; - let pinCode = ''; - let pinInput; + export let value = ''; + export let title = $t('user.settings.verifyPIN'); + export let cancel = () => (pin = ''); - let cancel = () => ($pin = '000000'); + let pin = ''; - $: pinCode.length > 5 && ($pin = pinCode); + $: update(value); + let update = (v) => (pin = v) || console.log('updated', v, pin); + + $: pin.toString().length > 5 && (value = pin.toString()); </script> -<div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-20"> - <div class="relative top-1/3 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white space-y-5"> - <h1 class="text-center text-2xl font-semibold">Please enter your PIN</h1> - <input bind:value={pinCode} use:focus /> +<div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"> + <div class="relative top-40 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white space-y-5"> + <h1 class="text-center text-2xl font-semibold">{title}</h1> + <Pinpad bind:v={pin} {cancel} /> <div class="w-full flex"> <button - type="submit" class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" - on:click={cancel} + on:click|preventDefault={cancel} > <div class="my-auto">Cancel</div> </button> diff --git a/src/components/Pinpad.svelte b/src/components/Pinpad.svelte new file mode 100644 index 00000000..bf3778f7 --- /dev/null +++ b/src/components/Pinpad.svelte @@ -0,0 +1,81 @@ +<script> + import { Left, Icon } from '$comp'; + import { pin, selectedRate } from '$lib/store'; + import { f, s, focus, post, warning, sat, sats } from '$lib/utils'; + import { t } from '$lib/translations'; + + export let v; + export let cancel; + + let arrow = '<'; + let loading = false; + + const numPad = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'C', '0', '<']; + + const handleInput = (n) => { + v = (v || '').toString(); + if (n === 'C') return (v = ''); + if (n === '<') return (v = v.length > 1 ? Math.floor(v / 10) : ''); + if (v.length > 5) n = ''; + if (parseInt(n) >= 0) v += n; + }; + + let validate = (e) => { + let k = e.key || e.code; + if (k === 'Escape') cancel(); + if (e.key.length <= 1 && !(e.metaKey || e.ctrlKey || e.altKey) && !(k >= '0' && k <= '9')) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + } + }; + + let hide = true; +</script> + +<div class="flex justify-center items-center"> + <div class="space-y-5"> + <div class="text-5xl md:text-6xl font-semibold relative w-[300px]"> + {#if hide} + <input + on:keydown={validate} + use:focus + bind:value={v} + type="password" + class="outline-none border-0 text-center py-0" + pattern="[0-9]+" + /> + {:else} + <input + on:keydown={validate} + bind:value={v} + class="outline-none border-0 text-center py-0" + type="text" + pattern="[0-9]+" + /> + {/if} + <button type="button" on:click={() => (hide = !hide)} class="absolute -right-5 top-5"> + <Icon icon={hide ? 'eye-off' : 'eye'} style="w-8" /> + </button> + </div> + + <div class="grid grid-cols-3 gap-2 w-[300px] mx-auto grayscale"> + {#each numPad as value} + {#if value === arrow} + <button + type="button" + class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white flex justify-center items-center hover:opacity-80" + on:click={() => handleInput(value)} + > + <Left /> + </button> + {:else} + <button + type="button" + class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white hover:opacity-80" + on:click={() => handleInput(value)}>{value}</button + > + {/if} + {/each} + </div> + </div> +</div> diff --git a/src/components/RegisterOrLogin.svelte b/src/components/RegisterOrLogin.svelte index 7ac2fbb3..6c099178 100644 --- a/src/components/RegisterOrLogin.svelte +++ b/src/components/RegisterOrLogin.svelte @@ -1,28 +1,32 @@ <script> import { applyAction, deserialize } from '$app/forms'; import { tick } from 'svelte'; - import { Pincode, PincodeInput } from 'svelte-pincode'; import { fly } from 'svelte/transition'; import { enhance } from '$app/forms'; - import { Icon, Spinner } from '$comp'; - import { focus } from '$lib/utils'; + import { Pin, Icon, Spinner } from '$comp'; + import { focus, fail } from '$lib/utils'; import { password, loginRedirect } from '$lib/store'; import { t } from '$lib/translations'; import { page } from '$app/stores'; import { generate } from '$lib/nostr'; import { invalidateAll } from '$app/navigation'; - let token, tokenInput, formElement; + export let form; + export let pageID; + + let token, formElement; let code = []; let redirect; $password = undefined; $: need2fa = form?.message === '2fa'; - $: if (need2fa) tokenInput && tick().then(tokenInput.focusFirstInput); - - export let form; - export let pageID; + let cancel = () => (need2fa = false); + $: if (form?.message === '2fa' && form.token === token) { + token = ''; + console.log('TOKEN', token); + fail('Invalid token, try again'); + } let username, email, btn; @@ -66,6 +70,10 @@ } </script> +{#if need2fa} + <Pin bind:value={token} title="Enter 2FA Code" {cancel} /> +{/if} + <div class="pt-10"> <div class="w-[243px] mx-auto mb-10"> <a href="/"> @@ -75,126 +83,97 @@ <div class="flex justify-center items-center"> <div class="shadow-xl rounded-3xl p-10 pb-12 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]"> - {#if need2fa} - <h1 class="text-2xl font-bold text-center">Enter 2FA Code</h1> + <h1 class="text-2xl font-bold text-center">{$t('login.' + pageID)}</h1> - {#if form?.token} - <div class="text-red-600 text-center" in:fly>Invalid token, try again</div> - {/if} - - <form class="space-y-5" {action} method="POST" use:enhance> - <input type="hidden" name="username" value={username} /> - <input type="hidden" name="password" value={$password} /> - <input type="hidden" name="token" value={token} /> - - <div> - <Pincode bind:code bind:value={token} bind:this={tokenInput}> - <PincodeInput /> - <PincodeInput /> - <PincodeInput /> - <PincodeInput /> - <PincodeInput /> - <PincodeInput /> - </Pincode> - </div> - <button - bind:this={btn} - type="submit" - class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" - >{$t('login.' + pageID)} - </button> - </form> - {:else} - <h1 class="text-2xl font-bold text-center">{$t('login.' + pageID)}</h1> + {#if form?.error} + <div class="text-red-600 text-center" in:fly> + {form.error} + </div> + {/if} - {#if form?.error} - <div class="text-red-600 text-center" in:fly> - {form.error} - </div> - {/if} + <form class="space-y-5" on:submit|preventDefault={handleSubmit} method="POST"> + <input type="hidden" name="loginRedirect" value={$loginRedirect} /> + <input type="hidden" name="token" value={token} /> - <form class="space-y-5" on:submit|preventDefault={handleSubmit} method="POST"> - <input type="hidden" name="loginRedirect" value={$loginRedirect} /> + <div> + <label for="username" class="font-semibold">{$t('login.username')}</label> + <input + name="username" + type="text" + required + class="bg-primary" + bind:value={username} + use:focus + autocapitalize="none" + /> + </div> - <div> - <label for="username" class="font-semibold">{$t('login.username')}</label> + <div class="relative"> + <label for="password" class="block font-semibold">{$t('login.password')}</label> + {#if revealPassword} <input - name="username" + name="password" type="text" required class="bg-primary" - bind:value={username} - use:focus + bind:value={$password} autocapitalize="none" /> - </div> - - <div class="relative"> - <label for="password" class="block font-semibold">{$t('login.password')}</label> - {#if revealPassword} - <input - name="password" - type="text" - required - class="bg-primary" - bind:value={$password} - autocapitalize="none" - /> - {:else} - <input - name="password" - type="password" - required - class="bg-primary" - bind:value={$password} - autocapitalize="none" - /> - {/if} - <button - type="button" - on:click={() => (revealPassword = !revealPassword)} - class="absolute right-5 top-10" - > - <Icon icon={revealPassword ? 'eye' : 'eye-off'} /> - </button> - </div> - - {#if pageID === 'register'} - <p class="text-secondary text-sm"> - {$t('login.passwordRecommendation')} - </p> {:else} - <!-- TODO --> - <!-- <div class="flex justify-end items-center"> --> - <!-- <a href="/forgot" class="underline underline-offset-4 text-black text-sm" --> - <!-- >{$t('login.forgotUserOrPassword')}</a --> - <!-- > --> - <!-- </div> --> + <input + name="password" + type="password" + required + class="bg-primary" + bind:value={$password} + autocapitalize="none" + /> {/if} - <button - type="submit" - class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" - disabled={loading} + type="button" + on:click={() => (revealPassword = !revealPassword)} + class="absolute right-5 top-10" > - {#if loading} - <Spinner /> - {:else} - {$t('login.' + pageID)} - {/if} + <Icon icon={revealPassword ? 'eye' : 'eye-off'} /> </button> - </form> + </div> - <p class="text-secondary text-center font-medium"> - {pageID === 'register' ? $t('login.haveAccount') : $t('login.noAccount')} - <a - href={pageID === 'register' ? '/login' : '/register'} - class="block md:inline text-black underline underline-offset-4 hover:opacity-80" - > - {pageID === 'register' ? $t('login.signIn') : $t('login.register')} - </a> - </p> - {/if} + {#if pageID === 'register'} + <p class="text-secondary text-sm"> + {$t('login.passwordRecommendation')} + </p> + {:else} + <!-- TODO --> + <!-- <div class="flex justify-end items-center"> --> + <!-- <a href="/forgot" class="underline underline-offset-4 text-black text-sm" --> + <!-- >{$t('login.forgotUserOrPassword')}</a --> + <!-- > --> + <!-- </div> --> + {/if} + + <button + type="submit" + class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" + disabled={loading} + bind:this={btn} + > + {#if loading} + <Spinner /> + {:else} + {$t('login.' + pageID)} + {/if} + </button> + </form> + + <p class="text-secondary text-center font-medium"> + {pageID === 'register' ? $t('login.haveAccount') : $t('login.noAccount')} + <a + href={pageID === 'register' ? '/login' : '/register'} + class="block md:inline text-black underline underline-offset-4 hover:opacity-80" + > + {pageID === 'register' ? $t('login.signIn') : $t('login.register')} + </a> + </p> </div> </div> </div> diff --git a/src/components/index.js b/src/components/index.js index 18a821ff..ab54e09f 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,3 +1,4 @@ +export { default as Pinpad } from './Pinpad.svelte'; export { default as Balance } from './Balance.svelte'; export { default as Lnurlp } from './Lnurlp.svelte'; export { default as Lnurlw } from './Lnurlw.svelte'; |
