Initial commit with project setup
This commit is contained in:
173
templates/home.html
Normal file
173
templates/home.html
Normal file
@@ -0,0 +1,173 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Home{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<button id="open-filter-menu" class="sm:hidden btn-main mb-4 w-full">Filter</button>
|
||||
<div id="filter-modal" class="fixed inset-0 bg-black bg-opacity-40 z-50 flex items-center justify-center hidden sm:static sm:bg-transparent sm:z-auto sm:flex sm:items-start sm:justify-start">
|
||||
<div class="bg-white rounded-xl p-6 w-full max-w-md mx-auto relative sm:bg-transparent sm:p-0 sm:w-auto sm:max-w-none sm:mx-0">
|
||||
<button id="close-filter-menu" class="sm:hidden absolute top-4 right-4 text-2xl">×</button>
|
||||
<form id="plant-filter-form" method="get"
|
||||
class="flex flex-col sm:flex-row flex-wrap gap-4 items-center p-0 w-full mb-8">
|
||||
<input type="text" id="search" name="search" value="{{ search }}" placeholder="Search..." class="rounded-lg border border-gray-300 px-3 py-1 text-sm focus:border-[#6b8f71] focus:ring-[#6b8f71]" style="min-width: 160px;" autocomplete="off">
|
||||
<select id="climate" name="climate" class="rounded-lg border border-gray-300 px-3 py-1 text-sm focus:border-[#6b8f71] focus:ring-[#6b8f71]">
|
||||
<option value="">All Climates</option>
|
||||
{% for climate in climates %}
|
||||
<option value="{{ climate.id }}" {% if selected_climate == climate.id|string %}selected{% endif %}>{{ climate.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select id="environment" name="environment" class="rounded-lg border border-gray-300 px-3 py-1 text-sm focus:border-[#6b8f71] focus:ring-[#6b8f71]">
|
||||
<option value="">All Environments</option>
|
||||
{% for environment in environments %}
|
||||
<option value="{{ environment.id }}" {% if selected_environment == environment.id|string %}selected{% endif %}>{{ environment.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select id="light" name="light" class="rounded-lg border border-gray-300 px-3 py-1 text-sm focus:border-[#6b8f71] focus:ring-[#6b8f71]">
|
||||
<option value="">All Light</option>
|
||||
{% for light in lights %}
|
||||
<option value="{{ light.id }}" {% if selected_light == light.id|string %}selected{% endif %}>{{ light.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select id="toxicity" name="toxicity" class="rounded-lg border border-gray-300 px-3 py-1 text-sm focus:border-[#6b8f71] focus:ring-[#6b8f71]">
|
||||
<option value="">All Toxicity</option>
|
||||
{% for toxicity in toxicities %}
|
||||
<option value="{{ toxicity.id }}" {% if selected_toxicity == toxicity.id|string %}selected{% endif %}>{{ toxicity.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select id="size" name="size" class="rounded-lg border border-gray-300 px-3 py-1 text-sm focus:border-[#6b8f71] focus:ring-[#6b8f71]">
|
||||
<option value="">All Sizes</option>
|
||||
{% for size in sizes %}
|
||||
<option value="{{ size.id }}" {% if selected_size == size.id|string %}selected{% endif %}>{{ size.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select id="care_difficulty" name="care_difficulty" class="rounded-lg border border-gray-300 px-3 py-1 text-sm focus:border-[#6b8f71] focus:ring-[#6b8f71]">
|
||||
<option value="">All Care Difficulty</option>
|
||||
{% for difficulty in difficulties %}
|
||||
<option value="{{ difficulty.id }}" {% if selected_care_difficulty == difficulty.id|string %}selected{% endif %}>{{ difficulty.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select id="growth_rate" name="growth_rate" class="rounded-lg border border-gray-300 px-3 py-1 text-sm focus:border-[#6b8f71] focus:ring-[#6b8f71]">
|
||||
<option value="">All Growth Rates</option>
|
||||
{% for rate in growth_rates %}
|
||||
<option value="{{ rate.id }}" {% if selected_growth_rate == rate.id|string %}selected{% endif %}>{{ rate.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<a href="{{ url_for('home') }}" class="btn-secondary px-4 py-1 text-sm font-semibold ml-2 sm:ml-0">Clear</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Debounce function
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func.apply(this, args), wait);
|
||||
};
|
||||
}
|
||||
const form = document.getElementById('plant-filter-form');
|
||||
const searchInput = document.getElementById('search');
|
||||
const selects = [document.getElementById('climate'), document.getElementById('environment'), document.getElementById('light'), document.getElementById('toxicity'), document.getElementById('size'), document.getElementById('care_difficulty'), document.getElementById('growth_rate')];
|
||||
|
||||
// Auto-submit on select change
|
||||
selects.forEach(sel => sel.addEventListener('change', () => form.submit()));
|
||||
// Debounced auto-submit on search
|
||||
searchInput.addEventListener('input', debounce(() => form.submit(), 400));
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const openBtn = document.getElementById('open-filter-menu');
|
||||
const closeBtn = document.getElementById('close-filter-menu');
|
||||
const modal = document.getElementById('filter-modal');
|
||||
if (openBtn && modal) {
|
||||
openBtn.addEventListener('click', () => modal.classList.remove('hidden'));
|
||||
}
|
||||
if (closeBtn && modal) {
|
||||
closeBtn.addEventListener('click', () => modal.classList.add('hidden'));
|
||||
}
|
||||
if (modal) {
|
||||
modal.addEventListener('click', (e) => {
|
||||
if (e.target === modal) modal.classList.add('hidden');
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<div class="masonry md:columns-2 xl:columns-3 gap-8">
|
||||
{% for plant in plants %}
|
||||
<a href="{{ url_for('plant', plant_id=plant.id) }}" class="block group focus:outline-none focus:ring-2 focus:ring-[#6b8f71] rounded-2xl">
|
||||
<article class="plant-card opacity-0 translate-y-8 transition-all duration-700 bg-white/90 shadow-xl rounded-2xl p-6 flex flex-col hover:shadow-2xl hover:scale-[1.02] group-hover:shadow-2xl group-hover:scale-[1.02] cursor-pointer">
|
||||
{% if plant.picture %}
|
||||
<img src="{{ url_for('static', filename='uploads/' ~ plant.picture) }}" alt="{{ plant.name }}" class="w-full h-64 object-cover rounded-xl shadow-md border-2 border-[#e6ebe0] mb-4">
|
||||
{% else %}
|
||||
<img src="{{ url_for('static', filename='images/placeholder-plant.svg') }}" alt="No image available" class="w-full h-64 object-cover rounded-xl shadow-md border-2 border-[#e6ebe0] mb-4 opacity-50">
|
||||
{% endif %}
|
||||
<div class="w-full flex flex-col gap-2">
|
||||
<h2 class="text-2xl font-bold mb-1 text-[#4e6b50] group-hover:text-[#3e5637] transition">{{ plant.name }}</h2>
|
||||
<div class="flex flex-wrap gap-2 mb-1">
|
||||
{% if plant.climate %}
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-[#d0e7d2] text-[#3e5637] text-xs font-semibold">
|
||||
{% if plant.climate_icon %}
|
||||
<img src="{{ url_for('static', filename='icons/' ~ plant.climate_icon) }}" alt="Climate icon" class="w-4 h-4 mr-1 inline-block align-middle" />
|
||||
{% endif %}
|
||||
{{ plant.climate }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if plant.environment %}
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-[#d0e7d2] text-[#3e5637] text-xs font-semibold">
|
||||
{% if plant.environment_icon %}
|
||||
<img src="{{ url_for('static', filename='icons/' ~ plant.environment_icon) }}" alt="Environment icon" class="w-4 h-4 mr-1 inline-block align-middle" />
|
||||
{% endif %}
|
||||
{{ plant.environment }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if plant.light %}
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-[#d0e7d2] text-[#3e5637] text-xs font-semibold">
|
||||
{% if plant.light_icon %}
|
||||
<img src="{{ url_for('static', filename='icons/' ~ plant.light_icon) }}" alt="Light icon" class="w-4 h-4 mr-1 inline-block align-middle" />
|
||||
{% endif %}
|
||||
{{ plant.light }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if plant.toxicity %}
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-[#d0e7d2] text-[#3e5637] text-xs font-semibold">
|
||||
{% if plant.toxicity_icon %}
|
||||
<img src="{{ url_for('static', filename='icons/' ~ plant.toxicity_icon) }}" alt="Toxicity icon" class="w-4 h-4 mr-1 inline-block align-middle" />
|
||||
{% endif %}
|
||||
{{ plant.toxicity }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 text-xs mb-1">
|
||||
{% if plant.size %}
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-[#e6ebe0] text-[#3e5637] font-semibold">
|
||||
{% if plant.size_icon %}
|
||||
<img src="{{ url_for('static', filename='icons/' ~ plant.size_icon) }}" alt="Size icon" class="w-4 h-4 mr-1 inline-block align-middle" />
|
||||
{% endif %}
|
||||
{{ plant.size }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if plant.care_difficulty %}
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-[#e6ebe0] text-[#3e5637] font-semibold">
|
||||
{% if plant.care_difficulty_icon %}
|
||||
<img src="{{ url_for('static', filename='icons/' ~ plant.care_difficulty_icon) }}" alt="Care difficulty icon" class="w-4 h-4 mr-1 inline-block align-middle" />
|
||||
{% endif %}
|
||||
{{ plant.care_difficulty }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if plant.growth_rate %}
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-[#e6ebe0] text-[#3e5637] font-semibold">
|
||||
{% if plant.growth_rate_icon %}
|
||||
<img src="{{ url_for('static', filename='icons/' ~ plant.growth_rate_icon) }}" alt="Growth rate icon" class="w-4 h-4 mr-1 inline-block align-middle" />
|
||||
{% endif %}
|
||||
{{ plant.growth_rate }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="text-[#4e6b50] mt-2 text-sm">{{ plant.description[:120] }}{% if plant.description and plant.description|length > 120 %}...{% endif %}</p>
|
||||
<div class="text-xs text-[#6b8f71] mt-2">Added on <span class="local-date" data-date="{{ plant.date_added.isoformat() }}"></span></div>
|
||||
</div>
|
||||
</article>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user