Files
linkvault/app/templates/index.html
Erik Thiele d4d43ed5d9 Fix loading-spinner spacing and add logo to header brand
The "Hinzufügen" buttons reserved layout space for their loading
spinner even when idle, since .htmx-indicator only toggled opacity
(not display), leaving a visible gap before the centered text. Switch
to display:none/inline-flex so the spinner takes no space until an
htmx request is in flight, and drop the static plus icon next to
"Hinzufügen" so the idle button just shows centered text with the
spinner appearing in its place while loading.

Also adds the favicon as a small logo image in front of "LinkVault"
in the shared topbar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 16:19:42 +02:00

120 lines
5.4 KiB
HTML

{% extends "base.html" %}
{% import "_icons.html" as icons %}
{% block title %}Meine Links · LinkVault{% endblock %}
{% block body %}
{% include "_topbar.html" %}
<div class="layout">
<aside class="sidebar">
<div class="panel">
<a href="/?sort={{ sort }}&amp;facet_sort={{ facet_sort }}" class="facet {% if not active_category and not active_manufacturer and not review_only %}active{% endif %}">
<span>{{ icons.grid(size=14) }} Alle Links</span>
</a>
<div style="display:flex; justify-content:flex-end; margin-top:12px;">
<select onchange="const u=new window.URL(location); u.searchParams.set('facet_sort', this.value); location.href=u;"
title="Sortierung der Kategorie-/Hersteller-Listen" style="font-size:.75rem; padding:3px 6px;">
{% for value, label in facet_sort_options.items() %}
<option value="{{ value }}" {% if facet_sort == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
<div class="facet-group">
<h3>Kategorien</h3>
{% for name, count in facets.categories %}
<a href="/?category={{ name | urlencode }}&amp;sort={{ sort }}&amp;facet_sort={{ facet_sort }}"
class="facet {% if active_category == name and not review_only %}active{% endif %}">
<span>{{ name }}</span><span class="count">{{ count }}</span>
</a>
{% else %}
<div class="muted" style="font-size:.85rem; padding:4px 8px;">noch keine</div>
{% endfor %}
</div>
<div class="facet-group">
<h3>Hersteller / Quellen</h3>
{% for name, count in facets.manufacturers %}
<a href="/?manufacturer={{ name | urlencode }}&amp;sort={{ sort }}&amp;facet_sort={{ facet_sort }}"
class="facet {% if active_manufacturer == name and not review_only %}active{% endif %}">
<span>{{ name }}</span><span class="count">{{ count }}</span>
</a>
{% else %}
<div class="muted" style="font-size:.85rem; padding:4px 8px;">noch keine</div>
{% endfor %}
</div>
<div class="facet-group">
<h3>Merkliste</h3>
<a href="/?review=1&amp;sort={{ sort }}&amp;facet_sort={{ facet_sort }}" class="facet {% if review_only %}active{% endif %}">
<span>{{ icons.bookmark(size=14) }} Zur Durchsicht</span><span class="count">{{ facets.review_count }}</span>
</a>
</div>
</div>
</aside>
<main class="main">
<div class="panel">
<form hx-post="/links" hx-target="#links" hx-swap="afterbegin"
hx-disabled-elt="button"
hx-on::after-request="if(event.detail.successful){this.reset(); var e=document.getElementById('empty-state'); if(e) e.remove();}">
<div style="display:flex; gap:8px; flex-wrap:wrap;">
<input type="url" name="url" placeholder="Link einfügen, z.B. https://hersteller.de/produkt" required
style="flex:1 1 220px; width:auto;">
<button type="submit" style="white-space:nowrap;">
<span class="htmx-indicator icon-spin">{{ icons.spinner(size=14) }}</span>
Hinzufügen
</button>
</div>
<div class="muted" style="font-size:.8rem; margin-top:6px;">
Der Link wird automatisch geladen, zusammengefasst und einsortiert.
</div>
</form>
</div>
<div class="panel">
<form id="searchform" onsubmit="return false;" style="margin:0;">
<input type="hidden" name="category" value="{{ active_category }}">
<input type="hidden" name="manufacturer" value="{{ active_manufacturer }}">
<input type="hidden" name="review" value="{{ '1' if review_only else '' }}">
<div class="input-icon">
{{ icons.search(size=15) }}
<input type="text" name="q" value="{{ q }}"
placeholder="Suche in Titel, Zusammenfassung, Tags..."
hx-get="/search" hx-target="#links" hx-swap="innerHTML"
hx-trigger="keyup changed delay:400ms, search"
hx-include="#searchform">
</div>
<div style="display:flex; justify-content:space-between; align-items:center; gap:12px; margin-top:10px; flex-wrap:wrap;">
{% if ai_enabled %}
<label class="muted" style="display:inline-flex; align-items:center; gap:6px; font-size:.85rem;">
<input type="checkbox" name="semantic" value="1" {% if semantic %}checked{% endif %}
hx-get="/search" hx-target="#links" hx-swap="innerHTML"
hx-trigger="change" hx-include="#searchform" style="width:auto;">
KI-Suche (findet auch sinnverwandte Treffer)
</label>
{% else %}
<span></span>
{% endif %}
<label class="muted" style="display:inline-flex; align-items:center; gap:6px; font-size:.85rem;">
Sortierung:
<select name="sort"
hx-get="/search" hx-target="#links" hx-swap="innerHTML"
hx-trigger="change" hx-include="#searchform">
{% for value, label in sort_options.items() %}
<option value="{{ value }}" {% if sort == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</label>
</div>
</form>
</div>
<div id="links">
{% include "_links_list.html" %}
</div>
</main>
</div>
{% endblock %}