142 lines
7.2 KiB
HTML
142 lines
7.2 KiB
HTML
{% extends 'base/layout.html' %}
|
|
{% load static %}
|
|
|
|
{% block content %}
|
|
<div style="display: grid; grid-template-columns: 250px 1fr; gap: 2rem;">
|
|
<!-- Sidebar Filters -->
|
|
<aside
|
|
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">
|
|
<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|slugify == 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;">
|
|
<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>
|
|
|
|
<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
|
|
Filters</a>
|
|
</form>
|
|
</aside>
|
|
|
|
<!-- Card Grid -->
|
|
<div>
|
|
<h2 style="margin-top: 0;">Browse Cards</h2>
|
|
<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;">
|
|
<div style="aspect-ratio: 2.5/3.5; background: #000; position: relative;">
|
|
<!-- Placeholder or Real Image -->
|
|
{% if card.image_url %}
|
|
<img src="{{ card.image_url }}" alt="{{ 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;">
|
|
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;">
|
|
{{ card.name }}</h4>
|
|
<div
|
|
style="display: flex; justify-content: space-between; align-items: center; font-size: 0.875rem; color: #94a3b8;">
|
|
<span>{{ card.set.code|default:card.set.game.name }}</span>
|
|
<span>{{ card.rarity }}</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;">
|
|
{% with card.listings.first as cheapest %}
|
|
{% if cheapest %}
|
|
<span style="font-weight: 700; color: var(--text-color);">From ${{ cheapest.price }}</span>
|
|
{% else %}
|
|
<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>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
{% empty %}
|
|
<p>No cards found matching your criteria.</p>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
{% 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"
|
|
style="padding: 0.25rem 0.5rem; font-size: 0.875rem;">Prev</a>
|
|
{% endif %}
|
|
|
|
<span
|
|
style="padding: 0.25rem 0.75rem; background: var(--card-bg); border-radius: 0.25rem; border: 1px solid var(--border-color);">
|
|
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
|
|
</span>
|
|
|
|
{% if page_obj.has_next %}
|
|
<a href="?page={{ page_obj.next_page_number }}&game={{ current_game }}&q={{ search_query }}" class="btn"
|
|
style="padding: 0.25rem 0.5rem; font-size: 0.875rem;">Next</a>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
const stockCounters = document.querySelectorAll('.stock-counter');
|
|
stockCounters.forEach(counter => {
|
|
const cardId = counter.getAttribute('data-card-id');
|
|
fetch(`/store/api/stock/${cardId}/`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.total_stock > 0) {
|
|
counter.textContent = `${data.total_stock} in stock`;
|
|
counter.style.color = '#10b981'; // green
|
|
} else {
|
|
counter.textContent = 'Out of Stock';
|
|
counter.style.color = '#ef4444'; // red
|
|
}
|
|
})
|
|
.catch(err => {
|
|
counter.textContent = 'Stock unknown';
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %} |