style: earthy merged dashboard design

This commit is contained in:
2026-04-23 09:54:33 -04:00
parent 5315dca6d7
commit daf21f67ad
+154 -136
View File
@@ -1,24 +1,20 @@
"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import {
BadgeDollarSign,
Clock3,
Loader2,
PartyPopper,
RefreshCw,
ShieldCheck,
PlusCircle,
History,
LayoutDashboard,
Trophy,
} from "lucide-react";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { api, authApi, overseerApi, userApi } from "@/lib/api";
import { useStore } from "@/lib/store";
@@ -35,35 +31,6 @@ interface WalletData {
totalSpent: number;
}
function StatTile({
label,
value,
hint,
icon: Icon,
}: {
label: string;
value: string;
hint: string;
icon: any;
}) {
return (
<div className="rounded-2xl border border-primary/10 bg-card/80 p-4 shadow-[0_12px_30px_-20px_rgba(0,0,0,0.45)] backdrop-blur-sm">
<div className="flex items-center justify-between gap-3">
<div>
<div className="text-xs uppercase tracking-[0.25em] text-muted-foreground">
{label}
</div>
<div className="mt-2 text-3xl font-bold text-foreground">{value}</div>
<div className="mt-1 text-sm text-muted-foreground">{hint}</div>
</div>
<div className="flex h-11 w-11 items-center justify-center rounded-2xl bg-primary/10 text-primary">
<Icon className="h-5 w-5" />
</div>
</div>
</div>
);
}
export default function DashboardPage() {
const router = useRouter();
const { isAuthenticated, logout } = useStore();
@@ -123,119 +90,170 @@ export default function DashboardPage() {
if (isLoading)
return (
<div className="flex min-h-screen items-center justify-center">
<Loader2 className="h-8 w-8 animate-spin text-primary" />
<div className="flex min-h-screen items-center justify-center bg-background">
<Loader2 className="h-10 w-10 animate-spin text-primary" />
</div>
);
return (
<div className="relative min-h-screen overflow-hidden px-4 py-6 sm:px-6 lg:px-8">
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top_left,_rgba(185,28,28,0.12),_transparent_30%),radial-gradient(circle_at_top_right,_rgba(217,119,6,0.10),_transparent_28%),radial-gradient(circle_at_bottom,_rgba(120,53,15,0.06),_transparent_40%)]" />
<div className="mx-auto max-w-7xl space-y-6">
<div className="flex items-center justify-between gap-3 rounded-2xl border border-primary/10 bg-card/70 px-5 py-4 shadow-sm backdrop-blur-sm">
<div className="relative min-h-screen bg-background p-4 sm:p-8">
<div className="pointer-events-none absolute inset-0 overflow-hidden">
<div className="absolute -top-[10%] -left-[5%] h-[40%] w-[30%] rounded-full bg-secondary/30 blur-[120px]" />
<div className="absolute -bottom-[10%] -right-[5%] h-[40%] w-[30%] rounded-full bg-primary/10 blur-[120px]" />
</div>
<div className="relative mx-auto max-w-7xl space-y-8">
<div className="flex flex-col gap-6 md:flex-row md:items-center md:justify-between">
<div>
<div className="text-xs uppercase tracking-[0.3em] text-muted-foreground">
Dashboard
<div className="flex items-center gap-2 text-xs font-bold uppercase tracking-[0.3em] text-primary/80">
<div className="h-1 w-4 bg-primary" />
Barnyard coop
</div>
<h1 className="font-display text-3xl">Barnyard coop</h1>
<h1 className="font-display text-4xl mt-1 text-foreground">
Nest Dashboard
</h1>
</div>
<div className="flex items-center gap-2">
<Button variant="secondary" onClick={handleRefresh}>
<RefreshCw className="mr-2 h-4 w-4" />
Refresh
<div className="flex items-center gap-3">
<Button
onClick={() => setIsSearchModalOpen(true)}
size="lg"
className="rounded-full px-8 shadow-lg shadow-primary/20 hover:scale-105 transition-transform"
>
<PlusCircle className="mr-2 h-5 w-5" />
Request feed
</Button>
<Button variant="outline" onClick={handleLogout}>
<Button
variant="outline"
size="icon"
onClick={handleRefresh}
className="rounded-full border-primary/20 bg-card/50 text-primary hover:bg-primary/10"
>
<RefreshCw className="h-5 w-5" />
</Button>
<Button
variant="ghost"
onClick={handleLogout}
className="text-muted-foreground hover:text-destructive"
>
Logout
</Button>
</div>
</div>
<div className="grid gap-4 md:grid-cols-3">
<StatTile
label="Nest Egg"
value={`${formatNumber(wallet?.balance || 0)} $COOP`}
hint="Ready to spend"
icon={ShieldCheck}
/>
<StatTile
label="Pending requests"
value={String(pendingRequests.length)}
hint="Waiting in coop"
icon={Clock3}
/>
<StatTile
label="Request costs"
value={`${requestCosts.movie}/${requestCosts.tv}`}
hint="Movie / TV"
icon={BadgeDollarSign}
/>
</div>
<div className="grid gap-6 lg:grid-cols-[1.35fr_0.65fr]">
<Card className="border-primary/10 bg-card/80 shadow-[0_18px_50px_-30px_rgba(0,0,0,0.45)] backdrop-blur-sm">
<CardHeader className="pb-3">
<CardTitle className="font-display text-2xl">
Harvest board
</CardTitle>
<CardDescription>
Watch, requests, leaderboard. All feed, no smoke.
</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="history" className="w-full">
<TabsList className="grid w-full grid-cols-3 bg-secondary/60">
<TabsTrigger value="history">History</TabsTrigger>
<TabsTrigger value="requests">Requests</TabsTrigger>
<TabsTrigger value="leaderboard">Leaderboard</TabsTrigger>
</TabsList>
<TabsContent value="history" className="mt-6">
<WatchHistory />
</TabsContent>
<TabsContent value="requests" className="mt-6">
<RequestHistory onRefresh={handleRefresh} />
</TabsContent>
<TabsContent value="leaderboard" className="mt-6">
<Leaderboard />
</TabsContent>
</Tabs>
</CardContent>
</Card>
<div className="grid gap-6 lg:grid-cols-[1fr_380px]">
<div className="space-y-6">
<Card className="border-primary/10 bg-card/80 shadow-[0_18px_50px_-30px_rgba(0,0,0,0.45)] backdrop-blur-sm">
<CardHeader>
<CardTitle className="font-display text-xl">
Quick request
</CardTitle>
<CardDescription>Grab content fast.</CardDescription>
</CardHeader>
<CardContent>
<Button
className="w-full"
onClick={() => setIsSearchModalOpen(true)}
>
Request content
</Button>
<Button
variant="secondary"
className="mt-3 w-full"
onClick={handleRefresh}
>
<RefreshCw className="mr-2 h-4 w-4" />
Sync requests
</Button>
</CardContent>
</Card>
<Card className="border-primary/10 bg-card/80 shadow-[0_18px_50px_-30px_rgba(0,0,0,0.45)] backdrop-blur-sm">
<CardHeader>
<CardTitle className="font-display text-xl">
Recent activity
</CardTitle>
<CardDescription>Newest barn noise.</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3">
<div className="rounded-[2rem] bg-secondary/40 p-6 border border-secondary/20 shadow-sm transition-all hover:shadow-md">
<div className="flex items-center gap-3 text-secondary-foreground/60">
<ShieldCheck className="h-4 w-4" />
<span className="text-[10px] uppercase tracking-widest font-bold">
Nest Egg
</span>
</div>
<div className="mt-3 text-4xl font-bold text-foreground leading-none">
{formatNumber(wallet?.balance || 0)}
<span className="ml-2 text-sm text-muted-foreground">
$COOP
</span>
</div>
</div>
<div className="rounded-[2rem] bg-accent/20 p-6 border border-accent/20 shadow-sm transition-all hover:shadow-md">
<div className="flex items-center gap-3 text-accent-foreground/60">
<Clock3 className="h-4 w-4" />
<span className="text-[10px] uppercase tracking-widest font-bold">
In Transit
</span>
</div>
<div className="mt-3 text-4xl font-bold text-foreground leading-none">
{pendingRequests.length}
<span className="ml-2 text-sm text-muted-foreground text-opacity-70">
Pipes
</span>
</div>
</div>
<div className="hidden rounded-[2rem] bg-card p-6 border shadow-sm transition-all hover:shadow-md sm:block">
<div className="flex items-center gap-3 text-muted-foreground">
<BadgeDollarSign className="h-4 w-4" />
<span className="text-[10px] uppercase tracking-widest font-bold">
Costs
</span>
</div>
<div className="mt-3 text-2xl font-bold text-foreground leading-none">
{requestCosts.movie} / {requestCosts.tv}
<div className="mt-1 text-[10px] text-muted-foreground">
Movie / TV
</div>
</div>
</div>
</div>
<div className="rounded-[2.5rem] bg-card/60 p-2 border border-primary/5 shadow-inner backdrop-blur-md">
<Tabs defaultValue="history" className="w-full">
<TabsList className="grid w-full grid-cols-3 rounded-[2rem] bg-muted/50 p-1">
<TabsTrigger
value="history"
className="rounded-[1.5rem] py-3 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-lg"
>
<History className="mr-2 h-4 w-4" />
History
</TabsTrigger>
<TabsTrigger
value="requests"
className="rounded-[1.5rem] py-3 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-lg"
>
<LayoutDashboard className="mr-2 h-4 w-4" />
Requests
</TabsTrigger>
<TabsTrigger
value="leaderboard"
className="rounded-[1.5rem] py-3 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-lg"
>
<Trophy className="mr-2 h-4 w-4" />
Flock
</TabsTrigger>
</TabsList>
<div className="p-4 sm:p-6">
<TabsContent
value="history"
className="mt-0 focus-visible:outline-none"
>
<WatchHistory />
</TabsContent>
<TabsContent
value="requests"
className="mt-0 focus-visible:outline-none"
>
<RequestHistory onRefresh={handleRefresh} />
</TabsContent>
<TabsContent
value="leaderboard"
className="mt-0 focus-visible:outline-none"
>
<Leaderboard />
</TabsContent>
</div>
</Tabs>
</div>
</div>
<div className="space-y-6">
<div className="rounded-[2.5rem] bg-card/80 p-6 border border-primary/5 shadow-xl backdrop-blur-md">
<div className="mb-6 flex items-center justify-between">
<h3 className="font-display text-2xl text-foreground">
Barn Noise
</h3>
<div className="h-2 w-2 animate-pulse rounded-full bg-primary" />
</div>
<div className="max-h-[600px] overflow-y-auto pr-2 scrollbar-hide">
<ActivityFeed />
</CardContent>
</Card>
</div>
</div>
</div>
</div>
<SearchRequestModal
open={isSearchModalOpen}
onOpenChange={setIsSearchModalOpen}