2025-05-21 21:34:22 +03:00
< script lang = "ts" >
import * as Card from '$lib/components/ui/card';
import { Badge } from '$lib/components/ui/badge';
2025-05-24 15:50:10 +03:00
import { getTimeBasedGreeting , formatPrice , formatMarketCap } from '$lib/utils';
2025-05-22 14:00:43 +03:00
import { USER_DATA } from '$lib/stores/user-data';
import SignInConfirmDialog from '$lib/components/self/SignInConfirmDialog.svelte';
2025-05-23 19:48:23 +03:00
import CoinIcon from '$lib/components/self/CoinIcon.svelte';
2025-05-25 18:44:06 +03:00
import DataTable from '$lib/components/self/DataTable.svelte';
2025-05-27 14:12:29 +03:00
import HomeSkeleton from '$lib/components/self/skeletons/HomeSkeleton.svelte';
2025-05-23 16:26:02 +03:00
import { onMount } from 'svelte';
import { toast } from 'svelte-sonner';
2025-05-25 18:44:06 +03:00
import { goto } from '$app/navigation';
2025-05-22 14:00:43 +03:00
let shouldSignIn = $state(false);
2025-05-23 16:26:02 +03:00
let coins = $state< any [ ] > ([]);
let loading = $state(true);
onMount(async () => {
try {
const response = await fetch('/api/coins/top');
if (response.ok) {
const result = await response.json();
coins = result.coins;
} else {
toast.error('Failed to load coins');
}
} catch (e) {
console.error('Failed to fetch coins:', e);
toast.error('Failed to load coins');
} finally {
loading = false;
}
});
2025-05-25 18:44:06 +03:00
const marketColumns = [
{
key: 'name',
label: 'Name',
class: 'font-medium',
render: (value: any, row: any) => {
return {
component: 'link',
href: `/coin/${ row . symbol } `,
content: {
icon: row.icon,
symbol: row.symbol,
name: row.name
}
};
}
},
{
key: 'price',
label: 'Price',
render: (value: any) => `$${ formatPrice ( value )} `
},
{
key: 'change24h',
label: '24h Change',
render: (value: any) => ({
component: 'badge',
variant: value >= 0 ? 'success' : 'destructive',
text: `${ value >= 0 ? '+' : '' } ${ value . toFixed ( 2 )} %`
})
},
{
key: 'marketCap',
label: 'Market Cap',
class: 'hidden md:table-cell',
render: (value: any) => formatMarketCap(value)
},
{
key: 'volume24h',
label: 'Volume (24h)',
class: 'hidden md:table-cell',
render: (value: any) => formatMarketCap(value)
}
];
2025-05-21 21:34:22 +03:00
< / script >
2025-05-22 14:00:43 +03:00
< SignInConfirmDialog bind:open = { shouldSignIn } / >
2025-05-21 21:34:22 +03:00
< div class = "container mx-auto p-6" >
< header class = "mb-8" >
2025-05-22 14:00:43 +03:00
< h1 class = "mb-2 text-3xl font-bold" >
{ $USER_DATA ? getTimeBasedGreeting ( $USER_DATA ? . name ) : 'Welcome to Rugplay!' }
< / h1 >
< p class = "text-muted-foreground" >
{ #if $USER_DATA }
Here's the market overview for today.
{ : else }
You need to < button
class="text-primary underline hover:cursor-pointer"
onclick={() => ( shouldSignIn = ! shouldSignIn )} >sign in< /button
>
or{ ' ' }
< button
class="text-primary underline hover:cursor-pointer"
onclick={() => ( shouldSignIn = ! shouldSignIn )} >create an account< /button
> to play.
{ /if }
< / p >
2025-05-21 21:34:22 +03:00
< / header >
2025-05-23 16:26:02 +03:00
{ #if loading }
2025-05-27 14:12:29 +03:00
< HomeSkeleton / >
2025-05-23 16:26:02 +03:00
{ :else if coins . length === 0 }
< div class = "flex h-96 items-center justify-center" >
< div class = "text-center" >
< div class = "text-muted-foreground mb-4 text-xl" > No coins available< / div >
< p class = "text-muted-foreground text-sm" > Be the first to create a coin!< / p >
< / div >
< / div >
{ : else }
< div class = "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3" >
{ #each coins . slice ( 0 , 6 ) as coin }
< a href = { `/coin/ ${ coin . symbol } ` } class="block" >
2025-05-23 19:48:23 +03:00
< Card.Root class = "hover:bg-card/50 h-full transition-all hover:shadow-md" >
2025-05-23 16:26:02 +03:00
< Card.Header >
< Card.Title class = "flex items-center justify-between" >
< div class = "flex items-center gap-2" >
2025-05-23 19:48:23 +03:00
< CoinIcon icon = { coin . icon } symbol= { coin . symbol } name = { coin . name } size= { 6 } />
2025-05-23 16:26:02 +03:00
< span > { coin . name } (*{ coin . symbol } )</ span >
< / div >
< Badge variant = { coin . change24h >= 0 ? 'success' : 'destructive' } class="ml-2" >
{ coin . change24h >= 0 ? '+' : '' }{ coin . change24h . toFixed ( 2 )} %
< / Badge >
< / Card.Title >
< Card.Description > Market Cap: { formatMarketCap ( coin . marketCap )} </ Card.Description >
< / Card.Header >
< Card.Content >
< div class = "flex items-baseline justify-between" >
< span class = "text-3xl font-bold" > ${ formatPrice ( coin . price )} </ span >
< span class = "text-muted-foreground text-sm" >
24h Vol: { formatMarketCap ( coin . volume24h )}
< / span >
< / div >
< / Card.Content >
< / Card.Root >
< / a >
{ /each }
< / div >
2025-05-21 21:34:22 +03:00
2025-05-23 16:26:02 +03:00
< div class = "mt-12" >
< h2 class = "mb-4 text-2xl font-bold" > Market Overview< / h2 >
< Card.Root >
< Card.Content class = "p-0" >
2025-05-25 18:44:06 +03:00
< DataTable
columns={ marketColumns }
data={ coins }
onRowClick={( coin ) => goto ( `/coin/$ { coin . symbol } `) }
/>
2025-05-23 16:26:02 +03:00
< / Card.Content >
< / Card.Root >
< / div >
{ /if }
2025-05-21 21:34:22 +03:00
< / div >