feat: make thumbhash work with image slider
Some checks failed
Deploy to SFTP Server / build (push) Has been cancelled
Some checks failed
Deploy to SFTP Server / build (push) Has been cancelled
This commit is contained in:
@ -49,6 +49,7 @@ const link = translatePath(`/${collection}/${slug.split("/")[0]}`);
|
||||
<a href={link}>
|
||||
<Image
|
||||
hash
|
||||
loader={false}
|
||||
src={cover}
|
||||
alt={"cover for " + title}
|
||||
class="right-0 h-full object-cover object-center rounded-none border-l border-neutral"
|
||||
|
@ -1,40 +1,20 @@
|
||||
---
|
||||
import type { ImageMetadata } from "astro";
|
||||
import { Picture as AstroImage } from "astro:assets";
|
||||
import { generateThumbHash } from "@helpers/image";
|
||||
interface Props {
|
||||
src: ImageMetadata;
|
||||
alt: string;
|
||||
class?: string;
|
||||
caption?: string;
|
||||
hash?: boolean;
|
||||
loader?: boolean;
|
||||
maxWidth?: number;
|
||||
}
|
||||
import { rgbaToThumbHash } from "thumbhash";
|
||||
|
||||
const { src: image, hash = true, alt, maxWidth } = Astro.props;
|
||||
const { src: image, loader = true, hash = true, alt, maxWidth } = Astro.props;
|
||||
|
||||
let thumbhash = "";
|
||||
|
||||
const s = await import("sharp");
|
||||
const sharp = s.default;
|
||||
|
||||
if (hash) {
|
||||
const scaleFactor = 100 / Math.max(image.width, image.height);
|
||||
|
||||
const smallWidth = Math.floor(image.width * scaleFactor);
|
||||
const smallHeight = Math.floor(image.height * scaleFactor);
|
||||
|
||||
//@ts-ignore
|
||||
const smallImg = await sharp(image.fsPath)
|
||||
.resize(smallWidth, smallHeight)
|
||||
.withMetadata()
|
||||
.raw()
|
||||
.ensureAlpha()
|
||||
.toBuffer();
|
||||
|
||||
const buffer = rgbaToThumbHash(smallWidth, smallHeight, smallImg);
|
||||
thumbhash = Buffer.from(buffer).toString("base64");
|
||||
}
|
||||
let thumbhash = hash ? await generateThumbHash(image) : "";
|
||||
|
||||
const sizes = [
|
||||
{
|
||||
@ -59,7 +39,9 @@ const sizes = [
|
||||
src={image}
|
||||
alt={alt}
|
||||
data-thumbhash={thumbhash}
|
||||
pictureAttributes={{ class: hash ? "block h-full relative" : "" }}
|
||||
pictureAttributes={{
|
||||
class: `${hash ? "block h-full relative" : ""} ${loader ? "thumb" : ""}`,
|
||||
}}
|
||||
class={Astro.props.class}
|
||||
widths={sizes.map((size) => size.width)}
|
||||
sizes={sizes
|
||||
|
@ -1,8 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let slot: HTMLDivElement;
|
||||
let images: HTMLImageElement[];
|
||||
let images: (HTMLPictureElement | HTMLImageElement)[];
|
||||
|
||||
export let title: string;
|
||||
|
||||
@ -10,17 +8,24 @@
|
||||
let height: number;
|
||||
let loaded = false;
|
||||
|
||||
function hide(img: HTMLImageElement) {
|
||||
function hide(img: HTMLPictureElement) {
|
||||
img.classList.remove("active");
|
||||
}
|
||||
|
||||
function show(img: HTMLImageElement) {
|
||||
function show(img: HTMLPictureElement) {
|
||||
img.classList.add("active");
|
||||
if (img?.alt) altText = img.alt;
|
||||
const _img = img.querySelector("img");
|
||||
if (!_img) return;
|
||||
_img.addEventListener("load", () => {
|
||||
img.classList.remove("thumb-loading");
|
||||
_img.style.opacity = "1";
|
||||
console.log("loaded");
|
||||
});
|
||||
if (_img?.alt) altText = _img.alt;
|
||||
else altText = "";
|
||||
height = img.getBoundingClientRect().height;
|
||||
height = _img.getBoundingClientRect().height;
|
||||
setTimeout(() => {
|
||||
height = img.getBoundingClientRect().height;
|
||||
height = _img.getBoundingClientRect().height;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
@ -33,8 +38,8 @@
|
||||
show(images[index]);
|
||||
}
|
||||
|
||||
$: if (slot) {
|
||||
images = Array.from(slot.querySelectorAll("img"));
|
||||
$: if (slot && !images?.length) {
|
||||
images = Array.from(slot.querySelectorAll("picture"));
|
||||
if (images?.length) {
|
||||
images.forEach(hide);
|
||||
show(images[index]);
|
||||
@ -52,12 +57,26 @@
|
||||
<div
|
||||
class="wrapper grid overflow-hidden rounded-xl border border-light"
|
||||
class:title
|
||||
class:not-loaded={!loaded}
|
||||
class:loaded
|
||||
style={`--height:${height}px`}
|
||||
>
|
||||
{#if title}
|
||||
<div class="flex items-center p-x-4 bg">
|
||||
<div class="flex items-center p-x-4 bg justify-between">
|
||||
<h3>{title}</h3>
|
||||
|
||||
<div class="overflow-hidden rounded-md bg-light gap-2 flex p-1">
|
||||
<button
|
||||
class="flex-1 i-tabler-arrow-left"
|
||||
aria-label="previous image"
|
||||
on:click={() => setIndex(index - 1)}
|
||||
/>
|
||||
<button
|
||||
class="flex-1 i-tabler-arrow-right"
|
||||
aria-label="next image"
|
||||
on:click={() => setIndex(index + 1)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@ -65,22 +84,14 @@
|
||||
<slot />
|
||||
</div>
|
||||
<div class="p-2 flex place-content-between bg">
|
||||
<p>{index + 1}/{images?.length}</p>
|
||||
<p>
|
||||
{#if images?.length}
|
||||
{index + 1}/{images?.length}
|
||||
{/if}
|
||||
</p>
|
||||
{#if altText}
|
||||
<p class="text-right">{altText}</p>
|
||||
<p class="flex-1 text-center">{altText}</p>
|
||||
{/if}
|
||||
<div class="overflow-hidden rounded-md bg-light gap-2 flex p-1">
|
||||
<button
|
||||
class="flex-1 i-tabler-arrow-left"
|
||||
aria-label="previous image"
|
||||
on:click={() => setIndex(index - 1)}
|
||||
/>
|
||||
<button
|
||||
class="flex-1 i-tabler-arrow-right"
|
||||
aria-label="next image"
|
||||
on:click={() => setIndex(index + 1)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -102,11 +113,15 @@
|
||||
height: calc(var(--height) + 40px);
|
||||
}
|
||||
|
||||
.not-loaded .images :global(picture):first-child {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.wrapper.title.loaded {
|
||||
height: calc(var(--height) + 80px);
|
||||
}
|
||||
|
||||
.images :global(img) {
|
||||
.images :global(picture) {
|
||||
border-radius: 0px;
|
||||
display: none;
|
||||
}
|
||||
|
@ -13,7 +13,13 @@ const t = useTranslations(Astro.url);
|
||||
classes="googley-eye-target relative rounded-diag-md border border-neutral gradient grid grid-cols-[250px_1fr] h-[180px] mt-8"
|
||||
>
|
||||
<div class="image">
|
||||
<Image src={MaxImg} alt="its mee" hash={false} maxWidth={700} />
|
||||
<Image
|
||||
src={MaxImg}
|
||||
alt="its mee"
|
||||
hash={false}
|
||||
maxWidth={700}
|
||||
loader={false}
|
||||
/>
|
||||
<div class="eye right">
|
||||
<GoogleyEye client:load />
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user