feat: AI-powered prediction market (Hopium)
This commit is contained in:
parent
4fcc55fa72
commit
2a92c37d26
33 changed files with 7009 additions and 4518 deletions
|
|
@ -7,7 +7,6 @@
|
|||
import {
|
||||
Moon,
|
||||
Sun,
|
||||
ShieldAlert,
|
||||
Home,
|
||||
Store,
|
||||
BriefcaseBusiness,
|
||||
|
|
@ -24,7 +23,9 @@
|
|||
Gift,
|
||||
Shield,
|
||||
Ticket,
|
||||
BarChart3
|
||||
PiggyBank,
|
||||
ChartColumn,
|
||||
TrendingUpDown
|
||||
} from 'lucide-svelte';
|
||||
import { mode, setMode } from 'mode-watcher';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
|
|
@ -37,15 +38,17 @@
|
|||
import { signOut } from '$lib/auth-client';
|
||||
import { formatValue, getPublicUrl } from '$lib/utils';
|
||||
import { goto } from '$app/navigation';
|
||||
import { liveTradesStore, isLoadingTrades, type LiveTrade } from '$lib/stores/websocket';
|
||||
import { liveTradesStore, isLoadingTrades } from '$lib/stores/websocket';
|
||||
|
||||
const data = {
|
||||
navMain: [
|
||||
{ title: 'Home', url: '/', icon: Home },
|
||||
{ title: 'Market', url: '/market', icon: Store },
|
||||
{ title: 'Portfolio', url: '/portfolio', icon: BriefcaseBusiness },
|
||||
{ title: 'Hopium', url: '/hopium', icon: TrendingUpDown },
|
||||
{ title: 'Gambling', url: '/gambling', icon: PiggyBank },
|
||||
{ title: 'Leaderboard', url: '/leaderboard', icon: Trophy },
|
||||
{ title: 'Treemap', url: '/treemap', icon: BarChart3 },
|
||||
{ title: 'Portfolio', url: '/portfolio', icon: BriefcaseBusiness },
|
||||
{ title: 'Treemap', url: '/treemap', icon: ChartColumn },
|
||||
{ title: 'Create coin', url: '/coin/create', icon: Coins }
|
||||
]
|
||||
};
|
||||
|
|
@ -364,7 +367,12 @@
|
|||
<Settings />
|
||||
Settings
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={() => { showPromoCode = true; setOpenMobile(false); }}>
|
||||
<DropdownMenu.Item
|
||||
onclick={() => {
|
||||
showPromoCode = true;
|
||||
setOpenMobile(false);
|
||||
}}
|
||||
>
|
||||
<Gift />
|
||||
Promo code
|
||||
</DropdownMenu.Item>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,194 @@
|
|||
<script lang="ts">
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Separator } from '$lib/components/ui/separator';
|
||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||
</script>
|
||||
|
||||
<!-- Header Section -->
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-muted rounded-lg p-4">
|
||||
<Skeleton class="h-14 w-14" />
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<Skeleton class="mb-2 h-8 w-3/4" />
|
||||
<Skeleton class="h-4 w-1/3" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Creator Info -->
|
||||
<div class="mb-4 mt-3 flex flex-wrap items-center gap-1.5">
|
||||
<Skeleton class="h-3 w-16" />
|
||||
<Skeleton class="h-4 w-4 rounded-full" />
|
||||
<Skeleton class="h-4 w-32" />
|
||||
</div>
|
||||
|
||||
<div class="grid gap-8">
|
||||
<!-- Main content grid -->
|
||||
<div class="grid grid-cols-1 gap-8 lg:grid-cols-3">
|
||||
<!-- Left: Chart (2/3 width) -->
|
||||
<div class="lg:col-span-2">
|
||||
<Card.Root class="shadow-sm">
|
||||
<Card.Header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<Skeleton class="h-6 w-6" />
|
||||
<Skeleton class="h-6 w-16" />
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<Skeleton class="mb-1 h-10 w-20" />
|
||||
<Skeleton class="h-4 w-16" />
|
||||
</div>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<Skeleton class="h-[400px] w-full rounded-lg" />
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
|
||||
<!-- Right: Trading Controls (1/3 width) -->
|
||||
<div class="space-y-6 lg:col-span-1">
|
||||
<!-- Trading Card -->
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Skeleton class="h-6 w-20" />
|
||||
</Card.Header>
|
||||
<Card.Content class="space-y-6">
|
||||
<!-- YES/NO Buttons -->
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<Skeleton class="h-12 w-full rounded-md" />
|
||||
<Skeleton class="h-12 w-full rounded-md" />
|
||||
</div>
|
||||
|
||||
<!-- Amount Input -->
|
||||
<Skeleton class="h-10 w-full rounded-md" />
|
||||
|
||||
<!-- Quick Amount Buttons -->
|
||||
<div class="flex gap-2">
|
||||
<Skeleton class="h-9 flex-1 rounded-md" />
|
||||
<Skeleton class="h-9 flex-1 rounded-md" />
|
||||
<Skeleton class="h-9 flex-1 rounded-md" />
|
||||
<Skeleton class="h-9 flex-1 rounded-md" />
|
||||
</div>
|
||||
|
||||
<!-- Win Estimation -->
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between">
|
||||
<Skeleton class="h-4 w-16" />
|
||||
<Skeleton class="h-4 w-12" />
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<Skeleton class="h-4 w-16" />
|
||||
<Skeleton class="h-4 w-12" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pay Button -->
|
||||
<Skeleton class="h-12 w-full rounded-md" />
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Position and Stats Cards below chart -->
|
||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
||||
<!-- Position Card -->
|
||||
<Card.Root class="gap-1">
|
||||
<Card.Header>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-muted rounded-full p-2">
|
||||
<Skeleton class="h-5 w-5" />
|
||||
</div>
|
||||
<Skeleton class="h-6 w-32" />
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Content class="pb-4">
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<Skeleton class="mb-1 h-4 w-16" />
|
||||
<Skeleton class="h-3 w-20" />
|
||||
</div>
|
||||
<Skeleton class="h-6 w-16" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<Skeleton class="mb-1 h-4 w-14" />
|
||||
<Skeleton class="h-3 w-20" />
|
||||
</div>
|
||||
<Skeleton class="h-6 w-16" />
|
||||
</div>
|
||||
<Separator />
|
||||
<div class="flex items-center justify-between">
|
||||
<Skeleton class="h-4 w-24" />
|
||||
<Skeleton class="h-6 w-16" />
|
||||
</div>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
<!-- Market Stats Card -->
|
||||
<Card.Root class="gap-1">
|
||||
<Card.Header>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-muted rounded-full p-2">
|
||||
<Skeleton class="h-5 w-5" />
|
||||
</div>
|
||||
<Skeleton class="h-6 w-28" />
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between">
|
||||
<Skeleton class="h-4 w-20" />
|
||||
<Skeleton class="h-4 w-16" />
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<Skeleton class="h-4 w-16" />
|
||||
<Skeleton class="h-4 w-8" />
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<Skeleton class="h-4 w-14" />
|
||||
<Skeleton class="h-4 w-20" />
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<Skeleton class="h-4 w-16" />
|
||||
<Skeleton class="h-4 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activity Section -->
|
||||
<Card.Root class="shadow-sm">
|
||||
<Card.Header>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-muted rounded-full p-2">
|
||||
<Skeleton class="h-6 w-6" />
|
||||
</div>
|
||||
<Skeleton class="h-6 w-32" />
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Content class="pb-6">
|
||||
<div class="space-y-4">
|
||||
{#each Array(3) as _}
|
||||
<div class="flex items-center justify-between rounded-xl border p-4">
|
||||
<div class="flex items-center gap-4">
|
||||
<Skeleton class="h-10 w-10 rounded-full" />
|
||||
<div>
|
||||
<Skeleton class="mb-1 h-4 w-24" />
|
||||
<Skeleton class="h-3 w-16" />
|
||||
</div>
|
||||
<Skeleton class="h-5 w-8 rounded-full" />
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<Skeleton class="mb-1 h-5 w-12" />
|
||||
<Skeleton class="h-3 w-16" />
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<script lang="ts">
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||
</script>
|
||||
|
||||
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{#each Array(6) as _}
|
||||
<Card.Root class="flex flex-col">
|
||||
<Card.Header class="pb-4">
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="flex-1 space-y-3">
|
||||
<!-- Question title skeleton -->
|
||||
<Skeleton class="h-6 w-full" />
|
||||
<Skeleton class="h-6 w-3/4" />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-end gap-2">
|
||||
<!-- Probability meter skeleton -->
|
||||
<div class="relative flex h-12 w-16 items-end justify-center">
|
||||
<Skeleton class="h-10 w-16 rounded-full" />
|
||||
<div class="absolute bottom-0">
|
||||
<Skeleton class="h-4 w-8" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Time and amount info skeleton -->
|
||||
<div class="flex items-center gap-2">
|
||||
<Skeleton class="h-4 w-24" />
|
||||
<Skeleton class="h-1 w-1 rounded-full" />
|
||||
<Skeleton class="h-4 w-16" />
|
||||
</div>
|
||||
|
||||
<!-- Creator info skeleton -->
|
||||
<div class="mb-2 mt-2 flex items-center gap-2">
|
||||
<Skeleton class="h-5 w-5 rounded-full" />
|
||||
<Skeleton class="h-4 w-20" />
|
||||
</div>
|
||||
</Card.Header>
|
||||
</Card.Root>
|
||||
{/each}
|
||||
</div>
|
||||
16
website/src/lib/components/ui/tabs/index.ts
Normal file
16
website/src/lib/components/ui/tabs/index.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import Root from "./tabs.svelte";
|
||||
import Content from "./tabs-content.svelte";
|
||||
import List from "./tabs-list.svelte";
|
||||
import Trigger from "./tabs-trigger.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
Content,
|
||||
List,
|
||||
Trigger,
|
||||
//
|
||||
Root as Tabs,
|
||||
Content as TabsContent,
|
||||
List as TabsList,
|
||||
Trigger as TabsTrigger,
|
||||
};
|
||||
17
website/src/lib/components/ui/tabs/tabs-content.svelte
Normal file
17
website/src/lib/components/ui/tabs/tabs-content.svelte
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<script lang="ts">
|
||||
import { Tabs as TabsPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: TabsPrimitive.ContentProps = $props();
|
||||
</script>
|
||||
|
||||
<TabsPrimitive.Content
|
||||
bind:ref
|
||||
data-slot="tabs-content"
|
||||
class={cn("flex-1 outline-none", className)}
|
||||
{...restProps}
|
||||
/>
|
||||
20
website/src/lib/components/ui/tabs/tabs-list.svelte
Normal file
20
website/src/lib/components/ui/tabs/tabs-list.svelte
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<script lang="ts">
|
||||
import { Tabs as TabsPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: TabsPrimitive.ListProps = $props();
|
||||
</script>
|
||||
|
||||
<TabsPrimitive.List
|
||||
bind:ref
|
||||
data-slot="tabs-list"
|
||||
class={cn(
|
||||
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
/>
|
||||
20
website/src/lib/components/ui/tabs/tabs-trigger.svelte
Normal file
20
website/src/lib/components/ui/tabs/tabs-trigger.svelte
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<script lang="ts">
|
||||
import { Tabs as TabsPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: TabsPrimitive.TriggerProps = $props();
|
||||
</script>
|
||||
|
||||
<TabsPrimitive.Trigger
|
||||
bind:ref
|
||||
data-slot="tabs-trigger"
|
||||
class={cn(
|
||||
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-2 py-1 text-sm font-medium transition-[color,box-shadow] focus-visible:outline-1 focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
/>
|
||||
19
website/src/lib/components/ui/tabs/tabs.svelte
Normal file
19
website/src/lib/components/ui/tabs/tabs.svelte
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<script lang="ts">
|
||||
import { Tabs as TabsPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
value = $bindable(""),
|
||||
class: className,
|
||||
...restProps
|
||||
}: TabsPrimitive.RootProps = $props();
|
||||
</script>
|
||||
|
||||
<TabsPrimitive.Root
|
||||
bind:ref
|
||||
bind:value
|
||||
data-slot="tabs"
|
||||
class={cn("flex flex-col gap-2", className)}
|
||||
{...restProps}
|
||||
/>
|
||||
Reference in a new issue