| ---
|
| import { Picture } from "astro:assets";
|
| import * as path from "node:path";
|
| import type { ImageMetadata } from "astro";
|
| import {
|
| getFallbackFormat,
|
| getImageFormats,
|
| getImageQuality,
|
| } from "@/utils/image-utils";
|
| import { url } from "@/utils/url-utils";
|
|
|
| interface Props {
|
| config: {
|
| src: {
|
| desktop?: string;
|
| mobile?: string;
|
| };
|
| position?: string;
|
| zIndex?: number;
|
| opacity?: number;
|
| blur?: number;
|
| };
|
| className?: string;
|
| }
|
|
|
| const { config, className } = Astro.props;
|
|
|
|
|
| const desktopSrc = config.src.desktop || config.src.mobile || "";
|
| const mobileSrc = config.src.mobile || config.src.desktop || "";
|
|
|
|
|
| if (!desktopSrc && !mobileSrc) {
|
| return null;
|
| }
|
|
|
|
|
| const isLocalImage = (src: string) => {
|
| return (
|
| src &&
|
| !src.startsWith("/") &&
|
| !src.startsWith("http") &&
|
| !src.startsWith("https") &&
|
| !src.startsWith("data:")
|
| );
|
| };
|
|
|
| const isPublicImage = (src: string) => src.startsWith("/");
|
|
|
|
|
| let desktopImg: ImageMetadata | null = null;
|
| let mobileImg: ImageMetadata | null = null;
|
|
|
| if (isLocalImage(desktopSrc)) {
|
| const files = import.meta.glob<ImageMetadata>("../../**", {
|
| import: "default",
|
| });
|
| const normalizedPath = path
|
| .normalize(path.join("../../", desktopSrc))
|
| .replace(/\\/g, "/");
|
| const file = files[normalizedPath];
|
| if (file) {
|
| desktopImg = await file();
|
| }
|
| }
|
|
|
| if (isLocalImage(mobileSrc)) {
|
| const files = import.meta.glob<ImageMetadata>("../../**", {
|
| import: "default",
|
| });
|
| const normalizedPath = path
|
| .normalize(path.join("../../", mobileSrc))
|
| .replace(/\\/g, "/");
|
| const file = files[normalizedPath];
|
| if (file) {
|
| mobileImg = await file();
|
| }
|
| }
|
|
|
|
|
| const position = config.position || "center";
|
| const zIndex = config.zIndex || -1;
|
| const opacity = config.opacity || 0.8;
|
| const blur = config.blur || 0;
|
|
|
|
|
| const imageFormats = getImageFormats();
|
| const fallbackFormat = getFallbackFormat();
|
| const desktopQuality = getImageQuality();
|
| const mobileQuality = Math.round(getImageQuality() * 0.9);
|
|
|
| const imageStyle = `object-position: ${position};${blur > 0 ? ` filter: blur(${blur}px);` : ""}`;
|
| ---
|
|
|
| <div
|
| class:list={[
|
| "fixed inset-0 w-full h-full overflow-hidden pointer-events-none",
|
| className
|
| ].filter(Boolean)}
|
| style={`z-index: ${zIndex}; opacity: ${opacity};`}
|
| data-overlay-wallpaper
|
| >
|
|
|
| {desktopSrc && (
|
| <div class="hidden lg:block w-full h-full relative">
|
| {desktopImg ? (
|
| <Picture
|
| src={desktopImg}
|
| alt="Desktop wallpaper"
|
| class="absolute inset-0 w-full h-full object-cover"
|
| style={imageStyle}
|
| formats={imageFormats}
|
| fallbackFormat={fallbackFormat}
|
| widths={[1280, 1920, 2560]}
|
| sizes="100vw"
|
| loading="eager"
|
| fetchpriority="high"
|
| quality={desktopQuality}
|
| />
|
| ) : (
|
| <img
|
| src={isPublicImage(desktopSrc) ? url(desktopSrc) : desktopSrc}
|
| alt="Desktop wallpaper"
|
| class="absolute inset-0 w-full h-full object-cover"
|
| style={imageStyle}
|
| loading="eager"
|
| fetchpriority="high"
|
| />
|
| )}
|
| </div>
|
| )}
|
|
|
|
|
| {mobileSrc && (
|
| <div class="block lg:hidden w-full h-full relative">
|
| {mobileImg ? (
|
| <Picture
|
| src={mobileImg}
|
| alt="Mobile wallpaper"
|
| class="absolute inset-0 w-full h-full object-cover"
|
| style={imageStyle}
|
| formats={imageFormats}
|
| fallbackFormat={fallbackFormat}
|
| widths={[640, 750, 1080]}
|
| sizes="100vw"
|
| loading="eager"
|
| fetchpriority="high"
|
| quality={mobileQuality}
|
| />
|
| ) : (
|
| <img
|
| src={isPublicImage(mobileSrc) ? url(mobileSrc) : mobileSrc}
|
| alt="Mobile wallpaper"
|
| class="absolute inset-0 w-full h-full object-cover"
|
| style={imageStyle}
|
| loading="eager"
|
| fetchpriority="high"
|
| />
|
| )}
|
| </div>
|
| )}
|
| </div>
|
|
|
|
|