summaryrefslogtreecommitdiffstats
path: root/src/ui/objects/Lightbox.tsx
diff options
context:
space:
mode:
authorVolpeon <git@volpeon.ink>2026-07-22 19:40:59 +0200
committerVolpeon <git@volpeon.ink>2026-07-22 19:40:59 +0200
commitc1e28224aa2e1450031669d9a7e359b63e04687d (patch)
tree68f3d8905c763a91f68001d868197effa92adafa /src/ui/objects/Lightbox.tsx
downloadcorvos-website-c1e28224aa2e1450031669d9a7e359b63e04687d.tar.gz
corvos-website-c1e28224aa2e1450031669d9a7e359b63e04687d.tar.bz2
corvos-website-c1e28224aa2e1450031669d9a7e359b63e04687d.zip
Init
Diffstat (limited to 'src/ui/objects/Lightbox.tsx')
-rw-r--r--src/ui/objects/Lightbox.tsx122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/ui/objects/Lightbox.tsx b/src/ui/objects/Lightbox.tsx
new file mode 100644
index 0000000..00268cc
--- /dev/null
+++ b/src/ui/objects/Lightbox.tsx
@@ -0,0 +1,122 @@
1/** Biome-ignore-all lint/a11y/useValidAnchor: <explanation> */
2/** Biome-ignore-all lint/a11y/useAltText: <explanation> */
3
4import type { HTMLAttributes } from "corvos/plugins/jsx.ts";
5
6import { Icon } from "$/ui/objects/Icon.tsx";
7
8import { ActionButton } from "./ActionButton.tsx";
9import { LoadingIndicator } from "./LoadingIndicator.tsx";
10import { Thumbnail } from "./Thumbnail.tsx";
11
12export type Props = HTMLAttributes<"dialog">;
13
14export const Lightbox = ({ class: cls, ...props }: Props) => (
15 <dialog
16 class:list={["o-lightbox o-lightbox--static-black is-modal t-static-white", cls]}
17 closedby="any"
18 x-id="['lightbox']"
19 x-bind:id="$id('lightbox')"
20 x-data="lightbox"
21 x-on:close="handleClose"
22 x-on:touchstart="handleTouchStart"
23 x-on:touchend="handleTouchEnd"
24 {...{
25 "x-on:keydown.document.capture": "handleKeyDown",
26 }}
27 {...props}
28 >
29 <div x-show="items.length > 1" class="o-lightbox__info">
30 <small class="u-mis-100 u-mie-200 u-d-none@sm-lo">
31 <strong x-text="current + 1"></strong> <span class="u-c-mute-more u-mi-50">&#x2044;</span>{" "}
32 <strong x-text="items.length"></strong>
33 </small>
34 <ActionButton
35 x-on:click="prev"
36 as="button"
37 pill
38 level="quiet"
39 icon={<Icon icon="caret-left" variant="bold" />}
40 variant="static-white"
41 />
42 <ActionButton
43 x-on:click="next"
44 as="button"
45 pill
46 level="quiet"
47 icon={<Icon icon="caret-right" variant="bold" />}
48 variant="static-white"
49 />
50 </div>
51
52 <div class="o-lightbox__controls">
53 <ActionButton
54 x-show="zoomedFull"
55 x-on:click="toggleZoom"
56 as="button"
57 class="u-mie-100"
58 pill
59 level="quiet"
60 icon={<Icon icon="magnifying-glass-minus" variant="bold" />}
61 variant="static-white"
62 />
63 <ActionButton
64 x-show="!zoomedFull"
65 x-on:click="toggleZoom"
66 as="button"
67 class="u-mie-100"
68 pill
69 level="quiet"
70 icon={<Icon icon="magnifying-glass-plus" variant="bold" />}
71 variant="static-white"
72 />
73 <ActionButton
74 x-bind:commandfor="$id('lightbox')"
75 command="close"
76 as="button"
77 pill
78 level="quiet"
79 icon={<Icon icon="x" variant="bold" />}
80 variant="static-white"
81 />
82 </div>
83
84 <img
85 class="o-lightbox__img"
86 x-ref="img"
87 x-bind:src="currentItem?.src ?? ''"
88 x-bind:srcset="currentItem?.srcset ?? ''"
89 x-bind:alt="currentItem?.alt ?? ''"
90 x-on:load="loading = false"
91 x-on:mousemove="handleMouseMove"
92 x-on:touchmove="handleTouchMove"
93 x-on:dblclick="handleDoubleClick"
94 x-bind:class="{ 'is-hidden': loading }"
95 x-bind:style="{ transform: `translate(${offsetX}px, ${offsetY}px) scale(${zoom})` }"
96 {...{
97 "x-on:mousedown.prevent": "handleMouseDown",
98 "x-on:mouseup.window": "handleMouseUp",
99 "x-on:wheel.prevent": "handleScroll",
100 }}
101 />
102
103 <div class="o-lightbox__placeholder">
104 <LoadingIndicator />
105 </div>
106
107 <div class="o-lightbox__thumbnails" x-show="items.length > 1" x-ref="thumbnails">
108 <template x-for="(item, i) in items">
109 <Thumbnail
110 class="o-lightbox__thumbnail"
111 variant="static-white"
112 x-bind:src="item.thumbnail ?? item.src"
113 x-bind:srcset="item.srcset"
114 x-bind:alt="item.alt"
115 x-bind:href="item.src"
116 x-bind:class="{ 'is-selected': i === current }"
117 {...{ "x-on:click.prevent": "current = i" }}
118 />
119 </template>
120 </div>
121 </dialog>
122);