{% extends "base.html" %}
{% block title %}Recipes - Cook{% endblock %}
{% block content %}
<div>
{% if !breadcrumbs.is_empty() %}
<nav class="mb-4">
<ol class="flex items-center space-x-2 text-sm text-gray-600">
<li><a href="{{ prefix }}/{% if static_mode %}index.html{% endif %}" class="hover:text-gray-900">{{ tr.t("nav-recipes") }}</a></li>
{% for crumb in breadcrumbs %}
<li class="flex items-center">
<span class="mx-2 text-gray-400">/</span>
<a href="{{ prefix }}/directory/{{ crumb.path }}{% if static_mode %}.html{% endif %}" class="hover:text-gray-900">{{ crumb.name }}</a>
</li>
{% endfor %}
</ol>
</nav>
{% endif %}
<div class="flex items-center justify-between mb-8">
<h1 class="text-3xl font-bold bg-gradient-to-r from-orange-600 to-yellow-600 bg-clip-text text-transparent">
{{ current_name }}
</h1>
{% if !static_mode %}
<a href="{{ new_recipe_url }}" class="px-4 py-2 bg-gradient-to-r from-orange-500 to-red-500 text-white rounded-lg hover:from-orange-600 hover:to-red-600 transition-all shadow-md flex items-center gap-2">
<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="M12 4v16m8-8H4"></path>
</svg>
{{ tr.t("new-recipe") }}
</a>
{% endif %}
</div>
<div id="sort-controls" class="hidden items-center gap-2 mb-6">
<label for="sort-field" class="text-sm text-gray-500 dark:text-gray-400">{{ tr.t("sort-by") }}</label>
<select id="sort-field" class="text-sm border border-gray-300 dark:border-gray-600 rounded-lg px-2 py-1.5 bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:ring-2 focus:ring-purple-300">
<option value="name">{{ tr.t("sort-name") }}</option>
<option value="modified">{{ tr.t("sort-modified") }}</option>
<option value="created" id="sort-created-option">{{ tr.t("sort-created") }}</option>
</select>
<button id="sort-dir" class="px-2 py-1.5 text-sm border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors" title="{{ tr.t("sort-direction-toggle") }}">↑</button>
</div>
{% match todays_menu %}
{% when Some with (menu) %}
<div class="mb-8 bg-gradient-to-r from-purple-600 to-pink-600 rounded-2xl shadow-lg p-6 text-white">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div class="flex-1">
<div class="flex items-center gap-3 mb-2">
<span class="text-2xl">📋</span>
<h2 class="text-xl font-bold">{{ tr.t("todays-menu-title") }}</h2>
<span class="text-sm opacity-80">{{ menu.date_display }}</span>
</div>
<p class="text-sm opacity-90">{{ tr.t("todays-menu-from") }}: {{ menu.menu_name }}</p>
</div>
<a href="{{ prefix }}/{% if static_mode %}menu{% else %}recipe{% endif %}/{{ menu.menu_path }}{% if static_mode %}.html{% endif %}" class="inline-flex items-center gap-2 px-6 py-3 bg-white text-purple-700 rounded-xl font-semibold hover:bg-purple-50 transition-colors shadow-md self-start sm:self-center whitespace-nowrap">
{{ tr.t("todays-menu-view") }}
<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="M9 5l7 7-7 7"></path>
</svg>
</a>
</div>
</div>
{% when None %}
{% endmatch %}
<div id="recipes-grid" class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{% for item in items %}
{% if item.is_directory %}
<a href="{{ prefix }}/directory/{{ item.path }}{% if static_mode %}.html{% endif %}" data-type="directory" class="bg-white rounded-2xl shadow-lg overflow-hidden hover:shadow-xl transition-all hover:scale-105 recipe-card flex flex-col">
<div class="p-6 flex-1">
<div class="flex items-center justify-center w-16 h-16 bg-gradient-to-br from-yellow-400 to-orange-500 rounded-full mb-4">
<span class="text-2xl">📁</span>
</div>
<h3 class="font-bold text-lg mb-2">{{ item.name }}</h3>
{% match item.count %}
{% when Some with (count) %}
<span class="text-sm text-orange-600 font-medium">{{ count }} recipes</span>
{% when None %}
{% endmatch %}
</div>
</a>
{% else %}
<a href="{{ prefix }}/{% if static_mode %}{% if item.is_menu %}menu{% else %}recipe{% endif %}{% else %}recipe{% endif %}/{{ item.path }}{% if static_mode %}.html{% endif %}"
data-type="recipe"
{% if let Some(ts) = item.modified_at %}data-modified="{{ ts }}"{% endif %}
{% if let Some(ts) = item.created_at %}data-created="{{ ts }}"{% endif %}
class="bg-white rounded-2xl shadow-lg overflow-hidden hover:shadow-xl transition-all hover:scale-105 recipe-card flex flex-col">
{% match item.image_path %}
{% when Some with (img) %}
<div class="h-48 bg-gray-100 overflow-hidden">
<img src="{{ img }}" alt="{{ item.name }}" class="w-full h-full object-cover hover:scale-110 transition-transform duration-300">
</div>
<div class="p-6">
{% when None %}
<div class="p-6">
<div class="flex items-center justify-center w-16 h-16 bg-gradient-to-br {% if item.is_menu %}from-purple-400 to-pink-500{% else %}from-orange-400 to-pink-500{% endif %} rounded-full mb-4">
<span class="text-2xl">{% if item.is_menu %}📋{% else %}🍽️{% endif %}</span>
</div>
{% endmatch %}
<h3 class="font-bold text-lg mb-2 text-gray-800">
{{ item.name }}
{% if item.is_menu %}
<span class="ml-2 text-xs bg-gradient-to-r from-purple-100 to-pink-100 text-purple-700 px-2 py-1 rounded-full font-semibold">{{ tr.t("recipe-type-menu") }}</span>
{% endif %}
</h3>
{% match item.description %}
{% when Some with (description) %}
<p class="text-gray-600 text-sm">{{ description }}</p>
{% when None %}
{% endmatch %}
{% if !item.tags.is_empty() %}
<div class="mt-3 flex flex-wrap gap-2">
{% for tag in item.tags.iter().take(3) %}
<span class="text-xs bg-gradient-to-r from-yellow-100 to-orange-100 text-orange-700 px-2 py-1 rounded-full font-medium">{{ tag }}</span>
{% endfor %}
{% if item.tags.len() > 3 %}
<span class="text-xs text-gray-500">+{{ item.tags.len() - 3 }}</span>
{% endif %}
</div>
{% endif %}
</div>
</a>
{% endif %}
{% endfor %}
{% if items.is_empty() %}
<div class="text-gray-500 text-center py-8">
{{ tr.t("recipes-empty") }}
</div>
{% endif %}
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
(function () {
const grid = document.getElementById('recipes-grid');
const controls = document.getElementById('sort-controls');
const fieldSelect = document.getElementById('sort-field');
const dirBtn = document.getElementById('sort-dir');
const createdOption = document.getElementById('sort-created-option');
if (!grid) return;
let sortField = 'name';
let sortDir = 'asc';
const allRecipeCards = grid.querySelectorAll('[data-type="recipe"]');
const allHaveCreated = allRecipeCards.length > 0 &&
Array.from(allRecipeCards).every(el => el.hasAttribute('data-created'));
if (!allHaveCreated && createdOption) {
createdOption.remove();
}
const recipeCount = grid.querySelectorAll('[data-type="recipe"]').length;
if (recipeCount >= 2) {
controls.classList.remove('hidden');
controls.classList.add('flex');
}
function getValue(el) {
if (sortField === 'name') {
return (el.querySelector('h3')?.textContent ?? '').trim().toLowerCase();
}
const attr = sortField === 'modified' ? 'data-modified' : 'data-created';
const raw = el.getAttribute(attr);
if (raw === null) return null;
const n = parseInt(raw, 10);
return Number.isNaN(n) ? null : n;
}
function applySort() {
const all = Array.from(grid.children);
const dirs = all.filter(el => el.dataset.type === 'directory');
const recipes = all.filter(el => el.dataset.type === 'recipe');
const others = all.filter(el => !el.dataset.type);
recipes.sort((a, b) => {
const av = getValue(a);
const bv = getValue(b);
if (av === null && bv === null) return 0;
if (av === null) return 1;
if (bv === null) return -1;
const cmp = typeof av === 'string' ? av.localeCompare(bv) : av - bv;
return sortDir === 'asc' ? cmp : -cmp;
});
dirs.forEach(el => grid.appendChild(el));
recipes.forEach(el => grid.appendChild(el));
others.forEach(el => grid.appendChild(el));
dirBtn.textContent = sortDir === 'asc' ? '↑' : '↓';
}
fieldSelect.addEventListener('change', function () {
sortField = this.value;
sortDir = sortField === 'name' ? 'asc' : 'desc';
applySort();
});
dirBtn.addEventListener('click', function () {
sortDir = sortDir === 'asc' ? 'desc' : 'asc';
applySort();
});
})();
</script>
{% endblock %}