softbuilders-react-video-player 1.1.15 → 1.1.16
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +21 -21
- package/README.md +126 -126
- package/dist/components/BufferTracker/index.tsx +19 -19
- package/dist/components/ChapterTooltip/index.tsx +65 -65
- package/dist/components/ChaptersPanal/index.tsx +40 -40
- package/dist/components/ControlBar/index.js.map +1 -1
- package/dist/components/ControlBar/index.tsx +1 -1
- package/dist/components/CreateNoteMenu/index.tsx +61 -61
- package/dist/components/CurrentTimeLabel/index.tsx +13 -13
- package/dist/components/CurrentTimeTracker/index.tsx +18 -18
- package/dist/components/Menu/index.tsx +49 -49
- package/dist/components/NoteTooltip/index.tsx +46 -46
- package/dist/components/NotesPanal/index.tsx +34 -34
- package/dist/components/TimeSlider/index.js +13 -13
- package/dist/components/TimeSlider/index.tsx +107 -107
- package/dist/components/TimeSliderContainer/index.tsx +35 -35
- package/dist/components/Tooltip/index.tsx +16 -16
- package/dist/components/VideoPlayerComponent/provider.tsx +82 -82
- package/dist/components/VideoPlayerComponent/style/style.css +36 -36
- package/dist/styles/tailwind.css +101 -101
- package/package.json +1 -1
@@ -1,61 +1,61 @@
|
|
1
|
-
import React, { useState } from "react";
|
2
|
-
import MenuButton from "../MenuButton";
|
3
|
-
import { useSoftBuildersVideoPlayerContext } from "../VideoPlayerComponent/provider";
|
4
|
-
import { ClosedNoteIcon } from "../../images";
|
5
|
-
|
6
|
-
type Props<T> = {
|
7
|
-
handleSaveNoteAction?: (time: number, note: string) => Promise<T>;
|
8
|
-
};
|
9
|
-
const CreateNoteMenu = <T,>({ handleSaveNoteAction }: Props<T>) => {
|
10
|
-
const { player } = useSoftBuildersVideoPlayerContext();
|
11
|
-
|
12
|
-
const [note, setNote] = useState("");
|
13
|
-
|
14
|
-
const handleSaveNote = () => {
|
15
|
-
if (handleSaveNoteAction) {
|
16
|
-
const time = player?.currentTime() || 0;
|
17
|
-
handleSaveNoteAction(time, note).then((response) => {
|
18
|
-
setNote("");
|
19
|
-
});
|
20
|
-
} else {
|
21
|
-
window.alert(
|
22
|
-
"Video Player, there is no implementation for the handleSaveNoteAction function"
|
23
|
-
);
|
24
|
-
}
|
25
|
-
};
|
26
|
-
|
27
|
-
return (
|
28
|
-
<MenuButton
|
29
|
-
buttonContent={<ClosedNoteIcon className="sb-w-3 sb-h-3" />}
|
30
|
-
menuContent={
|
31
|
-
<div className="sb-rounded-md sb-bg-[#303030] sb-bg-opacity-50 sb-py-5 sb-w-[220px]">
|
32
|
-
<div className="sb-flex sb-flex-col sb-gap-3">
|
33
|
-
<h3 className="sb-px-5">Add Note</h3>
|
34
|
-
|
35
|
-
<div className="sb-w-full sb-h-[.1px] sb-bg-[#AAAAAA] sb-bg-opacity-70" />
|
36
|
-
|
37
|
-
<div className="sb-px-5 sb-flex sb-flex-col sb-gap-4 sb-items-start">
|
38
|
-
<input
|
39
|
-
name="note"
|
40
|
-
type="text"
|
41
|
-
placeholder="Add a note"
|
42
|
-
value={note}
|
43
|
-
onChange={(e) => setNote(e.target.value)}
|
44
|
-
required
|
45
|
-
className="sb-text-white placeholder:sb-text-white sb-w-full sb-bg-transparent sb-px-4 sb-py-3 sb-border sb-border-[#AAAAAA] sb-rounded-md"
|
46
|
-
/>
|
47
|
-
|
48
|
-
<button className="sb-w-full" onClick={handleSaveNote}>
|
49
|
-
<div className="sb-px-4 sb-py-3 sb-text-center sb-font-bold sb-bg-orange-500 sb-rounded-md">
|
50
|
-
Save
|
51
|
-
</div>
|
52
|
-
</button>
|
53
|
-
</div>
|
54
|
-
</div>
|
55
|
-
</div>
|
56
|
-
}
|
57
|
-
/>
|
58
|
-
);
|
59
|
-
};
|
60
|
-
|
61
|
-
export default CreateNoteMenu;
|
1
|
+
import React, { useState } from "react";
|
2
|
+
import MenuButton from "../MenuButton";
|
3
|
+
import { useSoftBuildersVideoPlayerContext } from "../VideoPlayerComponent/provider";
|
4
|
+
import { ClosedNoteIcon } from "../../images";
|
5
|
+
|
6
|
+
type Props<T> = {
|
7
|
+
handleSaveNoteAction?: (time: number, note: string) => Promise<T>;
|
8
|
+
};
|
9
|
+
const CreateNoteMenu = <T,>({ handleSaveNoteAction }: Props<T>) => {
|
10
|
+
const { player } = useSoftBuildersVideoPlayerContext();
|
11
|
+
|
12
|
+
const [note, setNote] = useState("");
|
13
|
+
|
14
|
+
const handleSaveNote = () => {
|
15
|
+
if (handleSaveNoteAction) {
|
16
|
+
const time = player?.currentTime() || 0;
|
17
|
+
handleSaveNoteAction(time, note).then((response) => {
|
18
|
+
setNote("");
|
19
|
+
});
|
20
|
+
} else {
|
21
|
+
window.alert(
|
22
|
+
"Video Player, there is no implementation for the handleSaveNoteAction function"
|
23
|
+
);
|
24
|
+
}
|
25
|
+
};
|
26
|
+
|
27
|
+
return (
|
28
|
+
<MenuButton
|
29
|
+
buttonContent={<ClosedNoteIcon className="sb-w-3 sb-h-3" />}
|
30
|
+
menuContent={
|
31
|
+
<div className="sb-rounded-md sb-bg-[#303030] sb-bg-opacity-50 sb-py-5 sb-w-[220px]">
|
32
|
+
<div className="sb-flex sb-flex-col sb-gap-3">
|
33
|
+
<h3 className="sb-px-5">Add Note</h3>
|
34
|
+
|
35
|
+
<div className="sb-w-full sb-h-[.1px] sb-bg-[#AAAAAA] sb-bg-opacity-70" />
|
36
|
+
|
37
|
+
<div className="sb-px-5 sb-flex sb-flex-col sb-gap-4 sb-items-start">
|
38
|
+
<input
|
39
|
+
name="note"
|
40
|
+
type="text"
|
41
|
+
placeholder="Add a note"
|
42
|
+
value={note}
|
43
|
+
onChange={(e) => setNote(e.target.value)}
|
44
|
+
required
|
45
|
+
className="sb-text-white placeholder:sb-text-white sb-w-full sb-bg-transparent sb-px-4 sb-py-3 sb-border sb-border-[#AAAAAA] sb-rounded-md"
|
46
|
+
/>
|
47
|
+
|
48
|
+
<button className="sb-w-full" onClick={handleSaveNote}>
|
49
|
+
<div className="sb-px-4 sb-py-3 sb-text-center sb-font-bold sb-bg-orange-500 sb-rounded-md">
|
50
|
+
Save
|
51
|
+
</div>
|
52
|
+
</button>
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
}
|
57
|
+
/>
|
58
|
+
);
|
59
|
+
};
|
60
|
+
|
61
|
+
export default CreateNoteMenu;
|
@@ -1,13 +1,13 @@
|
|
1
|
-
"use client";
|
2
|
-
import React, { useEffect } from "react";
|
3
|
-
import { durationFormater } from "../../utils";
|
4
|
-
import { useSoftBuildersVideoPlayerContext } from "../VideoPlayerComponent/provider";
|
5
|
-
type Props = {};
|
6
|
-
|
7
|
-
const CurrentTimeLabel = ({}: Props) => {
|
8
|
-
const { currentTime } = useSoftBuildersVideoPlayerContext();
|
9
|
-
|
10
|
-
return <p>{durationFormater(currentTime)}</p>;
|
11
|
-
};
|
12
|
-
|
13
|
-
export default CurrentTimeLabel;
|
1
|
+
"use client";
|
2
|
+
import React, { useEffect } from "react";
|
3
|
+
import { durationFormater } from "../../utils";
|
4
|
+
import { useSoftBuildersVideoPlayerContext } from "../VideoPlayerComponent/provider";
|
5
|
+
type Props = {};
|
6
|
+
|
7
|
+
const CurrentTimeLabel = ({}: Props) => {
|
8
|
+
const { currentTime } = useSoftBuildersVideoPlayerContext();
|
9
|
+
|
10
|
+
return <p>{durationFormater(currentTime)}</p>;
|
11
|
+
};
|
12
|
+
|
13
|
+
export default CurrentTimeLabel;
|
@@ -1,18 +1,18 @@
|
|
1
|
-
import React, { useEffect } from "react";
|
2
|
-
import { useSoftBuildersVideoPlayerContext } from "../VideoPlayerComponent/provider";
|
3
|
-
|
4
|
-
const CurrentTimeTracker = () => {
|
5
|
-
const { setCurrentTime, player } = useSoftBuildersVideoPlayerContext();
|
6
|
-
|
7
|
-
useEffect(() => {
|
8
|
-
const intervalId = setInterval(() => {
|
9
|
-
setCurrentTime(player?.currentTime() || 0);
|
10
|
-
}, 500);
|
11
|
-
|
12
|
-
// Cleanup function to clear the interval
|
13
|
-
return () => clearInterval(intervalId);
|
14
|
-
}, [player]);
|
15
|
-
return <></>;
|
16
|
-
};
|
17
|
-
|
18
|
-
export default CurrentTimeTracker;
|
1
|
+
import React, { useEffect } from "react";
|
2
|
+
import { useSoftBuildersVideoPlayerContext } from "../VideoPlayerComponent/provider";
|
3
|
+
|
4
|
+
const CurrentTimeTracker = () => {
|
5
|
+
const { setCurrentTime, player } = useSoftBuildersVideoPlayerContext();
|
6
|
+
|
7
|
+
useEffect(() => {
|
8
|
+
const intervalId = setInterval(() => {
|
9
|
+
setCurrentTime(player?.currentTime() || 0);
|
10
|
+
}, 500);
|
11
|
+
|
12
|
+
// Cleanup function to clear the interval
|
13
|
+
return () => clearInterval(intervalId);
|
14
|
+
}, [player]);
|
15
|
+
return <></>;
|
16
|
+
};
|
17
|
+
|
18
|
+
export default CurrentTimeTracker;
|
@@ -1,49 +1,49 @@
|
|
1
|
-
import React from "react";
|
2
|
-
|
3
|
-
type Props = {
|
4
|
-
name: string;
|
5
|
-
};
|
6
|
-
|
7
|
-
const Menu = ({ name }: Props) => {
|
8
|
-
return (
|
9
|
-
<div className="absolute right-0 z-10 w-48 mt-2 origin-top-right bg-white border border-gray-300 rounded-md shadow-lg focus:outline-none">
|
10
|
-
<div
|
11
|
-
className="py-1"
|
12
|
-
role="menu"
|
13
|
-
aria-orientation="vertical"
|
14
|
-
aria-labelledby={`${name}-button`}
|
15
|
-
>
|
16
|
-
<a
|
17
|
-
href="#"
|
18
|
-
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
19
|
-
role="menuitem"
|
20
|
-
>
|
21
|
-
Dashboard
|
22
|
-
</a>
|
23
|
-
<a
|
24
|
-
href="#"
|
25
|
-
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
26
|
-
role="menuitem"
|
27
|
-
>
|
28
|
-
Settings
|
29
|
-
</a>
|
30
|
-
<a
|
31
|
-
href="#"
|
32
|
-
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
33
|
-
role="menuitem"
|
34
|
-
>
|
35
|
-
Profile
|
36
|
-
</a>
|
37
|
-
<a
|
38
|
-
href="#"
|
39
|
-
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
40
|
-
role="menuitem"
|
41
|
-
>
|
42
|
-
Logout
|
43
|
-
</a>
|
44
|
-
</div>
|
45
|
-
</div>
|
46
|
-
);
|
47
|
-
};
|
48
|
-
|
49
|
-
export default Menu;
|
1
|
+
import React from "react";
|
2
|
+
|
3
|
+
type Props = {
|
4
|
+
name: string;
|
5
|
+
};
|
6
|
+
|
7
|
+
const Menu = ({ name }: Props) => {
|
8
|
+
return (
|
9
|
+
<div className="absolute right-0 z-10 w-48 mt-2 origin-top-right bg-white border border-gray-300 rounded-md shadow-lg focus:outline-none">
|
10
|
+
<div
|
11
|
+
className="py-1"
|
12
|
+
role="menu"
|
13
|
+
aria-orientation="vertical"
|
14
|
+
aria-labelledby={`${name}-button`}
|
15
|
+
>
|
16
|
+
<a
|
17
|
+
href="#"
|
18
|
+
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
19
|
+
role="menuitem"
|
20
|
+
>
|
21
|
+
Dashboard
|
22
|
+
</a>
|
23
|
+
<a
|
24
|
+
href="#"
|
25
|
+
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
26
|
+
role="menuitem"
|
27
|
+
>
|
28
|
+
Settings
|
29
|
+
</a>
|
30
|
+
<a
|
31
|
+
href="#"
|
32
|
+
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
33
|
+
role="menuitem"
|
34
|
+
>
|
35
|
+
Profile
|
36
|
+
</a>
|
37
|
+
<a
|
38
|
+
href="#"
|
39
|
+
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
40
|
+
role="menuitem"
|
41
|
+
>
|
42
|
+
Logout
|
43
|
+
</a>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
);
|
47
|
+
};
|
48
|
+
|
49
|
+
export default Menu;
|
@@ -1,46 +1,46 @@
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
2
|
-
import Tooltip from "../Tooltip";
|
3
|
-
import { durationFormater } from "../../utils";
|
4
|
-
import { useSoftBuildersVideoPlayerContext } from "../VideoPlayerComponent/provider";
|
5
|
-
import { SoftBuildersVideoPlayerNote } from "../../types";
|
6
|
-
type Note = SoftBuildersVideoPlayerNote & { percentage: number };
|
7
|
-
|
8
|
-
type Props = {
|
9
|
-
note: Note;
|
10
|
-
};
|
11
|
-
|
12
|
-
const NoteTooltip = ({ note }: Props) => {
|
13
|
-
const [open, setOpen] = useState(false);
|
14
|
-
const { currentTime } = useSoftBuildersVideoPlayerContext();
|
15
|
-
|
16
|
-
useEffect(() => {
|
17
|
-
if (currentTime === Math.floor(note.time)) {
|
18
|
-
setOpen(true);
|
19
|
-
|
20
|
-
setTimeout(() => {
|
21
|
-
setOpen(false);
|
22
|
-
}, 5000);
|
23
|
-
}
|
24
|
-
}, [currentTime, note.time]);
|
25
|
-
return (
|
26
|
-
<div
|
27
|
-
className="sb-w-1 sb-h-1 sb-rounded-full sb-bg-white sb-absolute sb-z-30"
|
28
|
-
style={{ left: `${note.percentage}%` }}
|
29
|
-
onMouseEnter={() => setOpen(true)}
|
30
|
-
onMouseLeave={() => setOpen(false)}
|
31
|
-
>
|
32
|
-
<div className="sb-relative">
|
33
|
-
<Tooltip open={open}>
|
34
|
-
<div className="sb-flex sb-flex-col sb-gap-2 sb-items-center">
|
35
|
-
<p>{note.label}</p>
|
36
|
-
<p className="sb-p-2 sb-bg-[#303030] sb-bg-opacity-50 sb-rounded-md">
|
37
|
-
{durationFormater(note.time)}
|
38
|
-
</p>
|
39
|
-
</div>
|
40
|
-
</Tooltip>
|
41
|
-
</div>
|
42
|
-
</div>
|
43
|
-
);
|
44
|
-
};
|
45
|
-
|
46
|
-
export default NoteTooltip;
|
1
|
+
import React, { useEffect, useState } from "react";
|
2
|
+
import Tooltip from "../Tooltip";
|
3
|
+
import { durationFormater } from "../../utils";
|
4
|
+
import { useSoftBuildersVideoPlayerContext } from "../VideoPlayerComponent/provider";
|
5
|
+
import { SoftBuildersVideoPlayerNote } from "../../types";
|
6
|
+
type Note = SoftBuildersVideoPlayerNote & { percentage: number };
|
7
|
+
|
8
|
+
type Props = {
|
9
|
+
note: Note;
|
10
|
+
};
|
11
|
+
|
12
|
+
const NoteTooltip = ({ note }: Props) => {
|
13
|
+
const [open, setOpen] = useState(false);
|
14
|
+
const { currentTime } = useSoftBuildersVideoPlayerContext();
|
15
|
+
|
16
|
+
useEffect(() => {
|
17
|
+
if (currentTime === Math.floor(note.time)) {
|
18
|
+
setOpen(true);
|
19
|
+
|
20
|
+
setTimeout(() => {
|
21
|
+
setOpen(false);
|
22
|
+
}, 5000);
|
23
|
+
}
|
24
|
+
}, [currentTime, note.time]);
|
25
|
+
return (
|
26
|
+
<div
|
27
|
+
className="sb-w-1 sb-h-1 sb-rounded-full sb-bg-white sb-absolute sb-z-30"
|
28
|
+
style={{ left: `${note.percentage}%` }}
|
29
|
+
onMouseEnter={() => setOpen(true)}
|
30
|
+
onMouseLeave={() => setOpen(false)}
|
31
|
+
>
|
32
|
+
<div className="sb-relative">
|
33
|
+
<Tooltip open={open}>
|
34
|
+
<div className="sb-flex sb-flex-col sb-gap-2 sb-items-center">
|
35
|
+
<p>{note.label}</p>
|
36
|
+
<p className="sb-p-2 sb-bg-[#303030] sb-bg-opacity-50 sb-rounded-md">
|
37
|
+
{durationFormater(note.time)}
|
38
|
+
</p>
|
39
|
+
</div>
|
40
|
+
</Tooltip>
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
);
|
44
|
+
};
|
45
|
+
|
46
|
+
export default NoteTooltip;
|
@@ -1,34 +1,34 @@
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
2
|
-
import NoteTooltip from "../NoteTooltip";
|
3
|
-
import { useSoftBuildersVideoPlayerContext } from "../VideoPlayerComponent/provider";
|
4
|
-
import { SoftBuildersVideoPlayerNote } from "../../types";
|
5
|
-
|
6
|
-
type Note = SoftBuildersVideoPlayerNote & { percentage: number };
|
7
|
-
type Props = {
|
8
|
-
notes: SoftBuildersVideoPlayerNote[];
|
9
|
-
};
|
10
|
-
const NotesPanal = ({ notes }: Props) => {
|
11
|
-
const [ns, setNs] = useState<Note[]>([]);
|
12
|
-
|
13
|
-
const { duration } = useSoftBuildersVideoPlayerContext();
|
14
|
-
|
15
|
-
useEffect(() => {
|
16
|
-
const newNs = notes.map((n) => {
|
17
|
-
const percentage = Math.floor((n.time * 100) / duration);
|
18
|
-
return {
|
19
|
-
...n,
|
20
|
-
percentage,
|
21
|
-
};
|
22
|
-
});
|
23
|
-
setNs(newNs);
|
24
|
-
}, [notes, duration]);
|
25
|
-
return (
|
26
|
-
<div id="notes-panal" className="sb-w-full sb-h-full sb-relative ">
|
27
|
-
{ns.map((n, i) => (
|
28
|
-
<NoteTooltip key={`note-${i}-${n.time}`} note={n} />
|
29
|
-
))}
|
30
|
-
</div>
|
31
|
-
);
|
32
|
-
};
|
33
|
-
|
34
|
-
export default NotesPanal;
|
1
|
+
import React, { useEffect, useState } from "react";
|
2
|
+
import NoteTooltip from "../NoteTooltip";
|
3
|
+
import { useSoftBuildersVideoPlayerContext } from "../VideoPlayerComponent/provider";
|
4
|
+
import { SoftBuildersVideoPlayerNote } from "../../types";
|
5
|
+
|
6
|
+
type Note = SoftBuildersVideoPlayerNote & { percentage: number };
|
7
|
+
type Props = {
|
8
|
+
notes: SoftBuildersVideoPlayerNote[];
|
9
|
+
};
|
10
|
+
const NotesPanal = ({ notes }: Props) => {
|
11
|
+
const [ns, setNs] = useState<Note[]>([]);
|
12
|
+
|
13
|
+
const { duration } = useSoftBuildersVideoPlayerContext();
|
14
|
+
|
15
|
+
useEffect(() => {
|
16
|
+
const newNs = notes.map((n) => {
|
17
|
+
const percentage = Math.floor((n.time * 100) / duration);
|
18
|
+
return {
|
19
|
+
...n,
|
20
|
+
percentage,
|
21
|
+
};
|
22
|
+
});
|
23
|
+
setNs(newNs);
|
24
|
+
}, [notes, duration]);
|
25
|
+
return (
|
26
|
+
<div id="notes-panal" className="sb-w-full sb-h-full sb-relative ">
|
27
|
+
{ns.map((n, i) => (
|
28
|
+
<NoteTooltip key={`note-${i}-${n.time}`} note={n} />
|
29
|
+
))}
|
30
|
+
</div>
|
31
|
+
);
|
32
|
+
};
|
33
|
+
|
34
|
+
export default NotesPanal;
|
@@ -44,20 +44,20 @@ const TimeSlider = ({ chapters }) => {
|
|
44
44
|
return (_jsxs("div", { className: " sb-w-full sb-h-2 sb-flex sb-items-center sb-justify-center", children: [_jsx("div", { className: "sb-absolute sb-top-0 sb-left-0 sb-w-full sb-z-10", children: _jsx(Slider, { value: timeSlider, handleValueChange: handleValueChange, min: MIN, max: MAX, style: {
|
45
45
|
background: "transparent",
|
46
46
|
} }) }), _jsx("div", { className: "sb-absolute sb-top-0 sb-left-0 sb-w-full sb-h-2 sb-bg-slate-400 sb-rounded-md", style: {
|
47
|
-
background: `
|
48
|
-
linear-gradient(to right,
|
49
|
-
#f97316 0%,
|
50
|
-
#f97316 ${timeSlider}%,
|
51
|
-
#f9731640 ${timeSlider}%,
|
52
|
-
#f9731640 ${downloadedBufferPercentage}%,
|
53
|
-
#30303030 ${timeSlider}%,
|
54
|
-
#30303030 100%
|
55
|
-
)
|
47
|
+
background: `
|
48
|
+
linear-gradient(to right,
|
49
|
+
#f97316 0%,
|
50
|
+
#f97316 ${timeSlider}%,
|
51
|
+
#f9731640 ${timeSlider}%,
|
52
|
+
#f9731640 ${downloadedBufferPercentage}%,
|
53
|
+
#30303030 ${timeSlider}%,
|
54
|
+
#30303030 100%
|
55
|
+
)
|
56
56
|
`,
|
57
|
-
maskImage: `
|
58
|
-
linear-gradient(to right,
|
59
|
-
${maskCuttes}
|
60
|
-
)
|
57
|
+
maskImage: `
|
58
|
+
linear-gradient(to right,
|
59
|
+
${maskCuttes}
|
60
|
+
)
|
61
61
|
`,
|
62
62
|
maskSize: "100% 100%",
|
63
63
|
maskRepeat: "no-repeat",
|