Skip to content

Commit 8d03607

Browse files
committed
feat: update Feature type to support both image and video backgrounds
1 parent 0b33854 commit 8d03607

File tree

4 files changed

+182
-64
lines changed

4 files changed

+182
-64
lines changed

apps/frontend/components/sections/sectionComponents/Features.tsx

Lines changed: 74 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,73 @@ import { cx } from "cva";
1010
import { useState } from "react";
1111

1212
export default function Features(props: FeaturesProps) {
13-
const [videoReplay, setVideoReplay] = useState(
13+
const [interactionState, setInteractionState] = useState(
1414
props.features?.reduce((o, key) => ({ ...o, [key._key!]: false }), {}) ||
1515
{},
1616
);
17-
const getSides = (index: number) => {
18-
return {
19-
right: true,
20-
left: index === 1 || index === 3 || index === 4,
21-
bottom: index === 3 || index === 4 || index === 5,
22-
top: index === 1 || index === 2 || index === 3,
23-
};
24-
};
2517

26-
const getMobileSides = (index: number) => {
27-
return {
28-
right: true,
29-
left: true,
30-
bottom: index === 5,
31-
top: true,
32-
};
33-
};
18+
const getSides = (index: number) => ({
19+
right: true,
20+
left: index === 1 || index === 3 || index === 4,
21+
bottom: index === 3 || index === 4 || index === 5,
22+
top: index === 1 || index === 2 || index === 3,
23+
});
24+
25+
const getMobileSides = (index: number) => ({
26+
right: true,
27+
left: true,
28+
bottom: index === 5,
29+
top: true,
30+
});
3431

3532
function handleInteraction(_key: string) {
36-
setVideoReplay((prev) => ({ ...prev, [_key]: true }));
33+
setInteractionState((prev) => ({ ...prev, [_key]: true }));
3734
setTimeout(() => {
38-
setVideoReplay((prev) => ({ ...prev, [_key]: false }));
35+
setInteractionState((prev) => ({ ...prev, [_key]: false }));
3936
}, 1000);
4037
}
4138

39+
const renderBackground = (
40+
background: any,
41+
replay: boolean,
42+
isDark: boolean,
43+
) => {
44+
if (!background) return null;
45+
46+
const version = isDark ? background.dark : background.light;
47+
48+
if (version?.type === "video" && version.asset) {
49+
return (
50+
<MuxVideo
51+
replay={replay}
52+
playOnView
53+
className={isDark ? "hidden dark:block" : "dark:hidden"}
54+
video={version.asset}
55+
/>
56+
);
57+
}
58+
59+
if (version?.type === "image" && version.image) {
60+
return (
61+
<img
62+
className={
63+
isDark
64+
? "hidden dark:block w-full h-auto"
65+
: "dark:hidden w-full h-auto"
66+
}
67+
src={version.image.asset?.url}
68+
alt=""
69+
/>
70+
);
71+
}
72+
73+
return null;
74+
};
75+
4276
return (
4377
<>
44-
<div className="hidden w-full px-6 py-[60px] lg:grid lg:grid-cols-2 lg:px-20 lg:py-[80px] ">
78+
{/* Desktop */}
79+
<div className="hidden w-full px-6 py-[60px] lg:grid lg:grid-cols-2 lg:px-20 lg:py-[80px]">
4580
{props?.features?.map((feature, index) => {
4681
const size = index === 2 ? "large" : "small";
4782
return (
@@ -53,27 +88,21 @@ export default function Features(props: FeaturesProps) {
5388
)}
5489
>
5590
<div
56-
className={cx("absolute z-10", {
91+
className={cx("absolute z-10", {
5792
"left-0 top-0 w-full": size === "small",
5893
"right-0 top-1/2 my-auto w-1/2 -translate-y-1/2 transform":
5994
size !== "small",
6095
})}
6196
>
62-
{feature.bgVideo?.dark?.asset && (
63-
<MuxVideo
64-
replay={videoReplay[feature._key!]}
65-
playOnView
66-
className="hidden dark:block"
67-
video={feature.bgVideo?.dark?.asset}
68-
/>
97+
{renderBackground(
98+
feature.background,
99+
interactionState[feature._key!],
100+
true,
69101
)}
70-
{feature.bgVideo?.light?.asset && (
71-
<MuxVideo
72-
replay={videoReplay[feature._key!]}
73-
playOnView
74-
className="dark:hidden"
75-
video={feature.bgVideo?.light.asset}
76-
/>
102+
{renderBackground(
103+
feature.background,
104+
interactionState[feature._key!],
105+
false,
77106
)}
78107
<div className="absolute bottom-0 h-1/4 w-full bg-gradient-to-t from-white dark:from-background-dark" />
79108
</div>
@@ -84,7 +113,7 @@ export default function Features(props: FeaturesProps) {
84113
>
85114
<div
86115
className={cx(
87-
"flex h-[600px] flex-col items-start p-l lg:p-xl",
116+
"flex h-[600px] flex-col items-start p-l lg:p-xl",
88117
size === "small"
89118
? "justify-end lg:h-[586px]"
90119
: "max-w-[460px] justify-center lg:h-[590px]",
@@ -127,9 +156,9 @@ export default function Features(props: FeaturesProps) {
127156
})}
128157
</div>
129158

159+
{/* Mobile */}
130160
<div className="grid w-full grid-cols-2 px-6 py-[60px] lg:hidden lg:px-20 lg:py-[80px]">
131161
{props?.features?.map((feature, index) => {
132-
// const { cleaned: size } = vercelStegaSplit(feature?.size || "");
133162
return (
134163
<div key={feature._key} className={cx("col-span-2")}>
135164
<GradientBorderBox
@@ -142,21 +171,15 @@ export default function Features(props: FeaturesProps) {
142171
)}
143172
>
144173
<div className={cx("-mt-l w-full sm:-mx-l", {})}>
145-
{feature.bgVideo?.dark?.asset && (
146-
<MuxVideo
147-
replay={videoReplay[feature._key!]}
148-
playOnView
149-
className="hidden dark:block"
150-
video={feature.bgVideo?.dark?.asset}
151-
/>
174+
{renderBackground(
175+
feature.background,
176+
interactionState[feature._key!],
177+
true,
152178
)}
153-
{feature.bgVideo?.light?.asset && (
154-
<MuxVideo
155-
replay={videoReplay[feature._key!]}
156-
playOnView
157-
className="dark:hidden"
158-
video={feature.bgVideo?.light.asset}
159-
/>
179+
{renderBackground(
180+
feature.background,
181+
interactionState[feature._key!],
182+
false,
160183
)}
161184
</div>
162185
{feature?.tag ? (

apps/frontend/data/sanity/queries.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,35 @@ const SECTIONS_FRAGMENT = groq`
4545
_id,
4646
features {
4747
...,
48-
bgVideo {
49-
light ${MUX_VIDEO_FRAGMENT},
50-
dark ${MUX_VIDEO_FRAGMENT},
48+
background {
49+
light {
50+
type,
51+
asset ${MUX_VIDEO_FRAGMENT},
52+
image {
53+
...,
54+
asset->{
55+
url,
56+
metadata
57+
}
58+
}
59+
},
60+
dark {
61+
type,
62+
asset ${MUX_VIDEO_FRAGMENT},
63+
image {
64+
...,
65+
asset->{
66+
url,
67+
metadata
68+
}
69+
}
70+
}
5171
},
52-
5372
}[]
5473
},
5574
_type == "section.fullWidthMedia" => {
5675
${FULL_WIDTH_MEDIA_FRAGMENT}
5776
},
58-
5977
_type == "section.registry" => {
6078
...,
6179
"filterIconDictionary": *[_type == "filterIconDictionary"][0],

apps/frontend/sanity/schemas/sections/features.ts

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,73 @@ export const features = defineSection({
3030
icon: BlockContentIcon,
3131
fields: [
3232
{
33-
name: "bgVideo",
34-
title: "Background Video",
33+
name: "background",
34+
title: "Background",
3535
type: "object",
3636
fields: [
3737
{
3838
name: "light",
3939
title: "Light Version",
40-
type: "mux.video",
40+
type: "object",
41+
fields: [
42+
{
43+
name: "type",
44+
title: "Type",
45+
type: "string",
46+
options: {
47+
list: [
48+
{ title: "Image", value: "image" },
49+
{ title: "Video", value: "video" },
50+
],
51+
layout: "radio",
52+
},
53+
validation: (Rule) => Rule.required(),
54+
},
55+
{
56+
name: "asset",
57+
title: "Asset",
58+
type: "mux.video",
59+
hidden: ({ parent }) => parent?.type !== "video",
60+
},
61+
{
62+
name: "image",
63+
title: "Image",
64+
type: "image",
65+
hidden: ({ parent }) => parent?.type !== "image",
66+
},
67+
],
4168
},
4269
{
4370
name: "dark",
4471
title: "Dark Version",
45-
type: "mux.video",
72+
type: "object",
73+
fields: [
74+
{
75+
name: "type",
76+
title: "Type",
77+
type: "string",
78+
options: {
79+
list: [
80+
{ title: "Image", value: "image" },
81+
{ title: "Video", value: "video" },
82+
],
83+
layout: "radio",
84+
},
85+
validation: (Rule) => Rule.required(),
86+
},
87+
{
88+
name: "asset",
89+
title: "Asset",
90+
type: "mux.video",
91+
hidden: ({ parent }) => parent?.type !== "video",
92+
},
93+
{
94+
name: "image",
95+
title: "Image",
96+
type: "image",
97+
hidden: ({ parent }) => parent?.type !== "image",
98+
},
99+
],
46100
},
47101
],
48102
},
@@ -62,7 +116,6 @@ export const features = defineSection({
62116
name: "description",
63117
title: "Description",
64118
},
65-
66119
{
67120
type: "string",
68121
name: "snippet",

apps/frontend/types/index.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,33 @@ export type Feature = {
233233
snippet?: string;
234234
toastText?: string;
235235
cta?: SanityLinkType;
236-
bgVideo?: {
237-
light?: MuxVideo;
238-
dark?: MuxVideo;
236+
background?: {
237+
light?: {
238+
type: "image" | "video";
239+
asset?: MuxVideo;
240+
image?: {
241+
asset: {
242+
url: string;
243+
metadata?: {
244+
dimensions?: { width: number; height: number };
245+
lqip?: string; // Low-quality image placeholder
246+
};
247+
};
248+
};
249+
};
250+
dark?: {
251+
type: "image" | "video";
252+
asset?: MuxVideo;
253+
image?: {
254+
asset: {
255+
url: string;
256+
metadata?: {
257+
dimensions?: { width: number; height: number };
258+
lqip?: string; // Low-quality image placeholder
259+
};
260+
};
261+
};
262+
};
239263
};
240264
};
241265

0 commit comments

Comments
 (0)