mirror of
https://github.com/kremalicious/asi-calculator.git
synced 2024-12-22 09:23:16 +01:00
reorg
This commit is contained in:
parent
a9c5c20bc2
commit
ac386a6ef4
37
README.md
37
README.md
@ -1,36 +1,3 @@
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
# asi-calculator
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||
> Calculate how much ASI you get for your OCEAN, AGIX, or FET.
|
||||
|
@ -1,15 +1,17 @@
|
||||
:root {
|
||||
--max-width: 620px;
|
||||
--border-radius: 12px;
|
||||
--max-width: 800px;
|
||||
--border-radius: 0.3rem;
|
||||
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
--foreground-rgb: 20, 20, 20;
|
||||
--foreground-rgb-highlight: 0, 0, 0;
|
||||
--background-start-rgb: 214, 219, 220;
|
||||
--background-end-rgb: 255, 255, 255;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--foreground-rgb: 255, 255, 255;
|
||||
--foreground-rgb: 220, 220, 220;
|
||||
--foreground-rgb-highlight: 255, 255, 255;
|
||||
--background-start-rgb: 0, 0, 0;
|
||||
--background-end-rgb: 0, 0, 0;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ const firaCode = Fira_Code({ subsets: ['latin'] })
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'OCEAN + AGIX + FET = ASI',
|
||||
description: 'Calculate how much ASI you get for your OCEAN, AGIX, or FET'
|
||||
description: 'Calculate how much ASI you get for your OCEAN, AGIX, or FET.'
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
|
@ -1,12 +1,23 @@
|
||||
.main,
|
||||
.footer {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.title,
|
||||
.description {
|
||||
color: rgb(var(--foreground-rgb-highlight));
|
||||
max-width: var(--max-width);
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-bottom: 2rem;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { Prices } from '@/features/Prices'
|
||||
import styles from './page.module.css'
|
||||
import { metadata } from './layout'
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<main className={styles.main}>
|
||||
<h1 className={styles.title}>Should I Buy OCEAN or AGIX or FET?</h1>
|
||||
<h1 className={styles.title}>{`${metadata.title}`}</h1>
|
||||
<p className={styles.description}>{`${metadata.description}`}</p>
|
||||
<Prices />
|
||||
</main>
|
||||
<footer className={styles.footer}>Send ❤️ to krema.eth</footer>
|
||||
|
23
features/Prices/components/FormAmount.module.css
Normal file
23
features/Prices/components/FormAmount.module.css
Normal file
@ -0,0 +1,23 @@
|
||||
.form {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.input {
|
||||
all: unset;
|
||||
width: auto;
|
||||
padding-left: 0.2rem;
|
||||
padding-right: 0.2rem;
|
||||
text-align: center;
|
||||
background-color: rgba(var(--foreground-rgb), 0.15);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.input:hover {
|
||||
background-color: rgba(var(--foreground-rgb), 0.2);
|
||||
}
|
||||
|
||||
.input:focus-within {
|
||||
outline: none;
|
||||
background-color: rgba(var(--foreground-rgb), 0.3);
|
||||
color: rgb(var(--foreground-rgb-highlight));
|
||||
}
|
21
features/Prices/components/FormAmount.tsx
Normal file
21
features/Prices/components/FormAmount.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import styles from './FormAmount.module.css'
|
||||
|
||||
export function FormAmount({
|
||||
amount,
|
||||
setAmount
|
||||
}: {
|
||||
amount: number
|
||||
setAmount: (amount: number) => void
|
||||
}) {
|
||||
return (
|
||||
<form className={styles.form}>
|
||||
<input
|
||||
className={styles.input}
|
||||
type="text"
|
||||
value={amount}
|
||||
onChange={(e) => setAmount(Number(e.target.value))}
|
||||
size={1}
|
||||
/>
|
||||
</form>
|
||||
)
|
||||
}
|
@ -1,7 +1,23 @@
|
||||
.header {
|
||||
max-width: var(--max-width);
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: 2rem;
|
||||
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||
max-width: calc(var(--max-width) * 2);
|
||||
margin: 2rem auto;
|
||||
}
|
||||
|
||||
.results {
|
||||
margin-top: 2rem;
|
||||
border: 1px solid rgba(var(--foreground-rgb), 0.2);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 1.25rem 1.5rem;
|
||||
}
|
||||
|
||||
.results h3 {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import useSWR from 'swr'
|
||||
import { useDebounce } from 'use-debounce'
|
||||
import styles from './Prices.module.css'
|
||||
import { Result } from './Result'
|
||||
import {
|
||||
@ -10,28 +11,30 @@ import {
|
||||
exampleBuyInUsd,
|
||||
ratioFetToAsi
|
||||
} from '@/constants'
|
||||
|
||||
const fetcher = async (url: string) => {
|
||||
const res = await fetch(url)
|
||||
if (!res.ok) throw new Error('Failed to fetch')
|
||||
return await res.json()
|
||||
}
|
||||
import { useState } from 'react'
|
||||
import { FormAmount } from './FormAmount'
|
||||
import { fetcher } from '../utils'
|
||||
|
||||
export function Prices() {
|
||||
const [amountSwap, setAmountSwap] = useState(100)
|
||||
const [debouncedAmountSwap] = useDebounce(amountSwap, 500)
|
||||
|
||||
console.log(debouncedAmountSwap)
|
||||
|
||||
const { data: dataPrices } = useSWR(
|
||||
`https://web3.kremalicious.com/api/prices/?tokens=${tokens.toString()}`,
|
||||
fetcher
|
||||
)
|
||||
const { data: dataSwapOceanToAgix } = useSWR(
|
||||
`/api/quote/?src=${tokens[0]}&dst=${tokens[2]}&amount=${
|
||||
exampleBuyInUsd * 1e18
|
||||
debouncedAmountSwap * 1e18
|
||||
}`,
|
||||
fetcher
|
||||
)
|
||||
|
||||
const { data: dataSwapOceanToFet } = useSWR(
|
||||
`/api/quote/?src=${tokens[0]}&dst=${tokens[1]}&amount=${
|
||||
exampleBuyInUsd * 1e18
|
||||
debouncedAmountSwap * 1e18
|
||||
}`,
|
||||
fetcher
|
||||
)
|
||||
@ -43,87 +46,94 @@ export function Prices() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
1 OCEAN = {ratioOceanToAsi} ASI (fixed) = ${priceOcean}
|
||||
</p>
|
||||
<p>
|
||||
1 AGIX = {ratioAgixToAsi} ASI (fixed) = ${priceAgix}
|
||||
</p>
|
||||
<p>1 Fet = 1 ASI (fixed) = ${priceAsi}</p>
|
||||
|
||||
<div className={styles.results}>
|
||||
<h3>Buying with ${exampleBuyInUsd} right now gets you:</h3>
|
||||
<Result
|
||||
symbol="OCEAN"
|
||||
amount={exampleBuyInUsd / priceOcean}
|
||||
amountAsi={(exampleBuyInUsd / priceOcean) * ratioOceanToAsi}
|
||||
amountFiat={
|
||||
(exampleBuyInUsd / priceOcean) * ratioOceanToAsi * priceAsi
|
||||
}
|
||||
/>
|
||||
<Result
|
||||
symbol="AGIX"
|
||||
amount={exampleBuyInUsd / priceAgix}
|
||||
amountAsi={(exampleBuyInUsd / priceAgix) * ratioAgixToAsi}
|
||||
amountFiat={(exampleBuyInUsd / priceAgix) * ratioAgixToAsi * priceAsi}
|
||||
/>
|
||||
<Result
|
||||
symbol="FET"
|
||||
amount={exampleBuyInUsd / priceFet}
|
||||
amountAsi={(exampleBuyInUsd / priceFet) * ratioFetToAsi}
|
||||
amountFiat={(exampleBuyInUsd / priceFet) * ratioFetToAsi * priceAsi}
|
||||
/>
|
||||
<div className={styles.header}>
|
||||
<p>
|
||||
1 OCEAN = {ratioOceanToAsi} ASI (fixed) = ${priceOcean}
|
||||
</p>
|
||||
<p>
|
||||
1 AGIX = {ratioAgixToAsi} ASI (fixed) = ${priceAgix}
|
||||
</p>
|
||||
<p>1 Fet = 1 ASI (fixed) = ${priceAsi}</p>
|
||||
</div>
|
||||
|
||||
<div className={styles.results}>
|
||||
<h3>
|
||||
Swapping 100 OCEAN (${(100 * priceOcean).toFixed(2)}) right now gets
|
||||
you:
|
||||
</h3>
|
||||
<div className={styles.grid}>
|
||||
<div className={styles.results}>
|
||||
<h3>${exampleBuyInUsd} right now gets you:</h3>
|
||||
<Result
|
||||
symbol="OCEAN"
|
||||
amount={exampleBuyInUsd / priceOcean}
|
||||
amountAsi={(exampleBuyInUsd / priceOcean) * ratioOceanToAsi}
|
||||
amountFiat={
|
||||
(exampleBuyInUsd / priceOcean) * ratioOceanToAsi * priceAsi
|
||||
}
|
||||
/>
|
||||
<Result
|
||||
symbol="AGIX"
|
||||
amount={exampleBuyInUsd / priceAgix}
|
||||
amountAsi={(exampleBuyInUsd / priceAgix) * ratioAgixToAsi}
|
||||
amountFiat={
|
||||
(exampleBuyInUsd / priceAgix) * ratioAgixToAsi * priceAsi
|
||||
}
|
||||
/>
|
||||
<Result
|
||||
symbol="FET"
|
||||
amount={exampleBuyInUsd / priceFet}
|
||||
amountAsi={(exampleBuyInUsd / priceFet) * ratioFetToAsi}
|
||||
amountFiat={(exampleBuyInUsd / priceFet) * ratioFetToAsi * priceAsi}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Result
|
||||
symbol="OCEAN"
|
||||
amount={100}
|
||||
amountAsi={100 * ratioOceanToAsi}
|
||||
amountFiat={100 * ratioOceanToAsi * priceAsi}
|
||||
/>
|
||||
<div className={styles.results}>
|
||||
<h3>
|
||||
<FormAmount amount={amountSwap} setAmount={setAmountSwap} /> OCEAN
|
||||
(${(debouncedAmountSwap * priceOcean).toFixed(2)}) right now gets
|
||||
you:
|
||||
</h3>
|
||||
|
||||
<Result
|
||||
symbol="AGIX"
|
||||
amount={
|
||||
dataSwapOceanToAgix?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToAgix?.dstToken?.decimals}`) || 0
|
||||
}
|
||||
amountAsi={
|
||||
(dataSwapOceanToAgix?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToAgix?.dstToken?.decimals}`) || 0) *
|
||||
ratioAgixToAsi
|
||||
}
|
||||
amountFiat={
|
||||
(dataSwapOceanToAgix?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToAgix?.dstToken?.decimals}`) || 0) *
|
||||
ratioAgixToAsi *
|
||||
priceAsi
|
||||
}
|
||||
/>
|
||||
<Result
|
||||
symbol="OCEAN"
|
||||
amount={debouncedAmountSwap}
|
||||
amountAsi={debouncedAmountSwap * ratioOceanToAsi}
|
||||
amountFiat={debouncedAmountSwap * ratioOceanToAsi * priceAsi}
|
||||
/>
|
||||
|
||||
<Result
|
||||
symbol="FET"
|
||||
amount={
|
||||
dataSwapOceanToFet?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToFet?.dstToken?.decimals}`) || 0
|
||||
}
|
||||
amountAsi={
|
||||
(dataSwapOceanToFet?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToFet?.dstToken?.decimals}`) || 0) *
|
||||
ratioFetToAsi
|
||||
}
|
||||
amountFiat={
|
||||
(dataSwapOceanToFet?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToFet?.dstToken?.decimals}`) || 0) *
|
||||
priceAsi
|
||||
}
|
||||
/>
|
||||
<Result
|
||||
symbol="AGIX"
|
||||
amount={
|
||||
dataSwapOceanToAgix?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToAgix?.dstToken?.decimals}`) || 0
|
||||
}
|
||||
amountAsi={
|
||||
(dataSwapOceanToAgix?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToAgix?.dstToken?.decimals}`) || 0) *
|
||||
ratioAgixToAsi
|
||||
}
|
||||
amountFiat={
|
||||
(dataSwapOceanToAgix?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToAgix?.dstToken?.decimals}`) || 0) *
|
||||
ratioAgixToAsi *
|
||||
priceAsi
|
||||
}
|
||||
/>
|
||||
|
||||
<Result
|
||||
symbol="FET"
|
||||
amount={
|
||||
dataSwapOceanToFet?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToFet?.dstToken?.decimals}`) || 0
|
||||
}
|
||||
amountAsi={
|
||||
(dataSwapOceanToFet?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToFet?.dstToken?.decimals}`) || 0) *
|
||||
ratioFetToAsi
|
||||
}
|
||||
amountFiat={
|
||||
(dataSwapOceanToFet?.dstAmount /
|
||||
Number(`1e${dataSwapOceanToFet?.dstToken?.decimals}`) || 0) *
|
||||
priceAsi
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
@ -2,5 +2,9 @@
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.result:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.amount {
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { formatCurrency } from '@coingecko/cryptoformat'
|
||||
import styles from './Result.module.css'
|
||||
import { formatNumber } from '../utils'
|
||||
|
||||
type Props = {
|
||||
symbol: string
|
||||
@ -8,22 +8,14 @@ type Props = {
|
||||
amountFiat: number
|
||||
}
|
||||
|
||||
function formatPrice(price: number, currency: string) {
|
||||
return formatCurrency(price, currency, 'en', false, {
|
||||
decimalPlaces: 3,
|
||||
significantFigures: 5
|
||||
})
|
||||
}
|
||||
|
||||
export function Result({ symbol, amount, amountAsi, amountFiat }: Props) {
|
||||
return (
|
||||
<div className={styles.result}>
|
||||
<p>{formatNumber(amount, symbol)}</p>
|
||||
<p>
|
||||
{formatPrice(amount, symbol)} →{' '}
|
||||
<strong title={`${amountAsi}`}>{formatPrice(amountAsi, 'ASI')}</strong>
|
||||
</p>
|
||||
<p>
|
||||
= <strong>{formatPrice(amountFiat, 'USD')}</strong>
|
||||
→{' '}
|
||||
<strong title={`${amountAsi}`}>{formatNumber(amountAsi, 'ASI')}</strong>{' '}
|
||||
= <strong>{formatNumber(amountFiat, 'USD')}</strong>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
|
14
features/Prices/utils.ts
Normal file
14
features/Prices/utils.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { formatCurrency } from '@coingecko/cryptoformat'
|
||||
|
||||
export function formatNumber(price: number, currency: string) {
|
||||
return formatCurrency(price, currency, 'en', false, {
|
||||
decimalPlaces: 3,
|
||||
significantFigures: 5
|
||||
})
|
||||
}
|
||||
|
||||
export async function fetcher(url: string) {
|
||||
const res = await fetch(url)
|
||||
if (!res.ok) throw new Error('Failed to fetch')
|
||||
return await res.json()
|
||||
}
|
18
package-lock.json
generated
18
package-lock.json
generated
@ -1,18 +1,19 @@
|
||||
{
|
||||
"name": "ocean-fetch-price-difference",
|
||||
"name": "asi-calculator",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ocean-fetch-price-difference",
|
||||
"name": "asi-calculator",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@coingecko/cryptoformat": "^0.8.1",
|
||||
"next": "14.1.4",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"swr": "^2.2.5"
|
||||
"swr": "^2.2.5",
|
||||
"use-debounce": "^10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
@ -4075,6 +4076,17 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-debounce": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.0.tgz",
|
||||
"integrity": "sha512-XRjvlvCB46bah9IBXVnq/ACP2lxqXyZj0D9hj4K5OzNroMDpTEBg8Anuh1/UfRTRs7pLhQ+RiNxxwZu9+MVl1A==",
|
||||
"engines": {
|
||||
"node": ">= 16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "ocean-fetch-price-difference",
|
||||
"name": "asi-calculator",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@ -13,7 +13,8 @@
|
||||
"next": "14.1.4",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"swr": "^2.2.5"
|
||||
"swr": "^2.2.5",
|
||||
"use-debounce": "^10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
|
Loading…
Reference in New Issue
Block a user