feat: improve lighthouse report

This commit is contained in:
Filipe Medeiros 2021-12-04 16:04:10 +00:00
parent f5fdc37fc3
commit 03d965bfc9
17 changed files with 446 additions and 349 deletions

View file

@ -48,7 +48,7 @@ const Balance: FC<Props> = ({ className }) => {
}
className="hover:cursor-pointer"
>
<h3 className="text-4xl">
<h1 className="text-4xl">
<span className="transition-colors">Ӿ</span>
<span
className={clsx(
@ -72,11 +72,11 @@ const Balance: FC<Props> = ({ className }) => {
'NO'
)}
</span>
</h3>
</h1>
{showFiatBalance && (
<h4 className="text-xl transition-colors">
<h2 className="text-xl transition-colors">
$ {(Number(xnoBalance) * xnoPrice).toFixed(2)}
</h4>
</h2>
)}
</div>
</div>

View file

@ -59,17 +59,20 @@ const BottomMenu: FC<Props> = ({ className }) => {
{pathname !== '/dashboard' && (
<Link href="/dashboard">
<a
role="menuitem"
className={clsx(
'h-12 p-1 bg-purple-400 transition-colors rounded shadow hover:bg-purple-400 disabled:hover:bg-purple-400 disabled:cursor-default',
{ 'pointer-events-none': isWelcoming }
)}
>
<span className="hidden">go back to the dashboard</span>
<HomeIcon className="h-full text-purple-50 dark:text-gray-900 transition-colors" />
</a>
</Link>
)}
<div
role="menuitem"
className={clsx(
'flex gap-4 xs:gap-6 items-end',
leftHanded ? 'flex-row-reverse' : 'flex-row'
@ -77,6 +80,7 @@ const BottomMenu: FC<Props> = ({ className }) => {
>
{'share' in navigator ? (
<button
aria-label="Share your nano address"
disabled={isWelcoming}
className="w-10 h-16 p-1 bg-purple-400 transition-colors rounded shadow hover:bg-purple-400 disabled:hover:bg-purple-400 disabled:cursor-default"
onClick={onShare}
@ -85,6 +89,7 @@ const BottomMenu: FC<Props> = ({ className }) => {
</button>
) : (
<button
aria-label="Copy your nano address to the clipboard"
disabled={isWelcoming || confirmCopyAddress}
className={clsx(
'p-1 h-16 w-10 rounded shadow transition-colors',
@ -105,12 +110,14 @@ const BottomMenu: FC<Props> = ({ className }) => {
<div className={clsx('flex h-16', { 'flex-row-reverse': leftHanded })}>
<Link href="/receive/qr">
<a
role="navigation"
className={clsx(
'bg-purple-400 transition-colors h-16 px-1 xs:px-2 w-10 xs:w-14 hover:bg-purple-400 disabled:hover:bg-purple-400 shadow disabled:cursor-default',
leftHanded ? 'rounded-r' : 'rounded-l',
{ 'pointer-events-none': isWelcoming }
)}
>
<span className="hidden">see your qrcode</span>
<LoginIcon
className={
'h-full text-purple-50 dark:text-gray-900 transition-colors w-full -rotate-child-90'
@ -118,17 +125,22 @@ const BottomMenu: FC<Props> = ({ className }) => {
/>
</a>
</Link>
<div className="h-16 p-1 border-t-2 border-b-2 border-purple-400 shadow">
<div
role="presentation"
className="h-16 p-1 border-t-2 border-b-2 border-purple-400 shadow"
>
<QrcodeIcon className="h-full text-gray-900 dark:text-purple-100 transition-colors" />
</div>
<Link href="/send/qrOrAddress">
<a
role="navigation"
className={clsx(
'bg-purple-400 transition-colors h-16 px-1 xs:px-2 w-10 xs:w-14 hover:bg-purple-400 disabled:hover:bg-purple-400 shadow disabled:cursor-default',
leftHanded ? 'rounded-l' : 'rounded-r',
{ 'pointer-events-none': isWelcoming }
)}
>
<span className="hidden">send ӾNO</span>
<PaperAirplaneIcon className="h-full text-purple-50 dark:text-gray-900 transition-colors w-full rotate-[30deg] translate-x-1 -translate-y-0.5" />
</a>
</Link>

View file

@ -2,6 +2,7 @@ import { ChevronUpIcon, ClockIcon } from '@heroicons/react/outline'
import { DownloadIcon, RefreshIcon, UploadIcon } from '@heroicons/react/solid'
import clsx from 'clsx'
import { Unit, convert } from 'nanocurrency'
import Link from 'next/link'
import { FC, useEffect, useState } from 'react'
import useAccountHistory from '../lib/hooks/useAccountHistory'
@ -70,9 +71,9 @@ const RecentTransactions: FC<Props> = () => {
className="flex items-center justify-between gap-1"
onClick={() => setReceivablesExpanded(prev => !prev)}
>
<h2 className="flex-1 text-2xl font-semibold transition-colors text-gray-900 dark:text-purple-50">
<h1 className="flex-1 text-2xl font-semibold transition-colors text-gray-900 dark:text-purple-50">
incoming
</h2>
</h1>
<span className="w-6 text-base text-center dark:text-gray-900 text-purple-50 rounded-full bg-purple-400 dark:bg-purple-50">
{receivableBlocks.length}
@ -98,6 +99,7 @@ const RecentTransactions: FC<Props> = () => {
className="flex items-center justify-between px-3 py-3 text-black border-r-4 border-yellow-400 rounded shadow bg-gray-50 transition-colors dark:hover:bg-gray-700 dark:bg-gray-800 dark:text-purple-50 gap-2"
>
<button
aria-label={`Receive transaction from ${receivable.from}`}
className="contents"
onClick={() => onIncomingClick(receivable)}
>
@ -132,11 +134,12 @@ const RecentTransactions: FC<Props> = () => {
)}
<section className="flex flex-col flex-1 w-full min-h-0 gap-3">
<div className="flex items-center justify-between gap-1">
<h2 className="text-2xl font-semibold text-gray-900 dark:text-purple-50">
<h1 className="text-2xl font-semibold text-gray-900 dark:text-purple-50">
recent transactions
</h2>
</h1>
{hasHistory && (
<button
aria-label="Refresh transaction history"
onClick={() => {
setRefectingHistory(true)
refetchHistory()
@ -163,40 +166,46 @@ const RecentTransactions: FC<Props> = () => {
txn.type === 'send' ? 'border-yellow-300' : 'border-green-300'
)}
>
<button className="contents" onClick={() => {}}>
{txn.type === 'send' ? (
<UploadIcon className="flex-shrink-0 w-6 text-yellow-300" />
) : (
<DownloadIcon
className={clsx('w-6 flex-shrink-0 text-green-300')}
/>
)}
<div className="flex-1 overflow-hidden text-left overflow-ellipsis whitespace-nowrap">
{Intl.DateTimeFormat([], {
day: '2-digit',
month: '2-digit',
year: '2-digit',
}).format(Number(txn.local_timestamp) * 1000)}{' '}
- {<span className="text-xs">{txn.account}</span>}
</div>
<span className="flex-shrink-0 font-medium">
Ӿ{' '}
{rawToNanoDisplay(txn.amount) === 'small' ? (
'<0.01'
) : rawToNanoDisplay(txn.amount).startsWith('0.') ? (
<>
<span className="text-sm font-semibold">0</span>
{rawToNanoDisplay(txn.amount).substring(1)}
</>
<Link href={`/transaction/${txn.hash}`}>
<a className="contents pointer-events-none">
<span className="hidden">
see {txn.hash} transaction details
</span>
{txn.type === 'send' ? (
<UploadIcon className="flex-shrink-0 w-6 text-yellow-300" />
) : (
rawToNanoDisplay(txn.amount)
<DownloadIcon
className={clsx('w-6 flex-shrink-0 text-green-300')}
/>
)}
</span>
</button>
<div className="flex-1 overflow-hidden text-left overflow-ellipsis whitespace-nowrap">
{Intl.DateTimeFormat([], {
day: '2-digit',
month: '2-digit',
year: '2-digit',
}).format(Number(txn.local_timestamp) * 1000)}{' '}
- {<span className="text-xs">{txn.account}</span>}
</div>
<span className="flex-shrink-0 font-medium">
Ӿ{' '}
{rawToNanoDisplay(txn.amount) === 'small' ? (
'<0.01'
) : rawToNanoDisplay(txn.amount).startsWith('0.') ? (
<>
<span className="text-sm font-semibold">0</span>
{rawToNanoDisplay(txn.amount).substring(1)}
</>
) : (
rawToNanoDisplay(txn.amount)
)}
</span>
</a>
</Link>
</li>
))}
{hasMore && (
<button
aria-label="Load more transactions"
className="px-4 py-1.5 font-bold transition-colors bg-purple-400 rounded text-purple-50 shadow dark:text-gray-900 place-self-center"
onClick={loadMore}
>

View file

@ -75,6 +75,7 @@ const TopMenu: FC<Props> = () => {
{!isWelcoming && (
<div className="relative z-20" ref={advancedButtonRef}>
<button
aria-label="Open adavanced menu"
className={clsx(
'w-10 p-1 rounded bg-purple-400 shadow text-purple-50 dark:text-gray-900 hover:cursor-pointer hover:bg-purple-400 transition-colors dark:hover:text-purple-50'
)}
@ -96,6 +97,7 @@ const TopMenu: FC<Props> = () => {
>
<li>
<button
aria-label="Copy your nano seed to your clipboard"
className={clsx(
'p-1 rounded transition-colors dark:hover:text-gray-900 w-full hover:bg-purple-300 bg-purple-400 dark:text-gray-900 text-purple-50'
)}
@ -133,6 +135,7 @@ const TopMenu: FC<Props> = () => {
<div className="relative z-20" ref={preferencesButtonRef}>
<button
aria-label="Open preferences menu"
className={clsx(
'w-10 p-1 rounded bg-purple-400 shadow text-purple-50 hover:cursor-pointer hover:bg-purple-400 transition-colors dark:hover:text-purple-50 dark:text-gray-900'
)}
@ -173,6 +176,7 @@ const TopMenu: FC<Props> = () => {
)} */}
<li role="menuitem">
<button
aria-label="Toggle dark mode"
disabled={!showPreferences}
className={clsx(
'p-1 rounded transition-colors duration-100 w-full dark:hover:text-purple-50 hover:bg-purple-300 dark:text-purple-400 dark:bg-gray-900 bg-purple-400 text-purple-50',
@ -188,6 +192,7 @@ const TopMenu: FC<Props> = () => {
</li>
<li role="menuitem">
<button
aria-label="Toggle left handed mode"
disabled={!showPreferences}
className={clsx(
'p-1 rounded transition-colors duration-100 w-full dark:hover:text-purple-50 bg-purple-400',

View file

@ -21,8 +21,8 @@ const _fetchAccountReceivable = (
// most nodes haven't upgraded yet https://docs.nano.org/commands/rpc-protocol/#accounts_pending
// this will be the future api for this function
const fetchAccountReceivable = async (address: string, count = 20) =>
_fetchAccountReceivable(address, count).catch(() =>
_fetchAccountReceivable(address, count, true)
_fetchAccountReceivable(address, count, true).catch(() =>
_fetchAccountReceivable(address, count)
)
export default fetchAccountReceivable

View file

@ -5,6 +5,7 @@ import withAnalyzer from '@next/bundle-analyzer'
*/
const nextConfig = {
compress: true,
productionBrowserSourceMaps: true,
}
export default withAnalyzer({

View file

@ -1,4 +1,5 @@
import type { AppProps } from 'next/app'
import Head from 'next/head'
import { FC } from 'react'
import { SWRConfig } from 'swr'
@ -18,13 +19,18 @@ const MyApp: FC<AppProps> = ({ Component, pageProps }) => {
if (validatingCredential) return null // todo
return (
<SWRConfig value={{ fetcher }}>
<MemCacheProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</MemCacheProvider>
</SWRConfig>
<>
<Head>
<title>zep - nano wallet</title>
</Head>
<SWRConfig value={{ fetcher }}>
<MemCacheProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</MemCacheProvider>
</SWRConfig>
</>
)
}

View file

@ -13,7 +13,7 @@ class MyDocument extends Document {
render() {
return (
<Html className="dark">
<Html className="dark" lang="en">
<Head>
<link rel="manifest" href="/manifest.json" />
<link rel="apple-touch-icon" href="/images/icon-small.png" />
@ -30,6 +30,7 @@ class MyDocument extends Document {
href="/images/favicon-16x16.png"
/>
<meta name="theme-color" content="#8a5cf6" />
<meta name="description" content="nano digital currency wallet" />
</Head>
<body>
<Main />

View file

@ -1,9 +1,17 @@
import type { NextPage } from 'next'
import Head from 'next/head'
import RecentTransactions from '../components/RecentTransactions'
const Dashboard: NextPage = () => {
return <RecentTransactions />
return (
<>
<Head>
<title>zep - dashboard</title>
</Head>
<RecentTransactions />
</>
)
}
export default Dashboard

View file

@ -1,5 +1,6 @@
import { FingerPrintIcon } from '@heroicons/react/outline'
import { useRouter } from 'next/dist/client/router'
import Head from 'next/head'
import { useEffect } from 'react'
import { checkBiometrics } from '../lib/biometrics'
@ -22,15 +23,23 @@ const Landing = () => {
}, [push, biometricsAuth])
return (
<main className="flex flex-col items-center w-full h-full">
<h1 className="text-4xl font-medium mb-16">welcome</h1>
<button className="p-3 dark:bg-gray-800 bg-purple-50 mb-3 rounded shadow hover:cursor-pointer">
<FingerPrintIcon className="h-16 text-gray-900 dark:text-purple-50" />
</button>
<h2 className="text-2xl text-center">
please sign in with your biometrics
</h2>
</main>
<>
<Head>
<title>zep - sign in</title>
</Head>
<main className="flex flex-col items-center w-full h-full">
<h1 className="text-4xl font-medium mb-16">welcome</h1>
<button
aria-label="Trigger biometrics authentication"
className="p-3 dark:bg-gray-800 bg-purple-50 mb-3 rounded shadow hover:cursor-pointer"
>
<FingerPrintIcon className="h-16 text-gray-900 dark:text-purple-50" />
</button>
<h2 className="text-2xl text-center">
please sign in with your biometrics
</h2>
</main>
</>
)
}

View file

@ -1,5 +1,6 @@
import { LoginIcon } from '@heroicons/react/outline'
import type { NextPage } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { useState } from 'react'
@ -19,22 +20,24 @@ const MyQrCode: NextPage = () => {
const [xnoToSend, setXnoToSend] = useState('')
return (
<div className="h-full flex flex-col gap-8">
<span className="flex items-center justify-start gap-2">
<LoginIcon className="-rotate-child-90 dark:text-purple-50 h-7 xs:h-10 text-gray-900 translate-x-1 transition-colors" />
<h1 className="text-3xl sm:text-5xl">receive</h1>
</span>
<>
<Head>
<title>zep - my qrcode</title>
</Head>
<div className="h-full flex flex-col gap-8">
<span className="flex items-center justify-start gap-2">
<LoginIcon className="-rotate-child-90 dark:text-purple-50 h-7 xs:h-10 text-gray-900 translate-x-1 transition-colors" />
<h1 className="text-3xl sm:text-5xl">receive</h1>
</span>
<canvas
className="!w-64 !h-64 rounded place-self-center shadow-lg"
ref={canvasRef}
/>
<canvas className="rounded place-self-center shadow" ref={canvasRef} />
<div className="flex flex-col place-self-center items-center gap-3">
<span className="text-xl transition-colors">optional amount</span>
<XnoInput value={xnoToSend} onChange={setXnoToSend} />
<div className="flex flex-col place-self-center items-center gap-3">
<span className="text-xl transition-colors">optional amount</span>
<XnoInput value={xnoToSend} onChange={setXnoToSend} />
</div>
</div>
</div>
</>
)
}

View file

@ -3,6 +3,7 @@ import { PaperAirplaneIcon } from '@heroicons/react/solid'
import clsx from 'clsx'
import { Unit, convert } from 'nanocurrency'
import type { NextPage } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { useCallback, useEffect, useState } from 'react'
@ -60,79 +61,83 @@ const Send: NextPage = () => {
}, [amount, xnoToSend, hasQueryAmount])
return (
<div className="flex flex-col h-full gap-8 pb-4">
<span className="flex items-center gap-2">
<PaperAirplaneIcon className="transition-colors dark:text-purple-50 h-7 xs:h-10 text-gray-900 rotate-[30deg] translate-x-1" />
<h1 className="text-3xl sm:text-5xl">send</h1>
</span>
<form
onSubmit={ev => ev.preventDefault()}
className="flex flex-col gap-3 items-center h-full"
>
<XnoInput value={xnoToSend} onChange={setXnoToSend} />
<span className="flex-1 text-lg text-center">
<span className="text-extrabold">to</span>
<br />
<span className="text-purple-400 font-medium">
{address?.substring(0, 10)}
</span>
{address?.substring(10, 21)}
<br />
{address?.substring(21, 42)}
<br />
{address?.substring(42, 56)}
<span className="text-purple-400 font-medium">
{address?.substring(56)}
</span>
<>
<Head>
<title>zep - send ӾNO</title>
</Head>
<div className="flex flex-col h-full gap-8 pb-4">
<span className="flex items-center gap-2">
<PaperAirplaneIcon className="transition-colors dark:text-purple-50 h-7 xs:h-10 text-gray-900 rotate-[30deg] translate-x-1" />
<h1 className="text-3xl sm:text-5xl">send</h1>
</span>
<div
className={clsx(
'dark:bg-gray-800 bg-purple-100 rounded-2xl p-2 relative w-72 z-10 transition-all hover:cursor-pointer',
{
'opacity-50': disableSlider,
}
)}
onMouseMove={ev => {
if (sliding && !disableSlider) setCurrentX(ev.clientX)
}}
onMouseUp={() => {
if (sliderPercentage !== 1 && !disableSlider) backToBase()
}}
onMouseLeave={() => {
if (sliderPercentage !== 1 && !disableSlider) backToBase()
}}
<form
onSubmit={ev => ev.preventDefault()}
className="flex flex-col gap-3 items-center h-full"
>
<XnoInput value={xnoToSend} onChange={setXnoToSend} />
<span className="flex-1 text-lg text-center">
<span className="text-extrabold">to</span>
<br />
<span className="text-purple-400 font-medium">
{address?.substring(0, 10)}
</span>
{address?.substring(10, 21)}
<br />
{address?.substring(21, 42)}
<br />
{address?.substring(42, 56)}
<span className="text-purple-400 font-medium">
{address?.substring(56)}
</span>
</span>
<div
className={clsx(
'dark:bg-purple-50 bg-purple-400 p-2 rounded-xl w-11 z-30 transform-gpu transition-colors',
'dark:bg-gray-800 bg-purple-100 rounded-2xl p-2 relative w-72 z-10 transition-all hover:cursor-pointer',
{
'transition-all': !sliding,
'opacity-50': disableSlider,
}
)}
style={{
transform: `translate3d(${sliderPercentage * 228}px, 0, 0)`,
onMouseMove={ev => {
if (sliding && !disableSlider) setCurrentX(ev.clientX)
}}
onTouchStart={ev => {
if (!disableSlider) {
setSliding(true)
setStartX(ev.touches.item(0).clientX)
}
onMouseUp={() => {
if (sliderPercentage !== 1 && !disableSlider) backToBase()
}}
onTouchMove={ev => {
if (sliding && !disableSlider)
setCurrentX(ev.touches.item(0).clientX)
}}
onTouchEnd={() => {
if (!disableSlider) backToBase()
}}
onMouseDown={ev => {
if (!disableSlider) {
setSliding(true)
setStartX(ev.clientX)
}
onMouseLeave={() => {
if (sliderPercentage !== 1 && !disableSlider) backToBase()
}}
>
{/* <PaperAirplaneIcon
<div
className={clsx(
'dark:bg-purple-50 bg-purple-400 p-2 rounded-xl w-11 z-30 transform-gpu transition-colors',
{
'transition-all': !sliding,
}
)}
style={{
transform: `translate3d(${sliderPercentage * 228}px, 0, 0)`,
}}
onTouchStart={ev => {
if (!disableSlider) {
setSliding(true)
setStartX(ev.touches.item(0).clientX)
}
}}
onTouchMove={ev => {
if (sliding && !disableSlider)
setCurrentX(ev.touches.item(0).clientX)
}}
onTouchEnd={() => {
if (!disableSlider) backToBase()
}}
onMouseDown={ev => {
if (!disableSlider) {
setSliding(true)
setStartX(ev.clientX)
}
}}
>
{/* <PaperAirplaneIcon
className="h-7 dark:text-gray-900 translate-x-0.5"
style={{
transform: `translateX(var(--tw-translate-x)) rotate(${
@ -140,26 +145,27 @@ const Send: NextPage = () => {
}deg)`,
}}
/> */}
<span
className="dark:text-gray-900 text-purple-50 text-3xl font-medium flex justify-center select-none"
style={{
transform: `scale3d(${1 + 0.4 * sliderPercentage}, ${
1 + 0.4 * sliderPercentage
}, 1)`,
}}
>
Ӿ
</span>
</div>
<span
className="dark:text-gray-900 text-purple-50 text-3xl font-medium flex justify-center select-none"
style={{
transform: `scale3d(${1 + 0.4 * sliderPercentage}, ${
1 + 0.4 * sliderPercentage
}, 1)`,
}}
className="absolute dark:text-purple-50 text-purple-400 text-2xl left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 select-none transition-colors"
style={{ opacity: 0.7 - 0.7 * sliderPercentage, zIndex: -10 }}
>
Ӿ
slide to send
</span>
</div>
<span
className="absolute dark:text-purple-50 text-purple-400 text-2xl left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 select-none transition-colors"
style={{ opacity: 0.7 - 0.7 * sliderPercentage, zIndex: -10 }}
>
slide to send
</span>
</div>
</form>
</div>
</form>
</div>
</>
)
}

View file

@ -1,6 +1,7 @@
import { PaperAirplaneIcon } from '@heroicons/react/solid'
import clsx from 'clsx'
import type { NextPage } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { useCallback, useState } from 'react'
@ -26,32 +27,37 @@ const ReadQrCode: NextPage = () => {
const [address, setAddress] = useState('')
return (
<div className="flex flex-col h-full min-h-0 gap-8 pb-4">
<span className="flex items-center gap-2">
<PaperAirplaneIcon className=" dark:text-purple-50 h-7 xs:h-10 text-gray-900 rotate-[30deg] transition-colors translate-x-1" />
<h1 className="text-3xl sm:text-5xl">send</h1>
</span>
<video
className={clsx('rounded flex-1 shadow-md min-h-0', {
hidden: !videoLive,
})}
ref={videoRef}
/>
{!videoLive && (
<div className="w-full flex-1 h-64 rounded dark:bg-gray-800 bg-purple-50 animate-pulse"></div>
)}
<div className="flex flex-col justify-self-end items-center gap-2 text-gray-900 dark:text-purple-50">
<span className="text-2xl">or</span>
<form
onSubmit={e => {
e.preventDefault()
if (address !== '') push(`/send?address=${address}`)
}}
>
<AddressInput value={address} onChange={setAddress} />
</form>
<>
<Head>
<title>zep - read qrcode</title>
</Head>
<div className="flex flex-col h-full min-h-0 gap-8 pb-4">
<span className="flex items-center gap-2">
<PaperAirplaneIcon className=" dark:text-purple-50 h-7 xs:h-10 text-gray-900 rotate-[30deg] transition-colors translate-x-1" />
<h1 className="text-3xl sm:text-5xl">send</h1>
</span>
<video
className={clsx('rounded flex-1 shadow-md min-h-0', {
hidden: !videoLive,
})}
ref={videoRef}
/>
{!videoLive && (
<div className="w-full flex-1 h-64 rounded dark:bg-gray-800 bg-purple-50 animate-pulse"></div>
)}
<div className="flex flex-col justify-self-end items-center gap-2 text-gray-900 dark:text-purple-50">
<span className="text-2xl">or</span>
<form
onSubmit={e => {
e.preventDefault()
if (address !== '') push(`/send?address=${address}`)
}}
>
<AddressInput value={address} onChange={setAddress} />
</form>
</div>
</div>
</div>
</>
)
}

View file

@ -1,23 +1,29 @@
import type { NextPage } from 'next'
import Head from 'next/head'
import Link from 'next/link'
import { useRouter } from 'next/router'
const Done: NextPage = () => {
const { push } = useRouter()
return (
<div className="flex flex-col items-center justify-start h-full px-4 text-center gap-2 text-gray-900 transition-colors dark:text-purple-50">
<h1 className="font-extrabold text-9xl">3</h1>
<p className="text-3xl">you&apos;re done!</p>
<p className="mb-5 text-xl">
all the buttons are now enabled and you can start using <b>zep</b> and{' '}
<b>nano</b>!
</p>
<button
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-colors text-purple-50 rounded dark:bg-gray-800"
onClick={() => push('/dashboard')}
>
go!
</button>
</div>
<>
<Head>
<title>zep - welcome</title>
</Head>
<div className="flex flex-col items-center justify-start h-full px-4 text-center gap-2 text-gray-900 transition-colors dark:text-purple-50">
<h1 className="font-extrabold text-9xl">3</h1>
<p className="text-3xl">you&apos;re done!</p>
<p className="mb-5 text-xl">
all the buttons are now enabled and you can start using <b>zep</b> and{' '}
<b>nano</b>!
</p>
<Link href="/dashboard">
<a className="px-5 py-2 text-xl font-bold bg-purple-400 transition-colors text-purple-50 rounded dark:bg-gray-800">
go! <span className="hidden">to your dashboard</span>
</a>
</Link>
</div>
</>
)
}

View file

@ -1,45 +1,51 @@
import type { NextPage } from 'next'
import Head from 'next/head'
import Link from 'next/link'
import { useRouter } from 'next/router'
const Welcome: NextPage = () => {
return (
<div className="flex flex-col justify-center w-full h-full text-center text-gray-900 transition-colors dark:text-purple-50">
<h1 className="mb-3 text-5xl font-extrabold">hey!</h1>
<p className="mb-3 text-xl font-medium">
do you already have a
<br />
<b>nano</b> passphrase?
</p>
<>
<Head>
<title>zep - welcome</title>
</Head>
<div className="flex flex-col justify-center w-full h-full text-center text-gray-900 transition-colors dark:text-purple-50">
<h1 className="mb-3 text-5xl font-extrabold">hey!</h1>
<p className="mb-3 text-xl font-medium">
do you already have a
<br />
<b>nano</b> passphrase?
</p>
<div className="flex flex-col justify-center w-full gap-3 mb-6">
<Link href="/welcome/seedOrPassphrase">
<a className="px-5 py-2 text-lg font-bold text-purple-50 transition-all rounded shadow-lg bg-purple-400 dark:bg-gray-800 dark:text-purple-50 hover:bg-purple-300 dark:hover:bg-gray-800 hover:shadow-md active:shadow">
i have a passphrase/seed
</a>
</Link>
<Link href="/welcome/new">
<a className="px-5 py-2 text-lg font-bold text-purple-50 transition-all rounded shadow-lg bg-purple-400 dark:bg-gray-800 dark:text-purple-50 hover:bg-purple-300 dark:hover:bg-gray-800 hover:shadow-md active:shadow">
what&apos;s a passphrase?
</a>
</Link>
<div className="flex flex-col justify-center w-full gap-3 mb-6">
<Link href="/welcome/seedOrPassphrase">
<a className="px-5 py-2 text-lg font-bold text-purple-50 transition-all rounded shadow-lg bg-purple-400 dark:bg-gray-800 dark:text-purple-50 hover:bg-purple-300 dark:hover:bg-gray-800 hover:shadow-md active:shadow">
i have a passphrase/seed
</a>
</Link>
<Link href="/welcome/new">
<a className="px-5 py-2 text-lg font-bold text-purple-50 transition-all rounded shadow-lg bg-purple-400 dark:bg-gray-800 dark:text-purple-50 hover:bg-purple-300 dark:hover:bg-gray-800 hover:shadow-md active:shadow">
what&apos;s a passphrase?
</a>
</Link>
</div>
<aside className="mb-3 text-xs">
your passphrase will{' '}
<b className="font-extrabold">
<em>never</em>
</b>{' '}
leave your device,
<br />
and will only be decrypted for a few moments to send nano
</aside>
<p className="text-xs">
<em>
psst: you can already see all the cool buttons below, but
they&apos;re all disabled for now
</em>
</p>
</div>
<aside className="mb-3 text-xs">
your passphrase will{' '}
<b className="font-extrabold">
<em>never</em>
</b>{' '}
leave your device,
<br />
and will only be decrypted for a few moments to send nano
</aside>
<p className="text-xs">
<em>
psst: you can already see all the cool buttons below, but they&apos;re
all disabled for now
</em>
</p>
</div>
</>
)
}

View file

@ -1,4 +1,5 @@
import type { NextPage } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
@ -24,48 +25,54 @@ const New: NextPage = () => {
}
return (
<div className="flex flex-col items-center justify-start h-full px-4 text-center gap-2 text-gray-900 dark:text-purple-50 transition-colors">
<h1 className="font-extrabold text-9xl">{!storing ? 1 : 2}</h1>
{!storing ? (
<>
<p className="text-lg">
generate a <b>passphrase</b> and copy it to your clipboard
</p>
<button
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-colors text-purple-50 rounded dark:bg-gray-800"
onClick={storeSeedLazy}
>
generate passphrase
</button>
<p className="text-xl">
<b>
store this passphrase securely: you&apos;ll need it in case
something happens to this device
</b>
</p>
</>
) : (
<>
<p className="text-lg">
store the <b>passphrase</b> securely in zep
</p>
<button
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-colors text-purple-50 rounded dark:bg-gray-800"
onClick={onStoreClick}
>
store passphrase
</button>
<aside className="text-xs">
again, your passphrase will{' '}
<b className="font-extrabold">
<em>never</em>
</b>{' '}
leave your device, and will only be decrypted for a brief moment on
each transaction
</aside>
</>
)}
</div>
<>
<Head>
<title>zep - welcome</title>
</Head>
<div className="flex flex-col items-center justify-start h-full px-4 text-center gap-2 text-gray-900 dark:text-purple-50 transition-colors">
<h1 className="font-extrabold text-9xl">{!storing ? 1 : 2}</h1>
{!storing ? (
<>
<p className="text-lg">
generate a <b>passphrase</b> and copy it to your clipboard
</p>
<button
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-colors text-purple-50 rounded dark:bg-gray-800"
onClick={storeSeedLazy}
>
generate passphrase
</button>
<p className="text-xl">
<b>
store this passphrase securely: you&apos;ll need it in case
something happens to this device
</b>
</p>
</>
) : (
<>
<p className="text-lg">
store the <b>passphrase</b> securely in zep
</p>
<button
aria-label="Store passphrase securely on device storage"
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-colors text-purple-50 rounded dark:bg-gray-800"
onClick={onStoreClick}
>
store passphrase
</button>
<aside className="text-xs">
again, your passphrase will{' '}
<b className="font-extrabold">
<em>never</em>
</b>{' '}
leave your device, and will only be decrypted for a brief moment
on each transaction
</aside>
</>
)}
</div>
</>
)
}

View file

@ -1,6 +1,7 @@
import clsx from 'clsx'
import { wallet } from 'nanocurrency-web'
import type { NextPage } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { useEffect, useRef, useState } from 'react'
@ -93,106 +94,117 @@ const SeedOrPassphrase: NextPage = () => {
}
return (
<div className="flex flex-col items-center justify-start h-full px-4 text-center gap-6 text-gray-900 dark:text-purple-50 transition-colors">
{registering ? (
<>
<h1 className="font-extrabold text-3xl">register your biometrics</h1>
<button
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-colors text-purple-50 rounded dark:bg-gray-800"
onClick={onRegisterClick}
>
register biometrics
</button>
<p>
<em>this will be used to encrypt your seed inside your device</em>
</p>
</>
) : (
<>
<h1 className="font-extrabold text-3xl">input your secret</h1>
<p className="text-lg">
store the <b>secret</b> securely in zep
</p>
<div className="flex gap-4">
<>
<Head>
<title>zep - welcome</title>
</Head>
<div className="flex flex-col items-center justify-start h-full px-4 text-center gap-6 text-gray-900 dark:text-purple-50 transition-colors">
{registering ? (
<>
<h1 className="font-extrabold text-3xl">
register your biometrics
</h1>
<button
className={clsx(
'px-4 py-1 text-lg font-bold bg-purple-400 transition-all text-purple-50 rounded dark:bg-gray-800',
isPassphrase ? 'scale-110' : 'opacity-80'
)}
onClick={() => setIsPassphrase(true)}
aria-label="Register biometrics"
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-colors text-purple-50 rounded dark:bg-gray-800"
onClick={onRegisterClick}
>
passphrase
register biometrics
</button>
<button
className={clsx(
'px-4 py-1 text-lg font-bold bg-purple-400 transition-all text-purple-50 rounded dark:bg-gray-800',
!isPassphrase ? 'scale-110' : 'opacity-80'
)}
onClick={() => setIsPassphrase(false)}
>
seed
</button>
</div>
{!isPassphrase ? (
<SeedInput value={seedInput} onChange={setSeedInput} />
) : (
<ol className="flex w-full gap-2 overflow-x-auto">
<li className="min-w-[150px]">
<MnemonicInput
onPaste={onPaste}
number={1}
value={passphraseInputs[0] ?? ''}
onChange={value => {
console.log(value)
if (value.split(' ').length !== 24)
setpassphraseInputs(prev => {
const newInputs = [...prev]
newInputs[0] = value
return newInputs
})
}}
/>
</li>
{new Array(24).fill(0, 0, 23).map((_, idx) => (
<li key={idx} className="min-w-[150px]">
<p>
<em>this will be used to encrypt your seed inside your device</em>
</p>
</>
) : (
<>
<h1 className="font-extrabold text-3xl">input your secret</h1>
<p className="text-lg">
store the <b>secret</b> securely in zep
</p>
<div className="flex gap-4">
<button
aria-label="Use passphrase"
className={clsx(
'px-4 py-1 text-lg font-bold bg-purple-400 transition-all text-purple-50 rounded dark:bg-gray-800',
isPassphrase ? 'scale-110' : 'opacity-80'
)}
onClick={() => setIsPassphrase(true)}
>
passphrase
</button>
<button
aria-label="Use seed"
className={clsx(
'px-4 py-1 text-lg font-bold bg-purple-400 transition-all text-purple-50 rounded dark:bg-gray-800',
!isPassphrase ? 'scale-110' : 'opacity-80'
)}
onClick={() => setIsPassphrase(false)}
>
seed
</button>
</div>
{!isPassphrase ? (
<SeedInput value={seedInput} onChange={setSeedInput} />
) : (
<ol className="flex w-full gap-2 overflow-x-auto">
<li className="min-w-[150px]">
<MnemonicInput
onPaste={onPaste}
number={idx + 2}
value={passphraseInputs[idx] ?? ''}
number={1}
value={passphraseInputs[0] ?? ''}
onChange={value => {
console.log(value)
if (value.split(' ').length !== 24)
setpassphraseInputs(prev => {
const newInputs = [...prev]
newInputs[idx] = value
newInputs[0] = value
return newInputs
})
}}
/>
</li>
))}
</ol>
)}
<button
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-all text-purple-50 rounded dark:bg-gray-800 disabled:cursor-default disabled:opacity-60"
disabled={
(seedInput === '' && !isPassphrase) ||
(passphraseInputs.length !== 24 && isPassphrase)
}
onClick={onStoreClick}
>
store passphrase
</button>
<aside className="text-xs">
again, your passphrase will{' '}
<b className="font-extrabold">
<em>never</em>
</b>{' '}
leave your device, and will only be decrypted for a brief moment on
each transaction
</aside>
</>
)}
</div>
{new Array(24).fill(0, 0, 23).map((_, idx) => (
<li key={idx} className="min-w-[150px]">
<MnemonicInput
onPaste={onPaste}
number={idx + 2}
value={passphraseInputs[idx] ?? ''}
onChange={value => {
if (value.split(' ').length !== 24)
setpassphraseInputs(prev => {
const newInputs = [...prev]
newInputs[idx] = value
return newInputs
})
}}
/>
</li>
))}
</ol>
)}
<button
aria-label="Store passphrase securely on device storage"
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-all text-purple-50 rounded dark:bg-gray-800 disabled:cursor-default disabled:opacity-60"
disabled={
(seedInput === '' && !isPassphrase) ||
(passphraseInputs.length !== 24 && isPassphrase)
}
onClick={onStoreClick}
>
store passphrase
</button>
<aside className="text-xs">
again, your passphrase will{' '}
<b className="font-extrabold">
<em>never</em>
</b>{' '}
leave your device, and will only be decrypted for a brief moment
on each transaction
</aside>
</>
)}
</div>
</>
)
}