diff --git a/README.md b/README.md index c403366..b5b02f8 100644 --- a/README.md +++ b/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. diff --git a/app/globals.css b/app/globals.css index 84dd377..698772a 100644 --- a/app/globals.css +++ b/app/globals.css @@ -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; } diff --git a/app/layout.tsx b/app/layout.tsx index 9a2b00f..4a00b66 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -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({ diff --git a/app/page.module.css b/app/page.module.css index 5283d05..3ab6606 100644 --- a/app/page.module.css +++ b/app/page.module.css @@ -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 { diff --git a/app/page.tsx b/app/page.tsx index 42b9b9b..c7f3d18 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,11 +1,13 @@ import { Prices } from '@/features/Prices' import styles from './page.module.css' +import { metadata } from './layout' export default function Home() { return ( <>
-

Should I Buy OCEAN or AGIX or FET?

+

{`${metadata.title}`}

+

{`${metadata.description}`}

diff --git a/features/Prices/components/FormAmount.module.css b/features/Prices/components/FormAmount.module.css new file mode 100644 index 0000000..5b2dd5a --- /dev/null +++ b/features/Prices/components/FormAmount.module.css @@ -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)); +} diff --git a/features/Prices/components/FormAmount.tsx b/features/Prices/components/FormAmount.tsx new file mode 100644 index 0000000..4df7353 --- /dev/null +++ b/features/Prices/components/FormAmount.tsx @@ -0,0 +1,21 @@ +import styles from './FormAmount.module.css' + +export function FormAmount({ + amount, + setAmount +}: { + amount: number + setAmount: (amount: number) => void +}) { + return ( +
+ setAmount(Number(e.target.value))} + size={1} + /> +
+ ) +} diff --git a/features/Prices/components/Prices.module.css b/features/Prices/components/Prices.module.css index 399056e..eec4cac 100644 --- a/features/Prices/components/Prices.module.css +++ b/features/Prices/components/Prices.module.css @@ -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; } diff --git a/features/Prices/components/Prices.tsx b/features/Prices/components/Prices.tsx index 528951d..8f8569e 100644 --- a/features/Prices/components/Prices.tsx +++ b/features/Prices/components/Prices.tsx @@ -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 ( <> -

- 1 OCEAN = {ratioOceanToAsi} ASI (fixed) = ${priceOcean} -

-

- 1 AGIX = {ratioAgixToAsi} ASI (fixed) = ${priceAgix} -

-

1 Fet = 1 ASI (fixed) = ${priceAsi}

- -
-

Buying with ${exampleBuyInUsd} right now gets you:

- - - +
+

+ 1 OCEAN = {ratioOceanToAsi} ASI (fixed) = ${priceOcean} +

+

+ 1 AGIX = {ratioAgixToAsi} ASI (fixed) = ${priceAgix} +

+

1 Fet = 1 ASI (fixed) = ${priceAsi}

-
-

- Swapping 100 OCEAN (${(100 * priceOcean).toFixed(2)}) right now gets - you: -

+
+
+

${exampleBuyInUsd} right now gets you:

+ + + +
- +
+

+ OCEAN + (${(debouncedAmountSwap * priceOcean).toFixed(2)}) right now gets + you: +

- + - + + + +
) diff --git a/features/Prices/components/Result.module.css b/features/Prices/components/Result.module.css index eb7bd41..c9ea56e 100644 --- a/features/Prices/components/Result.module.css +++ b/features/Prices/components/Result.module.css @@ -2,5 +2,9 @@ margin-bottom: 1rem; } +.result:last-child { + margin-bottom: 0; +} + .amount { } diff --git a/features/Prices/components/Result.tsx b/features/Prices/components/Result.tsx index 0db1ed9..5407c2b 100644 --- a/features/Prices/components/Result.tsx +++ b/features/Prices/components/Result.tsx @@ -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 (
+

{formatNumber(amount, symbol)}

- {formatPrice(amount, symbol)} →{' '} - {formatPrice(amountAsi, 'ASI')} -

-

- = {formatPrice(amountFiat, 'USD')} + →{' '} + {formatNumber(amountAsi, 'ASI')}{' '} + = {formatNumber(amountFiat, 'USD')}

) diff --git a/features/Prices/utils.ts b/features/Prices/utils.ts new file mode 100644 index 0000000..77063f9 --- /dev/null +++ b/features/Prices/utils.ts @@ -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() +} diff --git a/package-lock.json b/package-lock.json index 464eb1e..7afbc91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 40c16c7..bc50a50 100644 --- a/package.json +++ b/package.json @@ -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",