{% extends "layout.html" %}
{% block content %}
<div class="flex flex-col lg:flex-row gap-6">
<!-- Main content -->
<div class="flex-1 min-w-0 bg-white dark:bg-gray-800 shadow-sm rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div class="flex flex-wrap items-center justify-between gap-3 mb-6">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">{{ resource_name }}</h1>
<div class="flex items-center gap-2">
{% if has_filters %}
<button type="button" onclick="adminxToggleFilters()" title="Filters"
class="inline-flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium border transition
{% if has_active_filters %}border-indigo-400 text-indigo-700 bg-indigo-50 dark:border-indigo-500/50 dark:text-indigo-300 dark:bg-indigo-500/10{% else %}border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700{% endif %}">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.414A1 1 0 013 6.707V4z"/></svg>
Filters
{% if has_active_filters %}<span class="text-xs px-1.5 py-0.5 rounded-full bg-indigo-600 text-white">On</span>{% endif %}
</button>
{% endif %}
<a href="{{ mount | safe }}/{{ base_path | safe }}/list?download=csv" class="inline-flex items-center gap-1 px-3 py-2 rounded-lg text-sm font-medium border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition">CSV</a>
<a href="{{ mount | safe }}/{{ base_path | safe }}/list?download=json" class="inline-flex items-center gap-1 px-3 py-2 rounded-lg text-sm font-medium border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition">JSON</a>
<a href="{{ mount | safe }}/{{ base_path | safe }}/new" class="inline-flex items-center gap-1 px-4 py-2 rounded-lg text-sm font-semibold text-white bg-gradient-to-r from-indigo-600 to-fuchsia-600 shadow hover:opacity-95 transition">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
New
</a>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-700/50">
<tr>
{% for h in headers %}
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">{{ h | replace(from="_", to=" ") | title }}</th>
{% endfor %}
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
{% for row in rows %}
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/40 transition-colors">
{% for h in headers %}
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">{{ row[h] | default(value="") }}</td>
{% endfor %}
<td class="px-6 py-4 whitespace-nowrap text-right text-sm">
<div class="flex items-center justify-end gap-1">
<a href="{{ mount | safe }}/{{ base_path | safe }}/view/{{ row[pk] }}" title="View" class="p-1.5 rounded-lg text-gray-500 hover:text-indigo-600 hover:bg-indigo-50 dark:hover:bg-indigo-500/10 transition">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/></svg>
</a>
<a href="{{ mount | safe }}/{{ base_path | safe }}/edit/{{ row[pk] }}" title="Edit" class="p-1.5 rounded-lg text-gray-500 hover:text-indigo-600 hover:bg-indigo-50 dark:hover:bg-indigo-500/10 transition">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg>
</a>
<form method="post" action="{{ mount | safe }}/{{ base_path | safe }}/{{ row[pk] }}/delete" class="inline" onsubmit="return confirm('Delete this {{ resource_name }}?');">
<input type="hidden" name="_csrf" value="{{ csrf_token }}">
<button type="submit" title="Delete" class="p-1.5 rounded-lg text-gray-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-500/10 transition">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/></svg>
</button>
</form>
</div>
</td>
</tr>
{% else %}
<tr><td colspan="{{ headers | length + 1 }}" class="px-6 py-10 text-center text-sm text-gray-400 dark:text-gray-500">No records. <a href="{{ mount | safe }}/{{ base_path | safe }}/new" class="text-indigo-600 dark:text-indigo-400 hover:underline">Create the first one</a>.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="flex items-center justify-between mt-6 text-sm text-gray-600 dark:text-gray-400">
<span>{{ total }} total ยท page {{ page }}</span>
<span class="flex gap-2">
{% if page > 1 %}<a href="{{ mount | safe }}/{{ base_path | safe }}/list?page={{ page - 1 }}&per_page={{ per_page }}" class="px-3 py-1.5 rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 transition">Prev</a>{% endif %}
{% if page * per_page < total %}<a href="{{ mount | safe }}/{{ base_path | safe }}/list?page={{ page + 1 }}&per_page={{ per_page }}" class="px-3 py-1.5 rounded-lg border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 transition">Next</a>{% endif %}
</span>
</div>
</div>
<!-- Right filter sidebar: hidden by default; opens on the Filters button,
and starts open when filters are already applied. -->
{% if has_filters %}
<aside id="filter-sidebar" class="{% if not has_active_filters %}hidden {% endif %}w-full lg:w-72 shrink-0 bg-white dark:bg-gray-800 shadow-sm rounded-xl border border-gray-200 dark:border-gray-700 p-6 h-fit">
<div class="flex items-center justify-between mb-4">
<h3 class="text-base font-semibold text-gray-900 dark:text-white">Filters</h3>
<button type="button" onclick="adminxToggleFilters()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" title="Close">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
</button>
</div>
<form method="get" action="{{ mount | safe }}/{{ base_path | safe }}/list" class="space-y-4">
{% for f in filter_fields %}
<div>
<label for="f_{{ f.field }}" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5">{{ f.label }}</label>
{% set input_cls = "w-full px-3 py-2 rounded-lg text-sm border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-400 focus:ring-2 focus:ring-indigo-500" %}
{% if f.kind == "select" or f.kind == "boolean" %}
<select id="f_{{ f.field }}" name="{{ f.field }}" class="{{ input_cls }}">
<option value="">All</option>
{% for o in f.options %}
<option value="{{ o.value }}" {% if current_filters[f.field] and current_filters[f.field] == o.value %}selected{% endif %}>{{ o.label }}</option>
{% endfor %}
</select>
{% elif f.kind == "date_range" %}
{% set from_key = f.field ~ "_from" %}
{% set to_key = f.field ~ "_to" %}
<div class="grid grid-cols-2 gap-2">
<input type="date" name="{{ from_key }}" value="{{ current_filters[from_key] | default(value='') }}" class="{{ input_cls }}">
<input type="date" name="{{ to_key }}" value="{{ current_filters[to_key] | default(value='') }}" class="{{ input_cls }}">
</div>
{% else %}
<input type="text" id="f_{{ f.field }}" name="{{ f.field }}"
value="{{ current_filters[f.field] | default(value='') }}" placeholder="{{ f.label }}"
class="{{ input_cls }}">
{% endif %}
</div>
{% endfor %}
<div class="flex items-center gap-2 pt-4 border-t border-gray-200 dark:border-gray-700">
<button type="submit" class="flex-1 px-4 py-2 rounded-lg text-sm font-semibold text-white bg-gradient-to-r from-indigo-600 to-fuchsia-600 shadow hover:opacity-95 transition">Apply</button>
{% if has_active_filters %}
<a href="{{ mount | safe }}/{{ base_path | safe }}/list" class="px-4 py-2 rounded-lg text-sm font-medium border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition">Clear</a>
{% endif %}
</div>
</form>
</aside>
{% endif %}
</div>
<script>
function adminxToggleFilters() {
var s = document.getElementById('filter-sidebar');
if (s) s.classList.toggle('hidden');
}
</script>
{% endblock content %}