5.4 KiB · text History c20d4f7
{% extends "root.html" %}

{% block inner %}
<div class="space-y-6 text-left">
  <h2 class="text-2xl font-bold text-accent">Search</h2>
  <p class="text-sm opacity-70">
    Match a phrase against any combination of data sources. Uncheck a source
    to exclude it. Tag-namespace boxes (User / OCR / Describe) match the
    namespace's <em>tag values</em>, so e.g. with OCR off, OCR-extracted text
    won't surface results.
  </p>

  <form method="get" action="/search" class="card bg-base-200 p-4 space-y-3">
    <input type="hidden" name="f" value="1"/>

    <label class="flex flex-col">
      <span class="text-xs">Query</span>
      <input class="input" type="text" name="q" value="{{ q }}" placeholder="mcmaster, species:macro, species:*, ..." autofocus/>
      <span class="text-xs opacity-60 mt-1">
        Bare phrase, <code>ns:value</code>, or <code>ns:*</code> to list every tag in a namespace.
      </span>
    </label>

    <fieldset class="border border-base-300 rounded-sm p-3">
      <legend class="text-xs px-1 opacity-70">Search in</legend>
      <div class="grid grid-cols-2 sm:grid-cols-3 gap-2">
        <label class="cursor-pointer flex items-center gap-2">
          <input type="checkbox" name="s_filename" class="checkbox checkbox-sm" {% if sources.filename %}checked{% endif %}/>
          <span>File name</span>
        </label>
        <label class="cursor-pointer flex items-center gap-2">
          <input type="checkbox" name="s_item_name" class="checkbox checkbox-sm" {% if sources.item_name %}checked{% endif %}/>
          <span>Item name</span>
        </label>
        <label class="cursor-pointer flex items-center gap-2">
          <input type="checkbox" name="s_description" class="checkbox checkbox-sm" {% if sources.description %}checked{% endif %}/>
          <span>Description</span>
        </label>
        <label class="cursor-pointer flex items-center gap-2">
          <input type="checkbox" name="s_user_tags" class="checkbox checkbox-sm" {% if sources.user_tags %}checked{% endif %}/>
          <span>User tags</span>
        </label>
        <label class="cursor-pointer flex items-center gap-2">
          <input type="checkbox" name="s_ocr" class="checkbox checkbox-sm" {% if sources.ocr %}checked{% endif %}/>
          <span>OCR text (<code>ocr:*</code>)</span>
        </label>
        <label class="cursor-pointer flex items-center gap-2">
          <input type="checkbox" name="s_desc" class="checkbox checkbox-sm" {% if sources.desc %}checked{% endif %}/>
          <span>Descriptions (<code>desc:*</code>)</span>
        </label>
        <label class="cursor-pointer flex items-center gap-2">
          <input type="checkbox" name="s_other_ns" class="checkbox checkbox-sm" {% if sources.other_ns %}checked{% endif %}/>
          <span>Other namespaces</span>
        </label>
      </div>
    </fieldset>

    <div class="flex gap-2">
      <button class="btn btn-primary btn-sm" type="submit">Search</button>
      <a href="/search" class="btn btn-ghost btn-sm">Reset</a>
    </div>
  </form>

  {% if submitted and q %}
    <p class="text-xs opacity-60">{{ total }} match{% if total != 1 %}es{% endif %} for "{{ q }}"</p>
    {% if uploads|length == 0 %}
      <p class="opacity-70">Nothing found. Try unchecking fewer sources, or broaden the phrase.</p>
    {% else %}
      <div class="grid grid-cols-2 md:grid-cols-4 gap-3">
        {% for u in uploads %}
          <a href="/uploads/{{ u.id }}" class="card bg-base-200 hover:bg-base-300 p-2">
            {% if u.content_type == "image/gif" or u.content_type is startingwith("video/") %}
              {# Anything that moves shows the `preview` worker's short animated WebP.
                 Until that exists, fall back to the still — the original GIF, or the
                 frame the `poster` worker extracted — and failing that, a label. #}
              <img class="w-full h-32 object-cover rounded-sm" loading="lazy"
                   src="/files/{{ u.item_path | derived("preview", "webp") }}"
                   data-fallback-src="/files/{% if u.content_type == "image/gif" %}{{ u.item_path }}{% else %}{{ u.item_path | derived("poster", "jpg") }}{% endif %}"
                   alt="{{ u.file_name_original }}" data-fallback="{% if u.content_type == "image/gif" %}gif{% else %}video{% endif %}"/>
            {% elif u.content_type is startingwith("image/") %}
              <img class="w-full h-32 object-cover rounded-sm" src="/files/{{ u.item_path }}" alt="{{ u.file_name_original }}"/>
            {% else %}
              <div class="w-full h-32 flex items-center justify-center bg-base-300 rounded-sm text-xs">
                {{ u.content_type or "binary" }}
              </div>
            {% endif %}
            <div class="text-xs mt-1 truncate">{{ u.item_name or u.file_name_original }}</div>
            <div class="text-[10px] opacity-60 flex flex-wrap items-center gap-1">
              <span>{{ u.processing_status }}</span>
              {% set hits = matched_tags[u.id] %}
              {% if hits %}
                {% for t in hits %}
                  <span class="badge badge-accent badge-xs"
                        title="{% if t.namespace %}{{ t.namespace }}:{% endif %}{{ t.tag_value }}">
                    {%- if t.namespace -%}{{ t.namespace }}:{%- endif -%}{{ t.tag_value }}
                  </span>
                {% endfor %}
              {% endif %}
            </div>
          </a>
        {% endfor %}
      </div>
    {% endif %}
  {% endif %}
</div>
{% endblock %}