Show alt text inside the image lightbox (opt-in)
This commit is contained in:
parent
e61d12ea94
commit
b5dfc37022
3 changed files with 41 additions and 0 deletions
|
|
@ -8,6 +8,7 @@ import { MediaType } from '@/lib/mediaType';
|
|||
interface PreviewItem {
|
||||
url: string;
|
||||
type: MediaType;
|
||||
altText?: string;
|
||||
}
|
||||
|
||||
const items = ref<PreviewItem[]>([]);
|
||||
|
|
@ -136,6 +137,15 @@ defineExpose({ open, openCollection, close });
|
|||
<IconChevronRight class="size-6" />
|
||||
</button>
|
||||
|
||||
<div
|
||||
v-if="currentItem?.altText"
|
||||
data-testid="lightbox-alt-text"
|
||||
class="pointer-events-none absolute left-1/2 max-w-2xl -translate-x-1/2 rounded-lg bg-black/70 px-4 py-2 text-center text-sm text-white backdrop-blur-sm"
|
||||
:class="showNav ? 'bottom-14' : 'bottom-4'"
|
||||
>
|
||||
{{ currentItem.altText }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="showNav"
|
||||
class="absolute bottom-3 left-1/2 -translate-x-1/2 rounded-full bg-black/60 px-3 py-1 text-xs text-white tabular-nums"
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ const openPreview = (item: MediaItem) => {
|
|||
media.value.map((m) => ({
|
||||
url: m.url,
|
||||
type: classify(m) ?? MediaType.Image,
|
||||
altText: m.meta?.alt_text,
|
||||
})),
|
||||
idx,
|
||||
);
|
||||
|
|
@ -244,6 +245,7 @@ const onAltTextSave = (value: string): void => {
|
|||
v-for="(item, index) in media"
|
||||
:key="item.id"
|
||||
:ref="(el) => { if (el) mediaThumbRefs[index] = el as HTMLElement; }"
|
||||
data-testid="media-thumbnail"
|
||||
class="group relative aspect-square cursor-zoom-in overflow-hidden rounded-xl border-2 border-foreground bg-muted shadow-2xs transition-all focus:outline-none focus:ring-2 focus:ring-foreground focus:ring-offset-2"
|
||||
:class="[
|
||||
dragMediaIndex === index ? 'opacity-40' : '',
|
||||
|
|
|
|||
|
|
@ -51,6 +51,29 @@ function waitForAutosave(mixed $page): void
|
|||
JS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll on the browser side until the lightbox alt-text caption has mounted and
|
||||
* laid out. The lightbox is a Radix dialog with an open animation, so the
|
||||
* element is not present the instant the thumbnail is clicked; the harness
|
||||
* assertions do not auto-wait, so we wait here first.
|
||||
*/
|
||||
function waitForLightboxAltText(mixed $page): void
|
||||
{
|
||||
$page->script(<<<'JS'
|
||||
(async () => {
|
||||
const visible = () => {
|
||||
const el = document.querySelector('[data-testid="lightbox-alt-text"]');
|
||||
if (! el) return false;
|
||||
const rect = el.getBoundingClientRect();
|
||||
return rect.width > 0 && rect.height > 0;
|
||||
};
|
||||
for (let attempt = 0; attempt < 100 && ! visible(); attempt++) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
})();
|
||||
JS);
|
||||
}
|
||||
|
||||
test('editing alt text on an attached image persists it to the post media', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = Workspace::factory()->create(['user_id' => $user->id]);
|
||||
|
|
@ -84,4 +107,10 @@ function waitForAutosave(mixed $page): void
|
|||
|
||||
expect($post->fresh()->media[0]['meta']['alt_text'])
|
||||
->toBe('a golden retriever on a beach');
|
||||
|
||||
$page->click('@media-thumbnail');
|
||||
|
||||
waitForLightboxAltText($page);
|
||||
|
||||
$page->assertSeeIn('@lightbox-alt-text', 'a golden retriever on a beach');
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue