fancybox — Lightbox link wrapper s hover overlay a ikonou lupy. Auto-bind přes data-fancybox.

app/components/Gallery/fancybox.latte
{*
	Fancybox — wrapper pro lightbox link s hover overlay.

	Single image:
		{include fancybox.latte, src => '/img/large.jpg', thumb => '/img/thumb.jpg', alt => 'Foto'}

	Group (galerie — všechny linky se stejným $group jsou navigovatelné):
		{include fancybox.latte, src => $url, thumb => $thumbUrl, group => 'gallery-1', alt => $alt}

	Parametry:
	- $src     (string)        URL plnohodnotného obrázku (povinné)
	- $thumb   (string|null)   URL náhledu (default = $src)
	- $alt     (string)        alt text (default '')
	- $group   (string|null)   group ID pro galerii (Fancybox data-fancybox)
	- $caption (string|null)   popisek v lightboxu
	- $class   (string|null)   extra třída
	- $showOverlay (bool)      hover overlay s ikonou (default true)
*}
{var $src = $src ?? null}
{var $thumb = $thumb ?? $src}
{var $alt = $alt ?? ''}
{var $group = $group ?? 'fancybox'}
{var $caption = $caption ?? null}
{var $class = $class ?? null}
{var $showOverlay = $showOverlay ?? true}

<a href="{$src}"
   class="fancybox-trigger{if $class} {$class}{/if}"
   data-fancybox="{$group}"
   {if $caption}data-caption="{$caption}"{/if}>
	<img src="{$thumb}" alt="{$alt}" loading="lazy">

	{if $showOverlay}
		<span class="fancybox-trigger__overlay" aria-hidden="true">
			<svg class="fancybox-trigger__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
				<circle cx="11" cy="11" r="7"/>
				<line x1="16.5" y1="16.5" x2="21" y2="21"/>
				<line x1="11" y1="8" x2="11" y2="14"/>
				<line x1="8" y1="11" x2="14" y2="11"/>
			</svg>
		</span>
	{/if}
</a>
resources/sass/components/_fancybox.scss
// ─── Configurable variables (override before @import) ──────────────────
$cgui-fancybox-trigger-cursor:        zoom-in !default;
$cgui-fancybox-trigger-overlay-bg:    rgba(0, 0, 0, 0.4) !default;
$cgui-fancybox-trigger-overlay-color: #fff !default;
$cgui-fancybox-trigger-icon-size:     38px !default;
$cgui-fancybox-trigger-radius:        $cgui-radius !default;
$cgui-fancybox-trigger-transition:    opacity 0.2s !default;
// ───────────────────────────────────────────────────────────────────────

// Wrapper kolem trigger linku — přidává hover overlay s ikonou lupy.
.fancybox-trigger {
	position: relative;
	display: block;
	overflow: hidden;
	border-radius: $cgui-fancybox-trigger-radius;
	cursor: $cgui-fancybox-trigger-cursor;

	img {
		display: block;
		width: 100%;
		height: auto;
		transition: transform 0.3s;
	}

	&__overlay {
		position: absolute;
		inset: 0;
		display: flex;
		align-items: center;
		justify-content: center;
		background: $cgui-fancybox-trigger-overlay-bg;
		color: $cgui-fancybox-trigger-overlay-color;
		opacity: 0;
		transition: $cgui-fancybox-trigger-transition;
		pointer-events: none;
	}

	&__icon {
		width: $cgui-fancybox-trigger-icon-size;
		height: $cgui-fancybox-trigger-icon-size;
	}

	&:hover,
	&:focus {
		.fancybox-trigger__overlay {
			opacity: 1;
		}

		img {
			transform: scale(1.03);
		}
	}
}
resources/js/components/fancybox.js
// Fancybox — auto-bind pro [data-fancybox]. Wraps Fancybox.
// Vyžaduje: npm install @fancyapps/ui

import { Fancybox } from '@fancyapps/ui';

const DEFAULT_OPTIONS = {
	hideScrollbar: true,
	Toolbar: {
		display: {
			left: ['infobar'],
			middle: [],
			right: ['slideshow', 'thumbs', 'close'],
		},
	},
	Thumbs: {
		type: 'classic',
	},
};

let bound = false;

export function bind(selector = '[data-fancybox]', options = {}) {
	Fancybox.bind(selector, { ...DEFAULT_OPTIONS, ...options });
	bound = true;
}

export function unbind(selector = '[data-fancybox]') {
	Fancybox.unbind(selector);
}

export function open(items, options = {}) {
	return Fancybox.show(items, { ...DEFAULT_OPTIONS, ...options });
}

// Auto-bind on first import
if (typeof document !== 'undefined' && !bound) {
	if (document.readyState !== 'loading') {
		bind();
	} else {
		document.addEventListener('DOMContentLoaded', () => bind());
	}
}

export { Fancybox };