fix: light mode
This commit is contained in:
parent
070764c408
commit
c3c41ac7f6
|
@ -41,11 +41,17 @@ const Balance: FC<Props> = ({ className }) => {
|
||||||
const xnoBalanceDisplay = rawToNanoDisplay(account?.balance ?? '0')
|
const xnoBalanceDisplay = rawToNanoDisplay(account?.balance ?? '0')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('dark:text-purple-50 text-gray-900 flex', className)}>
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'dark:text-purple-50 transition-colors text-gray-900 flex',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setPreference('showCurrencyDash', nextShowCurrency(showCurrencyDash))
|
setPreference('showCurrencyDash', nextShowCurrency(showCurrencyDash))
|
||||||
}
|
}
|
||||||
|
className="hover:cursor-pointer active:translate-y-0.5"
|
||||||
>
|
>
|
||||||
<h3 className="text-4xl">
|
<h3 className="text-4xl">
|
||||||
Ӿ
|
Ӿ
|
||||||
|
|
|
@ -57,8 +57,8 @@ const BottomMenu: FC<Props> = ({ className }) => {
|
||||||
>
|
>
|
||||||
{pathname !== '/dashboard' && (
|
{pathname !== '/dashboard' && (
|
||||||
<Link href={isWelcoming ? '#' : '/dashboard'}>
|
<Link href={isWelcoming ? '#' : '/dashboard'}>
|
||||||
<a className="h-12 p-1 bg-purple-400 rounded shadow-lg hover:bg-purple-400 disabled:hover:bg-purple-400 disabled:cursor-default">
|
<a className="h-12 p-1 bg-purple-400 transition-colors rounded shadow-lg hover:bg-purple-400 disabled:hover:bg-purple-400 disabled:cursor-default">
|
||||||
<HomeIcon className="h-full text-purple-50 dark:text-gray-900" />
|
<HomeIcon className="h-full text-purple-50 dark:text-gray-900 transition-colors" />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
|
@ -73,16 +73,16 @@ const BottomMenu: FC<Props> = ({ className }) => {
|
||||||
{'share' in navigator ? (
|
{'share' in navigator ? (
|
||||||
<button
|
<button
|
||||||
disabled={isWelcoming}
|
disabled={isWelcoming}
|
||||||
className="w-10 h-16 p-1 bg-purple-400 rounded shadow-lg hover:bg-purple-400 disabled:hover:bg-purple-400 disabled:cursor-default"
|
className="w-10 h-16 p-1 bg-purple-400 transition-colors rounded shadow-lg hover:bg-purple-400 disabled:hover:bg-purple-400 disabled:cursor-default"
|
||||||
onClick={onShare}
|
onClick={onShare}
|
||||||
>
|
>
|
||||||
<ShareIcon className="text-purple-50 dark:text-gray-900" />
|
<ShareIcon className="text-purple-50 dark:text-gray-900 transition-colors" />
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
disabled={isWelcoming || confirmCopyAddress}
|
disabled={isWelcoming || confirmCopyAddress}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'p-1 h-16 w-10 rounded shadow-lg',
|
'p-1 h-16 w-10 rounded shadow-lg transition-colors',
|
||||||
confirmCopyAddress
|
confirmCopyAddress
|
||||||
? 'bg-purple-50'
|
? 'bg-purple-50'
|
||||||
: 'bg-purple-400 hover:bg-purple-400 disabled:hover:bg-purple-400 disabled:cursor-default'
|
: 'bg-purple-400 hover:bg-purple-400 disabled:hover:bg-purple-400 disabled:cursor-default'
|
||||||
|
@ -92,7 +92,7 @@ const BottomMenu: FC<Props> = ({ className }) => {
|
||||||
{confirmCopyAddress ? (
|
{confirmCopyAddress ? (
|
||||||
<CheckIcon className="text-purple-400" />
|
<CheckIcon className="text-purple-400" />
|
||||||
) : (
|
) : (
|
||||||
<DocumentDuplicateIcon className="text-purple-50 dark:text-gray-900" />
|
<DocumentDuplicateIcon className="text-purple-50 dark:text-gray-900 transition-colors" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
@ -103,28 +103,28 @@ const BottomMenu: FC<Props> = ({ className }) => {
|
||||||
<Link href={isWelcoming ? '#' : '/receive/qr'}>
|
<Link href={isWelcoming ? '#' : '/receive/qr'}>
|
||||||
<a
|
<a
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'bg-purple-400 px-1 h-16 w-10 hover:bg-purple-400 disabled:hover:bg-purple-400 shadow-md disabled:cursor-default',
|
'bg-purple-400 transition-colors px-1 h-16 w-10 hover:bg-purple-400 disabled:hover:bg-purple-400 shadow-md disabled:cursor-default',
|
||||||
leftHanded ? 'rounded-r' : 'rounded-l'
|
leftHanded ? 'rounded-r' : 'rounded-l'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<LoginIcon
|
<LoginIcon
|
||||||
className={
|
className={
|
||||||
'h-full text-purple-50 dark:text-gray-900 w-full -rotate-child-90'
|
'h-full text-purple-50 dark:text-gray-900 transition-colors w-full -rotate-child-90'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<div className="h-16 p-1 border-t-2 border-b-2 border-purple-400 shadow-lg">
|
<div className="h-16 p-1 border-t-2 border-b-2 border-purple-400 shadow-lg">
|
||||||
<QrcodeIcon className="h-full text-gray-900 dark:text-purple-100" />
|
<QrcodeIcon className="h-full text-gray-900 dark:text-purple-100 transition-colors" />
|
||||||
</div>
|
</div>
|
||||||
<Link href={isWelcoming ? '#' : '/send/qr'}>
|
<Link href={isWelcoming ? '#' : '/send/qr'}>
|
||||||
<a
|
<a
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'bg-purple-400 px-1 h-16 w-10 hover:bg-purple-400 disabled:hover:bg-purple-400 shadow-md disabled:cursor-default',
|
'bg-purple-400 transition-colors px-1 h-16 w-10 hover:bg-purple-400 disabled:hover:bg-purple-400 shadow-md disabled:cursor-default',
|
||||||
leftHanded ? 'rounded-l' : 'rounded-r'
|
leftHanded ? 'rounded-l' : 'rounded-r'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<PaperAirplaneIcon className="h-full text-purple-50 dark:text-gray-900 w-full rotate-[30deg] translate-x-1" />
|
<PaperAirplaneIcon className="h-full text-purple-50 dark:text-gray-900 transition-colors w-full rotate-[30deg] translate-x-1" />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,24 +20,22 @@ const Layout: FC<Props> = ({ children }) => {
|
||||||
useListenToColorMedia()
|
useListenToColorMedia()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex flex-col w-screen h-screen gap-4 px-5 pt-4 pb-4 dark:text-purple-50 bg-purple-50 dark:bg-gray-900">
|
<div className="relative flex flex-col w-screen h-screen gap-4 px-5 pt-4 pb-4 dark:text-purple-50 bg-white dark:bg-gray-900 transition-colors">
|
||||||
<header
|
<header
|
||||||
className={clsx('flex justify-between items-center', {
|
className={clsx('flex justify-between items-center', {
|
||||||
'flex-row-reverse': leftHanded,
|
'flex-row-reverse': leftHanded,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className="flex items-start">
|
<div className="flex items-start text-gray-900 transition-colors dark:text-purple-100">
|
||||||
<h1 className="text-2xl font-extrabold text-gray-900 dark:text-purple-100">
|
<h1 className="text-2xl font-extrabold ">zep</h1>
|
||||||
zep
|
<LightningBoltIcon className="h-4" />
|
||||||
</h1>
|
|
||||||
<LightningBoltIcon className="h-4 text-gray-900 dark:text-purple-100" />
|
|
||||||
</div>
|
</div>
|
||||||
<TopMenu />
|
<TopMenu />
|
||||||
</header>
|
</header>
|
||||||
{pathname !== '/' ? (
|
{pathname !== '/' ? (
|
||||||
<>
|
<>
|
||||||
<Balance />
|
<Balance />
|
||||||
<hr className="w-1/3 border-2 " />
|
<hr className="w-1/3 border-2 border-gray-900 dark:border-purple-50 rounded-l-sm rounded-r transition-colors" />
|
||||||
{children}
|
{children}
|
||||||
<BottomMenu />
|
<BottomMenu />
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -8,31 +8,41 @@ import useAccountReceivable from '../lib/hooks/useAccountReceivable'
|
||||||
import useReceiveNano from '../lib/hooks/useReceiveNano'
|
import useReceiveNano from '../lib/hooks/useReceiveNano'
|
||||||
import rawToNanoDisplay from '../lib/xno/rawToNanoDisplay'
|
import rawToNanoDisplay from '../lib/xno/rawToNanoDisplay'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {}
|
||||||
className?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const RecentTransactions: FC<Props> = ({ className }) => {
|
const RecentTransactions: FC<Props> = () => {
|
||||||
const { receive } = useReceiveNano()
|
const { receive } = useReceiveNano()
|
||||||
|
|
||||||
const { receivableBlocks, onBlockReceived } = useAccountReceivable()
|
const { receivableBlocks, onBlockReceived } = useAccountReceivable()
|
||||||
const { data: accountHistory } = useAccountHistory()
|
const {
|
||||||
|
accountHistory,
|
||||||
|
loadMore,
|
||||||
|
hasMore,
|
||||||
|
loading: loadingHistory,
|
||||||
|
hasHistory,
|
||||||
|
} = useAccountHistory()
|
||||||
|
|
||||||
const hasReceivable =
|
const hasReceivable =
|
||||||
receivableBlocks !== undefined && receivableBlocks.length > 0
|
receivableBlocks !== undefined && receivableBlocks.length > 0
|
||||||
|
|
||||||
const [receivablesExpanded, setReceivablesExpanded] = useState(false)
|
const [receivablesExpanded, setReceivablesExpanded] = useState(false)
|
||||||
|
|
||||||
|
const mappedHistory = (accountHistory ?? []).flatMap(historyPage =>
|
||||||
|
historyPage.history !== '' ? historyPage.history : []
|
||||||
|
)
|
||||||
|
|
||||||
|
const initialLoading = loadingHistory && accountHistory === undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{hasReceivable && (
|
{hasReceivable && (
|
||||||
<section className="flex flex-col w-full gap-3">
|
<section className="flex flex-col w-full gap-3">
|
||||||
<div className="flex items-center justify-between gap-1">
|
<div className="flex items-center justify-between gap-1">
|
||||||
<h2 className="flex-1 text-2xl font-semibold text-purple-50">
|
<h2 className="flex-1 text-2xl font-semibold transition-colors text-gray-900 dark:text-purple-50">
|
||||||
incoming
|
incoming
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<span className="w-6 text-base text-center text-gray-900 rounded-full dark:bg-purple-50">
|
<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}
|
{receivableBlocks.length}
|
||||||
</span>
|
</span>
|
||||||
<ChevronUpIcon
|
<ChevronUpIcon
|
||||||
|
@ -47,14 +57,14 @@ const RecentTransactions: FC<Props> = ({ className }) => {
|
||||||
</div>
|
</div>
|
||||||
<ol
|
<ol
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'flex flex-col gap-3 w-full overflow-auto transition-height duration-300',
|
'flex flex-col gap-3 w-full overflow-auto transition-all duration-300 px-1',
|
||||||
receivablesExpanded ? 'h-32' : 'h-0'
|
receivablesExpanded ? 'max-h-32 pb-1' : 'max-h-0'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{receivableBlocks.map(receivable => (
|
{receivableBlocks.map(receivable => (
|
||||||
<li
|
<li
|
||||||
key={receivable.hash}
|
key={receivable.hash}
|
||||||
className="flex items-center justify-between px-3 py-3 text-black border-r-4 border-yellow-400 rounded shadow bg-purple-50 dark:hover:bg-gray-700 dark:bg-gray-800 dark:text-purple-50 gap-2"
|
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
|
<button
|
||||||
className="contents"
|
className="contents"
|
||||||
|
@ -93,16 +103,23 @@ const RecentTransactions: FC<Props> = ({ className }) => {
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
<section className="flex flex-col flex-1 w-full min-h-0 gap-3">
|
<section className="flex flex-col flex-1 w-full min-h-0 gap-3">
|
||||||
<h2 className="text-2xl font-semibold text-purple-50">
|
<h2 className="text-2xl font-semibold text-gray-900 dark:text-purple-50">
|
||||||
recent transactions
|
recent transactions
|
||||||
</h2>
|
</h2>
|
||||||
{accountHistory !== undefined && accountHistory.history !== '' ? (
|
{initialLoading ? (
|
||||||
<ol className="flex flex-col w-full overflow-auto gap-3">
|
<ul className="flex flex-col w-full overflow-auto px-0.5 pb-0.5 gap-2">
|
||||||
{accountHistory.history.map(txn => (
|
<li className="bg-gray-100 dark:bg-gray-800 shadow rounded h-12 animate-pulse transition-colors" />
|
||||||
|
<li className="bg-gray-100 dark:bg-gray-800 shadow rounded h-12 animate-pulse transition-colors" />
|
||||||
|
<li className="bg-gray-100 dark:bg-gray-800 shadow rounded h-12 animate-pulse transition-colors" />
|
||||||
|
<li className="bg-gray-100 dark:bg-gray-800 shadow rounded h-12 animate-pulse transition-colors" />
|
||||||
|
</ul>
|
||||||
|
) : hasHistory ? (
|
||||||
|
<ol className="flex flex-col w-full overflow-auto px-0.5 pb-0.5 gap-2">
|
||||||
|
{mappedHistory.map(txn => (
|
||||||
<li
|
<li
|
||||||
key={txn.hash}
|
key={txn.hash}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'bg-purple-50 dark:bg-gray-800 dark:text-purple-50 shadow rounded px-3 py-3 flex items-center justify-between gap-2 text-black border-r-4',
|
'bg-gray-50 dark:bg-gray-800 dark:text-purple-50 shadow rounded px-3 py-3 flex items-center justify-between gap-2 text-black border-r-4 transition-colors',
|
||||||
txn.type === 'send' ? 'border-yellow-300' : 'border-green-300'
|
txn.type === 'send' ? 'border-yellow-300' : 'border-green-300'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -138,9 +155,17 @@ const RecentTransactions: FC<Props> = ({ className }) => {
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
{hasMore && (
|
||||||
|
<button
|
||||||
|
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}
|
||||||
|
>
|
||||||
|
load more
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</ol>
|
</ol>
|
||||||
) : (
|
) : (
|
||||||
<div className="pt-8 text-center text-purple-50">
|
<div className="pt-8 text-center text-gray-900 dark:text-purple-50">
|
||||||
<p className="pb-4">no transactions yet...</p>
|
<p className="pb-4">no transactions yet...</p>
|
||||||
<p>
|
<p>
|
||||||
get your first nano
|
get your first nano
|
||||||
|
@ -150,14 +175,6 @@ const RecentTransactions: FC<Props> = ({ className }) => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
{false && (
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 font-bold bg-purple-200 rounded shadow dark:text-gray-900"
|
|
||||||
onClick={() => {}}
|
|
||||||
>
|
|
||||||
load more
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,50 @@
|
||||||
import useSWR from 'swr'
|
import { useCallback, useEffect } from 'react'
|
||||||
|
import useSWRInfinite from 'swr/infinite'
|
||||||
|
|
||||||
import { useCurrentAccount } from '../context/accountContext'
|
import { useCurrentAccount } from '../context/accountContext'
|
||||||
import type { AccountHistoryResponse } from '../types'
|
import type { AccountHistoryResponse } from '../types'
|
||||||
import fetchAccountHistory from '../xno/fetchAccountHistory'
|
import fetchAccountHistory from '../xno/fetchAccountHistory'
|
||||||
|
|
||||||
const useAccountHistory = () => {
|
const useAccountHistory = (pageSize = 20) => {
|
||||||
const account = useCurrentAccount()
|
const account = useCurrentAccount()
|
||||||
return useSWR<AccountHistoryResponse>(
|
|
||||||
account !== undefined ? `history:${account.address}` : null,
|
const getKey = (index: number, prevPage: AccountHistoryResponse | null) => {
|
||||||
(key: string) => fetchAccountHistory(key.split(':')[1])
|
if (account === undefined) return null
|
||||||
|
|
||||||
|
if (prevPage !== null && prevPage.previous === undefined) return null
|
||||||
|
|
||||||
|
if (index === 0) return `history`
|
||||||
|
|
||||||
|
return `history?cursor=${prevPage!.previous}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: accountHistory,
|
||||||
|
size,
|
||||||
|
setSize,
|
||||||
|
isValidating,
|
||||||
|
} = useSWRInfinite<AccountHistoryResponse>(getKey, (key: string) =>
|
||||||
|
fetchAccountHistory(
|
||||||
|
account!.address,
|
||||||
|
pageSize,
|
||||||
|
key.split('=')[1] === key ? undefined : key.split('=')[1]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const hasMore = accountHistory?.[size - 1]?.previous !== undefined
|
||||||
|
const loadMore = () => setSize(prev => prev + 1)
|
||||||
|
const hasHistory =
|
||||||
|
accountHistory !== undefined &&
|
||||||
|
accountHistory.length > 0 &&
|
||||||
|
accountHistory[0].history !== ''
|
||||||
|
|
||||||
|
return {
|
||||||
|
accountHistory,
|
||||||
|
loadMore,
|
||||||
|
hasMore,
|
||||||
|
loading: isValidating,
|
||||||
|
hasHistory,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useAccountHistory
|
export default useAccountHistory
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
import { useCallback } from 'react'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
|
|
||||||
import { useCurrentAccount } from '../context/accountContext'
|
import { useCurrentAccount } from '../context/accountContext'
|
||||||
import type {
|
import type { ConfirmationMessage } from '../types'
|
||||||
AccountReceivableResponse,
|
|
||||||
BlocksInfoResponse,
|
|
||||||
ConfirmationMessage,
|
|
||||||
} from '../types'
|
|
||||||
import fetchAccountReceivable from '../xno/fetchAccountReceivable'
|
import fetchAccountReceivable from '../xno/fetchAccountReceivable'
|
||||||
import fetchBlocksInfo from '../xno/fetchBlocksInfo'
|
import fetchBlocksInfo from '../xno/fetchBlocksInfo'
|
||||||
import useListenToReceivable from './useListenToReceivable'
|
import useListenToReceivable from './useListenToReceivable'
|
||||||
|
@ -40,7 +36,8 @@ const useAccountReceivable = () => {
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
|
{ revalidateOnFocus: false }
|
||||||
)
|
)
|
||||||
|
|
||||||
const onBlockReceived = useCallback(
|
const onBlockReceived = useCallback(
|
||||||
|
|
|
@ -11,7 +11,9 @@ const useReadQrFromVideo = (onQrCodeRead: (content: string) => void) => {
|
||||||
|
|
||||||
const start = async () => {
|
const start = async () => {
|
||||||
stream = await navigator.mediaDevices.getUserMedia({
|
stream = await navigator.mediaDevices.getUserMedia({
|
||||||
video: { facingMode: 'environment' },
|
video: {
|
||||||
|
facingMode: 'environment',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
video.srcObject = stream
|
video.srcObject = stream
|
||||||
video.setAttribute('playsinline', 'true') // required to tell iOS safari we don't want fullscreen
|
video.setAttribute('playsinline', 'true') // required to tell iOS safari we don't want fullscreen
|
||||||
|
@ -35,7 +37,8 @@ const useReadQrFromVideo = (onQrCodeRead: (content: string) => void) => {
|
||||||
video.height
|
video.height
|
||||||
)
|
)
|
||||||
|
|
||||||
if (qr !== null) {
|
if (qr !== null && qr.data !== '') {
|
||||||
|
console.log(qr)
|
||||||
onQrCodeRead(qr.data)
|
onQrCodeRead(qr.data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -48,7 +51,6 @@ const useReadQrFromVideo = (onQrCodeRead: (content: string) => void) => {
|
||||||
start()
|
start()
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
console.log(stream, video, stream?.getTracks())
|
|
||||||
if (stream !== undefined) {
|
if (stream !== undefined) {
|
||||||
stream.getTracks().forEach(track => track.stop())
|
stream.getTracks().forEach(track => track.stop())
|
||||||
stream.addEventListener('addtrack', track => track.track.stop())
|
stream.addEventListener('addtrack', track => track.track.stop())
|
||||||
|
|
|
@ -2,7 +2,7 @@ import fetcher from '../fetcher'
|
||||||
import { AccountHistoryResponse } from '../types'
|
import { AccountHistoryResponse } from '../types'
|
||||||
import { defaultUrls } from './constants'
|
import { defaultUrls } from './constants'
|
||||||
|
|
||||||
const fetchAccountHistory = (address: string, count = 20, head = undefined) =>
|
const fetchAccountHistory = (address: string, count = 20, head?: string) =>
|
||||||
fetcher(defaultUrls.rpc, {
|
fetcher(defaultUrls.rpc, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: {
|
body: {
|
||||||
|
|
|
@ -53,11 +53,7 @@ const Send: NextPage = () => {
|
||||||
if (sliderPercentage === 1) {
|
if (sliderPercentage === 1) {
|
||||||
const sendNano = async () => {
|
const sendNano = async () => {
|
||||||
try {
|
try {
|
||||||
await send(
|
await send(address as string, amount as string)
|
||||||
address as string,
|
|
||||||
(amount as string) ??
|
|
||||||
convert(xnoToSend, { from: Unit.Nano, to: Unit.raw })
|
|
||||||
)
|
|
||||||
push('/dashboard')
|
push('/dashboard')
|
||||||
} catch {
|
} catch {
|
||||||
backToBase()
|
backToBase()
|
||||||
|
@ -67,8 +63,16 @@ const Send: NextPage = () => {
|
||||||
}
|
}
|
||||||
}, [sliderPercentage, push, address, amount, xnoToSend, send, backToBase])
|
}, [sliderPercentage, push, address, amount, xnoToSend, send, backToBase])
|
||||||
|
|
||||||
|
const hasQueryAmount = amount !== undefined && amount !== '' && amount !== '0'
|
||||||
|
const disableSlider = !hasQueryAmount
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasQueryAmount && xnoToSend === '')
|
||||||
|
setXnoToSend(convert(amount, { from: Unit.raw, to: Unit.Nano }))
|
||||||
|
}, [amount, xnoToSend, hasQueryAmount])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full gap-8">
|
<div className="flex flex-col h-full gap-8 pb-4">
|
||||||
<span className="flex items-center gap-2">
|
<span className="flex items-center gap-2">
|
||||||
<PaperAirplaneIcon className=" dark:text-purple-50 h-7 xs:h-10 text-gray-900 rotate-[30deg] translate-x-1" />
|
<PaperAirplaneIcon className=" 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>
|
<h1 className="text-3xl sm:text-5xl">send</h1>
|
||||||
|
@ -77,7 +81,7 @@ const Send: NextPage = () => {
|
||||||
onSubmit={ev => ev.preventDefault()}
|
onSubmit={ev => ev.preventDefault()}
|
||||||
className="flex flex-col gap-3 items-center h-full"
|
className="flex flex-col gap-3 items-center h-full"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3 text-2xl rounded dark:bg-gray-800 py-2 px-4 w-full overflow-hidden dark:focus-within:bg-gray-700">
|
<div className="flex items-center gap-3 text-2xl rounded transition-colors dark:bg-gray-800 bg-purple-100 focus-within:bg-purple-200 py-2 px-4 w-48 overflow-hidden dark:focus-within:bg-gray-700">
|
||||||
<label htmlFor="xnoToSend">Ӿ</label>
|
<label htmlFor="xnoToSend">Ӿ</label>
|
||||||
<input
|
<input
|
||||||
name="xno-amount"
|
name="xno-amount"
|
||||||
|
@ -93,9 +97,10 @@ const Send: NextPage = () => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ArrowDownIcon className="h-7" />
|
<span className="flex-1 text-lg text-center">
|
||||||
<span className="flex-1 text-lg">
|
<span className="text-extrabold">to</span>
|
||||||
<span className="dark:text-purple-400 font-medium">
|
<br />
|
||||||
|
<span className="text-purple-400 font-medium">
|
||||||
{address?.substring(0, 10)}
|
{address?.substring(0, 10)}
|
||||||
</span>
|
</span>
|
||||||
{address?.substring(10, 21)}
|
{address?.substring(10, 21)}
|
||||||
|
@ -103,61 +108,71 @@ const Send: NextPage = () => {
|
||||||
{address?.substring(21, 42)}
|
{address?.substring(21, 42)}
|
||||||
<br />
|
<br />
|
||||||
{address?.substring(42, 56)}
|
{address?.substring(42, 56)}
|
||||||
<span className="dark:text-purple-400 font-medium">
|
<span className="text-purple-400 font-medium">
|
||||||
{address?.substring(56)}
|
{address?.substring(56)}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'dark:bg-gray-800 rounded-full p-2 relative w-72 z-10 transition-opacity',
|
'dark:bg-gray-800 bg-purple-100 rounded-2xl p-2 relative w-72 z-10 transition-all hover:cursor-pointer',
|
||||||
{
|
{
|
||||||
'opacity-50': xnoToSend === '',
|
'opacity-50': disableSlider,
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
onMouseMove={ev => {
|
onMouseMove={ev => {
|
||||||
if (sliding) setCurrentX(ev.clientX)
|
if (sliding && !disableSlider) setCurrentX(ev.clientX)
|
||||||
}}
|
}}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
if (sliderPercentage !== 1) backToBase()
|
if (sliderPercentage !== 1 && !disableSlider) backToBase()
|
||||||
}}
|
}}
|
||||||
onMouseLeave={() => {
|
onMouseLeave={() => {
|
||||||
if (sliderPercentage !== 1) backToBase()
|
if (sliderPercentage !== 1 && !disableSlider) backToBase()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'dark:bg-purple-50 p-2 rounded-full w-11 z-30 transform-gpu',
|
'dark:bg-purple-50 bg-purple-400 p-2 rounded-xl w-11 z-30 transform-gpu transition-colors',
|
||||||
{
|
{
|
||||||
'transition-transform': !sliding,
|
'transition-all': !sliding,
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
transform: `translate3d(${sliderPercentage * 228}px, 0, 0)`,
|
transform: `translate3d(${sliderPercentage * 228}px, 0, 0)`,
|
||||||
}}
|
}}
|
||||||
onTouchStart={ev => {
|
onTouchStart={ev => {
|
||||||
setSliding(true)
|
if (!disableSlider) {
|
||||||
setStartX(ev.touches.item(0).clientX)
|
setSliding(true)
|
||||||
|
setStartX(ev.touches.item(0).clientX)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
onTouchMove={ev => {
|
onTouchMove={ev => {
|
||||||
if (sliding) setCurrentX(ev.touches.item(0).clientX)
|
if (sliding && !disableSlider)
|
||||||
|
setCurrentX(ev.touches.item(0).clientX)
|
||||||
|
}}
|
||||||
|
onTouchEnd={() => {
|
||||||
|
if (!disableSlider) backToBase()
|
||||||
}}
|
}}
|
||||||
onTouchEnd={() => backToBase()}
|
|
||||||
onMouseDown={ev => {
|
onMouseDown={ev => {
|
||||||
setSliding(true)
|
if (!disableSlider) {
|
||||||
setStartX(ev.clientX)
|
setSliding(true)
|
||||||
|
setStartX(ev.clientX)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PaperAirplaneIcon
|
{/* <PaperAirplaneIcon
|
||||||
className="h-7 dark:text-gray-900 translate-x-0.5"
|
className="h-7 dark:text-gray-900 translate-x-0.5"
|
||||||
style={{
|
style={{
|
||||||
transform: `translateX(var(--tw-translate-x)) rotate(${
|
transform: `translateX(var(--tw-translate-x)) rotate(${
|
||||||
30 + 60 * sliderPercentage
|
30 + 60 * sliderPercentage
|
||||||
}deg)`,
|
}deg)`,
|
||||||
}}
|
}}
|
||||||
/>
|
/> */}
|
||||||
|
<span className="dark:text-gray-900 text-purple-50 text-3xl font-medium flex justify-center select-none">
|
||||||
|
Ӿ
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
className="absolute text-purple-50 text-2xl left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 select-none"
|
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 }}
|
style={{ opacity: 0.7 - 0.7 * sliderPercentage, zIndex: -10 }}
|
||||||
>
|
>
|
||||||
slide to send
|
slide to send
|
||||||
|
|
|
@ -22,13 +22,13 @@ const ReadQrCode: NextPage = () => {
|
||||||
const { videoLive, videoRef } = useReadQrFromVideo(onQrCodeRead)
|
const { videoLive, videoRef } = useReadQrFromVideo(onQrCodeRead)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full gap-8">
|
<div className="flex flex-col h-full min-h-0 gap-8">
|
||||||
<span className="flex items-center gap-2">
|
<span className="flex items-center gap-2">
|
||||||
<PaperAirplaneIcon className=" dark:text-purple-50 h-7 xs:h-10 text-gray-900 rotate-[30deg] translate-x-1" />
|
<PaperAirplaneIcon className=" 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>
|
<h1 className="text-3xl sm:text-5xl">send</h1>
|
||||||
</span>
|
</span>
|
||||||
<video
|
<video
|
||||||
className={clsx('rounded shadow-md', { hidden: !videoLive })}
|
className={clsx('rounded shadow-md min-h-0', { hidden: !videoLive })}
|
||||||
ref={videoRef}
|
ref={videoRef}
|
||||||
/>
|
/>
|
||||||
{!videoLive && (
|
{!videoLive && (
|
||||||
|
|
|
@ -3,9 +3,8 @@ import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
const Welcome: NextPage = () => {
|
const Welcome: NextPage = () => {
|
||||||
const { push } = useRouter()
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col justify-center w-full h-full text-center text-purple-50">
|
<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>
|
<h1 className="mb-3 text-5xl font-extrabold">hey!</h1>
|
||||||
<p className="mb-3 text-xl font-medium">
|
<p className="mb-3 text-xl font-medium">
|
||||||
do you already have a
|
do you already have a
|
||||||
|
@ -14,11 +13,11 @@ const Welcome: NextPage = () => {
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="flex flex-col justify-center w-full gap-3 mb-6">
|
<div className="flex flex-col justify-center w-full gap-3 mb-6">
|
||||||
<button className="px-5 py-2 text-lg font-bold text-gray-900 transition-all duration-100 rounded shadow-lg bg-purple-50 hover:bg-purple-100 hover:shadow-md active:shadow">
|
<button 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
|
i have a passphrase/seed
|
||||||
</button>
|
</button>
|
||||||
<Link href="/welcome/new">
|
<Link href="/welcome/new">
|
||||||
<a className="px-5 py-2 text-lg font-bold text-gray-900 transition-all duration-100 rounded shadow-lg bg-purple-50 hover:bg-purple-100 hover:shadow-md active:shadow">
|
<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's a passphrase?
|
what's a passphrase?
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { useRouter } from 'next/router'
|
||||||
const Done: NextPage = () => {
|
const Done: NextPage = () => {
|
||||||
const { push } = useRouter()
|
const { push } = useRouter()
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-start h-full px-4 text-center gap-2 text-purple-50">
|
<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>
|
<h1 className="font-extrabold text-9xl">3</h1>
|
||||||
<p className="text-3xl">you're done!</p>
|
<p className="text-3xl">you're done!</p>
|
||||||
<p className="mb-5 text-xl">
|
<p className="mb-5 text-xl">
|
||||||
|
@ -12,7 +12,7 @@ const Done: NextPage = () => {
|
||||||
<b>nano</b>!
|
<b>nano</b>!
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
className="px-5 py-2 text-xl font-bold text-gray-900 rounded dark:bg-gray-900 dark:text-purple-100 bg-purple-50"
|
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')}
|
onClick={() => push('/dashboard')}
|
||||||
>
|
>
|
||||||
go!
|
go!
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { useEffect, useState } from 'react'
|
||||||
import useSetupSeed from '../../../lib/hooks/useSetupSeed'
|
import useSetupSeed from '../../../lib/hooks/useSetupSeed'
|
||||||
|
|
||||||
const New: NextPage = () => {
|
const New: NextPage = () => {
|
||||||
const { lazy, seed, storeSeed } = useSetupSeed(true)
|
const { lazy: storeSeedLazy, seed, storeSeed } = useSetupSeed(true)
|
||||||
const { push } = useRouter()
|
const { push } = useRouter()
|
||||||
const [storing, setStoring] = useState(false)
|
const [storing, setStoring] = useState(false)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -24,7 +24,7 @@ const New: NextPage = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-start h-full px-4 text-center gap-2 text-purple-50">
|
<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>
|
<h1 className="font-extrabold text-9xl">{!storing ? 1 : 2}</h1>
|
||||||
{!storing ? (
|
{!storing ? (
|
||||||
<>
|
<>
|
||||||
|
@ -32,12 +32,12 @@ const New: NextPage = () => {
|
||||||
generate a <b>passphrase</b> and copy it to your clipboard
|
generate a <b>passphrase</b> and copy it to your clipboard
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
className="px-5 py-2 text-xl font-bold text-gray-900 rounded dark:bg-gray-900 dark:text-purple-100 bg-purple-50"
|
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-colors text-purple-50 rounded dark:bg-gray-800"
|
||||||
onClick={lazy}
|
onClick={storeSeedLazy}
|
||||||
>
|
>
|
||||||
generate passphrase
|
generate passphrase
|
||||||
</button>
|
</button>
|
||||||
<p className="text-lg">
|
<p className="text-xl">
|
||||||
<b>
|
<b>
|
||||||
store this passphrase securely: you'll need it in case
|
store this passphrase securely: you'll need it in case
|
||||||
something happens to this device
|
something happens to this device
|
||||||
|
@ -50,7 +50,7 @@ const New: NextPage = () => {
|
||||||
store the <b>passphrase</b> securely in zep
|
store the <b>passphrase</b> securely in zep
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
className="px-5 py-2 text-xl font-bold text-gray-900 rounded dark:bg-gray-900 dark:text-purple-100 bg-purple-50"
|
className="px-5 py-2 text-xl font-bold bg-purple-400 transition-colors text-purple-50 rounded dark:bg-gray-800"
|
||||||
onClick={onStoreClick}
|
onClick={onStoreClick}
|
||||||
>
|
>
|
||||||
store passphrase
|
store passphrase
|
||||||
|
|
|
@ -4,5 +4,6 @@
|
||||||
"738b5cb3315dd267fc882f1388911162ee9a241c800bf583c07c1bbbc34c64a9c2099e01b5d5e3ab217012717e3ecfbe3f735af431c7e105e1719eeb03476af5",
|
"738b5cb3315dd267fc882f1388911162ee9a241c800bf583c07c1bbbc34c64a9c2099e01b5d5e3ab217012717e3ecfbe3f735af431c7e105e1719eeb03476af5",
|
||||||
"75edd150e09bada0f5c68fab14c0b385239cc396ef6600029dea0f7b66be63fa6a7d8ebe30aaff66634f583c4e68067c0de136e27dddc96be76d2ac5bb14ef71",
|
"75edd150e09bada0f5c68fab14c0b385239cc396ef6600029dea0f7b66be63fa6a7d8ebe30aaff66634f583c4e68067c0de136e27dddc96be76d2ac5bb14ef71",
|
||||||
"b6203f57196d244f7eb6971cef41a4cd4ce961e81ae8046f4f8274a4057cb77b4ef97ad3c25e14b50598c1243fa3253644b44e89c8648fd9c18b3703d36372bb",
|
"b6203f57196d244f7eb6971cef41a4cd4ce961e81ae8046f4f8274a4057cb77b4ef97ad3c25e14b50598c1243fa3253644b44e89c8648fd9c18b3703d36372bb",
|
||||||
"penalty parrot sure holiday target what human sadness crack picnic idle pluck mean salad frog usual grab aspect pottery faith staff crash umbrella lumber"
|
"penalty parrot sure holiday target what human sadness crack picnic idle pluck mean salad frog usual grab aspect pottery faith staff crash umbrella lumber",
|
||||||
|
"6bfddd0bfd00bf13eb17bae35627a2dfdf49cb56027fc26988faff0ab8a20b31efb16d706ceac8e458d4d5c342f2459d24746521a6e6a62a0adb29b323455ed9"
|
||||||
]
|
]
|
||||||
|
|
Reference in a new issue