summaryrefslogtreecommitdiffstats
path: root/src/ui/objects/Lightbox.tsx
blob: 00268cc4439cff7b0bb052d50f9aa85c0926c958 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/** Biome-ignore-all lint/a11y/useValidAnchor: <explanation> */
/** Biome-ignore-all lint/a11y/useAltText: <explanation> */

import type { HTMLAttributes } from "corvos/plugins/jsx.ts";

import { Icon } from "$/ui/objects/Icon.tsx";

import { ActionButton } from "./ActionButton.tsx";
import { LoadingIndicator } from "./LoadingIndicator.tsx";
import { Thumbnail } from "./Thumbnail.tsx";

export type Props = HTMLAttributes<"dialog">;

export const Lightbox = ({ class: cls, ...props }: Props) => (
	<dialog
		class:list={["o-lightbox o-lightbox--static-black is-modal t-static-white", cls]}
		closedby="any"
		x-id="['lightbox']"
		x-bind:id="$id('lightbox')"
		x-data="lightbox"
		x-on:close="handleClose"
		x-on:touchstart="handleTouchStart"
		x-on:touchend="handleTouchEnd"
		{...{
			"x-on:keydown.document.capture": "handleKeyDown",
		}}
		{...props}
	>
		<div x-show="items.length > 1" class="o-lightbox__info">
			<small class="u-mis-100 u-mie-200 u-d-none@sm-lo">
				<strong x-text="current + 1"></strong> <span class="u-c-mute-more u-mi-50">&#x2044;</span>{" "}
				<strong x-text="items.length"></strong>
			</small>
			<ActionButton
				x-on:click="prev"
				as="button"
				pill
				level="quiet"
				icon={<Icon icon="caret-left" variant="bold" />}
				variant="static-white"
			/>
			<ActionButton
				x-on:click="next"
				as="button"
				pill
				level="quiet"
				icon={<Icon icon="caret-right" variant="bold" />}
				variant="static-white"
			/>
		</div>

		<div class="o-lightbox__controls">
			<ActionButton
				x-show="zoomedFull"
				x-on:click="toggleZoom"
				as="button"
				class="u-mie-100"
				pill
				level="quiet"
				icon={<Icon icon="magnifying-glass-minus" variant="bold" />}
				variant="static-white"
			/>
			<ActionButton
				x-show="!zoomedFull"
				x-on:click="toggleZoom"
				as="button"
				class="u-mie-100"
				pill
				level="quiet"
				icon={<Icon icon="magnifying-glass-plus" variant="bold" />}
				variant="static-white"
			/>
			<ActionButton
				x-bind:commandfor="$id('lightbox')"
				command="close"
				as="button"
				pill
				level="quiet"
				icon={<Icon icon="x" variant="bold" />}
				variant="static-white"
			/>
		</div>

		<img
			class="o-lightbox__img"
			x-ref="img"
			x-bind:src="currentItem?.src ?? ''"
			x-bind:srcset="currentItem?.srcset ?? ''"
			x-bind:alt="currentItem?.alt ?? ''"
			x-on:load="loading = false"
			x-on:mousemove="handleMouseMove"
			x-on:touchmove="handleTouchMove"
			x-on:dblclick="handleDoubleClick"
			x-bind:class="{ 'is-hidden': loading }"
			x-bind:style="{ transform: `translate(${offsetX}px, ${offsetY}px) scale(${zoom})` }"
			{...{
				"x-on:mousedown.prevent": "handleMouseDown",
				"x-on:mouseup.window": "handleMouseUp",
				"x-on:wheel.prevent": "handleScroll",
			}}
		/>

		<div class="o-lightbox__placeholder">
			<LoadingIndicator />
		</div>

		<div class="o-lightbox__thumbnails" x-show="items.length > 1" x-ref="thumbnails">
			<template x-for="(item, i) in items">
				<Thumbnail
					class="o-lightbox__thumbnail"
					variant="static-white"
					x-bind:src="item.thumbnail ?? item.src"
					x-bind:srcset="item.srcset"
					x-bind:alt="item.alt"
					x-bind:href="item.src"
					x-bind:class="{ 'is-selected': i === current }"
					{...{ "x-on:click.prevent": "current = i" }}
				/>
			</template>
		</div>
	</dialog>
);