Files
TurboTrades/frontend/src/views/HomePage.vue
2026-01-10 04:57:43 +00:00

420 lines
13 KiB
Vue

<script setup>
import { ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import { useMarketStore } from "@/stores/market";
import { useAuthStore } from "@/stores/auth";
import {
TrendingUp,
Shield,
Zap,
Users,
ArrowRight,
Sparkles,
ChevronRight,
} from "lucide-vue-next";
const router = useRouter();
const marketStore = useMarketStore();
const authStore = useAuthStore();
const featuredItems = ref([]);
const recentSales = ref([]);
const isLoading = ref(true);
const stats = ref({
totalUsers: "50,000+",
totalTrades: "1M+",
avgTradeTime: "< 2 min",
activeListings: "25,000+",
});
const features = [
{
icon: Zap,
title: "Instant Trading",
description: "Lightning-fast transactions with automated trade bot system",
},
{
icon: Shield,
title: "Secure & Safe",
description: "Bank-grade security with SSL encryption and fraud protection",
},
{
icon: TrendingUp,
title: "Best Prices",
description: "Competitive marketplace pricing with real-time market data",
},
{
icon: Users,
title: "Active Community",
description: "Join thousands of traders in our vibrant marketplace",
},
];
onMounted(async () => {
isLoading.value = true;
await Promise.all([
marketStore.fetchFeaturedItems(),
marketStore.fetchRecentSales(6),
]);
featuredItems.value = marketStore.featuredItems.slice(0, 8);
recentSales.value = marketStore.recentSales;
isLoading.value = false;
});
const navigateToMarket = () => {
router.push("/market");
};
const navigateToSell = () => {
if (authStore.isAuthenticated) {
router.push("/sell");
} else {
authStore.login();
}
};
const formatPrice = (price) => {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(price);
};
const formatTimeAgo = (timestamp) => {
const seconds = Math.floor((Date.now() - new Date(timestamp)) / 1000);
if (seconds < 60) return "Just now";
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
return `${Math.floor(seconds / 86400)}d ago`;
};
const getRarityColor = (rarity) => {
const colors = {
common: "text-gray-400",
uncommon: "text-green-400",
rare: "text-blue-400",
mythical: "text-purple-400",
legendary: "text-amber-400",
ancient: "text-red-400",
exceedingly: "text-orange-400",
};
return colors[rarity] || "text-gray-400";
};
</script>
<template>
<div class="home-page">
<!-- Hero Section -->
<section class="relative py-20 lg:py-32 overflow-hidden">
<!-- Background Effects -->
<div class="absolute inset-0 opacity-30">
<div
class="absolute top-1/4 left-1/4 w-96 h-96 bg-primary-500/20 rounded-full blur-3xl"
></div>
<div
class="absolute bottom-1/4 right-1/4 w-96 h-96 bg-accent-blue/20 rounded-full blur-3xl"
></div>
</div>
<div class="container-custom relative z-10">
<div class="max-w-4xl mx-auto text-center">
<!-- Badge -->
<div
class="inline-flex items-center gap-2 px-4 py-2 bg-surface-light/50 backdrop-blur-sm border border-primary-500/30 rounded-full mb-6 animate-fade-in"
>
<Sparkles class="w-4 h-4 text-primary-500" />
<span class="text-sm font-medium text-gray-300"
>Premium CS2 & Rust Marketplace</span
>
</div>
<!-- Heading -->
<h1
class="text-4xl sm:text-5xl lg:text-7xl font-display font-bold mb-6 animate-slide-up"
>
<span class="text-white">Trade Your Skins</span>
<br />
<span class="gradient-text">Lightning Fast</span>
</h1>
<!-- Description -->
<p
class="text-lg sm:text-xl text-gray-400 mb-10 max-w-2xl mx-auto animate-slide-up"
style="animation-delay: 0.1s"
>
Buy, sell, and trade CS2 and Rust skins with instant delivery. Join
thousands of traders in the most trusted marketplace.
</p>
<!-- CTA Buttons -->
<div
class="flex flex-col sm:flex-row items-center justify-center gap-4 animate-slide-up"
style="animation-delay: 0.2s"
>
<button
@click="navigateToMarket"
class="btn btn-primary btn-lg group"
>
Browse Market
<ArrowRight
class="w-5 h-5 group-hover:translate-x-1 transition-transform"
/>
</button>
<button @click="navigateToSell" class="btn btn-outline btn-lg">
Start Selling
</button>
</div>
<!-- Stats -->
<div
class="grid grid-cols-2 md:grid-cols-4 gap-6 mt-16 animate-slide-up"
style="animation-delay: 0.3s"
>
<div
v-for="(value, key) in stats"
:key="key"
class="p-6 bg-surface/50 backdrop-blur-sm rounded-xl border border-surface-lighter"
>
<div class="text-2xl sm:text-3xl font-bold text-primary-500 mb-1">
{{ value }}
</div>
<div class="text-sm text-gray-400 capitalize">
{{ key.replace(/([A-Z])/g, " $1").trim() }}
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Features Section -->
<section class="py-16 lg:py-24 bg-surface/30">
<div class="container-custom">
<div class="text-center mb-12">
<h2
class="text-3xl sm:text-4xl font-display font-bold text-white mb-4"
>
Why Choose TurboTrades?
</h2>
<p class="text-lg text-gray-400 max-w-2xl mx-auto">
Experience the best trading platform with industry-leading features
and security
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div
v-for="feature in features"
:key="feature.title"
class="p-6 bg-surface rounded-xl border border-surface-lighter hover:border-primary-500/50 transition-all group"
>
<div
class="w-12 h-12 bg-primary-500/10 rounded-lg flex items-center justify-center mb-4 group-hover:bg-primary-500/20 transition-colors"
>
<component :is="feature.icon" class="w-6 h-6 text-primary-500" />
</div>
<h3 class="text-xl font-semibold text-white mb-2">
{{ feature.title }}
</h3>
<p class="text-gray-400 text-sm">{{ feature.description }}</p>
</div>
</div>
</div>
</section>
<!-- Featured Items Section -->
<section class="py-16 lg:py-24">
<div class="container-custom">
<div class="flex items-center justify-between mb-8">
<div>
<h2
class="text-3xl sm:text-4xl font-display font-bold text-white mb-2"
>
Featured Items
</h2>
<p class="text-gray-400">Hand-picked premium skins</p>
</div>
<button @click="navigateToMarket" class="btn btn-ghost group">
View All
<ChevronRight
class="w-4 h-4 group-hover:translate-x-1 transition-transform"
/>
</button>
</div>
<!-- Loading State -->
<div
v-if="isLoading"
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6"
>
<div v-for="i in 8" :key="i" class="card">
<div class="aspect-square skeleton"></div>
<div class="card-body space-y-3">
<div class="h-4 skeleton w-3/4"></div>
<div class="h-3 skeleton w-1/2"></div>
</div>
</div>
</div>
<!-- Items Grid -->
<div
v-else
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6"
>
<div
v-for="item in featuredItems"
:key="item.id"
@click="router.push(`/item/${item.id}`)"
class="item-card group"
>
<!-- Image -->
<div class="relative">
<img :src="item.image" :alt="item.name" class="item-card-image" />
<div v-if="item.wear" class="item-card-wear">
{{ item.wear }}
</div>
<div
v-if="item.statTrak"
class="absolute top-2 right-2 badge badge-warning"
>
StatTrak
</div>
</div>
<!-- Content -->
<div class="p-4 space-y-3">
<div>
<h3 class="font-semibold text-white text-sm line-clamp-2 mb-1">
{{ item.name }}
</h3>
<p
:class="['text-xs font-medium', getRarityColor(item.rarity)]"
>
{{ item.rarity }}
</p>
</div>
<div class="flex items-center justify-between">
<span class="text-lg font-bold text-primary-500">
{{ formatPrice(item.price) }}
</span>
<button class="btn btn-sm btn-primary">Buy Now</button>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Recent Sales Section -->
<section class="py-16 lg:py-24 bg-surface/30">
<div class="container-custom">
<div class="text-center mb-12">
<h2
class="text-3xl sm:text-4xl font-display font-bold text-white mb-4"
>
Recent Sales
</h2>
<p class="text-lg text-gray-400">Live marketplace activity</p>
</div>
<div class="max-w-4xl mx-auto space-y-3">
<div
v-for="sale in recentSales"
:key="sale.id"
class="flex items-center gap-4 p-4 bg-surface rounded-lg border border-surface-lighter hover:border-primary-500/30 transition-colors"
>
<img
:src="sale.itemImage"
:alt="sale.itemName"
class="w-16 h-16 object-contain bg-surface-light rounded-lg"
/>
<div class="flex-1 min-w-0">
<h4 class="font-medium text-white text-sm truncate">
{{ sale.itemName }}
</h4>
<p class="text-xs text-gray-400">{{ sale.wear }}</p>
</div>
<div class="text-right">
<div class="font-bold text-accent-green">
{{ formatPrice(sale.price) }}
</div>
<div class="text-xs text-gray-500">
{{ formatTimeAgo(sale.soldAt) }}
</div>
</div>
</div>
</div>
</div>
</section>
<!-- CTA Section -->
<section class="py-16 lg:py-24">
<div class="container-custom">
<div
class="relative overflow-hidden rounded-2xl bg-gradient-to-r from-primary-600 to-primary-800 p-12 text-center"
>
<!-- Background Pattern -->
<div class="absolute inset-0 opacity-10">
<div
class="absolute top-0 left-1/4 w-72 h-72 bg-white rounded-full blur-3xl"
></div>
<div
class="absolute bottom-0 right-1/4 w-72 h-72 bg-white rounded-full blur-3xl"
></div>
</div>
<div class="relative z-10 max-w-3xl mx-auto">
<h2
class="text-3xl sm:text-5xl font-display font-bold text-white mb-6"
>
Ready to Start Trading?
</h2>
<p class="text-lg text-primary-100 mb-8">
Join TurboTrades today and experience the fastest, most secure way
to trade gaming skins
</p>
<div
class="flex flex-col sm:flex-row items-center justify-center gap-4"
>
<button
v-if="!authStore.isAuthenticated"
@click="authStore.login"
class="btn btn-lg bg-white text-primary-600 hover:bg-gray-100"
>
<img
src="https://community.cloudflare.steamstatic.com/public/images/signinthroughsteam/sits_01.png"
alt="Sign in through Steam"
class="h-6"
/>
</button>
<button
v-else
@click="navigateToMarket"
class="btn btn-lg bg-white text-primary-600 hover:bg-gray-100"
>
Browse Market
<ArrowRight class="w-5 h-5" />
</button>
</div>
</div>
</div>
</div>
</section>
</div>
</template>
<style scoped>
.home-page {
min-height: 100vh;
}
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>