Beta Final
This commit is contained in:
parent
77d103ab40
commit
9b6e5f4d03
@ -3,114 +3,203 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-2">
|
||||
<!-- Header with smaller button for mobile -->
|
||||
<!-- Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h4 class="mb-0 fw-bold">Accessories</h4>
|
||||
<a href="{% url 'add_accessory_item' %}" class="btn btn-primary btn-sm rounded-pill px-3 shadow-sm d-flex align-items-center">
|
||||
<i class="bi bi-plus-lg me-1"></i> <span class="d-none d-sm-inline">Add Accessory</span><span class="d-inline d-sm-none">Add</span>
|
||||
</a>
|
||||
<div class="d-flex gap-2">
|
||||
<!-- View Toggle -->
|
||||
<div class="btn-group btn-group-sm bg-secondary rounded-pill p-1 shadow-sm me-2">
|
||||
<button type="button" class="btn btn-sm rounded-pill px-3 active" id="view-grid" title="Grid View">
|
||||
<i class="fas fa-th-large"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm rounded-pill px-3" id="view-list" title="List View">
|
||||
<i class="fas fa-list"></i>
|
||||
</button>
|
||||
</div>
|
||||
<a href="{% url 'add_accessory_item' %}" class="btn btn-accent btn-sm rounded-pill px-3 shadow-sm d-flex align-items-center">
|
||||
<i class="fas fa-plus me-1"></i> <span class="d-none d-sm-inline">Add Accessory</span><span class="d-inline d-sm-none">Add</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter Toggle and Sort Bars -->
|
||||
<div class="mb-3">
|
||||
<button class="btn btn-outline-secondary btn-sm rounded-pill px-3 mb-2" type="button" data-bs-toggle="collapse" data-bs-target="#filterCollapse" aria-expanded="false">
|
||||
<i class="bi bi-filter me-1"></i> Filter
|
||||
<i class="fas fa-filter me-1"></i> Filter & Sort
|
||||
</button>
|
||||
|
||||
<div class="collapse {% if sort != 'recent' %}show{% endif %}" id="filterCollapse">
|
||||
<div class="d-flex flex-column gap-2 mt-2">
|
||||
<a href="?sort=recent{% if current_main %}&main_category={{ current_main.id }}{% endif %}{% if current_sub %}&subcategory={{ current_sub.id }}{% endif %}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}"
|
||||
class="btn {% if sort == 'recent' %}btn-lavender{% else %}btn-outline-secondary{% endif %} btn-sm py-2 text-start px-3 rounded-3 border-0 shadow-sm">
|
||||
Most Recently Added
|
||||
</a>
|
||||
<a href="?sort=alpha{% if current_main %}&main_category={{ current_main.id }}{% endif %}{% if current_sub %}&subcategory={{ current_sub.id }}{% endif %}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}"
|
||||
class="btn {% if sort == 'alpha' %}btn-lavender{% else %}btn-outline-secondary{% endif %} btn-sm py-2 text-start px-3 rounded-3 border-0 shadow-sm">
|
||||
A-Z
|
||||
</a>
|
||||
<div class="collapse {% if sort != 'recent' or request.GET.q %}show{% endif %}" id="filterCollapse">
|
||||
<div class="glass-card p-3 rounded-3 mb-3">
|
||||
<form method="get" class="mb-3">
|
||||
{% if current_main %}<input type="hidden" name="main_category" value="{{ current_main.id }}">{% endif %}
|
||||
{% if current_sub %}<input type="hidden" name="subcategory" value="{{ current_sub.id }}">{% endif %}
|
||||
<input type="hidden" name="sort" value="{{ sort }}">
|
||||
<div class="input-group input-group-sm bg-secondary rounded-pill px-2">
|
||||
<span class="input-group-text bg-transparent border-0 text-dim"><i class="fas fa-search"></i></span>
|
||||
<input type="text" name="q" class="form-control bg-transparent border-0 text-white" placeholder="Search accessories..." value="{{ request.GET.q }}">
|
||||
{% if request.GET.q %}
|
||||
<a href="?sort={{ sort }}{% if current_main %}&main_category={{ current_main.id }}{% endif %}{% if current_sub %}&subcategory={{ current_sub.id }}{% endif %}" class="btn btn-link text-dim p-0 me-2 d-flex align-items-center">
|
||||
<i class="fas fa-times-circle"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<a href="?sort=recent{% if current_main %}&main_category={{ current_main.id }}{% endif %}{% if current_sub %}&subcategory={{ current_sub.id }}{% endif %}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}"
|
||||
class="btn {% if sort == 'recent' %}btn-accent{% else %}btn-outline-secondary{% endif %} btn-xs rounded-pill px-3">
|
||||
Newest
|
||||
</a>
|
||||
<a href="?sort=alpha{% if current_main %}&main_category={{ current_main.id }}{% endif %}{% if current_sub %}&subcategory={{ current_sub.id }}{% endif %}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}"
|
||||
class="btn {% if sort == 'alpha' %}btn-accent{% else %}btn-outline-secondary{% endif %} btn-xs rounded-pill px-3">
|
||||
A-Z
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Categories Tabs -->
|
||||
<ul class="nav nav-pills mb-3 overflow-auto flex-nowrap pb-2 gap-2" id="mainCatTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link rounded-pill py-1 px-3 small {% if not current_main %}active bg-lavender{% else %}bg-secondary text-white{% endif %}" href="?sort={{ sort }}">All</a>
|
||||
</li>
|
||||
<div class="d-flex gap-2 overflow-auto no-scrollbar pb-3 mb-2">
|
||||
<a class="btn btn-xs rounded-pill px-3 {% if not current_main %}btn-accent{% else %}btn-outline-secondary{% endif %}" href="?sort={{ sort }}">All</a>
|
||||
{% for main_cat in main_categories %}
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link rounded-pill py-1 px-3 small {% if current_main.id == main_cat.id %}active bg-lavender{% else %}bg-secondary text-white{% endif %}"
|
||||
href="?main_category={{ main_cat.id }}&sort={{ sort }}">{{ main_cat.name }}</a>
|
||||
</li>
|
||||
<a class="btn btn-xs rounded-pill px-3 {% if current_main.id == main_cat.id %}btn-accent{% else %}btn-outline-secondary{% endif %}"
|
||||
href="?main_category={{ main_cat.id }}&sort={{ sort }}">{{ main_cat.name }}</a>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Subcategories Tabs -->
|
||||
{% if current_main and subcategories %}
|
||||
<div class="mb-3 overflow-auto">
|
||||
<div class="d-flex flex-nowrap gap-2 pb-2">
|
||||
<a href="?main_category={{ current_main.id }}&sort={{ sort }}"
|
||||
class="btn btn-sm {% if not current_sub %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill py-1 px-3 small">
|
||||
All {{ current_main.name }}
|
||||
</a>
|
||||
{% for sub in subcategories %}
|
||||
<a href="?main_category={{ current_main.id }}&subcategory={{ sub.id }}&sort={{ sort }}"
|
||||
class="btn btn-sm {% if current_sub.id == sub.id %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill py-1 px-3 small">
|
||||
{{ sub.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="d-flex gap-2 overflow-auto no-scrollbar pb-3 mb-3">
|
||||
<a href="?main_category={{ current_main.id }}&sort={{ sort }}"
|
||||
class="btn btn-xs {% if not current_sub %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill px-3">
|
||||
All {{ current_main.name }}
|
||||
</a>
|
||||
{% for sub in subcategories %}
|
||||
<a href="?main_category={{ current_main.id }}&subcategory={{ sub.id }}&sort={{ sort }}"
|
||||
class="btn btn-xs {% if current_sub.id == sub.id %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill px-3">
|
||||
{{ sub.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Search Bar -->
|
||||
<form method="get" class="mb-4">
|
||||
{% if current_main %}<input type="hidden" name="main_category" value="{{ current_main.id }}">{% endif %}
|
||||
{% if current_sub %}<input type="hidden" name="subcategory" value="{{ current_sub.id }}">{% endif %}
|
||||
<input type="hidden" name="sort" value="{{ sort }}">
|
||||
<div class="input-group input-group-sm glass-card p-1">
|
||||
<span class="input-group-text bg-transparent border-0 text-dim"><i class="fas fa-search"></i></span>
|
||||
<input type="text" name="q" class="form-control bg-transparent border-0 text-white" placeholder="Search accessories..." value="{{ request.GET.q }}">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Items Grid -->
|
||||
<div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-5 g-3">
|
||||
<!-- Items Grid/List Container -->
|
||||
<div class="row g-2" id="items-container">
|
||||
{% for item in items %}
|
||||
<div class="col">
|
||||
<div class="card h-100 bg-dark text-white border-secondary shadow-sm hover-card position-relative overflow-hidden" style="border-radius: 12px;">
|
||||
<div class="item-wrapper col-4 col-sm-3 col-md-2">
|
||||
<div class="item-card position-relative rounded-1 d-flex flex-column align-items-center p-1" style="cursor: pointer; transition: all 0.1s;">
|
||||
<a href="{% url 'accessory_item_detail' item.pk %}" class="stretched-link"></a>
|
||||
{% if item.image %}
|
||||
<img src="{{ item.image.url }}" class="card-img-top" style="aspect-ratio: 1/1; object-fit: cover;" alt="{{ item.name }}">
|
||||
{% else %}
|
||||
<div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" style="aspect-ratio: 1/1;">
|
||||
<i class="bi bi-gem text-muted" style="font-size: 2rem;"></i>
|
||||
|
||||
<!-- Grid Content (Default) -->
|
||||
<div class="item-img-container position-relative rounded-1 overflow-hidden bg-secondary w-100 shadow-sm" style="aspect-ratio: 1/1;">
|
||||
{% if item.image %}
|
||||
<img src="{{ item.image.url }}" class="w-100 h-100 object-fit-contain">
|
||||
{% else %}
|
||||
<div class="w-100 h-100 d-flex align-items-center justify-content-center">
|
||||
<i class="fas fa-gem text-muted"></i>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body p-2">
|
||||
<h6 class="card-title mb-0 text-truncate small fw-bold">{{ item.name|default:"Unnamed" }}</h6>
|
||||
<p class="card-text text-dim mb-0" style="font-size: 0.7rem;">{{ item.category.name|default:"Uncategorized" }}</p>
|
||||
<div class="item-name-label mt-1 text-center small text-truncate w-100 px-1" style="font-size: 0.65rem; color: var(--text-main);">
|
||||
{{ item.name|default:"Unnamed" }}
|
||||
</div>
|
||||
|
||||
<!-- List Content (Hidden) -->
|
||||
<div class="item-list-content d-none w-100 align-items-center gap-2 px-1 py-1">
|
||||
<div class="list-img-box rounded-1 bg-secondary overflow-hidden" style="width: 28px; height: 28px; flex-shrink: 0;">
|
||||
{% if item.image %}
|
||||
<img src="{{ item.image.url }}" class="w-100 h-100 object-fit-cover">
|
||||
{% else %}
|
||||
<div class="w-100 h-100 d-flex align-items-center justify-content-center">
|
||||
<i class="fas fa-gem text-muted" style="font-size: 0.5rem;"></i>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="flex-grow-1 text-truncate">
|
||||
<div class="small fw-bold text-truncate" style="font-size: 0.75rem;">{{ item.name|default:"Unnamed" }}</div>
|
||||
<div class="text-dim text-truncate" style="font-size: 0.6rem;">{{ item.category.name|default:"Uncategorized" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if item.season %}
|
||||
<span class="badge bg-primary position-absolute top-0 end-0 m-2" style="font-size: 0.6rem;">{{ item.get_season_display }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="col-12 text-center py-5">
|
||||
<i class="bi bi-inbox text-dim" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2 text-dim">No accessories found.</p>
|
||||
<i class="fas fa-gem text-dim mb-2" style="font-size: 3rem;"></i>
|
||||
<p class="text-dim">No accessories found.</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.bg-lavender { background-color: var(--accent-lavender) !important; color: #fff !important; }
|
||||
.btn-lavender { background-color: var(--accent-lavender); color: #fff; }
|
||||
.text-dim { color: var(--text-dim); }
|
||||
.hover-card { transition: transform 0.2s, box-shadow 0.2s; }
|
||||
.hover-card:hover { transform: translateY(-5px); box-shadow: 0 10px 20px rgba(0,0,0,0.5) !important; z-index: 1; }
|
||||
.nav-pills .nav-link { border: 1px solid transparent; }
|
||||
.border-secondary { border-color: rgba(255,255,255,0.1) !important; }
|
||||
.item-card:hover {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.list-mode .item-card {
|
||||
flex-direction: row !important;
|
||||
align-items: center !important;
|
||||
padding: 4px 8px !important;
|
||||
}
|
||||
.list-mode .item-img-container,
|
||||
.list-mode .item-name-label {
|
||||
display: none !important;
|
||||
}
|
||||
.list-mode .item-list-content {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||
.object-fit-contain { object-fit: contain; }
|
||||
.object-fit-cover { object-fit: cover; }
|
||||
|
||||
.btn-xs {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const viewGrid = document.getElementById('view-grid');
|
||||
const viewList = document.getElementById('view-list');
|
||||
const itemsContainer = document.getElementById('items-container');
|
||||
const wrappers = document.querySelectorAll('.item-wrapper');
|
||||
|
||||
if (viewGrid && viewList) {
|
||||
viewGrid.addEventListener('click', () => {
|
||||
viewGrid.classList.add('active');
|
||||
viewList.classList.remove('active');
|
||||
itemsContainer.classList.remove('list-mode');
|
||||
wrappers.forEach(w => {
|
||||
w.className = 'item-wrapper col-4 col-sm-3 col-md-2';
|
||||
});
|
||||
localStorage.setItem('accessories_view', 'grid');
|
||||
});
|
||||
|
||||
viewList.addEventListener('click', () => {
|
||||
viewList.classList.add('active');
|
||||
viewGrid.classList.remove('active');
|
||||
itemsContainer.classList.add('list-mode');
|
||||
wrappers.forEach(w => {
|
||||
w.className = 'item-wrapper col-12 col-sm-6 col-md-4';
|
||||
});
|
||||
localStorage.setItem('accessories_view', 'list');
|
||||
});
|
||||
|
||||
// Restore preference
|
||||
const savedView = localStorage.getItem('accessories_view');
|
||||
if (savedView === 'list') {
|
||||
viewList.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@ -40,10 +40,10 @@
|
||||
<div class="small text-accent" id="item-count">0 selected</div>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm bg-secondary rounded-pill p-1 shadow-sm">
|
||||
<button type="button" class="btn btn-sm rounded-pill px-3 active" id="view-grid-img" title="Pictures">
|
||||
<button type="button" class="btn btn-sm rounded-pill px-3 active" id="view-grid-img" title="Grid View (Icons)">
|
||||
<i class="fas fa-th-large"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm rounded-pill px-3" id="view-grid-text" title="Names Only">
|
||||
<button type="button" class="btn btn-sm rounded-pill px-3" id="view-list-mode" title="List View (Details)">
|
||||
<i class="fas fa-list"></i>
|
||||
</button>
|
||||
</div>
|
||||
@ -65,25 +65,35 @@
|
||||
</div>
|
||||
|
||||
<!-- Wardrobe Item Grid -->
|
||||
<div class="item-grid-container glass-card p-3 mb-4" style="height: 350px; overflow-y: auto;">
|
||||
<div class="row g-3" id="wardrobe-items-grid">
|
||||
<div class="item-grid-container glass-card p-3 mb-4" style="height: 380px; overflow-y: auto;">
|
||||
<div class="row g-2" id="wardrobe-items-grid">
|
||||
{% for item in wardrobe_items %}
|
||||
<div class="col-4 col-sm-3 col-md-2 item-wrapper"
|
||||
<div class="item-wrapper col-4 col-sm-3 col-md-2"
|
||||
data-cat-id="{% if item.category %}{{ item.category.id }}{% else %}none{% endif %}"
|
||||
data-parent-cat-id="{% if item.category %}{% if item.category.parent %}{{ item.category.parent.id }}{% else %}{{ item.category.id }}{% endif %}{% else %}none{% endif %}">
|
||||
<div class="item-card position-relative rounded-2 d-flex flex-column align-items-center p-2"
|
||||
data-id="{{ item.id }}" data-real-id="{{ item.id }}" data-type="item" style="cursor: pointer; transition: background 0.2s;">
|
||||
<div class="item-img-container position-relative rounded-2 overflow-hidden bg-secondary w-100 shadow-sm" style="aspect-ratio: 1/1;">
|
||||
<div class="item-card position-relative rounded-1 d-flex flex-column align-items-center p-1"
|
||||
data-id="{{ item.id }}" data-real-id="{{ item.id }}" data-type="item" style="cursor: pointer; transition: all 0.1s;">
|
||||
|
||||
<!-- Grid Content -->
|
||||
<div class="item-img-container position-relative rounded-1 overflow-hidden bg-secondary w-100 shadow-sm" style="aspect-ratio: 1/1;">
|
||||
<img src="{{ item.image.url }}" class="w-100 h-100 object-fit-contain item-img">
|
||||
<div class="check-overlay position-absolute top-0 end-0 p-1 d-none" style="z-index: 5;">
|
||||
<i class="fas fa-check-circle text-primary-accent shadow-sm" style="background: white; border-radius: 50%;"></i>
|
||||
<i class="fas fa-check-circle text-primary-accent bg-white rounded-circle shadow-sm"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-name-label mt-1 text-center small text-truncate w-100 px-1" style="font-size: 0.65rem; color: var(--text-main);">
|
||||
{{ item.name|default:"Item" }}
|
||||
</div>
|
||||
<div class="item-name-only d-none w-100 rounded-2 bg-secondary align-items-center justify-content-center p-2 text-center small fw-bold shadow-sm" style="aspect-ratio: 1/1; font-size: 0.7rem;">
|
||||
{{ item.name|default:"Item" }}
|
||||
|
||||
<!-- List Content (Hidden by default) -->
|
||||
<div class="item-list-content d-none w-100 align-items-center gap-2 px-1 py-1 position-relative">
|
||||
<div class="list-img-box rounded-1 bg-secondary overflow-hidden" style="width: 28px; height: 28px; flex-shrink: 0;">
|
||||
<img src="{{ item.image.url }}" class="w-100 h-100 object-fit-cover">
|
||||
</div>
|
||||
<span class="small text-truncate flex-grow-1" style="font-size: 0.75rem;">{{ item.name|default:"Item" }}</span>
|
||||
<div class="list-check-overlay d-none">
|
||||
<i class="fas fa-check-circle text-primary-accent" style="font-size: 0.8rem;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -94,22 +104,32 @@
|
||||
<div class="mb-4">
|
||||
<label class="form-label text-dim small text-uppercase fw-bold mb-2">Select Accessories</label>
|
||||
<div class="item-grid-container glass-card p-3" style="max-height: 250px; overflow-y: auto;">
|
||||
<div class="row g-3" id="accessories-grid">
|
||||
<div class="row g-2" id="accessories-grid">
|
||||
{% for acc in accessories %}
|
||||
<div class="col-4 col-sm-3 col-md-2 accessory-wrapper">
|
||||
<div class="item-card position-relative rounded-2 d-flex flex-column align-items-center p-2"
|
||||
data-id="{{ acc.id }}" data-real-id="{{ acc.id }}" data-type="accessory" style="cursor: pointer; transition: background 0.2s;">
|
||||
<div class="item-img-container position-relative rounded-2 overflow-hidden bg-secondary w-100 shadow-sm" style="aspect-ratio: 1/1;">
|
||||
<div class="item-wrapper col-4 col-sm-3 col-md-2">
|
||||
<div class="item-card position-relative rounded-1 d-flex flex-column align-items-center p-1"
|
||||
data-id="{{ acc.id }}" data-real-id="{{ acc.id }}" data-type="accessory" style="cursor: pointer; transition: all 0.1s;">
|
||||
|
||||
<!-- Grid Content -->
|
||||
<div class="item-img-container position-relative rounded-1 overflow-hidden bg-secondary w-100 shadow-sm" style="aspect-ratio: 1/1;">
|
||||
<img src="{{ acc.image.url }}" class="w-100 h-100 object-fit-contain item-img">
|
||||
<div class="check-overlay position-absolute top-0 end-0 p-1 d-none" style="z-index: 5;">
|
||||
<i class="fas fa-check-circle text-primary-accent shadow-sm" style="background: white; border-radius: 50%;"></i>
|
||||
<i class="fas fa-check-circle text-primary-accent bg-white rounded-circle shadow-sm"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-name-label mt-1 text-center small text-truncate w-100 px-1" style="font-size: 0.65rem; color: var(--text-main);">
|
||||
{{ acc.name|default:"Acc" }}
|
||||
</div>
|
||||
<div class="item-name-only d-none w-100 rounded-2 bg-secondary align-items-center justify-content-center p-2 text-center small fw-bold shadow-sm" style="aspect-ratio: 1/1; font-size: 0.7rem;">
|
||||
{{ acc.name|default:"Acc" }}
|
||||
|
||||
<!-- List Content (Hidden by default) -->
|
||||
<div class="item-list-content d-none w-100 align-items-center gap-2 px-1 py-1 position-relative">
|
||||
<div class="list-img-box rounded-1 bg-secondary overflow-hidden" style="width: 28px; height: 28px; flex-shrink: 0;">
|
||||
<img src="{{ acc.image.url }}" class="w-100 h-100 object-fit-cover">
|
||||
</div>
|
||||
<span class="small text-truncate flex-grow-1" style="font-size: 0.75rem;">{{ acc.name|default:"Acc" }}</span>
|
||||
<div class="list-check-overlay d-none">
|
||||
<i class="fas fa-check-circle text-primary-accent" style="font-size: 0.8rem;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -145,22 +165,37 @@
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
/* Windows Folder Grid Inspired Styling */
|
||||
/* Windows Folder Grid & List Styling */
|
||||
.item-card:hover {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.item-card.selected {
|
||||
background-color: rgba(var(--primary-accent-rgb, 187, 134, 252), 0.15) !important;
|
||||
}
|
||||
.item-card.selected .item-img-container,
|
||||
.item-card.selected .item-name-only {
|
||||
outline: 2px solid var(--primary-accent) !important;
|
||||
outline-offset: -2px;
|
||||
background-color: rgba(var(--primary-accent-rgb, 187, 134, 252), 0.2) !important;
|
||||
outline: 1px solid var(--primary-accent);
|
||||
}
|
||||
|
||||
/* Grid View Styles */
|
||||
.item-card.selected .check-overlay {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/* List View Styles */
|
||||
.list-mode .item-card {
|
||||
flex-direction: row !important;
|
||||
align-items: center !important;
|
||||
padding: 4px 8px !important;
|
||||
}
|
||||
.list-mode .item-img-container,
|
||||
.list-mode .item-name-label {
|
||||
display: none !important;
|
||||
}
|
||||
.list-mode .item-list-content {
|
||||
display: flex !important;
|
||||
}
|
||||
.list-mode .item-card.selected .list-check-overlay {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.border-transparent { border-color: transparent; }
|
||||
.text-primary-accent { color: var(--primary-accent); }
|
||||
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||
@ -171,15 +206,8 @@
|
||||
border-color: var(--primary-accent) !important;
|
||||
}
|
||||
|
||||
.item-card.text-only .item-img-container,
|
||||
.item-card.text-only .item-name-label {
|
||||
display: none !important;
|
||||
}
|
||||
.item-card.text-only .item-name-only {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.object-fit-contain { object-fit: contain; }
|
||||
.object-fit-cover { object-fit: cover; }
|
||||
|
||||
.item-grid-container::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
@ -209,7 +237,9 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const itemWrappers = document.querySelectorAll('.item-wrapper');
|
||||
|
||||
const viewGridImg = document.getElementById('view-grid-img');
|
||||
const viewGridText = document.getElementById('view-grid-text');
|
||||
const viewListMode = document.getElementById('view-list-mode');
|
||||
const wardrobeGrid = document.getElementById('wardrobe-items-grid');
|
||||
const accessoriesGrid = document.getElementById('accessories-grid');
|
||||
|
||||
function updateBadge() {
|
||||
const selectedCount = document.querySelectorAll('.item-card.selected').length;
|
||||
@ -238,20 +268,29 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
|
||||
// View Toggle Logic
|
||||
if (viewGridImg && viewGridText) {
|
||||
if (viewGridImg && viewListMode) {
|
||||
viewGridImg.addEventListener('click', () => {
|
||||
viewGridImg.classList.add('active');
|
||||
viewGridText.classList.remove('active');
|
||||
document.querySelectorAll('.item-card').forEach(card => {
|
||||
card.classList.remove('text-only');
|
||||
viewListMode.classList.remove('active');
|
||||
|
||||
wardrobeGrid.classList.remove('list-mode');
|
||||
accessoriesGrid.classList.remove('list-mode');
|
||||
|
||||
document.querySelectorAll('.item-wrapper').forEach(w => {
|
||||
w.className = 'item-wrapper col-4 col-sm-3 col-md-2';
|
||||
});
|
||||
});
|
||||
|
||||
viewGridText.addEventListener('click', () => {
|
||||
viewGridText.classList.add('active');
|
||||
viewListMode.addEventListener('click', () => {
|
||||
viewListMode.classList.add('active');
|
||||
viewGridImg.classList.remove('active');
|
||||
document.querySelectorAll('.item-card').forEach(card => {
|
||||
card.classList.add('text-only');
|
||||
|
||||
wardrobeGrid.classList.add('list-mode');
|
||||
accessoriesGrid.classList.add('list-mode');
|
||||
|
||||
// In List mode, we want wider columns
|
||||
document.querySelectorAll('.item-wrapper').forEach(w => {
|
||||
w.className = 'item-wrapper col-12 col-sm-6 col-md-4';
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -259,6 +298,9 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
// Category Filtering Logic
|
||||
function filterItems(mainCatId, subCatId = null) {
|
||||
itemWrappers.forEach(wrapper => {
|
||||
// Only filter wardrobe items, not accessories which might not have categories in this context
|
||||
if (!wrapper.dataset.parentCatId) return;
|
||||
|
||||
const itemMainCatId = wrapper.dataset.parentCatId;
|
||||
const itemSubCatId = wrapper.dataset.catId;
|
||||
|
||||
@ -338,4 +380,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
updateBadge();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@ -6,111 +6,200 @@
|
||||
<!-- Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h4 class="mb-0 fw-bold">Wardrobe</h4>
|
||||
<a href="{% url 'add_wardrobe_item' %}" class="btn btn-primary btn-sm rounded-pill px-3 shadow-sm d-flex align-items-center">
|
||||
<i class="bi bi-plus-lg me-1"></i> <span class="d-none d-sm-inline">Add Item</span><span class="d-inline d-sm-none">Add</span>
|
||||
</a>
|
||||
<div class="d-flex gap-2">
|
||||
<!-- View Toggle -->
|
||||
<div class="btn-group btn-group-sm bg-secondary rounded-pill p-1 shadow-sm me-2">
|
||||
<button type="button" class="btn btn-sm rounded-pill px-3 active" id="view-grid" title="Grid View">
|
||||
<i class="fas fa-th-large"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm rounded-pill px-3" id="view-list" title="List View">
|
||||
<i class="fas fa-list"></i>
|
||||
</button>
|
||||
</div>
|
||||
<a href="{% url 'add_wardrobe_item' %}" class="btn btn-accent btn-sm rounded-pill px-3 shadow-sm d-flex align-items-center">
|
||||
<i class="fas fa-plus me-1"></i> <span class="d-none d-sm-inline">Add Item</span><span class="d-inline d-sm-none">Add</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter Toggle and Sort Bars -->
|
||||
<div class="mb-3">
|
||||
<button class="btn btn-outline-secondary btn-sm rounded-pill px-3 mb-2" type="button" data-bs-toggle="collapse" data-bs-target="#filterCollapse" aria-expanded="false">
|
||||
<i class="bi bi-filter me-1"></i> Filter
|
||||
<i class="fas fa-filter me-1"></i> Filter & Sort
|
||||
</button>
|
||||
|
||||
<div class="collapse {% if sort != 'recent' %}show{% endif %}" id="filterCollapse">
|
||||
<div class="d-flex flex-column gap-2 mt-2">
|
||||
<a href="?sort=recent{% if current_main %}&main_category={{ current_main.id }}{% endif %}{% if current_sub %}&subcategory={{ current_sub.id }}{% endif %}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}"
|
||||
class="btn {% if sort == 'recent' %}btn-lavender{% else %}btn-outline-secondary{% endif %} btn-sm py-2 text-start px-3 rounded-3 border-0 shadow-sm">
|
||||
Most Recently Added
|
||||
</a>
|
||||
<a href="?sort=alpha{% if current_main %}&main_category={{ current_main.id }}{% endif %}{% if current_sub %}&subcategory={{ current_sub.id }}{% endif %}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}"
|
||||
class="btn {% if sort == 'alpha' %}btn-lavender{% else %}btn-outline-secondary{% endif %} btn-sm py-2 text-start px-3 rounded-3 border-0 shadow-sm">
|
||||
A-Z
|
||||
</a>
|
||||
<div class="collapse {% if sort != 'recent' or request.GET.q %}show{% endif %}" id="filterCollapse">
|
||||
<div class="glass-card p-3 rounded-3 mb-3">
|
||||
<form method="get" class="mb-3">
|
||||
{% if current_main %}<input type="hidden" name="main_category" value="{{ current_main.id }}">{% endif %}
|
||||
{% if current_sub %}<input type="hidden" name="subcategory" value="{{ current_sub.id }}">{% endif %}
|
||||
<input type="hidden" name="sort" value="{{ sort }}">
|
||||
<div class="input-group input-group-sm bg-secondary rounded-pill px-2">
|
||||
<span class="input-group-text bg-transparent border-0 text-dim"><i class="fas fa-search"></i></span>
|
||||
<input type="text" name="q" class="form-control bg-transparent border-0 text-white" placeholder="Search items..." value="{{ request.GET.q }}">
|
||||
{% if request.GET.q %}
|
||||
<a href="?sort={{ sort }}{% if current_main %}&main_category={{ current_main.id }}{% endif %}{% if current_sub %}&subcategory={{ current_sub.id }}{% endif %}" class="btn btn-link text-dim p-0 me-2 d-flex align-items-center">
|
||||
<i class="fas fa-times-circle"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<a href="?sort=recent{% if current_main %}&main_category={{ current_main.id }}{% endif %}{% if current_sub %}&subcategory={{ current_sub.id }}{% endif %}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}"
|
||||
class="btn {% if sort == 'recent' %}btn-accent{% else %}btn-outline-secondary{% endif %} btn-xs rounded-pill px-3">
|
||||
Newest
|
||||
</a>
|
||||
<a href="?sort=alpha{% if current_main %}&main_category={{ current_main.id }}{% endif %}{% if current_sub %}&subcategory={{ current_sub.id }}{% endif %}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}"
|
||||
class="btn {% if sort == 'alpha' %}btn-accent{% else %}btn-outline-secondary{% endif %} btn-xs rounded-pill px-3">
|
||||
A-Z
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Categories Tabs -->
|
||||
<ul class="nav nav-pills mb-3 overflow-auto flex-nowrap pb-2 gap-2" id="mainCatTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link rounded-pill py-1 px-3 small {% if not current_main %}active bg-lavender{% else %}bg-secondary text-white{% endif %}" href="?sort={{ sort }}">All</a>
|
||||
</li>
|
||||
<div class="d-flex gap-2 overflow-auto no-scrollbar pb-3 mb-2">
|
||||
<a class="btn btn-xs rounded-pill px-3 {% if not current_main %}btn-accent{% else %}btn-outline-secondary{% endif %}" href="?sort={{ sort }}">All</a>
|
||||
{% for main_cat in main_categories %}
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link rounded-pill py-1 px-3 small {% if current_main.id == main_cat.id %}active bg-lavender{% else %}bg-secondary text-white{% endif %}"
|
||||
href="?main_category={{ main_cat.id }}&sort={{ sort }}">{{ main_cat.name }}</a>
|
||||
</li>
|
||||
<a class="btn btn-xs rounded-pill px-3 {% if current_main.id == main_cat.id %}btn-accent{% else %}btn-outline-secondary{% endif %}"
|
||||
href="?main_category={{ main_cat.id }}&sort={{ sort }}">{{ main_cat.name }}</a>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Subcategories Tabs -->
|
||||
{% if current_main and subcategories %}
|
||||
<div class="mb-3 overflow-auto">
|
||||
<div class="d-flex flex-nowrap gap-2 pb-2">
|
||||
<a href="?main_category={{ current_main.id }}&sort={{ sort }}"
|
||||
class="btn btn-sm {% if not current_sub %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill py-1 px-3 small">
|
||||
All {{ current_main.name }}
|
||||
</a>
|
||||
{% for sub in subcategories %}
|
||||
<a href="?main_category={{ current_main.id }}&subcategory={{ sub.id }}&sort={{ sort }}"
|
||||
class="btn btn-sm {% if current_sub.id == sub.id %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill py-1 px-3 small">
|
||||
{{ sub.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="d-flex gap-2 overflow-auto no-scrollbar pb-3 mb-3">
|
||||
<a href="?main_category={{ current_main.id }}&sort={{ sort }}"
|
||||
class="btn btn-xs {% if not current_sub %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill px-3">
|
||||
All {{ current_main.name }}
|
||||
</a>
|
||||
{% for sub in subcategories %}
|
||||
<a href="?main_category={{ current_main.id }}&subcategory={{ sub.id }}&sort={{ sort }}"
|
||||
class="btn btn-xs {% if current_sub.id == sub.id %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill px-3">
|
||||
{{ sub.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Search Bar -->
|
||||
<form method="get" class="mb-4">
|
||||
{% if current_main %}<input type="hidden" name="main_category" value="{{ current_main.id }}">{% endif %}
|
||||
{% if current_sub %}<input type="hidden" name="subcategory" value="{{ current_sub.id }}">{% endif %}
|
||||
<input type="hidden" name="sort" value="{{ sort }}">
|
||||
<div class="input-group input-group-sm glass-card p-1">
|
||||
<span class="input-group-text bg-transparent border-0 text-dim"><i class="fas fa-search"></i></span>
|
||||
<input type="text" name="q" class="form-control bg-transparent border-0 text-white" placeholder="Search wardrobe..." value="{{ request.GET.q }}">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Items Grid -->
|
||||
<div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-5 g-3">
|
||||
<!-- Items Grid/List Container -->
|
||||
<div class="row g-2" id="items-container">
|
||||
{% for item in items %}
|
||||
<div class="col">
|
||||
<div class="card h-100 bg-dark text-white border-secondary shadow-sm hover-card position-relative overflow-hidden" style="border-radius: 12px;">
|
||||
<div class="item-wrapper col-4 col-sm-3 col-md-2">
|
||||
<div class="item-card position-relative rounded-1 d-flex flex-column align-items-center p-1" style="cursor: pointer; transition: all 0.1s;">
|
||||
<a href="{% url 'wardrobe_item_detail' item.pk %}" class="stretched-link"></a>
|
||||
{% if item.image %}
|
||||
<img src="{{ item.image.url }}" class="card-img-top" style="aspect-ratio: 3/4; object-fit: cover;" alt="{{ item.name }}">
|
||||
{% else %}
|
||||
<div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" style="aspect-ratio: 3/4;">
|
||||
<i class="bi bi-image text-muted" style="font-size: 2rem;"></i>
|
||||
|
||||
<!-- Grid Content (Default) -->
|
||||
<div class="item-img-container position-relative rounded-1 overflow-hidden bg-secondary w-100 shadow-sm" style="aspect-ratio: 1/1;">
|
||||
{% if item.image %}
|
||||
<img src="{{ item.image.url }}" class="w-100 h-100 object-fit-contain">
|
||||
{% else %}
|
||||
<div class="w-100 h-100 d-flex align-items-center justify-content-center">
|
||||
<i class="fas fa-image text-muted"></i>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body p-2">
|
||||
<h6 class="card-title mb-0 text-truncate small fw-bold">{{ item.name|default:"Unnamed" }}</h6>
|
||||
<p class="card-text text-dim mb-0" style="font-size: 0.7rem;">{{ item.category.name|default:"Uncategorized" }}</p>
|
||||
<div class="item-name-label mt-1 text-center small text-truncate w-100 px-1" style="font-size: 0.65rem; color: var(--text-main);">
|
||||
{{ item.name|default:"Unnamed" }}
|
||||
</div>
|
||||
|
||||
<!-- List Content (Hidden) -->
|
||||
<div class="item-list-content d-none w-100 align-items-center gap-2 px-1 py-1">
|
||||
<div class="list-img-box rounded-1 bg-secondary overflow-hidden" style="width: 28px; height: 28px; flex-shrink: 0;">
|
||||
{% if item.image %}
|
||||
<img src="{{ item.image.url }}" class="w-100 h-100 object-fit-cover">
|
||||
{% else %}
|
||||
<div class="w-100 h-100 d-flex align-items-center justify-content-center">
|
||||
<i class="fas fa-image text-muted" style="font-size: 0.5rem;"></i>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="flex-grow-1 text-truncate">
|
||||
<div class="small fw-bold text-truncate" style="font-size: 0.75rem;">{{ item.name|default:"Unnamed" }}</div>
|
||||
<div class="text-dim text-truncate" style="font-size: 0.6rem;">{{ item.category.name|default:"Uncategorized" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if item.season %}
|
||||
<span class="badge bg-primary position-absolute top-0 end-0 m-2" style="font-size: 0.6rem;">{{ item.get_season_display }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="col-12 text-center py-5">
|
||||
<i class="bi bi-inbox text-dim" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2 text-dim">No items found.</p>
|
||||
<i class="fas fa-box-open text-dim mb-2" style="font-size: 3rem;"></i>
|
||||
<p class="text-dim">No items found in your wardrobe.</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.bg-lavender { background-color: var(--accent-lavender) !important; color: #fff !important; }
|
||||
.btn-lavender { background-color: var(--accent-lavender); color: #fff; }
|
||||
.text-dim { color: var(--text-dim); }
|
||||
.hover-card { transition: transform 0.2s, box-shadow 0.2s; }
|
||||
.hover-card:hover { transform: translateY(-5px); box-shadow: 0 10px 20px rgba(0,0,0,0.5) !important; z-index: 1; }
|
||||
.nav-pills .nav-link { border: 1px solid transparent; }
|
||||
.border-secondary { border-color: rgba(255,255,255,0.1) !important; }
|
||||
.item-card:hover {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.list-mode .item-card {
|
||||
flex-direction: row !important;
|
||||
align-items: center !important;
|
||||
padding: 4px 8px !important;
|
||||
}
|
||||
.list-mode .item-img-container,
|
||||
.list-mode .item-name-label {
|
||||
display: none !important;
|
||||
}
|
||||
.list-mode .item-list-content {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||
.object-fit-contain { object-fit: contain; }
|
||||
.object-fit-cover { object-fit: cover; }
|
||||
|
||||
.btn-xs {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const viewGrid = document.getElementById('view-grid');
|
||||
const viewList = document.getElementById('view-list');
|
||||
const itemsContainer = document.getElementById('items-container');
|
||||
const wrappers = document.querySelectorAll('.item-wrapper');
|
||||
|
||||
if (viewGrid && viewList) {
|
||||
viewGrid.addEventListener('click', () => {
|
||||
viewGrid.classList.add('active');
|
||||
viewList.classList.remove('active');
|
||||
itemsContainer.classList.remove('list-mode');
|
||||
wrappers.forEach(w => {
|
||||
w.className = 'item-wrapper col-4 col-sm-3 col-md-2';
|
||||
});
|
||||
localStorage.setItem('wardrobe_view', 'grid');
|
||||
});
|
||||
|
||||
viewList.addEventListener('click', () => {
|
||||
viewList.classList.add('active');
|
||||
viewGrid.classList.remove('active');
|
||||
itemsContainer.classList.add('list-mode');
|
||||
wrappers.forEach(w => {
|
||||
w.className = 'item-wrapper col-12 col-sm-6 col-md-4';
|
||||
});
|
||||
localStorage.setItem('wardrobe_view', 'list');
|
||||
});
|
||||
|
||||
// Restore preference
|
||||
const savedView = localStorage.getItem('wardrobe_view');
|
||||
if (savedView === 'list') {
|
||||
viewList.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user