Added basic video functionnality
This commit is contained in:
parent
73ad43fe7d
commit
e3c2e4da1d
|
@ -14,7 +14,7 @@ module.exports = {
|
||||||
defaultLocale: "en",
|
defaultLocale: "en",
|
||||||
},
|
},
|
||||||
images: {
|
images: {
|
||||||
domains: ["img.accords-library.com"],
|
domains: ["img.accords-library.com", "watch.accords-library.com"],
|
||||||
},
|
},
|
||||||
serverRuntimeConfig: {
|
serverRuntimeConfig: {
|
||||||
locales: locales,
|
locales: locales,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { AppStaticProps } from "queries/getAppStaticProps";
|
||||||
import { prettyLanguage } from "queries/helpers";
|
import { prettyLanguage } from "queries/helpers";
|
||||||
import Button from "./Button";
|
import Button from "./Button";
|
||||||
|
|
||||||
type HorizontalLineProps = {
|
type Props = {
|
||||||
className?: string;
|
className?: string;
|
||||||
locales: (string | undefined)[];
|
locales: (string | undefined)[];
|
||||||
languages: AppStaticProps["languages"];
|
languages: AppStaticProps["languages"];
|
||||||
|
@ -11,8 +11,8 @@ type HorizontalLineProps = {
|
||||||
href?: string;
|
href?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function HorizontalLine(
|
export default function LanguageSwitcher(
|
||||||
props: HorizontalLineProps
|
props: Props
|
||||||
): JSX.Element {
|
): JSX.Element {
|
||||||
const { locales, langui, href } = props;
|
const { locales, langui, href } = props;
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
|
@ -207,20 +207,14 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
|
||||||
onClick={() => appLayout.setMainPanelOpen(false)}
|
onClick={() => appLayout.setMainPanelOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/*
|
|
||||||
|
|
||||||
<NavOption
|
<NavOption
|
||||||
url="/archives"
|
url="/archives"
|
||||||
icon="inventory"
|
icon="inventory"
|
||||||
title={langui.archives}
|
title={langui.archives}
|
||||||
|
|
||||||
reduced={appLayout.mainPanelReduced && isDesktop}
|
reduced={appLayout.mainPanelReduced && isDesktop}
|
||||||
onClick={() => appLayout.setMainPanelOpen(false)}
|
onClick={() => appLayout.setMainPanelOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
*/}
|
|
||||||
|
|
||||||
<NavOption
|
<NavOption
|
||||||
url="/about-us"
|
url="/about-us"
|
||||||
icon="info"
|
icon="info"
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
import Chip from "components/Chip";
|
||||||
|
import { GetVideosPreviewQuery } from "graphql/generated";
|
||||||
|
import Link from "next/link";
|
||||||
|
import {
|
||||||
|
getVideoThumbnailURL,
|
||||||
|
prettyDate,
|
||||||
|
prettyDuration,
|
||||||
|
prettyShortenNumber,
|
||||||
|
} from "queries/helpers";
|
||||||
|
|
||||||
|
export type Props = {
|
||||||
|
video: Exclude<
|
||||||
|
Exclude<
|
||||||
|
GetVideosPreviewQuery["videos"],
|
||||||
|
null | undefined
|
||||||
|
>["data"][number]["attributes"],
|
||||||
|
null | undefined
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function PostPreview(props: Props): JSX.Element {
|
||||||
|
const { video } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link href={`/archives/videos/${video.uid}`} passHref>
|
||||||
|
<div className="drop-shadow-shade-xl cursor-pointer grid items-end hover:scale-[1.02] [--bg-opacity:0] hover:[--bg-opacity:0.5] [--play-opacity:0] hover:[--play-opacity:100] transition-transform">
|
||||||
|
<div className="relative">
|
||||||
|
<img
|
||||||
|
className="aspect-video rounded-t-lg"
|
||||||
|
src={getVideoThumbnailURL(video.uid)}
|
||||||
|
alt={video.title}
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 text-light grid place-content-center drop-shadow-shade-lg bg-shade bg-opacity-[var(--bg-opacity)] transition-colors">
|
||||||
|
<span className="material-icons text-6xl opacity-[var(--play-opacity)] transition-opacity">
|
||||||
|
play_circle_outline
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="absolute right-2 bottom-2 text-light bg-black bg-opacity-60 px-2 rounded-full">
|
||||||
|
{prettyDuration(video.duration)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="linearbg-obi fine:drop-shadow-shade-lg rounded-b-md top-full transition-opacity z-20 grid p-4 gap-2">
|
||||||
|
<div className="flex flex-row flex-wrap gap-x-3 w-full">
|
||||||
|
<p className="mobile:text-xs text-sm">
|
||||||
|
<span className="material-icons !text-base translate-y-[.15em] mr-1">
|
||||||
|
event
|
||||||
|
</span>
|
||||||
|
{prettyDate(video.published_date)}
|
||||||
|
</p>
|
||||||
|
<p className="mobile:text-xs text-sm">
|
||||||
|
<span className="material-icons !text-base translate-y-[.15em] mr-1">
|
||||||
|
visibility
|
||||||
|
</span>
|
||||||
|
{prettyShortenNumber(video.views)}
|
||||||
|
</p>
|
||||||
|
{video.channel?.data?.attributes && (
|
||||||
|
<p className="mobile:text-xs text-sm">
|
||||||
|
<span className="material-icons !text-base translate-y-[.15em] mr-1">
|
||||||
|
person
|
||||||
|
</span>
|
||||||
|
{video.channel.data.attributes.title}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1 className="text-xl">{video.title}</h1>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-flow-col gap-1 overflow-x-scroll webkit-scrollbar:w-0 [scrollbar-width:none] place-content-start">
|
||||||
|
{video.categories?.data.map((category) => (
|
||||||
|
<Chip key={category.id} className="text-sm">
|
||||||
|
{category.attributes?.short}
|
||||||
|
</Chip>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
query getVideo($uid: String) {
|
||||||
|
videos(filters: { uid: { eq: $uid } }) {
|
||||||
|
data {
|
||||||
|
id
|
||||||
|
attributes {
|
||||||
|
uid
|
||||||
|
title
|
||||||
|
description
|
||||||
|
published_date {
|
||||||
|
year
|
||||||
|
month
|
||||||
|
day
|
||||||
|
}
|
||||||
|
channel {
|
||||||
|
data {
|
||||||
|
attributes {
|
||||||
|
uid
|
||||||
|
title
|
||||||
|
subscribers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
categories {
|
||||||
|
data {
|
||||||
|
id
|
||||||
|
attributes {
|
||||||
|
short
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
views
|
||||||
|
likes
|
||||||
|
source
|
||||||
|
audio_languages {
|
||||||
|
data {
|
||||||
|
id
|
||||||
|
attributes {
|
||||||
|
code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sub_languages {
|
||||||
|
data {
|
||||||
|
id
|
||||||
|
attributes {
|
||||||
|
code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
query getVideosPreview {
|
||||||
|
videos(pagination: { limit: -1 }) {
|
||||||
|
data {
|
||||||
|
id
|
||||||
|
attributes {
|
||||||
|
uid
|
||||||
|
title
|
||||||
|
views
|
||||||
|
duration
|
||||||
|
categories {
|
||||||
|
data {
|
||||||
|
id
|
||||||
|
attributes {
|
||||||
|
short
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
published_date {
|
||||||
|
...datePicker
|
||||||
|
}
|
||||||
|
channel {
|
||||||
|
data {
|
||||||
|
attributes {
|
||||||
|
uid
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
query getVideosSlugs {
|
||||||
|
videos(pagination: {limit:-1}) {
|
||||||
|
data {
|
||||||
|
id
|
||||||
|
attributes {
|
||||||
|
uid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import AppLayout from "components/AppLayout";
|
import AppLayout from "components/AppLayout";
|
||||||
|
import NavOption from "components/PanelComponents/NavOption";
|
||||||
import PanelHeader from "components/PanelComponents/PanelHeader";
|
import PanelHeader from "components/PanelComponents/PanelHeader";
|
||||||
import SubPanel from "components/Panels/SubPanel";
|
import SubPanel from "components/Panels/SubPanel";
|
||||||
import { GetStaticPropsContext } from "next";
|
import { GetStaticPropsContext } from "next";
|
||||||
|
@ -15,6 +16,7 @@ export default function Archives(props: ArchivesProps): JSX.Element {
|
||||||
title={langui.archives}
|
title={langui.archives}
|
||||||
description={langui.archives_description}
|
description={langui.archives_description}
|
||||||
/>
|
/>
|
||||||
|
<NavOption title={"Videos"} url="/archives/videos/" border />
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
import AppLayout from "components/AppLayout";
|
||||||
|
import Button from "components/Button";
|
||||||
|
import HorizontalLine from "components/HorizontalLine";
|
||||||
|
import InsetBox from "components/InsetBox";
|
||||||
|
import NavOption from "components/PanelComponents/NavOption";
|
||||||
|
import ReturnButton, {
|
||||||
|
ReturnButtonType,
|
||||||
|
} from "components/PanelComponents/ReturnButton";
|
||||||
|
import ContentPanel, {
|
||||||
|
ContentPanelWidthSizes,
|
||||||
|
} from "components/Panels/ContentPanel";
|
||||||
|
import SubPanel from "components/Panels/SubPanel";
|
||||||
|
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||||
|
import { GetVideoQuery } from "graphql/generated";
|
||||||
|
import { getReadySdk } from "graphql/sdk";
|
||||||
|
import { useMediaMobile } from "hooks/useMediaQuery";
|
||||||
|
import {
|
||||||
|
GetStaticPathsContext,
|
||||||
|
GetStaticPathsResult,
|
||||||
|
GetStaticPropsContext,
|
||||||
|
} from "next";
|
||||||
|
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||||
|
import { getVideoFile, prettyDate, prettyShortenNumber } from "queries/helpers";
|
||||||
|
|
||||||
|
interface Props extends AppStaticProps {
|
||||||
|
video: Exclude<
|
||||||
|
Exclude<
|
||||||
|
GetVideoQuery["videos"],
|
||||||
|
null | undefined
|
||||||
|
>["data"][number]["attributes"],
|
||||||
|
null | undefined
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Video(props: Props): JSX.Element {
|
||||||
|
const { langui, video } = props;
|
||||||
|
const isMobile = useMediaMobile();
|
||||||
|
const appLayout = useAppLayout();
|
||||||
|
const subPanel = (
|
||||||
|
<SubPanel>
|
||||||
|
<ReturnButton
|
||||||
|
href="/archives/videos/"
|
||||||
|
title={"Videos"}
|
||||||
|
langui={langui}
|
||||||
|
displayOn={ReturnButtonType.desktop}
|
||||||
|
className="mb-10"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<HorizontalLine />
|
||||||
|
|
||||||
|
<NavOption
|
||||||
|
title={langui.video}
|
||||||
|
url="#video"
|
||||||
|
border
|
||||||
|
onClick={() => appLayout.setSubPanelOpen(false)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<NavOption
|
||||||
|
title={"Channel"}
|
||||||
|
url="#channel"
|
||||||
|
border
|
||||||
|
onClick={() => appLayout.setSubPanelOpen(false)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<NavOption
|
||||||
|
title={"Description"}
|
||||||
|
url="#description"
|
||||||
|
border
|
||||||
|
onClick={() => appLayout.setSubPanelOpen(false)}
|
||||||
|
/>
|
||||||
|
</SubPanel>
|
||||||
|
);
|
||||||
|
|
||||||
|
const contentPanel = (
|
||||||
|
<ContentPanel width={ContentPanelWidthSizes.large}>
|
||||||
|
<ReturnButton
|
||||||
|
href="/library/"
|
||||||
|
title={langui.library}
|
||||||
|
langui={langui}
|
||||||
|
displayOn={ReturnButtonType.mobile}
|
||||||
|
className="mb-10"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="grid gap-12 place-items-center">
|
||||||
|
<div
|
||||||
|
id="video"
|
||||||
|
className="w-full rounded-xl shadow-shade shadow-lg overflow-hidden"
|
||||||
|
>
|
||||||
|
<video className="w-full" src={getVideoFile(video.uid)} controls></video>
|
||||||
|
<div className="p-6 mt-2">
|
||||||
|
<h1 className="text-2xl">{video.title}</h1>
|
||||||
|
<div className="flex flex-row flex-wrap gap-x-6 w-full">
|
||||||
|
<p>
|
||||||
|
<span className="material-icons !text-base translate-y-[.15em] mr-1">
|
||||||
|
event
|
||||||
|
</span>
|
||||||
|
{prettyDate(video.published_date)}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span className="material-icons !text-base translate-y-[.15em] mr-1">
|
||||||
|
visibility
|
||||||
|
</span>
|
||||||
|
{isMobile
|
||||||
|
? prettyShortenNumber(video.views)
|
||||||
|
: video.views.toLocaleString()}
|
||||||
|
</p>
|
||||||
|
{video.channel?.data?.attributes && (
|
||||||
|
<p>
|
||||||
|
<span className="material-icons !text-base translate-y-[.15em] mr-1">
|
||||||
|
thumb_up
|
||||||
|
</span>
|
||||||
|
{isMobile
|
||||||
|
? prettyShortenNumber(video.likes)
|
||||||
|
: video.likes.toLocaleString()}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<Button href="" className="!py-0 !px-3">{`View on ${video.source}`}</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{video.channel?.data?.attributes && (
|
||||||
|
<InsetBox id="channel" className="grid place-items-center">
|
||||||
|
<div className="w-[clamp(0px,100%,42rem)] grid place-items-center gap-4 text-center">
|
||||||
|
<h2 className="text-2xl">{"Channel"}</h2>
|
||||||
|
<div>
|
||||||
|
<Button href="#">
|
||||||
|
<h3>{video.channel.data.attributes.title}</h3>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{video.channel.data.attributes.subscribers.toLocaleString()}{" "}
|
||||||
|
subscribers
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</InsetBox>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<InsetBox id="description" className="grid place-items-center">
|
||||||
|
<div className="w-[clamp(0px,100%,42rem)] grid place-items-center gap-8">
|
||||||
|
<h2 className="text-2xl">{"Description"}</h2>
|
||||||
|
<p className="whitespace-pre-line">{video.description}</p>
|
||||||
|
</div>
|
||||||
|
</InsetBox>
|
||||||
|
</div>
|
||||||
|
</ContentPanel>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<AppLayout
|
||||||
|
navTitle={langui.archives}
|
||||||
|
subPanel={subPanel}
|
||||||
|
contentPanel={contentPanel}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticProps(
|
||||||
|
context: GetStaticPropsContext
|
||||||
|
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||||
|
const sdk = getReadySdk();
|
||||||
|
const videos = await sdk.getVideo({
|
||||||
|
uid: context.params?.uid ? context.params.uid.toString() : "",
|
||||||
|
});
|
||||||
|
if (!videos.videos?.data[0].attributes) return { notFound: true };
|
||||||
|
const props: Props = {
|
||||||
|
...(await getAppStaticProps(context)),
|
||||||
|
video: videos.videos.data[0].attributes,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
props: props,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticPaths(
|
||||||
|
context: GetStaticPathsContext
|
||||||
|
): Promise<GetStaticPathsResult> {
|
||||||
|
const sdk = getReadySdk();
|
||||||
|
const videos = await sdk.getVideo();
|
||||||
|
const paths: GetStaticPathsResult["paths"] = [];
|
||||||
|
if (videos.videos?.data)
|
||||||
|
videos.videos.data.map((video) => {
|
||||||
|
context.locales?.map((local) => {
|
||||||
|
if (video.attributes)
|
||||||
|
paths.push({ params: { uid: video.attributes.uid }, locale: local });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
paths,
|
||||||
|
fallback: "blocking",
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
import AppLayout from "components/AppLayout";
|
||||||
|
import HorizontalLine from "components/HorizontalLine";
|
||||||
|
import PanelHeader from "components/PanelComponents/PanelHeader";
|
||||||
|
import ReturnButton, {
|
||||||
|
ReturnButtonType,
|
||||||
|
} from "components/PanelComponents/ReturnButton";
|
||||||
|
import ContentPanel, {
|
||||||
|
ContentPanelWidthSizes,
|
||||||
|
} from "components/Panels/ContentPanel";
|
||||||
|
import SubPanel from "components/Panels/SubPanel";
|
||||||
|
import VideoPreview from "components/Videos/VideoPreview";
|
||||||
|
import { GetVideosPreviewQuery } from "graphql/generated";
|
||||||
|
import { getReadySdk } from "graphql/sdk";
|
||||||
|
import { GetStaticPropsContext } from "next";
|
||||||
|
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||||
|
|
||||||
|
interface Props extends AppStaticProps {
|
||||||
|
videos: Exclude<GetVideosPreviewQuery["videos"], null | undefined>["data"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Videos(props: Props): JSX.Element {
|
||||||
|
const { langui, videos } = props;
|
||||||
|
const subPanel = (
|
||||||
|
<SubPanel>
|
||||||
|
<ReturnButton
|
||||||
|
href="/archives/"
|
||||||
|
title={"Archives"}
|
||||||
|
langui={langui}
|
||||||
|
displayOn={ReturnButtonType.desktop}
|
||||||
|
className="mb-10"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<PanelHeader
|
||||||
|
icon="movie"
|
||||||
|
title="Videos"
|
||||||
|
description={langui.archives_description}
|
||||||
|
/>
|
||||||
|
</SubPanel>
|
||||||
|
);
|
||||||
|
|
||||||
|
const contentPanel = (
|
||||||
|
<ContentPanel width={ContentPanelWidthSizes.large}>
|
||||||
|
<div className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] pb-12 border-b-[3px] border-dotted last-of-type:border-0">
|
||||||
|
{videos.map((video) => (
|
||||||
|
<>{video.attributes && <VideoPreview video={video.attributes} />}</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ContentPanel>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<AppLayout
|
||||||
|
navTitle={langui.archives}
|
||||||
|
subPanel={subPanel}
|
||||||
|
contentPanel={contentPanel}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticProps(
|
||||||
|
context: GetStaticPropsContext
|
||||||
|
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||||
|
const sdk = getReadySdk();
|
||||||
|
const videos = await sdk.getVideosPreview();
|
||||||
|
if (!videos.videos) return { notFound: true };
|
||||||
|
const props: Props = {
|
||||||
|
...(await getAppStaticProps(context)),
|
||||||
|
videos: videos.videos.data,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
props: props,
|
||||||
|
};
|
||||||
|
}
|
|
@ -229,6 +229,37 @@ export function prettyItemSubType(
|
||||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function prettyShortenNumber(number: number): string {
|
||||||
|
if (number > 1000000) {
|
||||||
|
return number.toLocaleString(undefined, {
|
||||||
|
maximumSignificantDigits: 3,
|
||||||
|
});
|
||||||
|
} else if (number > 1000) {
|
||||||
|
return (number / 1000).toLocaleString(undefined, {
|
||||||
|
maximumSignificantDigits: 2,
|
||||||
|
}) + "K";
|
||||||
|
}
|
||||||
|
return number.toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function prettyDuration(seconds: number): string {
|
||||||
|
let hours = 0;
|
||||||
|
let minutes = 0;
|
||||||
|
while (seconds > 60) {
|
||||||
|
minutes += 1;
|
||||||
|
seconds -= 60;
|
||||||
|
}
|
||||||
|
while (minutes > 60) {
|
||||||
|
hours += 1;
|
||||||
|
minutes -= 60;
|
||||||
|
}
|
||||||
|
let result = "";
|
||||||
|
if (hours) result += hours.toString().padStart(2, "0") + ":";
|
||||||
|
result += minutes.toString().padStart(2, "0") + ":";
|
||||||
|
result += seconds.toString().padStart(2, "0");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
export function prettyLanguage(
|
export function prettyLanguage(
|
||||||
code: string,
|
code: string,
|
||||||
languages: AppStaticProps["languages"]
|
languages: AppStaticProps["languages"]
|
||||||
|
@ -417,3 +448,11 @@ export function getLocalesFromLanguages(
|
||||||
? languages.map((language) => language?.language?.data?.attributes?.code)
|
? languages.map((language) => language?.language?.data?.attributes?.code)
|
||||||
: [];
|
: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getVideoThumbnailURL(uid: string):string {
|
||||||
|
return `${process.env.NEXT_PUBLIC_URL_WATCH}/videos/${uid}.webp`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVideoFile(uid: string):string {
|
||||||
|
return `${process.env.NEXT_PUBLIC_URL_WATCH}/videos/${uid}.mp4`;
|
||||||
|
}
|
Loading…
Reference in New Issue