Files
ohm_streaming/templates/components/anime_search_results.html
T
root 4101d98a41 feat: complete UI redesign with DaisyUI + Tailwind CSS v4
Design system overhaul using DaisyUI v5 on Tailwind CSS v4:

- Custom 'ohmstream' dark theme with orange primary (#FF9F1C),
  magenta secondary, gold accent matching existing palette
- Tailwind CSS-first config (input.css source, style.css built output)
- DaisyUI components: navbar, drawer, cards, badges, alerts, tables,
  progress bars, tabs, toggles, stats, form controls, tooltips
- Mobile-first responsive layout with drawer navigation
- Eliminated ~500+ lines of embedded CSS across 15+ template files
- Removed all inline style spam from admin_panel and settings_section
- Preserved all HTMX triggers, Alpine.js state, and Jinja2 logic
- Updated auth-ui.js for DaisyUI tab-active class compatibility

Build: npm run build:css (minified) / npm run watch:css (dev)
2026-04-11 19:46:52 +00:00

129 lines
8.0 KiB
HTML

{% set default_lang = settings.default_lang if settings else 'vostfr' %}
{% set _groups = namespace(items={}) %}
{% for pid, items in (results or {}).items() %}
{% for item in items %}
{% set _key = item.title | lower | trim %}
{% if _key not in _groups.items %}
{% set _ = _groups.items.update({_key: {
"title": item.title,
"cover": item.cover_image or (item.metadata.poster_image if item.metadata else "") or "",
"synopsis": (item.metadata.synopsis if item.metadata and item.metadata.synopsis else ""),
"rating": item.metadata.rating if item.metadata and item.metadata.rating else "",
"genres": item.metadata.genres if item.metadata and item.metadata.genres else [],
"providers": [{ "id": item.provider_id or pid, "url": item.url }]
}}) %}
{% else %}
{% set _existing = _groups.items[_key] %}
{% if not _existing.cover and item.cover_image %}
{% set _ = _existing.update({"cover": item.cover_image}) %}
{% endif %}
{% if not _existing.synopsis and item.metadata and item.metadata.synopsis %}
{% set _ = _existing.update({"synopsis": item.metadata.synopsis}) %}
{% endif %}
{% if not _existing.rating and item.metadata and item.metadata.rating %}
{% set _ = _existing.update({"rating": item.metadata.rating}) %}
{% endif %}
{% set _ = _existing["providers"].append({"id": item.provider_id or pid, "url": item.url}) %}
{% endif %}
{% endfor %}
{% endfor %}
<div class="flex flex-col gap-4" x-data="{ openDropdown: null }">
{% if _groups.items.values() | list | length > 0 %}
{% for group in _groups.items.values() | list %}
{% set first_url = group.providers[0].url %}
<div class="card bg-base-200 border border-base-300 hover:border-primary transition-colors">
<div class="card-body p-5 flex-row gap-5">
<figure class="w-28 shrink-0">
<a href="{{ first_url }}" target="_blank" rel="noopener">
<img src="{{ group.cover or 'https://placehold.co/240x360/29274c/7e52a0?text=No+Image' }}"
alt="{{ group.title }}" loading="lazy" referrerpolicy="no-referrer"
class="rounded-lg w-full aspect-[2/3] object-cover"
onerror="this.src='https://placehold.co/240x360/29274c/7e52a0?text=Error'; this.onerror=null;">
</a>
</figure>
<div class="flex-1 min-w-0 flex flex-col gap-2">
<div class="flex items-baseline gap-3">
<h3 class="card-title text-base truncate">{{ group.title }}</h3>
{% if group.rating %}
<span class="badge badge-warning badge-sm shrink-0"><i class="fas fa-star"></i> {{ group.rating }}</span>
{% endif %}
</div>
{% if group.synopsis %}
<p class="text-sm text-base-content/60 line-clamp-3">{{ group.synopsis }}</p>
{% endif %}
{% if group.genres %}
<div class="flex flex-wrap gap-1">
{% for g in group.genres[:5] %}
<span class="badge badge-ghost badge-sm">{{ g }}</span>
{% endfor %}
</div>
{% endif %}
<div class="flex flex-wrap gap-1.5">
{% for p in group.providers %}
<a href="{{ p.url }}" target="_blank" rel="noopener"
class="badge badge-primary badge-outline text-xs uppercase tracking-wider hover:bg-primary hover:text-primary-content hover:border-primary transition-colors cursor-pointer">
{{ p.id | upper }}
</a>
{% endfor %}
</div>
<div class="flex flex-wrap gap-2 mt-1">
<a href="{{ first_url }}" target="_blank" rel="noopener"
class="btn btn-sm btn-primary">
<i class="fas fa-play"></i> Regarder
</a>
<div class="dropdown" @click.outside="openDropdown = null">
<div tabindex="0" role="button"
@click.stop="openDropdown = (openDropdown === '{{ first_url | urlencode }}') ? null : '{{ first_url | urlencode }}'">
<span class="btn btn-sm btn-secondary">
<i class="fas fa-download"></i> Telecharger <i class="fas fa-chevron-down text-[0.6rem] ml-1"></i>
</span>
</div>
<ul tabindex="0"
class="dropdown-content z-[1] menu p-2 shadow bg-base-200 rounded-box w-52 border border-base-300"
x-show="openDropdown === '{{ first_url | urlencode }}'"
x-transition>
<li>
<button class="flex items-center gap-2 text-sm"
hx-post="/api/anime/download-season?url={{ first_url | urlencode }}&lang={{ default_lang }}"
hx-swap="none"
hx-on::after-request="openDropdown = null">
<i class="fas fa-layer-group"></i> Saison complete
</button>
</li>
<li>
<button class="flex items-center gap-2 text-sm"
hx-get="/api/anime/episodes?url={{ first_url | urlencode }}&lang={{ default_lang }}&html=1"
hx-target="#player-container"
hx-swap="innerHTML"
hx-on::after-request="openDropdown = null; document.getElementById('player-container').scrollIntoView({behavior: 'smooth'})">
<i class="fas fa-list-ol"></i> Choisir des episodes
</button>
</li>
</ul>
</div>
<button class="btn btn-sm btn-accent btn-outline"
hx-post="/api/watchlist"
hx-vals='{"anime_url": "{{ first_url }}", "anime_title": "{{ group.title }}", "provider_id": "{{ group.providers[0].id }}", "lang": "{{ default_lang }}", "poster_image": "{{ group.cover }}"}'
hx-swap="none"
hx-on::after-request="if(event.detail.successful){this.innerHTML='<i class=\'fas fa-check\'></i> Suivi';this.disabled=true;this.classList.remove('btn-accent','btn-outline');this.classList.add('btn-accent','btn-ghost','pointer-events-none')}">
<i class="fas fa-plus"></i> Suivre
</button>
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="text-center py-20 text-base-content/40">
<i class="fas fa-search text-6xl mb-5 block opacity-20"></i>
<p>Aucun anime trouve pour votre recherche.</p>
</div>
{% endif %}
</div>