MASSIVE UPDATE:
bounty board feature buyers to see bounty boards seller profile page (like have theme chooser) Have the game and set name be filters. Add cards to vault manually update card inventory add to have the autocomplete for the card - store analytics, clicks, views, link to store (url/QR code) bulk item inventory creation -- Make the banner feature flag driven so I can have a beta site setup like the primary site don't use primary key values in urls - update to use uuid4 values site analytics. tianji is being sent item potent on the mtg and lorcana populate scripts Card item images for specific listings check that when you buy a card it is in the vault Buys should be able to search on store inventories More pie charts for the seller! post bounty board is slow to load seller reviews/ratings - show a historgram - need a way for someone to rate Report a seller feature for buyer to report Make sure the stlying is consistent based on the theme choosen smart minimum order quantity and shipping amounts (defined by the store itself) put virtual packs behind a feature flag like bounty board proxy service feature flag Terms of Service new description for TCGKof store SSN, ITIN, and EIN optomize for SEO
This commit is contained in:
@@ -4,246 +4,98 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Phantom Card Fam - Premium TCG Store{% endblock %}</title>
|
||||
<title>{% block title %}TCGKof - Premium TCG Store{% endblock %}</title>
|
||||
<meta name="description" content="{% block meta_description %}TCGKof is the premier marketplace for trading card games. Buy and sell Magic: The Gathering, Lorcana, and more.{% endblock %}">
|
||||
<meta name="keywords" content="{% block meta_keywords %}TCG, Magic: The Gathering, Lorcana, cards, marketplace, buy cards, sell cards{% endblock %}">
|
||||
<link rel="canonical" href="{% block canonical_url %}{{ request.build_absolute_uri }}{% endblock %}">
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="{% block og_type %}website{% endblock %}">
|
||||
<meta property="og:url" content="{{ request.build_absolute_uri }}">
|
||||
<meta property="og:title" content="{% block og_title %}{{ self.title }}{% endblock %}">
|
||||
<meta property="og:description" content="{% block og_description %}TCGKof is the premier marketplace for trading card games. Buy and sell Magic: The Gathering, Lorcana, and more.{% endblock %}">
|
||||
<meta property="og:image" content="{% block og_image %}{{ request.scheme }}://{{ request.get_host }}{% static 'img/og-default.jpg' %}{% endblock %}">
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:url" content="{{ request.build_absolute_uri }}">
|
||||
<meta property="twitter:title" content="{% block twitter_title %}{{ self.title }}{% endblock %}">
|
||||
<meta property="twitter:description" content="{% block twitter_description %}TCGKof is the premier marketplace for trading card games. Buy and sell Magic: The Gathering, Lorcana, and more.{% endblock %}">
|
||||
<meta property="twitter:image" content="{% block twitter_image %}{{ request.scheme }}://{{ request.get_host }}{% static 'img/og-default.jpg' %}{% endblock %}">
|
||||
|
||||
<link rel="stylesheet" href="{% static 'css/style.css' %}">
|
||||
{% if not debug %}
|
||||
<script async defer src="https://tianji.aimloperations.com/tracker.js" data-website-id="cmklg5jenh4wx14nrurt5yqyl"></script>
|
||||
{% endif %}
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #6366f1;
|
||||
--secondary-color: #a855f7;
|
||||
--bg-color: #0f172a;
|
||||
--text-color: #f8fafc;
|
||||
--card-bg: #1e293b;
|
||||
--border-color: #334155;
|
||||
}
|
||||
|
||||
[data-theme="light"] {
|
||||
--primary-color: #4f46e5;
|
||||
--secondary-color: #9333ea;
|
||||
--bg-color: #f8fafc;
|
||||
--text-color: #0f172a;
|
||||
--card-bg: #ffffff;
|
||||
--border-color: #e2e8f0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
transition: background-color 0.3s, color 0.3s;
|
||||
}
|
||||
|
||||
nav {
|
||||
background-color: var(--card-bg);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding: 1rem 2rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-brand {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
color: var(--text-color);
|
||||
text-decoration: none;
|
||||
margin-left: 1.5rem;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 2rem auto;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 0.375rem;
|
||||
font-weight: 600;
|
||||
transition: opacity 0.2s;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.tcg-card {
|
||||
background-color: var(--card-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.tcg-card:hover {
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
.tcg-card img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tcg-card-body {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.messages {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.messages li {
|
||||
padding: 1rem;
|
||||
border-radius: 0.375rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.messages .success { background-color: #064e3b; color: #a7f3d0; }
|
||||
.messages .error { background-color: #7f1d1d; color: #fecaca; }
|
||||
[data-theme="light"] .messages .success { background-color: #d1fae5; color: #065f46; }
|
||||
[data-theme="light"] .messages .error { background-color: #fce7f3; color: #9d174d; }
|
||||
|
||||
/* Auth Modal Styles */
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.3s, visibility 0.3s;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.modal-overlay.active {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.auth-modal {
|
||||
background-color: var(--card-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.75rem;
|
||||
padding: 2rem;
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
transform: translateY(20px);
|
||||
transition: transform 0.3s;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.modal-overlay.active .auth-modal {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.auth-modal h2 {
|
||||
margin-top: 0;
|
||||
color: var(--primary-color);
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.auth-modal p {
|
||||
margin-bottom: 2rem;
|
||||
color: var(--text-color);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.auth-modal-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background-color: transparent;
|
||||
border: 1px solid var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background-color: rgba(99, 102, 241, 0.1);
|
||||
}
|
||||
|
||||
.close-modal {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-color);
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.close-modal:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{% if FEATURE_DEMO_SITE %}
|
||||
<div style="background: #f59e0b; color: #000; text-align: center; padding: 0.5rem; font-weight: 600; font-size: 0.875rem;">
|
||||
DEMO SITE: This is an example application. No real products, payments, or purchases are processed.
|
||||
</div>
|
||||
{% endif %}
|
||||
<nav>
|
||||
<a href="{% url 'home' %}" class="nav-brand">Phantom Card Fam</a>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="{% url 'home' %}" class="nav-brand">TCGKof</a>
|
||||
<button class="mobile-menu-btn" aria-label="Toggle Navigation">
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="nav-links">
|
||||
<a href="{% url 'store:card_list' %}">Browse</a>
|
||||
<a href="{% url 'store:pack_list' %}">Packs</a>
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'decks:deck_list' %}">Decks</a>
|
||||
<a href="{% url 'users:vault' %}">Vault</a>
|
||||
<a href="{% url 'store:my_packs' %}">My Packs</a>
|
||||
<a href="{% url 'store:cart' %}">Cart ({{ user.cart.items.count|default:0 }})</a>
|
||||
<a href="{% url 'users:profile' %}">Profile</a>
|
||||
<form action="{% url 'logout' %}" method="post" style="display:inline;">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn" style="background:none; color:var(--text-color); margin-left:1rem;">Logout</button>
|
||||
</form>
|
||||
{% if user.seller_profile %}
|
||||
{# Seller Navigation #}
|
||||
<a href="{% url 'store:seller_dashboard' %}">Dashboard</a>
|
||||
<a href="{% url 'store:manage_listings' %}">Store</a>
|
||||
<a href="{% url 'store:manage_listings' %}">Inventory</a>
|
||||
{% if debug %}
|
||||
<a href="{% url 'store:bounty_list' %}">Bounties</a>
|
||||
{% endif %}
|
||||
<form action="{% url 'logout' %}" method="post" style="display:inline;">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn" style="background:none; color:var(--text-color); margin-left:1rem;">Logout</button>
|
||||
</form>
|
||||
{% elif user.buyer_profile %}
|
||||
{# Buyer Navigation #}
|
||||
<a href="{% url 'store:card_list' %}">Browse</a>
|
||||
{% if FEATURE_VIRTUAL_PACKS %}
|
||||
<a href="{% url 'store:pack_list' %}">Packs</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'decks:deck_list' %}">Decks</a>
|
||||
<a href="{% url 'users:vault' %}">Vault</a>
|
||||
{% if FEATURE_VIRTUAL_PACKS %}
|
||||
<a href="{% url 'store:my_packs' %}">My Packs</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'store:cart' %}">Cart ({{ user.buyer_profile.cart.items.count|default:0 }})</a>
|
||||
<a href="{% url 'users:profile' %}">Profile</a>
|
||||
<a href="{% url 'store:bounty_list' %}">Bounties</a>
|
||||
<form action="{% url 'logout' %}" method="post" style="display:inline;">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn" style="background:none; color:var(--text-color); margin-left:1rem;">Logout</button>
|
||||
</form>
|
||||
{% else %}
|
||||
{# Fallback for incomplete profiles #}
|
||||
<form action="{% url 'logout' %}" method="post" style="display:inline;">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn" style="background:none; color:var(--text-color);">Logout (Invalid Account)</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% if user.is_staff %}
|
||||
<a href="{% url 'store:admin_revenue_dashboard' %}" style="color: #f59e0b;">Platform Admin</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{# Public Navigation #}
|
||||
<a href="{% url 'store:card_list' %}">Browse</a>
|
||||
{% if FEATURE_VIRTUAL_PACKS %}
|
||||
<a href="{% url 'store:pack_list' %}">Packs</a>
|
||||
{% endif %}
|
||||
{% if debug %}
|
||||
<a href="{% url 'store:bounty_list' %}">Bounties</a>
|
||||
{% endif %}
|
||||
|
||||
<a href="{% url 'decks:deck_list' %}"
|
||||
class="auth-required"
|
||||
data-feature-title="Deck Builder"
|
||||
@@ -254,13 +106,16 @@
|
||||
data-feature-title="Collection Vault"
|
||||
data-feature-desc="Track your entire card collection, monitor value trends, and manage your inventory in one place. Log in to access your Vault.">Vault</a>
|
||||
|
||||
{% if FEATURE_VIRTUAL_PACKS %}
|
||||
<a href="{% url 'store:my_packs' %}"
|
||||
class="auth-required"
|
||||
data-feature-title="My Packs"
|
||||
data-feature-desc="Open virtual packs, collect rare cards, and grow your digital library. Sign up now to start cracking packs!">My Packs</a>
|
||||
{% endif %}
|
||||
|
||||
<a href="{% url 'login' %}">Login</a>
|
||||
<a href="{% url 'users:register' %}">Register</a>
|
||||
<a href="{% url 'store:seller_register' %}">Seller?</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
@@ -278,9 +133,27 @@
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
<footer style="text-align: center; padding: 2rem; color: #64748b; font-size: 0.875rem;">
|
||||
<p>© 2026 Phantom Card Fam TCG Store.</p>
|
||||
<p>Made by <a href="https://aimloperations.com" target="_blank" style="color: inherit; text-decoration: underline;">AI ML Operations, LLC</a></p>
|
||||
<footer style="background-color: #1e293b; border-top: 1px solid #334155; padding: 3rem 1rem; margin-top: 4rem; color: #94a3b8;">
|
||||
<div class="container" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 2rem; max-width: 1200px; margin: 0 auto;">
|
||||
<div style="text-align: left;">
|
||||
<h3 style="color: #f59e0b; font-weight: 700; font-size: 1.25rem; margin-bottom: 1rem;">TCGKof</h3>
|
||||
<p style="font-size: 0.875rem; line-height: 1.6;">The premier destination for trading card game buyers and sellers.</p>
|
||||
<p style="font-size: 0.875rem;">© 2026 TCGKof Store.</p>
|
||||
<p style="font-size: 0.875rem;">Operated by <a href="https://aimloperations.com" target="_blank" style="color: inherit; text-decoration: underline;">AI ML Operations, LLC</a></p>
|
||||
</div>
|
||||
<div style="text-align: left;">
|
||||
<h4 style="color: #e2e8f0; font-weight: 600; margin-bottom: 1rem;">Sellers</h4>
|
||||
<ul style="list-style: none; padding: 0;">
|
||||
<li style="margin-bottom: 0.5rem;"><a href="{% url 'users:sell_on_tcgkof' %}" style="color: inherit; text-decoration: none; transition: color 0.2s;">Sell on TCGKof</a></li>
|
||||
<li style="margin-bottom: 0.5rem;"><a href="{% url 'store:seller_register' %}" style="color: inherit; text-decoration: none; transition: color 0.2s;">Seller Registration</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div style="text-align: left;">
|
||||
<h4 style="color: #e2e8f0; font-weight: 600; margin-bottom: 1rem;">Legal</h4>
|
||||
<ul style="list-style: none; padding: 0;">
|
||||
<li style="margin-bottom: 0.5rem;"><a href="{% url 'store:terms' %}" style="color: inherit; text-decoration: none; transition: color 0.2s;">Terms and Service</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{% if not user.is_authenticated %}
|
||||
@@ -298,48 +171,59 @@
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const modal = document.getElementById('authModal');
|
||||
const closeBtn = document.querySelector('.close-modal');
|
||||
const modalTitle = document.getElementById('modalTitle');
|
||||
const modalDesc = document.getElementById('modalDesc');
|
||||
const authLinks = document.querySelectorAll('.auth-required');
|
||||
|
||||
function openModal(title, desc) {
|
||||
modalTitle.textContent = title;
|
||||
modalDesc.textContent = desc;
|
||||
modal.classList.add('active');
|
||||
document.body.style.overflow = 'hidden'; // Prevent scrolling
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
modal.classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
authLinks.forEach(link => {
|
||||
link.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const title = this.dataset.featureTitle || 'Login Required';
|
||||
const desc = this.dataset.featureDesc || 'Please log in to access this feature.';
|
||||
openModal(title, desc);
|
||||
// Mobile Menu Toggle
|
||||
const mobileBtn = document.querySelector('.mobile-menu-btn');
|
||||
const navLinks = document.querySelector('.nav-links');
|
||||
|
||||
if (mobileBtn) {
|
||||
mobileBtn.addEventListener('click', function() {
|
||||
navLinks.classList.toggle('active');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
closeBtn.addEventListener('click', closeModal);
|
||||
// Auth Modal Logic
|
||||
const modal = document.getElementById('authModal');
|
||||
if (modal) {
|
||||
const closeBtn = document.querySelector('.close-modal');
|
||||
const modalTitle = document.getElementById('modalTitle');
|
||||
const modalDesc = document.getElementById('modalDesc');
|
||||
const authLinks = document.querySelectorAll('.auth-required');
|
||||
|
||||
// Close on outside click
|
||||
modal.addEventListener('click', function(e) {
|
||||
if (e.target === modal) {
|
||||
closeModal();
|
||||
function openModal(title, desc) {
|
||||
modalTitle.textContent = title;
|
||||
modalDesc.textContent = desc;
|
||||
modal.classList.add('active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
});
|
||||
|
||||
// Close on Escape key
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape' && modal.classList.contains('active')) {
|
||||
closeModal();
|
||||
function closeModal() {
|
||||
modal.classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
});
|
||||
|
||||
authLinks.forEach(link => {
|
||||
link.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const title = this.dataset.featureTitle || 'Login Required';
|
||||
const desc = this.dataset.featureDesc || 'Please log in to access this feature.';
|
||||
openModal(title, desc);
|
||||
});
|
||||
});
|
||||
|
||||
closeBtn.addEventListener('click', closeModal);
|
||||
|
||||
modal.addEventListener('click', function(e) {
|
||||
if (e.target === modal) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape' && modal.classList.contains('active')) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base.html' %}
|
||||
{% extends 'base/layout.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-4">
|
||||
|
||||
33
templates/legal/terms.html
Normal file
33
templates/legal/terms.html
Normal file
@@ -0,0 +1,33 @@
|
||||
{% extends 'base/layout.html' %}
|
||||
|
||||
{% block title %}Terms and Service - TCGKof{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="terms-container" style="max-width: 800px; margin: 2rem auto; padding: 2rem; background: var(--bg-card); border-radius: var(--border-radius); border: 1px solid var(--border-color);">
|
||||
<h1 style="color: var(--primary-color); margin-bottom: 2rem; text-align: center;">Terms of Service</h1>
|
||||
|
||||
<div class="terms-content" style="color: var(--text-color); line-height: 1.6;">
|
||||
<p style="margin-bottom: 1.5rem;">Welcome to TCGKof. By accessing our website, you agree to these terms and conditions.</p>
|
||||
|
||||
<h2 style="color: var(--text-heading); font-size: 1.5rem; margin-top: 2rem; margin-bottom: 1rem;">1. General Terms</h2>
|
||||
<p style="margin-bottom: 1rem;">TCGKof is a platform for buying and selling trading cards. Users must be at least 18 years old or have parental consent to use this service.</p>
|
||||
|
||||
<h2 style="color: var(--text-heading); font-size: 1.5rem; margin-top: 2rem; margin-bottom: 1rem;">2. User Accounts</h2>
|
||||
<p style="margin-bottom: 1rem;">You are responsible for maintaining the confidentiality of your account and password. You agree to accept responsibility for all activities that occur under your account.</p>
|
||||
|
||||
<h2 style="color: var(--text-heading); font-size: 1.5rem; margin-top: 2rem; margin-bottom: 1rem;">3. Buying and Selling</h2>
|
||||
<p style="margin-bottom: 1rem;">Sellers must accurately describe items. Buyers must pay for items they commit to purchase. TCGKof facilitates transactions but is not a party to the contract between buyer and seller.</p>
|
||||
|
||||
<h2 style="color: var(--text-heading); font-size: 1.5rem; margin-top: 2rem; margin-bottom: 1rem;">4. Prohibited Content</h2>
|
||||
<p style="margin-bottom: 1rem;">Users may not post content that is illegal, obscene, threatening, defamatory, or otherwise objectionable.</p>
|
||||
|
||||
<h2 style="color: var(--text-heading); font-size: 1.5rem; margin-top: 2rem; margin-bottom: 1rem;">5. Limitation of Liability</h2>
|
||||
<p style="margin-bottom: 1rem;">TCGKof shall not be liable for any indirect, incidental, special, consequential, or punitive damages happening out of or in connection with your use of the site.</p>
|
||||
|
||||
<h2 style="color: var(--text-heading); font-size: 1.5rem; margin-top: 2rem; margin-bottom: 1rem;">6. Changes to Terms</h2>
|
||||
<p style="margin-bottom: 1rem;">We reserve the right to modify these terms at any time. Your continued use of the site constitutes acceptance of the modified terms.</p>
|
||||
|
||||
<p style="margin-top: 3rem; font-size: 0.875rem; color: var(--text-muted); text-align: center;">Last Updated: January 2026</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -13,5 +13,8 @@
|
||||
Don't have an account? <a href="{% url 'users:register' %}" style="color: var(--primary-color);">Register
|
||||
here</a>.
|
||||
</p>
|
||||
<p style="margin-top: 0.5rem; text-align: center;">
|
||||
Want to sell on TCGKof? <a href="{% url 'store:seller_register' %}" style="color: var(--primary-color);">Register here</a>.
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
6
templates/robots.txt
Normal file
6
templates/robots.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
User-agent: *
|
||||
Disallow: /admin/
|
||||
Disallow: /users/
|
||||
Disallow: /cart/
|
||||
Disallow: /checkout/
|
||||
Disallow: /api/
|
||||
164
templates/store/bounty_list.html
Normal file
164
templates/store/bounty_list.html
Normal file
@@ -0,0 +1,164 @@
|
||||
{% extends 'base/layout.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="browse-container" style="display: grid; grid-template-columns: 250px 1fr; gap: 2rem;">
|
||||
<!-- Sidebar Filters -->
|
||||
<aside class="browse-sidebar"
|
||||
style="background: var(--card-bg); padding: 1.5rem; border-radius: 0.5rem; border: 1px solid var(--border-color); height: fit-content;">
|
||||
<h3 style="margin-top: 0;">Filter Bounties</h3>
|
||||
<form method="get">
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label style="display: block; font-size: 0.875rem; margin-bottom: 0.5rem;">Game</label>
|
||||
<select name="game"
|
||||
style="width: 100%; padding: 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);"
|
||||
onchange="this.form.submit()">
|
||||
<option value="">All Games</option>
|
||||
{% for game in games %}
|
||||
<option value="{{ game.slug }}" {% if current_game == game.slug %}selected{% endif %}>
|
||||
{{game.name}}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{% if current_game %}
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label style="display: block; font-size: 0.875rem; margin-bottom: 0.5rem;">Set</label>
|
||||
<select name="set"
|
||||
style="width: 100%; padding: 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);">
|
||||
<option value="">All Sets</option>
|
||||
{% for set in sets %}
|
||||
<option value="{{ set.id }}" {% if request.GET.set|add:"0" == set.id %}selected{% endif %}>{{ set.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div style="margin-bottom: 1rem; position: relative;">
|
||||
<label style="display: block; font-size: 0.875rem; margin-bottom: 0.5rem;">Search</label>
|
||||
<input type="text" name="q" id="search-input" value="{{ search_query|default:'' }}" placeholder="Card or Bounty title..." autocomplete="off"
|
||||
style="width: 90%; padding: 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);">
|
||||
<ul id="suggestions-list" style="display: none; position: absolute; top: 100%; left: 0; width: 90%; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 0.25rem; z-index: 1000; list-style: none; padding: 0; margin: 0; max-height: 200px; overflow-y: auto;">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const suggestionsList = document.getElementById('suggestions-list');
|
||||
let debounceTimer;
|
||||
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener('input', function() {
|
||||
const query = this.value;
|
||||
clearTimeout(debounceTimer);
|
||||
if (query.length < 2) {
|
||||
suggestionsList.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
debounceTimer = setTimeout(() => {
|
||||
fetch(`/api/bounty-autocomplete/?q=${encodeURIComponent(query)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
suggestionsList.innerHTML = '';
|
||||
if (data.results.length > 0) {
|
||||
data.results.forEach(name => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = name;
|
||||
li.style.padding = '0.5rem';
|
||||
li.style.cursor = 'pointer';
|
||||
li.style.borderBottom = '1px solid var(--border-color)';
|
||||
|
||||
li.addEventListener('mouseenter', () => {
|
||||
li.style.background = 'var(--card-bg)';
|
||||
});
|
||||
li.addEventListener('mouseleave', () => {
|
||||
li.style.background = 'transparent';
|
||||
});
|
||||
|
||||
li.addEventListener('click', () => {
|
||||
searchInput.value = name;
|
||||
suggestionsList.style.display = 'none';
|
||||
searchInput.form.submit();
|
||||
});
|
||||
suggestionsList.appendChild(li);
|
||||
});
|
||||
suggestionsList.style.display = 'block';
|
||||
} else {
|
||||
suggestionsList.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target !== searchInput && e.target !== suggestionsList) {
|
||||
suggestionsList.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<button type="submit" class="btn" style="width: 100%;">Apply Filters</button>
|
||||
<a href="{% url 'store:bounty_list' %}"
|
||||
style="display: block; text-align: center; margin-top: 1rem; color: #94a3b8; font-size: 0.875rem; text-decoration: none;">Clear
|
||||
Filters</a>
|
||||
</form>
|
||||
</aside>
|
||||
|
||||
<!-- Bounty Grid -->
|
||||
<div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
|
||||
<h2 style="margin: 0;">Bounty Board</h2>
|
||||
{% if user.seller_profile %}
|
||||
<a href="{% url 'store:bounty_create' %}" class="btn btn-outline" style="padding: 0.5rem 1rem; font-size: 0.875rem;">Post a Bounty</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="card-grid">
|
||||
{% for bounty in bounties %}
|
||||
<div class="tcg-card">
|
||||
<a href="{% url 'store:bounty_detail' bounty.uuid %}" style="text-decoration: none; color: inherit;">
|
||||
<div style="aspect-ratio: 2.5/3.5; background: #000; position: relative;">
|
||||
{% if bounty.card.image_url %}
|
||||
<img src="{{ bounty.card.image_url }}" alt="{{ bounty.card.name }}"
|
||||
style="width: 100%; height: 100%; object-fit: cover;">
|
||||
{% else %}
|
||||
<div
|
||||
style="display: flex; align-items: center; justify-content: center; height: 100%; color: #64748b; background: #334155; padding: 1rem; text-align: center;">
|
||||
{{ bounty.title|default:"No Image" }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="tcg-card-body">
|
||||
<h4
|
||||
style="margin: 0 0 0.5rem; font-size: 1rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
{% if bounty.card %}{{ bounty.card.name }}{% else %}{{ bounty.title }}{% endif %}
|
||||
</h4>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; font-size: 0.875rem; color: #94a3b8;">
|
||||
<span>{% if bounty.card %}{{ bounty.card.set.code|default:bounty.card.set.game.name }}{% else %}Wanted{% endif %}</span>
|
||||
<span style="color: #10b981;">Offering ${{ bounty.target_price }}</span>
|
||||
</div>
|
||||
<div
|
||||
style="margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center;">
|
||||
<span style="font-size: 0.75rem; color: #94a3b8;">{{ bounty.offers.count }} Offers</span>
|
||||
|
||||
<span class="btn" style="padding: 0.25rem 0.5rem; font-size: 0.75rem;">View Bounty</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div style="grid-column: 1 / -1; text-align: center; padding: 3rem; background: var(--card-bg); border-radius: 0.5rem; border: 1px solid var(--border-color);">
|
||||
<p style="color: #94a3b8; font-size: 1.1rem; margin-bottom: 1rem;">No active bounties found matching your criteria.</p>
|
||||
<a href="{% url 'store:bounty_list' %}" class="btn btn-outline">Clear Filters</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,16 +1,52 @@
|
||||
{% extends 'base/layout.html' %}
|
||||
|
||||
{% block title %}{{ card.name }} - TCGKof{% endblock %}
|
||||
|
||||
{% block meta_description %}Buy {{ card.name }} ({{ card.set.name }}) on TCGKof. {{ listings|length }} listings available starting from ${{ listings.first.price|default:'0.00' }}.{% endblock %}
|
||||
|
||||
{% block meta_keywords %}{{ card.name }}, {{ card.set.name }}, {{ card.rarity }}, {{ card.set.game.name }}, buy {{ card.name }}, sell {{ card.name }}{% endblock %}
|
||||
|
||||
{% block og_title %}{{ card.name }} - {{ card.set.name }} | TCGKof{% endblock %}
|
||||
{% block og_description %}Buy {{ card.name }} from {{ card.set.name }} set. best prices on TCGKof.{% endblock %}
|
||||
{% block og_image %}{{ card.image_url|default:'' }}{% endblock %}
|
||||
{% block og_type %}product{% endblock %}
|
||||
|
||||
{% block twitter_title %}{{ card.name }} - {{ card.set.name }}{% endblock %}
|
||||
{% block twitter_description %}Find the best deals for {{ card.name }} on TCGKof.{% endblock %}
|
||||
{% block twitter_image %}{{ card.image_url|default:'' }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org/",
|
||||
"@type": "Product",
|
||||
"name": "{{ card.name }}",
|
||||
"image": "{{ card.image_url }}",
|
||||
"description": "Buy {{ card.name }} from the {{ card.set.name }} set.",
|
||||
"sku": "{{ card.uuid }}",
|
||||
"brand": {
|
||||
"@type": "Brand",
|
||||
"name": "{{ card.set.game.name }}"
|
||||
},
|
||||
"offers": {
|
||||
"@type": "AggregateOffer",
|
||||
"url": "{{ request.build_absolute_uri }}",
|
||||
"priceCurrency": "USD",
|
||||
"lowPrice": "{{ listings.first.price|default:'0.00' }}",
|
||||
"offerCount": "{{ listings|length }}",
|
||||
"availability": "https://schema.org/InStock"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<div style="display: grid; grid-template-columns: 1fr 2fr; gap: 3rem;">
|
||||
<!-- Image Column -->
|
||||
<div>
|
||||
<div
|
||||
style="background: #000; border-radius: 0.75rem; overflow: hidden; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);">
|
||||
style="background: var(--card-bg); border-radius: 0.75rem; overflow: hidden; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);">
|
||||
{% if card.image_url %}
|
||||
<img src="{{ card.image_url }}" alt="{{ card.name }}" style="width: 100%; display: block;">
|
||||
{% else %}
|
||||
<div
|
||||
style="aspect-ratio: 2.5/3.5; display: flex; align-items: center; justify-content: center; color: #64748b; background: #334155;">
|
||||
style="aspect-ratio: 2.5/3.5; display: flex; align-items: center; justify-content: center; color: var(--muted-text-color); background: var(--border-color);">
|
||||
No Image</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -19,13 +55,13 @@
|
||||
<div style="margin-top: 1.5rem; display: grid; gap: 0.5rem;">
|
||||
{% if card.tcgplayer_id %}
|
||||
<a href="https://www.tcgplayer.com/product/{{ card.tcgplayer_id }}" target="_blank"
|
||||
style="display: block; text-align: center; padding: 0.75rem; background: #27272a; color: white; border-radius: 0.375rem; text-decoration: none; font-size: 0.875rem;">
|
||||
style="display: block; text-align: center; padding: 0.75rem; background: var(--card-bg); color: var(--text-color); border-radius: 0.375rem; text-decoration: none; font-size: 0.875rem;">
|
||||
View on TCGPlayer
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="https://www.ebay.com/sch/i.html?_nkw={{ card.name|urlencode }}+{{ card.set.name|urlencode }}"
|
||||
target="_blank"
|
||||
style="display: block; text-align: center; padding: 0.75rem; background: #27272a; color: white; border-radius: 0.375rem; text-decoration: none; font-size: 0.875rem;">
|
||||
style="display: block; text-align: center; padding: 0.75rem; background: var(--card-bg); color: var(--text-color); border-radius: 0.375rem; text-decoration: none; font-size: 0.875rem;">
|
||||
Search on eBay
|
||||
</a>
|
||||
</div>
|
||||
@@ -36,7 +72,7 @@
|
||||
<div style="margin-bottom: 2rem;">
|
||||
<h4 style="margin: 0; color: var(--primary-color);">{{ card.set.game.name }} • {{ card.set.name }}</h4>
|
||||
<h1 style="margin: 0.5rem 0 0; font-size: 2.5rem;">{{ card.name }}</h1>
|
||||
<div style="margin-top: 1rem; display: flex; gap: 1rem; color: #94a3b8;">
|
||||
<div style="margin-top: 1rem; display: flex; gap: 1rem; color: var(--muted-text-color);">
|
||||
<span>Rarity: <strong style="color: var(--text-color);">{{ card.rarity }}</strong></span>
|
||||
<span>Collector #: <strong style="color: var(--text-color);">{{ card.collector_number }}</strong></span>
|
||||
</div>
|
||||
@@ -46,7 +82,7 @@
|
||||
Listings</h3>
|
||||
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label style="font-size: 0.875rem; color: #94a3b8;">Filter Condition:</label>
|
||||
<label style="font-size: 0.875rem; color: var(--muted-text-color);">Filter Condition:</label>
|
||||
<div style="display: flex; gap: 0.5rem; margin-top: 0.25rem;">
|
||||
<button onclick="filterCondition('ALL')" class="btn" style="padding: 0.25rem 0.75rem; font-size: 0.75rem; background: var(--card-bg); border: 1px solid var(--border-color);">All</button>
|
||||
<button onclick="filterCondition('NM')" class="btn" style="padding: 0.25rem 0.75rem; font-size: 0.75rem; background: var(--card-bg); border: 1px solid var(--border-color);">NM</button>
|
||||
@@ -61,30 +97,43 @@
|
||||
<div class="listing-item" data-condition="{{ listing.condition }}"
|
||||
style="display: flex; justify-content: space-between; align-items: center; background: var(--card-bg); padding: 1rem; border-radius: 0.5rem; border: 1px solid var(--border-color);">
|
||||
<div style="display: flex; gap: 1rem; align-items: center;">
|
||||
<span style="font-weight: 700; font-size: 1.25rem; width: 3rem; text-align: center;">{{
|
||||
listing.condition }}</span>
|
||||
{% if listing.image %}
|
||||
<img src="{{ listing.image.url }}" alt="Listing Image" style="width: 50px; height: 70px; object-fit: cover; border-radius: 4px; border: 1px solid #444;">
|
||||
{% endif %}
|
||||
<span style="font-weight: 700; font-size: 1.25rem;">
|
||||
{{ listing.condition }}</span>
|
||||
<div>
|
||||
<div style="font-size: 0.875rem; color: #94a3b8;">Condition</div>
|
||||
<div style="font-size: 0.875rem; color: var(--muted-text-color);">Condition</div>
|
||||
{% if listing.is_foil %}
|
||||
<span
|
||||
style="background: linear-gradient(45deg, #f59e0b, #d97706); -webkit-background-clip: text; color: transparent; font-weight: 700; font-size: 0.75rem; text-transform: uppercase;">Foil</span>
|
||||
style="background: linear-gradient(45deg, #f59e0b, #d97706); -webkit-background-clip: text; background-clip: text; color: transparent; font-weight: 700; font-size: 0.75rem; text-transform: uppercase;">Foil</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; align-items: center; gap: 2rem;">
|
||||
<div style="min-width: 150px;">
|
||||
<div style="font-size: 0.875rem; color: var(--muted-text-color);">Seller</div>
|
||||
<div style="font-weight: 500;">
|
||||
{% if listing.seller %}
|
||||
<a href="{% url 'store:seller_profile' listing.seller.slug %}" style="color: var(--info-color); text-decoration: none;">{{ listing.seller.store_name }}</a>
|
||||
{% else %}
|
||||
<span style="color: var(--muted-text-color);">TCGKof Direct</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-weight: 700; font-size: 1.5rem;">${{ listing.price }}</div>
|
||||
<div style="font-size: 0.75rem; color: #94a3b8;">{{ listing.quantity }} available</div>
|
||||
<div style="font-size: 0.75rem; color: var(--muted-text-color);">{{ listing.quantity }} available</div>
|
||||
</div>
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<form action="{% url 'store:add_to_cart' listing.id %}" method="post">
|
||||
<form action="{% url 'store:add_to_cart' listing.uuid %}" method="post">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn">Add to Cart</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<a href="{% url 'login' %}?next={{ request.path }}" class="btn" style="background: #334155;">Login
|
||||
<a href="{% url 'login' %}?next={{ request.path }}" class="btn" style="background: var(--border-color);">Login
|
||||
to Buy</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -92,21 +141,23 @@
|
||||
{% empty %}
|
||||
<div
|
||||
style="text-align: center; padding: 2rem; background: var(--card-bg); border-radius: 0.5rem; border: 1px dashed var(--border-color);">
|
||||
<p style="margin: 0; color: #94a3b8;">No listings currently available for this card.</p>
|
||||
<p style="margin: 0; color: var(--muted-text-color);">No listings currently available for this card.</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Proxy Service -->
|
||||
{% if FEATURE_PLAYTEST_PROXY %}
|
||||
<div style="margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--border-color);">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div>
|
||||
<h3 style="margin: 0 0 0.5rem;">Playtest Proxy Service</h3>
|
||||
<p style="margin: 0; color: #94a3b8; font-size: 0.875rem;">Download a high-res proxy for playtesting. Credit offered if you buy later.</p>
|
||||
<p style="margin: 0; color: var(--muted-text-color); font-size: 0.875rem;">Download a high-res proxy for playtesting. Credit offered if you buy later.</p>
|
||||
</div>
|
||||
<button onclick="alert('Proxy PDF generated! (Mockup)')" class="btn" style="background: transparent; border: 1px solid var(--border-color);">Download Proxy</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
function filterCondition(cond) {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div style="display: grid; grid-template-columns: 250px 1fr; gap: 2rem;">
|
||||
<div class="browse-container" style="display: grid; grid-template-columns: 250px 1fr; gap: 2rem;">
|
||||
<!-- Sidebar Filters -->
|
||||
<aside
|
||||
<aside class="browse-sidebar"
|
||||
style="background: var(--card-bg); padding: 1.5rem; border-radius: 0.5rem; border: 1px solid var(--border-color); height: fit-content;">
|
||||
<h3 style="margin-top: 0;">Filters</h3>
|
||||
<form method="get">
|
||||
@@ -29,19 +29,80 @@
|
||||
style="width: 100%; padding: 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);">
|
||||
<option value="">All Sets</option>
|
||||
{% for set in sets %}
|
||||
<option value="{{ set.id }}" {% if request.GET.set|add:"0" == set.id %}selected{% endif %}>{{ set.name
|
||||
}}</option>
|
||||
<option value="{{ set.id }}" {% if request.GET.set|add:"0" == set.id %}selected{% endif %}>{{ set.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label style="display: block; font-size: 0.875rem; margin-bottom: 0.5rem;">Search</label>
|
||||
<input type="text" name="q" value="{{ search_query|default:'' }}" placeholder="Card name..."
|
||||
style="width: 90%; padding: 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);">
|
||||
<div style="margin-bottom: 1rem; display: flex; align-items: center;">
|
||||
<input type="checkbox" id="hide_out_of_stock" name="hide_out_of_stock" {% if hide_oos == 'on' %}checked{% endif %} onchange="this.form.submit()" style="margin-right: 0.5rem;">
|
||||
<label for="hide_out_of_stock" style="font-size: 0.875rem; cursor: pointer;">Hide Out of Stock</label>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 1rem; position: relative;">
|
||||
<label style="display: block; font-size: 0.875rem; margin-bottom: 0.5rem;">Search</label>
|
||||
<input type="text" name="q" id="search-input" value="{{ search_query|default:'' }}" placeholder="Card name..." autocomplete="off"
|
||||
style="width: 90%; padding: 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);">
|
||||
<ul id="suggestions-list" style="display: none; position: absolute; top: 100%; left: 0; width: 90%; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 0.25rem; z-index: 1000; list-style: none; padding: 0; margin: 0; max-height: 200px; overflow-y: auto;">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const suggestionsList = document.getElementById('suggestions-list');
|
||||
let debounceTimer;
|
||||
|
||||
searchInput.addEventListener('input', function() {
|
||||
const query = this.value;
|
||||
clearTimeout(debounceTimer);
|
||||
if (query.length < 2) {
|
||||
suggestionsList.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
debounceTimer = setTimeout(() => {
|
||||
fetch(`/api/card-autocomplete/?q=${encodeURIComponent(query)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
suggestionsList.innerHTML = '';
|
||||
if (data.results.length > 0) {
|
||||
data.results.forEach(name => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = name;
|
||||
li.style.padding = '0.5rem';
|
||||
li.style.cursor = 'pointer';
|
||||
li.style.borderBottom = '1px solid var(--border-color)';
|
||||
|
||||
li.addEventListener('mouseenter', () => {
|
||||
li.style.background = 'var(--card-bg)';
|
||||
});
|
||||
li.addEventListener('mouseleave', () => {
|
||||
li.style.background = 'transparent';
|
||||
});
|
||||
|
||||
li.addEventListener('click', () => {
|
||||
searchInput.value = name;
|
||||
suggestionsList.style.display = 'none';
|
||||
searchInput.form.submit();
|
||||
});
|
||||
suggestionsList.appendChild(li);
|
||||
});
|
||||
suggestionsList.style.display = 'block';
|
||||
} else {
|
||||
suggestionsList.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target !== searchInput && e.target !== suggestionsList) {
|
||||
suggestionsList.style.display = 'none';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<button type="submit" class="btn" style="width: 100%;">Apply Filters</button>
|
||||
<a href="{% url 'store:card_list' %}"
|
||||
style="display: block; text-align: center; margin-top: 1rem; color: #94a3b8; font-size: 0.875rem; text-decoration: none;">Clear
|
||||
@@ -55,7 +116,7 @@
|
||||
<div class="card-grid">
|
||||
{% for card in page_obj %}
|
||||
<div class="tcg-card">
|
||||
<a href="{% url 'store:card_detail' card.id %}" style="text-decoration: none; color: inherit;">
|
||||
<a href="{% url 'store:card_detail' card.uuid %}" style="text-decoration: none; color: inherit;">
|
||||
<div style="aspect-ratio: 2.5/3.5; background: #000; position: relative;">
|
||||
<!-- Placeholder or Real Image -->
|
||||
{% if card.image_url %}
|
||||
@@ -85,7 +146,7 @@
|
||||
<span style="color: #64748b;">Out of Stock</span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<span id="stock-{{ card.id }}" class="stock-counter" data-card-id="{{ card.id }}" style="font-size: 0.75rem; color: #94a3b8; margin-left: auto;">...</span>
|
||||
<span id="stock-{{ card.uuid }}" class="stock-counter" data-card-id="{{ card.uuid }}" style="font-size: 0.75rem; color: #94a3b8; margin-left: auto;">...</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@@ -99,7 +160,7 @@
|
||||
{% if page_obj.has_other_pages %}
|
||||
<div style="margin-top: 2rem; display: flex; justify-content: center; gap: 0.5rem;">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?page={{ page_obj.previous_page_number }}&game={{ current_game }}&q={{ search_query }}" class="btn"
|
||||
<a href="?page={{ page_obj.previous_page_number }}&game={{ current_game }}&q={{ search_query }}&hide_out_of_stock={{ hide_oos }}" class="btn"
|
||||
style="padding: 0.25rem 0.5rem; font-size: 0.875rem;">Prev</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -109,7 +170,7 @@
|
||||
</span>
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<a href="?page={{ page_obj.next_page_number }}&game={{ current_game }}&q={{ search_query }}" class="btn"
|
||||
<a href="?page={{ page_obj.next_page_number }}&game={{ current_game }}&q={{ search_query }}&hide_out_of_stock={{ hide_oos }}" class="btn"
|
||||
style="padding: 0.25rem 0.5rem; font-size: 0.875rem;">Next</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,19 @@
|
||||
{% if cart and cart.items.count > 0 %}
|
||||
<div
|
||||
style="background: var(--card-bg); border-radius: 0.5rem; border: 1px solid var(--border-color); overflow: hidden;">
|
||||
{% for item in cart.items.all %}
|
||||
<div
|
||||
style="background: var(--card-bg); border-radius: 0.5rem; border: 1px solid var(--border-color); overflow: hidden;">
|
||||
|
||||
{% for section in cart_data %}
|
||||
<div style="background: rgba(0,0,0,0.05); padding: 0.75rem 1.5rem; border-bottom: 1px solid var(--border-color); font-weight: 600;">
|
||||
{% if section.seller %}
|
||||
Store: <a href="{% url 'store:seller_profile' section.seller.slug %}" style="text-decoration: none; color: inherit;">{{ section.seller.store_name }}</a>
|
||||
{% else %}
|
||||
System Items
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% for item in section.items %}
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; padding: 1.5rem; border-bottom: 1px solid var(--border-color);">
|
||||
<div style="display: flex; gap: 1.5rem; align-items: center;">
|
||||
@@ -43,12 +55,27 @@
|
||||
<div style="font-weight: 700; font-size: 1.25rem;">
|
||||
${{ item.total_price }}
|
||||
</div>
|
||||
<a href="{% url 'store:remove_from_cart' item.id %}"
|
||||
<a href="{% url 'store:remove_from_cart' item.uuid %}"
|
||||
style="color: #ef4444; text-decoration: none; font-size: 1.25rem;">×</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div style="padding: 1rem 1.5rem; border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center; background: rgba(0,0,0,0.02);">
|
||||
<div>
|
||||
{% if section.free_shipping_needed > 0 %}
|
||||
<span style="color: #ef4444; font-size: 0.875rem;">Add ${{ section.free_shipping_needed }} more for free shipping!</span>
|
||||
{% else %}
|
||||
<span style="color: #10b981; font-size: 0.875rem;">Free Shipping Qualifies!</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div style="text-align: right; font-size: 0.875rem;">
|
||||
<div>Subtotal: ${{ section.subtotal }}</div>
|
||||
<div>Shipping: ${{ section.shipping_cost }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div style="padding: 1rem 1.5rem; background: rgba(0,0,0,0.1); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 0.75rem;">
|
||||
<a href="{% url 'store:toggle_insurance' %}" style="text-decoration: none; display: flex; align-items: center; gap: 0.5rem; color: var(--text-color);">
|
||||
@@ -63,7 +90,7 @@
|
||||
<div
|
||||
style="padding: 1.5rem; background: rgba(0,0,0,0.2); display: flex; justify-content: space-between; align-items: center;">
|
||||
<span style="font-size: 1.25rem; font-weight: 600;">Total</span>
|
||||
<span style="font-size: 1.5rem; font-weight: 800;">${{ cart.total_price }}</span>
|
||||
<span style="font-size: 1.5rem; font-weight: 800;">${{ grand_total }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
<div class="tcg-card-body" style="text-align: center;">
|
||||
<h4 style="margin: 0 0 0.5rem; font-size: 1rem;">{{ pack.listing.name }}</h4>
|
||||
<a href="{% url 'store:open_pack' pack.id %}" class="btn" style="width: 100%; display: block; margin-top: 1rem;">Open Pack</a>
|
||||
<a href="{% url 'store:open_pack' pack.uuid %}" class="btn" style="width: 100%; display: block; margin-top: 1rem;">Open Pack</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
@@ -70,5 +70,85 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Rating Section -->
|
||||
{% if order.seller %}
|
||||
<div style="background: var(--card-bg); padding: 2rem; border-radius: 0.5rem; border: 1px solid var(--border-color); margin-top: 2rem;">
|
||||
<h3 style="margin-bottom: 1rem;">Rate Your Order</h3>
|
||||
|
||||
{% if order.rating %}
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<p style="margin: 0; color: #94a3b8;">You rated this order:</p>
|
||||
<div style="display: flex; gap: 0.25rem;">
|
||||
{% for i in "12345" %}
|
||||
{% if forloop.counter <= order.rating %}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#fbbf24" stroke="#fbbf24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
|
||||
</svg>
|
||||
{% else %}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
|
||||
</svg>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p style="margin: 0; font-weight: 600;">{{ order.rating }}/5</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<p style="color: #94a3b8; margin-bottom: 1rem;">How would you rate your experience with {{ order.seller.store_name }}?</p>
|
||||
<form method="post" style="display: flex; gap: 1rem; align-items: center;">
|
||||
{% csrf_token %}
|
||||
<div style="display: flex; gap: 0.5rem;" id="star-rating">
|
||||
{% for i in "12345" %}
|
||||
<label style="cursor: pointer;">
|
||||
<input type="radio" name="rating" value="{{ forloop.counter }}" style="display: none;" class="rating-input">
|
||||
<svg class="star-icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="transition: all 0.2s;">
|
||||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
|
||||
</svg>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<button type="submit" class="btn" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; opacity: 0.5; pointer-events: none;" id="submit-rating" disabled>Submit Rating</button>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
const stars = document.querySelectorAll('.star-icon');
|
||||
const ratingInputs = document.querySelectorAll('.rating-input');
|
||||
const submitBtn = document.getElementById('submit-rating');
|
||||
let selectedRating = 0;
|
||||
|
||||
stars.forEach((star, index) => {
|
||||
star.addEventListener('mouseenter', () => {
|
||||
highlightStars(index + 1);
|
||||
});
|
||||
|
||||
star.addEventListener('click', () => {
|
||||
selectedRating = index + 1;
|
||||
ratingInputs[index].checked = true;
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.style.opacity = '1';
|
||||
submitBtn.style.pointerEvents = 'auto';
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('star-rating').addEventListener('mouseleave', () => {
|
||||
highlightStars(selectedRating);
|
||||
});
|
||||
|
||||
function highlightStars(count) {
|
||||
stars.forEach((star, index) => {
|
||||
if (index < count) {
|
||||
star.setAttribute('fill', '#fbbf24');
|
||||
star.setAttribute('stroke', '#fbbf24');
|
||||
} else {
|
||||
star.setAttribute('fill', 'none');
|
||||
star.setAttribute('stroke', '#64748b');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -18,9 +18,17 @@
|
||||
</div>
|
||||
<div class="tcg-card-body">
|
||||
<h4 style="margin: 0 0 0.5rem; font-size: 1rem;">{{ pack.name }}</h4>
|
||||
<div style="font-size: 0.75rem; color: #94a3b8; margin-bottom: 0.5rem;">
|
||||
Sold by:
|
||||
{% if pack.seller %}
|
||||
<a href="{% url 'store:seller_profile' pack.seller.slug %}" style="color: #60a5fa;">{{ pack.seller.store_name }}</a>
|
||||
{% else %}
|
||||
TCGKof Direct
|
||||
{% endif %}
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1rem;">
|
||||
<span style="font-weight: 700;">${{ pack.price }}</span>
|
||||
<a href="{% url 'store:add_pack_to_cart' pack.id %}" class="btn" style="padding: 0.25rem 0.75rem; font-size: 0.875rem;">Add to Cart</a>
|
||||
<a href="{% url 'store:add_pack_to_cart' pack.uuid %}" class="btn" style="padding: 0.25rem 0.75rem; font-size: 0.875rem;">Add to Cart</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
{% if orders %}
|
||||
<div style="display: grid; gap: 1rem;">
|
||||
{% for order in orders %}
|
||||
<a href="{% url 'store:order_detail' order.id %}" style="text-decoration: none; color: inherit;">
|
||||
<a href="{% url 'store:order_detail' order.uuid %}" style="text-decoration: none; color: inherit;">
|
||||
<div
|
||||
style="background: var(--card-bg); padding: 1.5rem; border-radius: 0.5rem; border: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center; transition: transform 0.2s;"
|
||||
onmouseover="this.style.transform='translateY(-2px)'; this.style.borderColor='var(--accent-color)'"
|
||||
@@ -124,6 +124,14 @@
|
||||
style="display: inline-block; padding: 0.25rem 0.5rem; border-radius: 0.25rem; font-size: 0.75rem; background: #334155; margin-top: 0.5rem;">
|
||||
{{ order.get_status_display }}
|
||||
</span>
|
||||
{% if order.rating %}
|
||||
<div style="display: flex; align-items: center; justify-content: flex-end; gap: 0.25rem; margin-top: 0.5rem;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="#fbbf24" stroke="#fbbf24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
|
||||
</svg>
|
||||
<span style="font-size: 0.75rem; color: #fbbf24;">{{ order.rating }}/5</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
83
templates/users/sell_on_tcgkof.html
Normal file
83
templates/users/sell_on_tcgkof.html
Normal file
@@ -0,0 +1,83 @@
|
||||
{% extends 'base/layout.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}Sell on TCGKof - Become a Seller{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div style="padding: 4rem 1rem; max-width: 1200px; margin: 0 auto; text-align: center;">
|
||||
|
||||
<!-- Hero Section -->
|
||||
<div style="margin-bottom: 5rem;">
|
||||
<h1 style="font-size: 3.5rem; font-weight: 800; background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 1.5rem; letter-spacing: -0.025em;">
|
||||
Unlock the Value of Your Collection
|
||||
</h1>
|
||||
<p style="font-size: 1.25rem; color: var(--text-muted, #94a3b8); max-width: 600px; margin: 0 auto 2.5rem; line-height: 1.6;">
|
||||
Join the fastest-growing TCG marketplace. Turn your extra cards into cash with powerful tools designed for sellers of all sizes.
|
||||
</p>
|
||||
<div style="display: flex; gap: 1rem; justify-content: center;">
|
||||
<a href="{% url 'users:register' %}" class="btn" style="padding: 1rem 2.5rem; font-size: 1.1rem;">Start Selling Today</a>
|
||||
<a href="#benefits" class="btn btn-outline" style="padding: 1rem 2.5rem; font-size: 1.1rem;">Learn More</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats Section -->
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 2rem; margin-bottom: 5rem; padding: 2rem; background: rgba(255, 255, 255, 0.03); border-radius: 1rem; border: 1px solid rgba(255, 255, 255, 0.1);">
|
||||
<div>
|
||||
<div style="font-size: 2.5rem; font-weight: 700; color: #f59e0b;">$2M+</div>
|
||||
<div style="color: var(--text-muted, #94a3b8); margin-top: 0.5rem;">Paid to Sellers</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size: 2.5rem; font-weight: 700; color: #f59e0b;">50k+</div>
|
||||
<div style="color: var(--text-muted, #94a3b8); margin-top: 0.5rem;">Active Buyers</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size: 2.5rem; font-weight: 700; color: #f59e0b;">24h</div>
|
||||
<div style="color: var(--text-muted, #94a3b8); margin-top: 0.5rem;">Average Payout Time</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Benefits Section -->
|
||||
<div id="benefits" style="margin-bottom: 5rem; text-align: left;">
|
||||
<h2 style="font-size: 2.5rem; font-weight: 700; text-align: center; margin-bottom: 3rem;">Why Sell on TCGKof?</h2>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem;">
|
||||
<!-- Benefit 1 -->
|
||||
<div style="padding: 2rem; background: var(--bg-card, #1e293b); border-radius: 1rem; border: 1px solid var(--border-color, #334155); transition: transform 0.2s;">
|
||||
<div style="width: 50px; height: 50px; background: rgba(245, 158, 11, 0.1); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 1.5rem; color: #f59e0b;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="1" x2="12" y2="23"></line><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path></svg>
|
||||
</div>
|
||||
<h3 style="font-size: 1.25rem; font-weight: 600; margin-bottom: 1rem;">Low Selling Fees</h3>
|
||||
<p style="color: var(--text-muted, #94a3b8); line-height: 1.6;">Keep more of your profit with our straightforward 5% commission rate, one of the lowest in the industry.</p>
|
||||
</div>
|
||||
|
||||
<!-- Benefit 2 -->
|
||||
<div style="padding: 2rem; background: var(--bg-card, #1e293b); border-radius: 1rem; border: 1px solid var(--border-color, #334155); transition: transform 0.2s;">
|
||||
<div style="width: 50px; height: 50px; background: rgba(245, 158, 11, 0.1); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 1.5rem; color: #f59e0b;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
|
||||
</div>
|
||||
<h3 style="font-size: 1.25rem; font-weight: 600; margin-bottom: 1rem;">Massive Audience</h3>
|
||||
<p style="color: var(--text-muted, #94a3b8); line-height: 1.6;">Instantly connect with thousands of collectors actively looking for the cards you have in your binder.</p>
|
||||
</div>
|
||||
|
||||
<!-- Benefit 3 -->
|
||||
<div style="padding: 2rem; background: var(--bg-card, #1e293b); border-radius: 1rem; border: 1px solid var(--border-color, #334155); transition: transform 0.2s;">
|
||||
<div style="width: 50px; height: 50px; background: rgba(245, 158, 11, 0.1); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 1.5rem; color: #f59e0b;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
|
||||
</div>
|
||||
<h3 style="font-size: 1.25rem; font-weight: 600; margin-bottom: 1rem;">Secure Protection</h3>
|
||||
<p style="color: var(--text-muted, #94a3b8); line-height: 1.6;">Our Seller Protection Guarantee ensures you're covered against fraud, chargebacks, and shipping issues.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CTA Section -->
|
||||
<div style="padding: 4rem; background: linear-gradient(135deg, rgba(245, 158, 11, 0.1) 0%, rgba(30, 41, 59, 0) 100%); border-radius: 2rem; border: 1px solid rgba(245, 158, 11, 0.2);">
|
||||
<h2 style="font-size: 2rem; font-weight: 700; margin-bottom: 1rem;">Ready to Get Started?</h2>
|
||||
<p style="color: var(--text-muted, #94a3b8); margin-bottom: 2rem; max-width: 500px; margin-left: auto; margin-right: auto;">
|
||||
Create your account in less than 2 minutes and list your first card today. It's completely free to join.
|
||||
</p>
|
||||
<a href="{% url 'users:register' %}" class="btn" style="padding: 1rem 3rem; font-size: 1.1rem; box-shadow: 0 4px 14px 0 rgba(245, 158, 11, 0.39);">Create Seller Account</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
37
templates/users/seller_dashboard.html
Normal file
37
templates/users/seller_dashboard.html
Normal file
@@ -0,0 +1,37 @@
|
||||
{% extends 'base/layout.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}Seller Dashboard - TCGKof{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="dashboard-container" style="padding: 2rem 0;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem;">
|
||||
<h1 style="font-size: 2rem; font-weight: 700;">Seller Dashboard</h1>
|
||||
<a href="{% url 'store:card_list' %}" class="btn btn-outline">View Marketplace</a>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; margin-bottom: 3rem;">
|
||||
<!-- Stat Card 1 -->
|
||||
<div style="background: var(--bg-card, #1e293b); padding: 1.5rem; border-radius: 1rem; border: 1px solid var(--border-color, #334155);">
|
||||
<div style="color: var(--text-muted, #94a3b8); font-size: 0.875rem; margin-bottom: 0.5rem;">Total Sales</div>
|
||||
<div style="font-size: 1.5rem; font-weight: 700;">$0.00</div>
|
||||
</div>
|
||||
<!-- Stat Card 2 -->
|
||||
<div style="background: var(--bg-card, #1e293b); padding: 1.5rem; border-radius: 1rem; border: 1px solid var(--border-color, #334155);">
|
||||
<div style="color: var(--text-muted, #94a3b8); font-size: 0.875rem; margin-bottom: 0.5rem;">Active Listings</div>
|
||||
<div style="font-size: 1.5rem; font-weight: 700;">0</div>
|
||||
</div>
|
||||
<!-- Stat Card 3 -->
|
||||
<div style="background: var(--bg-card, #1e293b); padding: 1.5rem; border-radius: 1rem; border: 1px solid var(--border-color, #334155);">
|
||||
<div style="color: var(--text-muted, #94a3b8); font-size: 0.875rem; margin-bottom: 0.5rem;">Orders to Ship</div>
|
||||
<div style="font-size: 1.5rem; font-weight: 700;">0</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="background: var(--bg-card, #1e293b); padding: 2rem; border-radius: 1rem; border: 1px solid var(--border-color, #334155); text-align: center;">
|
||||
<h2 style="font-size: 1.5rem; font-weight: 600; margin-bottom: 1rem;">Start Listing</h2>
|
||||
<p style="color: var(--text-muted, #94a3b8); margin-bottom: 1.5rem;">You don't have any active listings yet. Add your cards to the marketplace to start selling.</p>
|
||||
<button class="btn" disabled style="opacity: 0.5; cursor: not-allowed;">Add New Listing (Coming Soon)</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -12,6 +12,14 @@
|
||||
<!-- Filters -->
|
||||
<div style="margin-bottom: 2rem; background: var(--card-bg); padding: 1rem; border-radius: 0.5rem; border: 1px solid var(--border-color);">
|
||||
<form method="get" style="display: flex; gap: 1rem; flex-wrap: wrap; align-items: center;">
|
||||
<div style="position: relative;">
|
||||
<label for="search-input" style="margin-right: 0.5rem; font-size: 0.875rem;">Search:</label>
|
||||
<input type="text" name="q" id="search-input" value="{{ search_query|default:'' }}" placeholder="Card name..." autocomplete="off"
|
||||
style="padding: 0.25rem 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);">
|
||||
<ul id="suggestions-list" style="display: none; position: absolute; top: 100%; left: 0; width: 100%; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 0.25rem; z-index: 1000; list-style: none; padding: 0; margin: 0; max-height: 200px; overflow-y: auto;">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="set" style="margin-right: 0.5rem; font-size: 0.875rem;">Set:</label>
|
||||
<select name="set" id="set" style="padding: 0.25rem 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);">
|
||||
@@ -35,6 +43,66 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const suggestionsList = document.getElementById('suggestions-list');
|
||||
let debounceTimer;
|
||||
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener('input', function() {
|
||||
const query = this.value;
|
||||
clearTimeout(debounceTimer);
|
||||
if (query.length < 2) {
|
||||
suggestionsList.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
debounceTimer = setTimeout(() => {
|
||||
// Correct URL for users app API
|
||||
fetch(`/users/api/vault-autocomplete/?q=${encodeURIComponent(query)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
suggestionsList.innerHTML = '';
|
||||
if (data.results.length > 0) {
|
||||
data.results.forEach(name => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = name;
|
||||
li.style.padding = '0.5rem';
|
||||
li.style.cursor = 'pointer';
|
||||
li.style.borderBottom = '1px solid var(--border-color)';
|
||||
|
||||
li.addEventListener('mouseenter', () => {
|
||||
li.style.background = 'var(--card-bg)';
|
||||
});
|
||||
li.addEventListener('mouseleave', () => {
|
||||
li.style.background = 'transparent';
|
||||
});
|
||||
|
||||
li.addEventListener('click', () => {
|
||||
searchInput.value = name;
|
||||
suggestionsList.style.display = 'none';
|
||||
searchInput.form.submit();
|
||||
});
|
||||
suggestionsList.appendChild(li);
|
||||
});
|
||||
suggestionsList.style.display = 'block';
|
||||
} else {
|
||||
suggestionsList.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target !== searchInput && e.target !== suggestionsList) {
|
||||
suggestionsList.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% if vault_items %}
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1.5rem;">
|
||||
{% for item in vault_items %}
|
||||
|
||||
Reference in New Issue
Block a user