1c2fb321bc
- Gallery photos: 220px → 280px height, 180px on mobile (≤480px) - Link preview cards: full CSS for horizontal card layout (text left, image right) - Lightbox: touch/swipe support for mobile (50px threshold) - URL linkification: bare URLs in content auto-wrapped in <a> tags before AP delivery Confab-Link: http://localhost:8080/sessions/c5b1471e-b046-44d9-b94f-ab5e68fae7cc
73 lines
4.1 KiB
Plaintext
73 lines
4.1 KiB
Plaintext
{# Media attachments partial — included from ap-item-card.njk #}
|
|
|
|
{# Photo gallery with lightbox #}
|
|
{% if item.photo and item.photo.length > 0 %}
|
|
{% set displayCount = item.photo.length if item.photo.length < 4 else 4 %}
|
|
{% set extraCount = item.photo.length - 4 %}
|
|
{% set totalPhotos = item.photo.length %}
|
|
<div x-data="{ lightbox: false, idx: 0, touchX: 0 }" class="ap-card__gallery ap-card__gallery--{{ displayCount }}">
|
|
{% for photo in item.photo %}
|
|
{# Support both old string format and new object format #}
|
|
{% set photoSrc = photo.url if photo.url else photo %}
|
|
{% set photoAlt = photo.alt if photo.alt else "" %}
|
|
{% set photoBlurhash = photo.blurhash if photo.blurhash else "" %}
|
|
{# Focus-point cropping: convert -1..1 range to CSS object-position percentages #}
|
|
{% set focusStyle = "" %}
|
|
{% if photo.focus and photo.focus.x != null and photo.focus.y != null %}
|
|
{% set fpX = ((photo.focus.x + 1) / 2 * 100) %}
|
|
{% set fpY = ((1 - (photo.focus.y + 1) / 2) * 100) %}
|
|
{% set focusStyle = "object-position:" + fpX + "% " + fpY + "%;" %}
|
|
{% endif %}
|
|
{% if loop.index0 < 4 %}
|
|
<div class="ap-card__gallery-item" x-data="{ showAlt: false }">
|
|
<button type="button" @click="idx = {{ loop.index0 }}; lightbox = true" class="ap-card__gallery-link{% if loop.index0 == 3 and extraCount > 0 %} ap-card__gallery-link--more{% endif %}">
|
|
<img src="{{ photoSrc }}" alt="{{ photoAlt }}" loading="lazy"{% if focusStyle %} style="{{ focusStyle }}"{% endif %}{% if photoBlurhash %} data-blurhash="{{ photoBlurhash }}"{% endif %}>
|
|
{% if loop.index0 == 3 and extraCount > 0 %}
|
|
<span class="ap-card__gallery-more">+{{ extraCount }}</span>
|
|
{% endif %}
|
|
</button>
|
|
{% if photoAlt %}
|
|
<button type="button" class="ap-media__alt-badge" @click.stop="showAlt = !showAlt" :aria-expanded="showAlt">ALT</button>
|
|
<div class="ap-media__alt-text" x-show="showAlt" x-cloak @click.stop>{{ photoAlt }}</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{# Lightbox modal — teleported to body to prevent overflow clipping #}
|
|
<template x-teleport="body">
|
|
<div x-show="lightbox" x-cloak @keydown.escape.window="lightbox = false" @click.self="lightbox = false" @touchstart="touchX = $event.changedTouches[0].clientX" @touchend="let dx = $event.changedTouches[0].clientX - touchX; if (dx < -50) idx = (idx + 1) % {{ totalPhotos }}; else if (dx > 50) idx = (idx - 1 + {{ totalPhotos }}) % {{ totalPhotos }}" class="ap-lightbox" role="dialog" aria-modal="true">
|
|
<button type="button" @click="lightbox = false" class="ap-lightbox__close" aria-label="Close">×</button>
|
|
{% if totalPhotos > 1 %}
|
|
<button type="button" @click="idx = (idx - 1 + {{ totalPhotos }}) % {{ totalPhotos }}" class="ap-lightbox__prev" aria-label="Previous image">‹</button>
|
|
{% endif %}
|
|
<img :src="[{% for photo in item.photo %}'{{ photo.url if photo.url else photo }}'{% if not loop.last %},{% endif %}{% endfor %}][idx]"
|
|
:alt="[{% for photo in item.photo %}'{{ (photo.alt if photo.alt else '') | replace(\"'\", \"\\'\") }}'{% if not loop.last %},{% endif %}{% endfor %}][idx]"
|
|
class="ap-lightbox__img">
|
|
{% if totalPhotos > 1 %}
|
|
<button type="button" @click="idx = (idx + 1) % {{ totalPhotos }}" class="ap-lightbox__next" aria-label="Next image">›</button>
|
|
<div class="ap-lightbox__counter" x-text="(idx + 1) + ' / ' + {{ totalPhotos }}"></div>
|
|
{% endif %}
|
|
</div>
|
|
</template>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Video embed #}
|
|
{% if item.video and item.video.length > 0 %}
|
|
<div class="ap-card__video">
|
|
<video controls preload="metadata" src="{{ item.video[0] }}">
|
|
{{ __("activitypub.reader.videoNotSupported") }}
|
|
</video>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Audio player #}
|
|
{% if item.audio and item.audio.length > 0 %}
|
|
<div class="ap-card__audio">
|
|
<audio controls preload="metadata" src="{{ item.audio[0] }}">
|
|
{{ __("activitypub.reader.audioNotSupported") }}
|
|
</audio>
|
|
</div>
|
|
{% endif %}
|