Skip to content

Commit 25028e1

Browse files
committed
Added set background feature
1 parent e2d1711 commit 25028e1

File tree

7 files changed

+152
-10
lines changed

7 files changed

+152
-10
lines changed

apps/web/components/admin/page-editor/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ export default function PageEditor({
436436
const editWidget = useMemo(
437437
() => (
438438
<EditWidget
439+
key={selectedWidget}
439440
widget={
440441
page &&
441442
layout?.filter((x) => x.widgetId === selectedWidget)[0]

packages/common-widgets/src/hero/admin-widget.tsx

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import React, { useEffect, useState } from "react";
3+
import { useEffect, useState } from "react";
44
import type {
55
Address,
66
Alignment,
@@ -29,8 +29,9 @@ import {
2929
verticalPadding as defaultVerticalPadding,
3030
horizontalPadding as defaultHorizontalPadding,
3131
mediaAspectRatio as defaultMediaAspectRatio,
32+
mediaLayout as defaultMediaLayout,
3233
} from "./defaults";
33-
import { MediaAspectRatio } from "./types";
34+
import { MediaAspectRatio, MediaLayout } from "./types";
3435

3536
interface AdminWidgetProps {
3637
name: string;
@@ -118,6 +119,15 @@ export default function AdminWidget({
118119
settings.mediaAspectRatio || defaultMediaAspectRatio,
119120
);
120121
const [cssId, setCssId] = useState(settings.cssId);
122+
const [backgroundMedia, setBackgroundMedia] = useState<Partial<Media>>(
123+
settings.backgroundMedia || {},
124+
);
125+
const [overlayColor, setOverlayColor] = useState<string>(settings.overlayColor || "#FFFFFF");
126+
const [overlayOpacity, setOverlayOpacity] = useState<number>(settings.overlayOpacity || 0.9);
127+
const [mediaLayout, setdMediaLayout] =
128+
useState<MediaLayout>(
129+
settings.mediaLayout || defaultMediaLayout,
130+
);
121131

122132
const onSettingsChanged = () =>
123133
onChange({
@@ -145,6 +155,10 @@ export default function AdminWidget({
145155
descriptionFontSize,
146156
contentAlignment,
147157
cssId,
158+
backgroundMedia,
159+
overlayColor,
160+
overlayOpacity,
161+
mediaLayout,
148162
});
149163

150164
useEffect(() => {
@@ -174,6 +188,10 @@ export default function AdminWidget({
174188
descriptionFontSize,
175189
contentAlignment,
176190
cssId,
191+
backgroundMedia,
192+
overlayColor,
193+
overlayOpacity,
194+
mediaLayout,
177195
]);
178196

179197
return (
@@ -246,6 +264,71 @@ export default function AdminWidget({
246264
/>
247265
)}
248266
</AdminWidgetPanel>
267+
<AdminWidgetPanel title="Background">
268+
<PageBuilderPropertyHeader label="Upload media" />
269+
<MediaSelector
270+
title=""
271+
src={backgroundMedia && backgroundMedia.thumbnail}
272+
srcTitle={
273+
backgroundMedia && backgroundMedia.originalFileName
274+
}
275+
profile={profile}
276+
address={address}
277+
onSelection={(backgroundMedia: Media) => {
278+
if (backgroundMedia) {
279+
setBackgroundMedia(backgroundMedia);
280+
}
281+
}}
282+
onRemove={() => {
283+
setBackgroundMedia({});
284+
}}
285+
strings={{}}
286+
access="public"
287+
mediaId={backgroundMedia && backgroundMedia.mediaId}
288+
type="page"
289+
/>
290+
<ColorSelector
291+
title="Overlay color"
292+
value={overlayColor || "inherit"}
293+
onChange={(value?: string) =>
294+
setOverlayColor(value)
295+
}
296+
/>
297+
<PageBuilderSlider
298+
className="mt-2"
299+
title="Overlay opacity"
300+
value={overlayOpacity}
301+
min={0}
302+
max={1}
303+
step={0.01}
304+
onChange={setOverlayOpacity}
305+
/>
306+
{backgroundMedia && backgroundMedia.mediaId && (
307+
<Select
308+
title="Layout"
309+
value={mediaLayout}
310+
options={[
311+
{
312+
label: "Cover",
313+
value: "object-cover",
314+
},
315+
{
316+
label: "Contain",
317+
value: "object-contain",
318+
},
319+
{ label: "Fill", value: "object-fill" },
320+
{
321+
label: "Scale down",
322+
value: "object-scale-down",
323+
},
324+
{ label: "Original", value: "object-none" },
325+
]}
326+
onChange={(value: MediaLayout) =>
327+
setdMediaLayout(value)
328+
}
329+
/>
330+
)}
331+
</AdminWidgetPanel>
249332
<AdminWidgetPanel title="Calls to action">
250333
<Accordion type="single" collapsible>
251334
<AccordionItem value="primary">
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { MediaAspectRatio } from "./types";
1+
import { MediaLayout, MediaAspectRatio } from "./types";
22

33
export const horizontalPadding = 100;
44
export const verticalPadding = 16;
55
export const mediaAspectRatio: MediaAspectRatio = "aspect-square";
6+
export const mediaLayout: MediaLayout = "object-cover";

packages/common-widgets/src/hero/settings.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
WidgetDefaultSettings,
55
} from "@courselit/common-models";
66
import { MediaAspectRatio } from "./types";
7+
import { MediaLayout } from "./types";
78

89
export default interface Settings extends WidgetDefaultSettings {
910
title?: string;
@@ -30,4 +31,8 @@ export default interface Settings extends WidgetDefaultSettings {
3031
descriptionFontSize?: number;
3132
contentAlignment?: Alignment;
3233
cssId?: string;
34+
backgroundMedia?: Media;
35+
overlayColor: string;
36+
overlayOpacity: number;
37+
mediaLayout?: MediaLayout;
3338
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export type MediaAspectRatio = "aspect-video" | "aspect-square" | "aspect-auto";
2+
export type MediaLayout = "object-cover" | "object-contain" | "object-fill" | "object-scale-down" | "object-none";

packages/common-widgets/src/hero/widget.tsx

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import React from "react";
21
import { WidgetProps } from "@courselit/common-models";
32
import Settings from "./settings";
43
import {
@@ -11,6 +10,7 @@ import {
1110
verticalPadding as defaultVerticalPadding,
1211
horizontalPadding as defaultHorizontalPadding,
1312
mediaAspectRatio as defaultMediaAspectRatio,
13+
mediaLayout as defaultMediaLayout,
1414
} from "./defaults";
1515
import clsx from "clsx";
1616

@@ -52,6 +52,10 @@ export default function Widget({
5252
descriptionFontSize,
5353
contentAlignment,
5454
cssId,
55+
backgroundMedia,
56+
overlayColor,
57+
overlayOpacity,
58+
mediaLayout = defaultMediaLayout,
5559
},
5660
}: WidgetProps<Settings>) {
5761
const hasHeroGraphic = youtubeLink || (media && media.mediaId);
@@ -69,7 +73,7 @@ export default function Widget({
6973

7074
return (
7175
<section
72-
className={`py-[${verticalPadding}px]`}
76+
className={`relative py-[${verticalPadding}px] overflow-hidden `}
7377
style={
7478
style === "card"
7579
? {}
@@ -80,7 +84,48 @@ export default function Widget({
8084
}
8185
id={cssId}
8286
>
83-
<div className="mx-auto lg:max-w-[1200px]">
87+
{backgroundMedia && backgroundMedia.mediaId && (
88+
<>
89+
<div
90+
className={`absolute inset-0 ${twRoundedMap[mediaRadius]} overflow-hidden`}
91+
>
92+
{backgroundMedia.mimeType.split("/")[0] === "image" && (
93+
<img
94+
src={backgroundMedia.file}
95+
alt={backgroundMedia.caption}
96+
className={`w-full h-full ${mediaLayout}`}
97+
/>
98+
)}
99+
{backgroundMedia.mimeType.split("/")[0] === "video" && (
100+
<video
101+
autoPlay
102+
loop
103+
muted
104+
controls
105+
controlsList="nodownload"
106+
className={clsx(
107+
"w-full h-full rounded mb-2",
108+
mediaLayout,
109+
)}
110+
>
111+
<source
112+
src={backgroundMedia.file}
113+
type={backgroundMedia.mimeType}
114+
/>
115+
Your browser does not support the video tag.
116+
</video>
117+
)}
118+
</div>
119+
<div
120+
className={`absolute inset-0 ${twRoundedMap[mediaRadius]}`}
121+
style={{
122+
backgroundColor: overlayColor,
123+
opacity: overlayOpacity,
124+
}}
125+
/>
126+
</>
127+
)}
128+
<div className="relative z-10 mx-auto lg:max-w-[1200px]">
84129
<div
85130
className={clsx(
86131
"w-full !mx-auto",
@@ -145,6 +190,9 @@ export default function Widget({
145190
{media.mimeType.split("/")[0] ===
146191
"video" && (
147192
<video
193+
autoPlay
194+
loop
195+
muted
148196
controls
149197
controlsList="nodownload" // eslint-disable-line react/no-unknown-property
150198
className={clsx(
@@ -154,7 +202,9 @@ export default function Widget({
154202
>
155203
<source
156204
src={media.file}
157-
type="video/mp4"
205+
type={
206+
backgroundMedia.mimeType
207+
}
158208
/>
159209
Your browser does not support
160210
the video tag.
@@ -165,9 +215,7 @@ export default function Widget({
165215
</div>
166216
)}
167217
<div
168-
className={`w-full ${
169-
hasHeroGraphic ? "md:w-1/2" : "md:w-full"
170-
} sm:pr-0 sm:pl-0 ${
218+
className={`w-full ${hasHeroGraphic ? "md:w-1/2" : "md:w-full"} sm:pr-0 sm:pl-0 ${
171219
hasHeroGraphic && alignment === "right"
172220
? "md:pr-1"
173221
: "md:pr-0"

packages/components-library/src/page-builder-slider.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export default function PageBuilderSlider({
77
min,
88
max,
99
value,
10+
step,
1011
onChange,
1112
tooltip,
1213
className,
@@ -15,6 +16,7 @@ export default function PageBuilderSlider({
1516
min: number;
1617
max: number;
1718
value: number;
19+
step?: number;
1820
onChange: (value: number) => void;
1921
tooltip?: string;
2022
className?: string;
@@ -38,6 +40,7 @@ export default function PageBuilderSlider({
3840
value={[value]}
3941
max={max}
4042
min={min}
43+
step={step}
4144
onValueChange={(value: number[]) => {
4245
onChange(value[0]);
4346
}}

0 commit comments

Comments
 (0)