2025-05-22 13:17:11 +03:00
< script lang = "ts" >
import * as Sidebar from '$lib/components/ui/sidebar';
2025-05-22 14:00:43 +03:00
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
import * as Avatar from '$lib/components/ui/avatar';
2025-05-23 16:26:02 +03:00
import { Badge } from '$lib/components/ui/badge';
2025-05-22 13:17:11 +03:00
import {
Moon,
Sun,
ShieldAlert,
Home,
Store,
BriefcaseBusiness,
2025-05-22 14:00:43 +03:00
Coins,
ChevronsUpDownIcon,
SparklesIcon,
BadgeCheckIcon,
CreditCardIcon,
BellIcon,
2025-05-23 16:26:02 +03:00
LogOutIcon,
2025-05-24 15:50:10 +03:00
Wallet,
Trophy
2025-05-22 13:17:11 +03:00
} from 'lucide-svelte';
import { mode , setMode } from 'mode-watcher';
import type { HTMLAttributes } from 'svelte/elements';
import { USER_DATA } from '$lib/stores/user-data';
2025-05-23 16:26:02 +03:00
import { PORTFOLIO_DATA , fetchPortfolioData } from '$lib/stores/portfolio-data';
2025-05-22 13:17:11 +03:00
import { useSidebar } from '$lib/components/ui/sidebar/index.js';
import SignInConfirmDialog from './SignInConfirmDialog.svelte';
2025-05-26 13:05:47 +03:00
import DailyRewards from './DailyRewards.svelte';
2025-05-22 14:00:43 +03:00
import { signOut } from '$lib/auth-client';
2025-05-23 16:26:02 +03:00
import { getPublicUrl } from '$lib/utils';
import { goto } from '$app/navigation';
2025-05-22 13:17:11 +03:00
const data = {
navMain: [
{ title : 'Home' , url : '/' , icon : Home } ,
{ title : 'Market' , url : '/market' , icon : Store } ,
{ title : 'Portfolio' , url : '/portfolio' , icon : BriefcaseBusiness } ,
2025-05-24 15:50:10 +03:00
{ title : 'Leaderboard' , url : '/leaderboard' , icon : Trophy } ,
2025-05-22 13:17:11 +03:00
{ title : 'Create coin' , url : '/coin/create' , icon : Coins }
],
navAdmin: [{ title : 'Admin' , url : '/admin' , icon : ShieldAlert } ]
};
type MenuButtonProps = HTMLAttributes< HTMLAnchorElement | HTMLButtonElement > ;
2025-05-22 14:00:43 +03:00
const { setOpenMobile , isMobile } = useSidebar();
2025-05-22 13:17:11 +03:00
let shouldSignIn = $state(false);
2025-05-23 16:26:02 +03:00
// Fetch portfolio data when user is authenticated
$effect(() => {
if ($USER_DATA) {
fetchPortfolioData();
} else {
PORTFOLIO_DATA.set(null);
}
});
2025-05-22 13:17:11 +03:00
function handleNavClick(title: string) {
setOpenMobile(false);
}
function handleModeToggle() {
setMode(mode.current === 'light' ? 'dark' : 'light');
setOpenMobile(false);
}
2025-05-23 16:26:02 +03:00
function formatCurrency(value: number): string {
return value.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}
2025-05-22 13:17:11 +03:00
< / script >
2025-05-22 14:00:43 +03:00
< SignInConfirmDialog bind:open = { shouldSignIn } / >
2025-05-22 13:17:11 +03:00
< Sidebar.Root collapsible = "offcanvas" >
< Sidebar.Header >
< div class = "flex items-center gap-1 px-2 py-2" >
< img src = "/placeholder_logo.png" class = "h-5 w-5" alt = "twoblade" / >
< div class = "flex items-center gap-2" >
< span class = "text-base font-semibold" > Rugplay< / span >
{ #if $USER_DATA ? . isAdmin }
< span class = "text-muted-foreground text-xs" > | Admin< / span >
{ /if }
< / div >
< / div >
< / Sidebar.Header >
< Sidebar.Content >
< Sidebar.Group >
< Sidebar.GroupContent >
< Sidebar.Menu >
{ #each data . navMain as item }
< Sidebar.MenuItem >
< Sidebar.MenuButton >
{ # snippet child ({ props } : { props : MenuButtonProps })}
< a
href={ item . url || '/' }
onclick={() => handleNavClick ( item . title )}
class={ ` ${ props . class } ` }
>
< item.icon / >
< span > { item . title } </ span >
< / a >
{ /snippet }
< / Sidebar.MenuButton >
< / Sidebar.MenuItem >
{ /each }
{ #if $USER_DATA ? . isAdmin }
{ #each data . navAdmin as item }
< Sidebar.MenuItem >
< Sidebar.MenuButton >
{ # snippet child ({ props } : { props : MenuButtonProps })}
< a
href={ item . url }
onclick={() => handleNavClick ( item . title )}
class={ ` ${ props . class } ` }
>
< item.icon / >
< span > { item . title } </ span >
< / a >
{ /snippet }
< / Sidebar.MenuButton >
< / Sidebar.MenuItem >
{ /each }
{ /if }
< Sidebar.MenuItem >
< Sidebar.MenuButton >
{ # snippet child ({ props } : { props : MenuButtonProps })}
< button onclick = { handleModeToggle } {... props } >
{ #if mode . current === 'light' }
< Moon class = "h-5 w-5" / >
< span > Dark Mode< / span >
{ : else }
< Sun class = "h-5 w-5" / >
< span > Light Mode< / span >
{ /if }
< / button >
{ /snippet }
< / Sidebar.MenuButton >
< / Sidebar.MenuItem >
< / Sidebar.Menu >
2025-05-26 13:05:47 +03:00
< / Sidebar.GroupContent > < / Sidebar.Group >
<!-- Daily Rewards -->
{ #if $USER_DATA }
< Sidebar.Group >
< Sidebar.GroupContent >
< div class = "px-2 py-1" >
< DailyRewards / >
< / div >
< / Sidebar.GroupContent >
< / Sidebar.Group >
{ /if }
2025-05-23 16:26:02 +03:00
<!-- Portfolio Summary -->
{ #if $USER_DATA && $PORTFOLIO_DATA }
< Sidebar.Group >
< Sidebar.GroupLabel > Portfolio< / Sidebar.GroupLabel >
< Sidebar.GroupContent >
< div class = "px-2 py-1 space-y-2" >
< div class = "flex items-center justify-between" >
< div class = "flex items-center gap-2" >
< Wallet class = "h-4 w-4 text-muted-foreground" / >
< span class = "text-sm font-medium" > Total Value< / span >
< / div >
< Badge variant = "secondary" class = "font-mono" >
${ formatCurrency ( $PORTFOLIO_DATA . totalValue )}
< / Badge >
< / div >
< div class = "space-y-1 text-xs text-muted-foreground" >
< div class = "flex justify-between" >
< span > Cash:< / span >
< span class = "font-mono" > ${ formatCurrency ( $PORTFOLIO_DATA . baseCurrencyBalance )} </ span >
< / div >
< div class = "flex justify-between" >
< span > Coins:< / span >
< span class = "font-mono" > ${ formatCurrency ( $PORTFOLIO_DATA . totalCoinValue )} </ span >
< / div >
< / div >
< / div >
< / Sidebar.GroupContent >
< / Sidebar.Group >
{ /if }
2025-05-22 13:17:11 +03:00
< / Sidebar.Content >
2025-05-22 14:00:43 +03:00
{ #if $USER_DATA }
< Sidebar.Footer >
< Sidebar.Menu >
< Sidebar.MenuItem >
< DropdownMenu.Root >
< DropdownMenu.Trigger >
{ # snippet child ({ props })}
< Sidebar.MenuButton
size="lg"
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
{... props }
>
< Avatar.Root class = "size-8 rounded-lg" >
2025-05-23 16:26:02 +03:00
< Avatar.Image src = { getPublicUrl ( $USER_DATA . image )} alt= { $USER_DATA . name } />
< Avatar.Fallback class = "rounded-lg" > ?< / Avatar.Fallback >
2025-05-22 14:00:43 +03:00
< / Avatar.Root >
< div class = "grid flex-1 text-left text-sm leading-tight" >
< span class = "truncate font-medium" > { $USER_DATA . name } </ span >
2025-05-23 16:26:02 +03:00
< span class = "truncate text-xs" > @{ $USER_DATA . username } </ span >
2025-05-22 14:00:43 +03:00
< / div >
< ChevronsUpDownIcon class = "ml-auto size-4" / >
< / Sidebar.MenuButton >
{ /snippet }
< / DropdownMenu.Trigger >
< DropdownMenu.Content
2025-05-22 14:06:21 +03:00
class="w-(--bits-dropdown-menu-anchor-width) min-w-56 rounded-lg p-2"
2025-05-22 14:00:43 +03:00
side={ isMobile ? 'bottom' : 'right' }
align="end"
sideOffset={ 4 }
>
< DropdownMenu.Label class = "p-0 font-normal" >
< div class = "flex items-center gap-2 px-1 py-1.5 text-left text-sm" >
< Avatar.Root class = "size-8 rounded-lg" >
2025-05-23 16:26:02 +03:00
< Avatar.Image src = { getPublicUrl ( $USER_DATA . image )} alt= { $USER_DATA . name } />
< Avatar.Fallback class = "rounded-lg" > ?< / Avatar.Fallback >
2025-05-22 14:00:43 +03:00
< / Avatar.Root >
< div class = "grid flex-1 text-left text-sm leading-tight" >
< span class = "truncate font-medium" > { $USER_DATA . name } </ span >
2025-05-23 16:26:02 +03:00
< span class = "truncate text-xs" > @{ $USER_DATA . username } </ span >
2025-05-22 14:00:43 +03:00
< / div >
< / div >
< / DropdownMenu.Label >
< DropdownMenu.Separator / >
< DropdownMenu.Group >
< DropdownMenu.Item disabled = { true } >
< SparklesIcon / >
Upgrade to Pro
< / DropdownMenu.Item >
< / DropdownMenu.Group >
< DropdownMenu.Separator / >
< DropdownMenu.Group >
2025-05-23 16:26:02 +03:00
< DropdownMenu.Item onclick = {() => goto ( '/settings' )} >
2025-05-22 14:00:43 +03:00
< BadgeCheckIcon / >
Account
< / DropdownMenu.Item >
< DropdownMenu.Item disabled = { true } >
< CreditCardIcon / >
Billing
< / DropdownMenu.Item >
< DropdownMenu.Item disabled = { true } >
< BellIcon / >
Notifications
< / DropdownMenu.Item >
< / DropdownMenu.Group >
< DropdownMenu.Separator / >
< DropdownMenu.Item
onclick={() => {
signOut().then(() => {
USER_DATA.set(null);
window.location.reload();
});
}}
>
< LogOutIcon / >
Log out
< / DropdownMenu.Item >
< / DropdownMenu.Content >
< / DropdownMenu.Root >
< / Sidebar.MenuItem >
< / Sidebar.Menu >
< / Sidebar.Footer >
{ /if }
2025-05-22 13:17:11 +03:00
< / Sidebar.Root >