first commit

This commit is contained in:
2026-01-10 04:57:43 +00:00
parent 16a76a2cd6
commit 232968de1e
131 changed files with 43262 additions and 0 deletions

View File

@@ -0,0 +1,143 @@
<script setup>
import { Github, Twitter, Mail, MessageCircle } from 'lucide-vue-next'
const currentYear = new Date().getFullYear()
const footerLinks = {
marketplace: [
{ name: 'Browse Market', path: '/market' },
{ name: 'Sell Items', path: '/sell' },
{ name: 'Recent Sales', path: '/market?tab=recent' },
{ name: 'Featured Items', path: '/market?tab=featured' },
],
support: [
{ name: 'FAQ', path: '/faq' },
{ name: 'Support Center', path: '/support' },
{ name: 'Contact Us', path: '/support' },
{ name: 'Report Issue', path: '/support' },
],
legal: [
{ name: 'Terms of Service', path: '/terms' },
{ name: 'Privacy Policy', path: '/privacy' },
{ name: 'Refund Policy', path: '/terms#refunds' },
{ name: 'Cookie Policy', path: '/privacy#cookies' },
],
}
const socialLinks = [
{ name: 'Discord', icon: MessageCircle, url: '#' },
{ name: 'Twitter', icon: Twitter, url: '#' },
{ name: 'GitHub', icon: Github, url: '#' },
{ name: 'Email', icon: Mail, url: 'mailto:support@turbotrades.com' },
]
</script>
<template>
<footer class="bg-surface-dark border-t border-surface-lighter mt-auto">
<div class="container-custom py-12">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-8">
<!-- Brand Column -->
<div class="lg:col-span-2">
<div class="flex items-center gap-2 mb-4">
<div class="w-10 h-10 bg-gradient-to-br from-primary-500 to-primary-700 rounded-lg flex items-center justify-center">
<span class="text-white font-bold">TT</span>
</div>
<span class="text-xl font-display font-bold text-white">TurboTrades</span>
</div>
<p class="text-gray-400 text-sm mb-6 max-w-md">
The premier marketplace for CS2 and Rust skins. Buy, sell, and trade with confidence. Fast transactions, secure trading, and competitive prices.
</p>
<!-- Social Links -->
<div class="flex items-center gap-3">
<a
v-for="social in socialLinks"
:key="social.name"
:href="social.url"
:aria-label="social.name"
class="w-10 h-10 flex items-center justify-center rounded-lg bg-surface-light hover:bg-surface-lighter border border-surface-lighter hover:border-primary-500/50 text-gray-400 hover:text-primary-500 transition-all"
target="_blank"
rel="noopener noreferrer"
>
<component :is="social.icon" class="w-5 h-5" />
</a>
</div>
</div>
<!-- Marketplace Links -->
<div>
<h3 class="text-white font-semibold mb-4">Marketplace</h3>
<ul class="space-y-2">
<li v-for="link in footerLinks.marketplace" :key="link.path">
<router-link
:to="link.path"
class="text-gray-400 hover:text-primary-500 text-sm transition-colors"
>
{{ link.name }}
</router-link>
</li>
</ul>
</div>
<!-- Support Links -->
<div>
<h3 class="text-white font-semibold mb-4">Support</h3>
<ul class="space-y-2">
<li v-for="link in footerLinks.support" :key="link.path">
<router-link
:to="link.path"
class="text-gray-400 hover:text-primary-500 text-sm transition-colors"
>
{{ link.name }}
</router-link>
</li>
</ul>
</div>
<!-- Legal Links -->
<div>
<h3 class="text-white font-semibold mb-4">Legal</h3>
<ul class="space-y-2">
<li v-for="link in footerLinks.legal" :key="link.path">
<router-link
:to="link.path"
class="text-gray-400 hover:text-primary-500 text-sm transition-colors"
>
{{ link.name }}
</router-link>
</li>
</ul>
</div>
</div>
<!-- Bottom Bar -->
<div class="mt-12 pt-8 border-t border-surface-lighter">
<div class="flex flex-col md:flex-row items-center justify-between gap-4">
<p class="text-gray-500 text-sm">
© {{ currentYear }} TurboTrades. All rights reserved.
</p>
<div class="flex items-center gap-6">
<span class="text-gray-500 text-sm">
Made with for the gaming community
</span>
</div>
</div>
<!-- Disclaimer -->
<div class="mt-4 text-center md:text-left">
<p class="text-gray-600 text-xs">
TurboTrades is not affiliated with Valve Corporation or Facepunch Studios.
CS2, Counter-Strike, and Rust are trademarks of their respective owners.
</p>
</div>
</div>
</div>
</footer>
</template>
<style scoped>
footer {
background: linear-gradient(180deg, rgba(15, 25, 35, 0.8) 0%, rgba(10, 15, 20, 0.95) 100%);
}
</style>

View File

@@ -0,0 +1,323 @@
<script setup>
import { ref, computed, onMounted, onUnmounted } from "vue";
import { useRouter } from "vue-router";
import { useAuthStore } from "@/stores/auth";
import {
Menu,
User,
LogOut,
Settings,
Package,
CreditCard,
History,
ShoppingCart,
Wallet,
TrendingUp,
Shield,
X,
ChevronDown,
Plus,
} from "lucide-vue-next";
const router = useRouter();
const authStore = useAuthStore();
const showMobileMenu = ref(false);
const showUserMenu = ref(false);
const showBalanceMenu = ref(false);
const userMenuRef = ref(null);
const balanceMenuRef = ref(null);
const navigationLinks = [
{ name: "Market", path: "/market", icon: ShoppingCart },
{ name: "Sell", path: "/sell", icon: TrendingUp, requiresAuth: true },
{ name: "FAQ", path: "/faq", icon: null },
];
const userMenuLinks = computed(() => [
{ name: "Profile", path: "/profile", icon: User },
{ name: "Inventory", path: "/inventory", icon: Package },
{ name: "Transactions", path: "/transactions", icon: History },
{ name: "Withdraw", path: "/withdraw", icon: CreditCard },
...(authStore.isAdmin
? [{ name: "Admin", path: "/admin", icon: Shield }]
: []),
]);
const formattedBalance = computed(() => {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(authStore.balance);
});
const handleLogin = () => {
authStore.login();
};
const handleLogout = async () => {
showUserMenu.value = false;
await authStore.logout();
};
const handleDeposit = () => {
showBalanceMenu.value = false;
router.push("/deposit");
};
const toggleMobileMenu = () => {
showMobileMenu.value = !showMobileMenu.value;
};
const toggleUserMenu = () => {
showUserMenu.value = !showUserMenu.value;
};
const toggleBalanceMenu = () => {
showBalanceMenu.value = !showBalanceMenu.value;
};
const closeMenus = () => {
showMobileMenu.value = false;
showUserMenu.value = false;
showBalanceMenu.value = false;
};
const handleClickOutside = (event) => {
if (userMenuRef.value && !userMenuRef.value.contains(event.target)) {
showUserMenu.value = false;
}
if (balanceMenuRef.value && !balanceMenuRef.value.contains(event.target)) {
showBalanceMenu.value = false;
}
};
onMounted(() => {
document.addEventListener("click", handleClickOutside);
});
onUnmounted(() => {
document.removeEventListener("click", handleClickOutside);
});
</script>
<template>
<nav
class="sticky top-0 z-40 bg-surface/95 backdrop-blur-md border-b border-surface-lighter"
>
<div class="w-full px-6">
<div class="flex items-center justify-between h-16">
<!-- Logo -->
<router-link
to="/"
class="flex items-center gap-2 text-xl font-display font-bold text-white hover:text-primary-500 transition-colors"
@click="closeMenus"
>
<div
class="w-8 h-8 bg-gradient-to-br from-primary-500 to-primary-700 rounded-lg flex items-center justify-center"
>
<span class="text-white text-sm font-bold">TT</span>
</div>
<span class="hidden sm:inline">TurboTrades</span>
</router-link>
<!-- Desktop Navigation - Centered -->
<div
class="hidden lg:flex items-center gap-8 absolute left-1/2 transform -translate-x-1/2"
>
<template v-for="link in navigationLinks" :key="link.path">
<router-link
v-if="!link.requiresAuth || authStore.isAuthenticated"
:to="link.path"
class="nav-link flex items-center gap-2"
active-class="nav-link-active"
>
<component :is="link.icon" v-if="link.icon" class="w-4 h-4" />
{{ link.name }}
</router-link>
</template>
</div>
<!-- Right Side Actions -->
<div class="flex items-center gap-3">
<!-- Balance with Inline Deposit Button (when authenticated) -->
<div
v-if="authStore.isAuthenticated"
class="hidden sm:flex items-center bg-surface-light rounded-lg border border-surface-lighter overflow-hidden h-10"
>
<!-- Balance Display -->
<div class="flex items-center gap-2 px-4 py-2">
<Wallet class="w-5 h-5 text-primary-500" />
<span class="text-base font-semibold text-white">{{
formattedBalance
}}</span>
</div>
<!-- Deposit Button -->
<button
@click="handleDeposit"
class="h-full px-4 bg-primary-500 hover:bg-primary-600 transition-colors flex items-center justify-center"
title="Deposit"
>
<Plus class="w-5 h-5 text-white" />
</button>
</div>
<!-- User Menu / Login Button -->
<div
v-if="authStore.isAuthenticated"
class="relative"
ref="userMenuRef"
>
<button
@click.stop="toggleUserMenu"
class="flex items-center gap-2 px-3 py-2 bg-surface-light hover:bg-surface-lighter rounded-lg border border-surface-lighter transition-colors"
>
<img
v-if="authStore.avatar"
:src="authStore.avatar"
:alt="authStore.username"
class="w-8 h-8 rounded-full"
/>
<div
v-else
class="w-8 h-8 rounded-full bg-primary-500 flex items-center justify-center"
>
<User class="w-4 h-4 text-white" />
</div>
<span class="hidden lg:inline text-sm font-medium text-white">
{{ authStore.username }}
</span>
<ChevronDown class="w-4 h-4 text-gray-400" />
</button>
<!-- User Dropdown Menu -->
<Transition name="fade">
<div
v-if="showUserMenu"
class="absolute right-0 mt-2 w-56 bg-surface-light border border-surface-lighter rounded-lg shadow-xl overflow-hidden"
>
<!-- Balance (Mobile) -->
<div
class="sm:hidden px-4 py-3 bg-surface-dark border-b border-surface-lighter"
>
<div class="flex items-center justify-between mb-2">
<span class="text-sm text-gray-400">Balance</span>
<span class="text-sm font-semibold text-primary-500">{{
formattedBalance
}}</span>
</div>
<button
@click="handleDeposit"
class="w-full px-3 py-1.5 bg-primary-500 hover:bg-primary-600 text-surface-dark text-sm font-medium rounded transition-colors flex items-center justify-center gap-1.5"
>
<Plus class="w-3.5 h-3.5" />
Deposit
</button>
</div>
<!-- Menu Items -->
<div class="py-2">
<router-link
v-for="link in userMenuLinks"
:key="link.path"
:to="link.path"
:class="[
'flex items-center gap-3 px-4 py-2.5 text-sm transition-colors',
link.name === 'Admin'
? 'bg-gradient-to-r from-yellow-900/40 to-yellow-800/40 text-yellow-400 hover:from-yellow-900/60 hover:to-yellow-800/60 hover:text-yellow-300 border-l-2 border-yellow-500'
: 'text-gray-300 hover:text-white hover:bg-surface',
]"
@click="closeMenus"
>
<component :is="link.icon" class="w-4 h-4" />
{{ link.name }}
</router-link>
</div>
<!-- Logout -->
<div class="border-t border-surface-lighter">
<button
@click="handleLogout"
class="w-full flex items-center gap-3 px-4 py-2.5 text-sm text-accent-red hover:bg-surface transition-colors"
>
<LogOut class="w-4 h-4" />
Logout
</button>
</div>
</div>
</Transition>
</div>
<!-- Login Button -->
<button v-else @click="handleLogin" class="btn btn-primary">
<img
src="https://community.cloudflare.steamstatic.com/public/images/signinthroughsteam/sits_01.png"
alt="Sign in through Steam"
class="h-6"
/>
</button>
<!-- Mobile Menu Toggle -->
<button
@click="toggleMobileMenu"
class="lg:hidden p-2 text-gray-400 hover:text-white transition-colors"
>
<Menu v-if="!showMobileMenu" class="w-6 h-6" />
<X v-else class="w-6 h-6" />
</button>
</div>
</div>
</div>
<!-- Mobile Menu -->
<Transition name="slide-down">
<div
v-if="showMobileMenu"
class="lg:hidden border-t border-surface-lighter bg-surface"
>
<div class="container-custom py-4 space-y-2">
<template v-for="link in navigationLinks" :key="link.path">
<router-link
v-if="!link.requiresAuth || authStore.isAuthenticated"
:to="link.path"
class="flex items-center gap-3 px-4 py-3 text-gray-300 hover:text-white hover:bg-surface-light rounded-lg transition-colors"
active-class="text-primary-500 bg-surface-light"
@click="closeMenus"
>
<component :is="link.icon" v-if="link.icon" class="w-5 h-5" />
{{ link.name }}
</router-link>
</template>
</div>
</div>
</Transition>
</nav>
</template>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.slide-down-enter-active,
.slide-down-leave-active {
transition: all 0.3s ease;
}
.slide-down-enter-from {
opacity: 0;
transform: translateY(-10px);
}
.slide-down-leave-to {
opacity: 0;
transform: translateY(-10px);
}
</style>