- Configure Wagtail database search backend with English search config - Add django.contrib.postgres to INSTALLED_APPS for full PG FTS support - Expand ArticlePage.search_fields: body_text (excl. code blocks), AutocompleteField(title), RelatedFields(tags), FilterFields - Add search view at /search/?q= with query guards (strip, max 200 chars, empty/whitespace handling) and pagination preserving query param - Replace nav Subscribe CTA with compact search box (desktop + mobile) - Add search box to article index page alongside category/tag filters - Create search results template reusing article_card component - Add update_index to deploy entrypoint for automated reindexing - Update existing tests for nav change, add comprehensive search tests Closes #41 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
73 lines
5.8 KiB
HTML
73 lines
5.8 KiB
HTML
{% extends 'base.html' %}
|
|
{% load core_tags seo_tags %}
|
|
{% block title %}Articles | No Hype AI{% endblock %}
|
|
{% block head_meta %}
|
|
{% canonical_url page as canonical %}
|
|
<link rel="canonical" href="{{ canonical }}" />
|
|
<meta name="description" content="Latest No Hype AI articles and benchmark-driven reviews." />
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:title" content="Articles | No Hype AI" />
|
|
<meta property="og:url" content="{{ canonical }}" />
|
|
{% endblock %}
|
|
{% block content %}
|
|
|
|
<!-- Page Header -->
|
|
<div class="py-8 md:py-12 border-b border-zinc-200 dark:border-zinc-800 mb-12">
|
|
{% if active_category %}
|
|
<nav aria-label="Breadcrumb" class="font-mono text-xs text-zinc-500 mb-4">
|
|
<a href="/" class="hover:text-brand-cyan">Home</a> / <a href="/articles/" class="hover:text-brand-cyan">Articles</a> / <span>{{ active_category.name }}</span>
|
|
</nav>
|
|
{% endif %}
|
|
<h1 class="font-display font-black text-4xl md:text-6xl mb-3">{% if active_category %}{{ active_category.name }}{% else %}{{ page.title }}{% endif %}</h1>
|
|
{% if active_category.description %}
|
|
<p class="text-zinc-600 dark:text-zinc-400 mb-6">{{ active_category.description }}</p>
|
|
{% endif %}
|
|
|
|
<!-- Filters / Search -->
|
|
<div class="flex flex-col md:flex-row justify-between gap-6 mb-4">
|
|
<!-- Category Filters -->
|
|
<div class="flex flex-wrap gap-3">
|
|
<a href="/articles/{% if active_tag %}?tag={{ active_tag }}{% endif %}" class="px-4 py-2 font-mono text-sm font-bold border transition-colors {% if not active_category %}bg-brand-dark text-brand-light dark:bg-brand-light dark:text-brand-dark border-transparent{% else %}bg-transparent text-zinc-600 dark:text-zinc-400 border-zinc-300 dark:border-zinc-700 hover:text-brand-dark dark:hover:text-brand-light hover:border-brand-dark dark:hover:border-brand-light{% endif %}" {% if not active_category %}aria-current="page"{% endif %}>Categories</a>
|
|
{% for category_link in category_links %}
|
|
<a href="{{ category_link.url }}{% if active_tag %}?tag={{ active_tag }}{% endif %}" class="px-4 py-2 font-mono text-sm font-bold border transition-colors {% if active_category and active_category.slug == category_link.category.slug %}bg-brand-dark text-brand-light dark:bg-brand-light dark:text-brand-dark border-transparent{% else %}bg-transparent text-zinc-600 dark:text-zinc-400 border-zinc-300 dark:border-zinc-700 hover:text-brand-dark dark:hover:text-brand-light hover:border-brand-dark dark:hover:border-brand-light{% endif %}" {% if active_category and active_category.slug == category_link.category.slug %}aria-current="page"{% endif %}>{{ category_link.category.name }}</a>
|
|
{% endfor %}
|
|
</div>
|
|
<form action="{% url 'search' %}" method="get" role="search" class="relative w-full md:w-64">
|
|
<svg class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-zinc-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" /></svg>
|
|
<input type="search" name="q" placeholder="Search articles..." aria-label="Search articles"
|
|
class="w-full bg-brand-surfaceLight dark:bg-brand-surfaceDark border border-zinc-300 dark:border-zinc-700 pl-10 pr-4 py-2 font-mono text-sm focus:outline-none focus:border-brand-cyan dark:focus:border-brand-cyan focus:ring-1 focus:ring-brand-cyan transition-shadow" />
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Tag Filters -->
|
|
<div class="flex flex-wrap gap-3">
|
|
<a href="{% if active_category %}{{ active_category_url }}{% else %}/articles/{% endif %}" class="px-4 py-2 font-mono text-sm font-bold border transition-colors {% if not active_tag %}bg-brand-dark text-brand-light dark:bg-brand-light dark:text-brand-dark border-transparent{% else %}bg-transparent text-zinc-600 dark:text-zinc-400 border-zinc-300 dark:border-zinc-700 hover:text-brand-dark dark:hover:text-brand-light hover:border-brand-dark dark:hover:border-brand-light{% endif %}" {% if not active_tag %}aria-current="page"{% endif %}>All</a>
|
|
{% for tag in available_tags %}
|
|
<a href="{% if active_category %}{{ active_category_url }}{% else %}/articles/{% endif %}?tag={{ tag.slug }}" class="px-4 py-2 font-mono text-sm font-bold border transition-colors {% if active_tag == tag.slug %}bg-brand-dark text-brand-light dark:bg-brand-light dark:text-brand-dark border-transparent{% else %}bg-transparent text-zinc-600 dark:text-zinc-400 border-zinc-300 dark:border-zinc-700 hover:text-brand-dark dark:hover:text-brand-light hover:border-brand-dark dark:hover:border-brand-light{% endif %}" {% if active_tag == tag.slug %}aria-current="page"{% endif %}>{{ tag.name }}</a>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Article List -->
|
|
<div class="space-y-8">
|
|
{% for article in articles %}
|
|
{% include 'components/article_card.html' with article=article %}
|
|
{% empty %}
|
|
<p class="font-mono text-zinc-500 py-12 text-center">No articles found.</p>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
{% if articles.has_previous or articles.has_next %}
|
|
<nav aria-label="Pagination" class="mt-12 flex justify-center items-center gap-4 font-mono text-sm">
|
|
{% if articles.has_previous %}
|
|
<a href="?page={{ articles.previous_page_number }}{% if active_tag %}&tag={{ active_tag }}{% endif %}" class="px-6 py-3 border border-zinc-300 dark:border-zinc-700 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors">← Previous</a>
|
|
{% endif %}
|
|
<span class="text-zinc-500">Page {{ articles.number }} of {{ paginator.num_pages }}</span>
|
|
{% if articles.has_next %}
|
|
<a href="?page={{ articles.next_page_number }}{% if active_tag %}&tag={{ active_tag }}{% endif %}" class="px-6 py-3 border border-zinc-300 dark:border-zinc-700 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors">Next →</a>
|
|
{% endif %}
|
|
</nav>
|
|
{% endif %}
|
|
{% endblock %}
|