Skip to content

Commit

Permalink
Update video input
Browse files Browse the repository at this point in the history
  • Loading branch information
siffogh committed Oct 16, 2024
1 parent 5b0e544 commit ed7546a
Show file tree
Hide file tree
Showing 12 changed files with 229 additions and 364 deletions.
23 changes: 10 additions & 13 deletions storefront/components/sections/hero/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import MuxVideo from "@/components/shared/mux-video";
import {SanityImage} from "@/components/shared/sanity-image";
import Video from "@/components/shared/video";
import {stegaClean} from "@sanity/client/stega";
import React from "react";

import type {ModularPageSection} from "../types";

import LargeHero from "./large-hero";
import SimpleHero from "./simple-hero";

interface VideoData {
playbackId?: string;
resolution?: string;
}

export default function Hero(props: ModularPageSection<"section.hero">) {
const mediaType = stegaClean(props.mediaType);
const video = stegaClean(props.video?.asset) as unknown as VideoData;
const video = props.video;
const largeImage = stegaClean(props.largeImage);
return (
<section
Expand All @@ -25,11 +19,14 @@ export default function Hero(props: ModularPageSection<"section.hero">) {
{mediaType === "image" && <SimpleHero {...props} />}
{mediaType === "video" && video && (
<LargeHero props={props}>
<MuxVideo
className="aspect-[16/9] min-h-[590px] w-full rounded-lg object-cover object-center"
loading="eager"
video={video}
/>
<div className="aspect-[16/9] min-h-[590px] w-full overflow-hidden rounded-lg object-cover object-center">
<Video
aspectRatio="16/9"
fetchPriority="high"
poster={video.poster}
videoUrl={video.url}
/>
</div>
</LargeHero>
)}
{mediaType === "largeImage" && largeImage && (
Expand Down
113 changes: 0 additions & 113 deletions storefront/components/shared/mux-video.tsx

This file was deleted.

122 changes: 113 additions & 9 deletions storefront/components/shared/sanity-image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,118 @@ import {SanityImage as SanityImageBase} from "@tinloof/sanity-web";

export type SanityImageProps = Omit<SanityImageBaseProps, "config">;

const imageConfig = {
dataset: config.sanity.dataset,
projectId: config.sanity.projectId,
};

export function SanityImage(props: SanityImageProps) {
return (
<SanityImageBase
config={{
dataset: config.sanity.dataset,
projectId: config.sanity.projectId,
}}
{...props}
/>
);
return <SanityImageBase config={imageConfig} {...props} />;
}

import type {ImageUrlBuilder} from "sanity";

import {getImageDimensions} from "@sanity/asset-utils";
import imageUrlBuilder from "@sanity/image-url";

const isDev = process.env.NODE_ENV === "development";

export function resolveImageData({aspectRatio, data}: SanityImageProps) {
if (!data || !data.asset) {
return null;
}

const _ref = data.asset._ref;
const {height, width} = getImageDimensions(_ref);
const aspectRatioValues = aspectRatio?.split("/");

if (aspectRatio && aspectRatioValues?.length !== 2 && isDev) {
console.warn(
`Invalid aspect ratio: ${aspectRatio}. Using the original aspect ratio. The aspect ratio should be in the format "width/height".`,
);
}

const aspectRatioWidth = aspectRatioValues
? parseFloat(aspectRatioValues[0])
: undefined;
const aspectRatioHeight = aspectRatioValues
? parseFloat(aspectRatioValues[1])
: undefined;

const urlBuilder = imageUrlBuilder(imageConfig)
.image({
_ref,
crop: data.crop,
hotspot: data.hotspot,
})
.auto("format");

// Values used for srcset attribute of image tag (in pixels)
const srcSetValues = [
50, 100, 200, 450, 600, 750, 900, 1000, 1250, 1500, 1750, 2000, 2500, 3000,
3500, 4000, 5000,
];

const src = generateImageUrl({
aspectRatioHeight,
aspectRatioWidth,
urlBuilder,
width,
});

// Create srcset attribute
const srcSet = srcSetValues
.filter((value) => value < width)
.map((value) => {
const imageUrl = generateImageUrl({
aspectRatioHeight,
aspectRatioWidth,
urlBuilder,
width: value,
});
if (width >= value) {
return `${imageUrl} ${value}w`;
}
return "";
})
.join(", ")
.concat(`, ${src} ${width}w`);

return {
height,
src,
srcSet,
width,
};
}

function generateImageUrl(args: {
aspectRatioHeight?: number;
aspectRatioWidth?: number;
blur?: number;
urlBuilder: ImageUrlBuilder;
width: number;
}) {
const {
aspectRatioHeight,
aspectRatioWidth,
blur = 0,
urlBuilder,
width,
} = args;
let imageUrl = urlBuilder.width(width);
const imageHeight =
aspectRatioHeight && aspectRatioWidth
? Math.round((width / aspectRatioWidth) * aspectRatioHeight)
: undefined;

if (imageHeight) {
imageUrl = imageUrl.height(imageHeight);
}

if (blur && blur > 0) {
imageUrl = imageUrl.blur(blur);
}

return imageUrl.url();
}
69 changes: 69 additions & 0 deletions storefront/components/shared/video.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"use client";

import type {Video as VideoType} from "@/types/sanity.generated";

import {SanityImage, resolveImageData} from "@/components/shared/sanity-image";
import React, {useEffect, useState} from "react";
import {preload} from "react-dom";

export type VideoProps = {
aspectRatio?: string;
controls?: boolean;
fetchPriority?: "default" | "high";
poster?: VideoType["poster"];
videoUrl?: null | string;
} & Omit<React.VideoHTMLAttributes<HTMLVideoElement>, "poster" | "src">;

export default function Video({
aspectRatio,
controls,
fetchPriority = "default",
poster,
videoUrl,
...props
}: VideoProps) {
const [appeared, setAppeared] = useState(fetchPriority === "high");

const posterData = !poster ? null : resolveImageData({data: poster});

useEffect(() => {
setAppeared(true);
}, []);

if (!poster || !posterData || !videoUrl) {
return null;
}

const videoElement = (
<video
autoPlay
controls={controls}
height={posterData.height}
loop
muted
playsInline
poster={posterData?.src}
src={videoUrl}
width={posterData.width}
{...props}
/>
);

if (fetchPriority === "high" && posterData?.src) {
preload(posterData.src, {
as: "image",
fetchPriority: "high",
});
return videoElement;
}

return (
<>
{!appeared ? (
<SanityImage aspectRatio={aspectRatio} data={poster} />
) : (
videoElement
)}
</>
);
}
11 changes: 0 additions & 11 deletions storefront/data/sanity/queries/section.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
import {groq} from "next-sanity";

export const HERO_SECTION_QUERY = /* groq */ `{
...,
video {
asset->{
"resolution": data.max_stored_resolution,
playbackId,
}
}
}`;

export const TESTIMONIALS_SECTION_QUERY = groq`{
...,
testimonials[] ->
}`;

export const SECTIONS_BODY_FRAGMENT = groq`{
...,
_type == "section.hero" => ${HERO_SECTION_QUERY},
_type == "section.testimonials" => ${TESTIMONIALS_SECTION_QUERY},
}`;
1 change: 0 additions & 1 deletion storefront/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const config = {
{hostname: "cdn.sanity.io"},
{hostname: "munchies.medusajs.app"},
{hostname: "tinloof-munchies.s3.eu-north-1.amazonaws.com"},
{hostname: "image.mux.com"},
],
},
eslint: {
Expand Down
2 changes: 1 addition & 1 deletion storefront/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
"nuqs": "^1.20.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.3.0",
"react-remove-scroll": "^2.6.0",
"sanity": "^3.48.1",
"sanity-plugin-hotspot-array": "^2.0.0",
"sanity-plugin-mux-input": "^2.3.6",
"zod": "^3.23.8"
},
"devDependencies": {
Expand Down
Loading

0 comments on commit ed7546a

Please sign in to comment.