58 lines
2.3 KiB
HTML
58 lines
2.3 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Services — Supernova{% endblock %}
|
|
{% block content %}
|
|
<div class="hero" style="padding:48px 0 24px">
|
|
<h1 style="font-size:2.4rem">Services</h1>
|
|
<p class="sub">Search the catalog. Every boost is fulfilled automatically.</p>
|
|
<div class="field" style="max-width:520px;margin:0 auto">
|
|
<input id="search" type="text" placeholder="Search — e.g. Instagram likes, TikTok views…" autocomplete="off">
|
|
</div>
|
|
</div>
|
|
|
|
<div id="catalog">
|
|
{% for cat, items in cats.items() %}
|
|
<section class="cat-block" data-cat="{{ cat|lower }}">
|
|
<h2 class="section-title">{{ cat }} <span class="muted" style="font-size:0.9rem">({{ items|length }})</span></h2>
|
|
<div class="platform-grid">
|
|
{% for s in items %}
|
|
<div class="card" data-name="{{ s.name|lower }}">
|
|
<h3>{{ s.name }}</h3>
|
|
<div class="meta">min {{ s.min }} · max {{ "{:,}".format(s.max) }}</div>
|
|
<div class="price">${{ "%.2f"|format(s.rate|float) }} <span class="muted" style="font-size:0.8rem">/ 1k</span></div>
|
|
<div class="row">
|
|
<span class="meta">{% if s.refill %}♻️ refill{% endif %}{% if s.dripfeed %} 💧 dripfeed{% endif %}{% if not s.refill and not s.dripfeed %}·{% endif %}</span>
|
|
<a class="btn sm" href="{{ url_for('order', service_id=s.service) }}">Boost →</a>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</section>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<div id="no-results" class="center muted" style="display:none;padding:40px 0">No services match your search.</div>
|
|
|
|
<script>
|
|
(function () {
|
|
const search = document.getElementById('search');
|
|
const cards = document.querySelectorAll('.card[data-name]');
|
|
const blocks = document.querySelectorAll('.cat-block');
|
|
const noRes = document.getElementById('no-results');
|
|
search.addEventListener('input', () => {
|
|
const q = search.value.trim().toLowerCase();
|
|
let any = false;
|
|
cards.forEach(c => {
|
|
const hit = !q || c.dataset.name.includes(q);
|
|
c.style.display = hit ? '' : 'none';
|
|
if (hit) any = true;
|
|
});
|
|
blocks.forEach(b => {
|
|
const has = Array.from(b.querySelectorAll('.card[data-name]')).some(c => c.style.display !== 'none');
|
|
b.style.display = has ? '' : 'none';
|
|
});
|
|
noRes.style.display = any ? 'none' : '';
|
|
});
|
|
})();
|
|
</script>
|
|
{% endblock %}
|