diff options
| author | Volpeon <git@volpeon.ink> | 2026-07-22 19:40:59 +0200 |
|---|---|---|
| committer | Volpeon <git@volpeon.ink> | 2026-07-22 19:40:59 +0200 |
| commit | c1e28224aa2e1450031669d9a7e359b63e04687d (patch) | |
| tree | 68f3d8905c763a91f68001d868197effa92adafa /src/ui/objects/Lightbox.tsx | |
| download | corvos-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.tsx | 122 |
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 | |||
| 4 | import type { HTMLAttributes } from "corvos/plugins/jsx.ts"; | ||
| 5 | |||
| 6 | import { Icon } from "$/ui/objects/Icon.tsx"; | ||
| 7 | |||
| 8 | import { ActionButton } from "./ActionButton.tsx"; | ||
| 9 | import { LoadingIndicator } from "./LoadingIndicator.tsx"; | ||
| 10 | import { Thumbnail } from "./Thumbnail.tsx"; | ||
| 11 | |||
| 12 | export type Props = HTMLAttributes<"dialog">; | ||
| 13 | |||
| 14 | export 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">⁄</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 | ); | ||
