Files

130 lines
6.4 KiB
HTML

{% extends "base.html" %}
{% block title %}
{% if filters.get('q') %}{{ _('Results for "%(q)s"', q=filters.get('q')) }} — Classifieds
{% elif filters.get('category') %}{{ _('Browse listings') }} — Classifieds
{% else %}{{ _('Browse listings') }} — Classifieds
{% endif %}
{% endblock %}
{% block meta_description %}<meta name="description" content="{{ _('Browse local classifieds — for sale, jobs, services, and more.') }}">{% endblock %}
{% block content %}
<div class="browse">
<aside class="filters card">
<h3>{{ _('Filter') }}</h3>
<form method="get" action="{{ url_for('listings.browse') }}">
<div class="field">
<label>{{ _('Keyword') }}</label>
<input class="input" name="q" value="{{ filters.get('q','') }}">
</div>
<div class="field">
<label>{{ _('Category') }}</label>
<select class="input" name="category">
<option value="">{{ _('All') }}</option>
{% for c in categories %}
<option value="{{ c.id }}" {{ 'selected' if filters.get('category')|string == c.id|string }}>{{ c.name }}</option>
{% endfor %}
</select>
</div>
{% set US_STATES = [
('AL','Alabama'),('AK','Alaska'),('AZ','Arizona'),('AR','Arkansas'),
('CA','California'),('CO','Colorado'),('CT','Connecticut'),('DE','Delaware'),
('DC','District of Columbia'),('FL','Florida'),('GA','Georgia'),('HI','Hawaii'),
('ID','Idaho'),('IL','Illinois'),('IN','Indiana'),('IA','Iowa'),('KS','Kansas'),
('KY','Kentucky'),('LA','Louisiana'),('ME','Maine'),('MD','Maryland'),
('MA','Massachusetts'),('MI','Michigan'),('MN','Minnesota'),('MS','Mississippi'),
('MO','Missouri'),('MT','Montana'),('NE','Nebraska'),('NV','Nevada'),
('NH','New Hampshire'),('NJ','New Jersey'),('NM','New Mexico'),('NY','New York'),
('NC','North Carolina'),('ND','North Dakota'),('OH','Ohio'),('OK','Oklahoma'),
('OR','Oregon'),('PA','Pennsylvania'),('RI','Rhode Island'),('SC','South Carolina'),
('SD','South Dakota'),('TN','Tennessee'),('TX','Texas'),('UT','Utah'),
('VT','Vermont'),('VA','Virginia'),('WA','Washington'),('WV','West Virginia'),
('WI','Wisconsin'),('WY','Wyoming')] %}
{% set state_names = dict(US_STATES) %}
{% set cur_state = filters.get('state','')|upper %}
<div class="field"><label>{{ _('State') }}</label>
<input class="input" id="state-search" list="us-states" autocomplete="off"
placeholder="{{ _('Type a state…') }}" value="{{ state_names.get(cur_state, '') }}">
<input type="hidden" name="state" id="state-code" value="{{ cur_state }}">
<datalist id="us-states">
{% for code, name in US_STATES %}<option value="{{ name }}">{{ code }}</option>{% endfor %}
</datalist></div>
<div class="row2">
<div class="field"><label>{{ _('Min $') }}</label>
<input class="input" name="min_price" type="number" value="{{ filters.get('min_price','') }}"></div>
<div class="field"><label>{{ _('Max $') }}</label>
<input class="input" name="max_price" type="number" value="{{ filters.get('max_price','') }}"></div>
</div>
<div class="row2">
<div class="field"><label>{{ _('Near ZIP') }}</label>
<input class="input" name="zip" value="{{ filters.get('zip','') }}"></div>
<div class="field"><label>{{ _('Radius (mi)') }}</label>
<input class="input" name="radius" type="number" value="{{ filters.get('radius','') }}"></div>
</div>
<button class="btn" type="submit">{{ _('Apply') }}</button>
</form>
{% set slot = "sidebar" %}{% include "ads/_slot.html" %}
</aside>
<section class="results">
{% if near %}<p class="muted">{{ _('%(n)s results within %(r)s mi of %(z)s', n=near.total, r=near.radius, z=near.zip) }}</p>{% endif %}
{% if not results %}<p class="muted">{{ _('No listings found.') }}</p>{% endif %}
<div class="grid">
{% for l, dist in results %}
{% if loop.index % 6 == 0 %}
{% set slot = "inline" %}{% include "ads/_slot.html" %}
{% endif %}
<a class="tile card" href="{{ url_for('listings.detail', listing_id=l.id) }}">
{% if l.cover %}<img class="thumb" src="{{ url_for('listings.media', rel=l.cover.thumb_path) }}" alt="">
{% else %}<div class="thumb noimg">{{ _('No photo') }}</div>{% endif %}
<div class="tile-body">
<div class="tile-title">{{ l.title }}</div>
<div class="tile-meta">
{% if l.price_display %}<span class="price">{{ l.price_display }}</span>{% endif %}
{% if l.is_featured %}<span class="badge">{{ _('Featured') }}</span>{% endif %}
</div>
<div class="muted small">
{% if l.city %}{{ l.city }}, {{ l.state }}{% endif %}
{% if dist is not none %} · {{ dist }} mi{% endif %}
</div>
</div>
</a>
{% endfor %}
</div>
<div class="pager">
{% if page > 1 %}<a href="{{ url_for('listings.browse', **merge_query(page=page-1)) }}">&larr; {{ _('Prev') }}</a>{% endif %}
{% if has_next %}<a href="{{ url_for('listings.browse', **merge_query(page=page+1)) }}">{{ _('Next') }} &rarr;</a>{% endif %}
</div>
</section>
</div>
<script>
// State combobox: user searches/selects a full state name; we submit the 2-letter
// code via the hidden field. Also accepts a raw 2-letter code typed directly.
(function () {
var input = document.getElementById('state-search');
var hidden = document.getElementById('state-code');
var dl = document.getElementById('us-states');
if (!input || !hidden || !dl) return;
var byName = {}, byCode = {};
Array.prototype.forEach.call(dl.options, function (o) {
var name = o.value, code = o.textContent.trim();
byName[name.toLowerCase()] = code;
byCode[code.toUpperCase()] = name;
});
function sync() {
var v = input.value.trim();
if (!v) { hidden.value = ''; return; }
if (byName[v.toLowerCase()]) { hidden.value = byName[v.toLowerCase()]; return; }
if (byCode[v.toUpperCase()]) { // user typed the code itself
hidden.value = v.toUpperCase();
input.value = byCode[v.toUpperCase()];
return;
}
hidden.value = ''; // unrecognized → no state filter
}
input.addEventListener('input', sync);
input.addEventListener('change', sync);
})();
</script>
{% endblock %}