diff --git a/components/resource/content/Content.tsx b/components/resource/content/Content.tsx index 4ad9f202..8040c866 100644 --- a/components/resource/content/Content.tsx +++ b/components/resource/content/Content.tsx @@ -14,6 +14,7 @@ import { Image } from "./components/image/Image"; import { Pre } from "./components/pre/Pre"; import { Quote } from "./components/quote/Quote"; import { Sandbox } from "./components/sandbox/Sandbox"; +import { Video } from "./components/video/Video"; interface ContentProps { readonly content: MDXRemoteSerializeResult; @@ -32,6 +33,7 @@ const customMdxComponents = { Image, Link, Quote, + Video, Highlight, Sandbox: ({ id }: { id: string }) => , pre: Pre, diff --git a/components/resource/content/components/video/Video.tsx b/components/resource/content/components/video/Video.tsx new file mode 100644 index 00000000..6368ef13 --- /dev/null +++ b/components/resource/content/components/video/Video.tsx @@ -0,0 +1,57 @@ +import clsx from "clsx"; +import { memo, useRef, useState } from "react"; + +import PauseIcon from "public/svg/pause.svg"; +import PlayIcon from "public/svg/play.svg"; + +import styles from "./video.module.scss"; + +type VideoProps = { readonly alt?: string } & JSX.IntrinsicElements["video"]; + +export const Video = memo(({ alt, ...props }: VideoProps) => { + const [paused, setPaused] = useState(!props.autoPlay); + const [controlsVisible, setControlsVisible] = useState(false); + const ref = useRef(null); + + const togglePlay = () => { + if (ref.current) { + if (ref.current.paused) { + setControlsVisible(false); + setPaused(false); + void ref.current.play(); + } else { + setControlsVisible(true); + setPaused(true); + ref.current.pause(); + } + } + }; + + return ( +
+
+
+ {alt ?
{alt}
: null} +
+ ); +}); + +Video.displayName = "Video"; diff --git a/components/resource/content/components/video/video.module.scss b/components/resource/content/components/video/video.module.scss new file mode 100644 index 00000000..08865891 --- /dev/null +++ b/components/resource/content/components/video/video.module.scss @@ -0,0 +1,57 @@ +@use "styles/_mixins"; + +.wrapper { + width: auto; + height: auto; + margin: 4rem -1.2rem; + position: relative; + @include mixins.flex; + flex-flow: column wrap; + gap: 1.4rem; + + @include mixins.mediaquery("sm") { + margin: 4rem -2rem; + } + + .videoWrapper { + position: relative; + + .video { + max-width: 100%; + border-radius: 2rem; + cursor: pointer; + } + + .control { + position: absolute; + inset: 0; + width: 6.5rem; + height: 6.5rem; + border-radius: 50%; + border: 0 none; + transition: opacity 500ms ease; + background-color: rgba(0, 0, 0, 0.5); + margin: auto; + pointer-events: none; + opacity: 0; + color: var(--white-200); + @include mixins.flex; + + &.visible { + opacity: 1; + } + + .icon { + width: 50%; + } + } + } + + .caption { + font-size: 1.4rem; + font-style: italic; + opacity: 0.6; + padding: 0 1rem; + text-align: center; + } +} diff --git a/public/svg/contribute.svg b/public/svg/contribute.svg index 0bcdf3eb..ecc31a9c 100644 --- a/public/svg/contribute.svg +++ b/public/svg/contribute.svg @@ -1,3 +1,3 @@ - + diff --git a/public/svg/fire.svg b/public/svg/fire.svg index 8972c244..5593dae4 100644 --- a/public/svg/fire.svg +++ b/public/svg/fire.svg @@ -1,3 +1,3 @@ - + diff --git a/public/svg/pause.svg b/public/svg/pause.svg new file mode 100644 index 00000000..ae070ccc --- /dev/null +++ b/public/svg/pause.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/svg/play.svg b/public/svg/play.svg new file mode 100644 index 00000000..3740fe5f --- /dev/null +++ b/public/svg/play.svg @@ -0,0 +1,3 @@ + + +