inital checkin
This commit is contained in:
142
templates/store/card_list.html
Normal file
142
templates/store/card_list.html
Normal file
@@ -0,0 +1,142 @@
|
||||
{% 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 %}
|
||||
Reference in New Issue
Block a user