Added media support in RTC
This commit is contained in:
parent
9a1cbd28f7
commit
35e2991086
3
TODO.md
3
TODO.md
|
@ -4,6 +4,9 @@
|
|||
|
||||
- [Timeline] inline links to pages not working (timeline 2026/06)
|
||||
- Save cookies for longer than just the session
|
||||
- [Image] media page
|
||||
- [Video] media page
|
||||
- [Audio] media page
|
||||
|
||||
## Mid term
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import Topbar from "./components/Topbar/Topbar.astro";
|
|||
import Footer from "./components/Footer.astro";
|
||||
import AppLayoutTitle from "./components/AppLayoutTitle.astro";
|
||||
import type { ComponentProps } from "astro/types";
|
||||
import type { PayloadImage } from "src/shared/payload/payload-sdk";
|
||||
|
||||
interface Props {
|
||||
openGraph?: ComponentProps<typeof Html>["openGraph"];
|
||||
|
@ -17,7 +16,7 @@ interface Props {
|
|||
illustration?: string;
|
||||
illustrationSize?: string;
|
||||
illustrationPosition?: string;
|
||||
backgroundImage?: PayloadImage | undefined;
|
||||
backgroundImage?: ComponentProps<typeof AppLayoutBackgroundImg>["img"] | undefined;
|
||||
hideFooterLinks?: boolean;
|
||||
hideHomeButton?: boolean;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import type { PayloadImage } from "src/shared/payload/payload-sdk";
|
|||
import { getRandomId } from "src/utils/random";
|
||||
|
||||
interface Props {
|
||||
img: PayloadImage;
|
||||
img: Pick<PayloadImage, "url" | "width" | "height">;
|
||||
}
|
||||
|
||||
const {
|
||||
|
|
|
@ -50,23 +50,14 @@ const { currentTheme } = Astro.locals;
|
|||
"light-theme": currentTheme === "light",
|
||||
"dark-theme": currentTheme === "dark",
|
||||
"texture-dots": !isIOS,
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link rel="stylesheet" href="/css/tippy.css" />
|
||||
<meta
|
||||
name="theme-color"
|
||||
media="(prefers-color-scheme: light)"
|
||||
content="#fdebd4"
|
||||
/>
|
||||
<meta
|
||||
name="theme-color"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
content="#27231e"
|
||||
/>
|
||||
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#fdebd4" />
|
||||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#27231e" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
|
||||
{/* Meta & OpenGraph */}
|
||||
|
@ -80,10 +71,7 @@ const { currentTheme } = Astro.locals;
|
|||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:image" content={thumbnail} />
|
||||
|
||||
<meta
|
||||
property="og:type"
|
||||
content={video ? "video.movie" : audio ? "music.song" : "website"}
|
||||
/>
|
||||
<meta property="og:type" content={video ? "video.movie" : audio ? "music.song" : "website"} />
|
||||
<meta property="og:locale" content={currentLocale} />
|
||||
<meta property="og:site_name" content={t("global.siteName")} />
|
||||
|
||||
|
@ -133,9 +121,7 @@ const { currentTheme } = Astro.locals;
|
|||
<AppLayoutSpinner />
|
||||
</html>
|
||||
|
||||
{
|
||||
/* ------------------------------------------- CSS -------------------------------------------- */
|
||||
}
|
||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||
|
||||
<style is:global>
|
||||
html {
|
||||
|
@ -467,8 +453,7 @@ const { currentTheme } = Astro.locals;
|
|||
backdrop-filter: blur(10px);
|
||||
|
||||
transition-duration: 250ms;
|
||||
transition-property: padding-top, box-shadow, background-color, color,
|
||||
border-color;
|
||||
transition-property: padding-top, box-shadow, background-color, color, border-color;
|
||||
|
||||
&:hover {
|
||||
--foreground-color: var(--color-base-1000);
|
||||
|
@ -587,19 +572,13 @@ const { currentTheme } = Astro.locals;
|
|||
}
|
||||
</style>
|
||||
|
||||
{
|
||||
/* ------------------------------------------- JS --------------------------------------------- */
|
||||
}
|
||||
{/* ------------------------------------------- JS --------------------------------------------- */}
|
||||
|
||||
<script is:inline>
|
||||
Array.from(document.querySelectorAll(".when-no-js")).forEach((node) =>
|
||||
node.remove()
|
||||
);
|
||||
Array.from(document.querySelectorAll(".when-no-js")).forEach((node) => node.remove());
|
||||
|
||||
document.addEventListener("astro:before-swap", ({ newDocument }) => {
|
||||
Array.from(newDocument.querySelectorAll(".when-no-js")).forEach((node) =>
|
||||
node.remove()
|
||||
);
|
||||
Array.from(newDocument.querySelectorAll(".when-no-js")).forEach((node) => node.remove());
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
interface Props {
|
||||
id?: string;
|
||||
header: number;
|
||||
}
|
||||
|
||||
const { header, id } = Astro.props;
|
||||
---
|
||||
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
{
|
||||
header === 1 ? (
|
||||
<h1 id={id}>
|
||||
<slot />
|
||||
</h1>
|
||||
) : header === 2 ? (
|
||||
<h2 id={id}>
|
||||
<slot />
|
||||
</h2>
|
||||
) : header === 3 ? (
|
||||
<h3 id={id}>
|
||||
<slot />
|
||||
</h3>
|
||||
) : header === 4 ? (
|
||||
<h4 id={id}>
|
||||
<slot />
|
||||
</h4>
|
||||
) : header === 5 ? (
|
||||
<h5 id={id}>
|
||||
<slot />
|
||||
</h5>
|
||||
) : (
|
||||
<h6 id={id}>
|
||||
<slot />
|
||||
</h6>
|
||||
)
|
||||
}
|
||||
|
||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||
|
||||
<style>
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
display: inline-flex;
|
||||
place-items: center;
|
||||
gap: 0.5em;
|
||||
}
|
||||
</style>
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
import GenericPreview from "components/Previews/GenericPreview.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import type { EndpointCollectiblePreview } from "src/shared/payload/payload-sdk";
|
||||
import type { EndpointCollectible } from "src/shared/payload/payload-sdk";
|
||||
|
||||
interface Props {
|
||||
collectible: EndpointCollectiblePreview;
|
||||
collectible: EndpointCollectible;
|
||||
}
|
||||
|
||||
const { getLocalizedMatch, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
import GenericPreview from "components/Previews/GenericPreview.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import type { EndpointPagePreview } from "src/shared/payload/payload-sdk";
|
||||
import type { EndpointPage } from "src/shared/payload/payload-sdk";
|
||||
|
||||
interface Props {
|
||||
page: EndpointPagePreview;
|
||||
page: EndpointPage;
|
||||
}
|
||||
|
||||
const { getLocalizedMatch, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
import HeaderTitle from "components/HeaderTitle.astro";
|
||||
import RichText from "components/RichText/RichText.astro";
|
||||
import type { RichTextSectionBlock } from "src/shared/payload/payload-sdk";
|
||||
import type { RichTextContext } from "src/utils/richText";
|
||||
|
@ -13,34 +14,10 @@ const { node, context } = Astro.props;
|
|||
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
{
|
||||
context.depth < 2 ? (
|
||||
<h2 id={node.anchorHash}>
|
||||
<HeaderTitle id={node.anchorHash} header={context.depth + 1}>
|
||||
<span>{`${node.anchorHash} `}</span>
|
||||
{node.fields.blockName}
|
||||
</h2>
|
||||
) : context.depth === 2 ? (
|
||||
<h3 id={node.anchorHash}>
|
||||
<span>{`${node.anchorHash} `}</span>
|
||||
{node.fields.blockName}
|
||||
</h3>
|
||||
) : context.depth === 3 ? (
|
||||
<h4 id={node.anchorHash}>
|
||||
<span>{`${node.anchorHash} `}</span>
|
||||
{node.fields.blockName}
|
||||
</h4>
|
||||
) : context.depth === 4 ? (
|
||||
<h5 id={node.anchorHash}>
|
||||
<span>{`${node.anchorHash} `}</span>
|
||||
{node.fields.blockName}
|
||||
</h5>
|
||||
) : (
|
||||
<h6 id={node.anchorHash}>
|
||||
<span>{`${node.anchorHash} `}</span>
|
||||
{node.fields.blockName}
|
||||
</h6>
|
||||
)
|
||||
}
|
||||
</HeaderTitle>
|
||||
|
||||
<RichText content={node.fields.content} context={{ ...context, depth: context.depth + 1 }} />
|
||||
|
||||
|
@ -51,6 +28,6 @@ const { node, context } = Astro.props;
|
|||
color: var(--color-base-650);
|
||||
font-weight: 500;
|
||||
font-size: 70%;
|
||||
margin-right: 0.3em;
|
||||
place-self: end;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -19,9 +19,7 @@ interface Props {
|
|||
const { node, context } = Astro.props;
|
||||
---
|
||||
|
||||
{
|
||||
/* ------------------------------------------- HTML ------------------------------------------- */
|
||||
}
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
{
|
||||
isUploadNodeImageNode(node) ? (
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
|
||||
interface Props {
|
||||
url: string;
|
||||
}
|
||||
|
||||
const { url } = Astro.props;
|
||||
const { t } = await getI18n(Astro.locals.currentLocale);
|
||||
---
|
||||
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
<div class="button">
|
||||
<a href={url}>
|
||||
<div class="pressable-label">
|
||||
<Icon name="material-symbols:left-click" />
|
||||
<p>{t("global.openMediaPage")}</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||
|
||||
<style>
|
||||
.button {
|
||||
display: flex;
|
||||
place-items: start;
|
||||
gap: 0.3em;
|
||||
font-size: 85%;
|
||||
|
||||
& > a > div {
|
||||
padding: 0.3em 0.6em;
|
||||
padding-right: 0.8em;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,32 +1,54 @@
|
|||
---
|
||||
import { type RichTextUploadAudioNode } from "src/shared/payload/payload-sdk";
|
||||
import type { RichTextContext } from "src/utils/richText";
|
||||
import OpenMediaPageButton from "./OpenMediaPageButton.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import HeaderTitle from "components/HeaderTitle.astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
||||
interface Props {
|
||||
node: RichTextUploadAudioNode;
|
||||
context: RichTextContext;
|
||||
}
|
||||
|
||||
const { node } = Astro.props;
|
||||
const {
|
||||
node: {
|
||||
value: { id, url, mimeType, translations },
|
||||
},
|
||||
context,
|
||||
} = Astro.props;
|
||||
|
||||
const { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||
const { title } = getLocalizedMatch(translations);
|
||||
---
|
||||
|
||||
{
|
||||
/* ------------------------------------------- HTML ------------------------------------------- */
|
||||
}
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
<audio controls>
|
||||
<source src={node.value.url} type={node.value.mimeType} />
|
||||
</audio>
|
||||
<div>
|
||||
<HeaderTitle header={context.depth + 2}>
|
||||
<Icon name="material-symbols:headphones" />
|
||||
{title}
|
||||
</HeaderTitle>
|
||||
|
||||
{
|
||||
/* ------------------------------------------- CSS -------------------------------------------- */
|
||||
}
|
||||
<audio controls>
|
||||
<source src={url} type={mimeType} />
|
||||
</audio>
|
||||
|
||||
<OpenMediaPageButton url={`/audios/${id}`} />
|
||||
</div>
|
||||
|
||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||
|
||||
<style>
|
||||
audio {
|
||||
div {
|
||||
margin-block: 4em;
|
||||
|
||||
& > audio {
|
||||
margin-top: 0.4em;
|
||||
margin-bottom: 0.2em;
|
||||
width: 100%;
|
||||
margin-block: 3em;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 5px 20px -10px var(--color-shadow);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,27 +1,60 @@
|
|||
---
|
||||
import { type RichTextUploadImageNode } from "src/shared/payload/payload-sdk";
|
||||
import type { RichTextContext } from "src/utils/richText";
|
||||
import OpenMediaPageButton from "./OpenMediaPageButton.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import HeaderTitle from "components/HeaderTitle.astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
||||
interface Props {
|
||||
node: RichTextUploadImageNode;
|
||||
context: RichTextContext;
|
||||
}
|
||||
|
||||
const { node } = Astro.props;
|
||||
const {
|
||||
node: {
|
||||
value: { id, url, translations },
|
||||
},
|
||||
context,
|
||||
} = Astro.props;
|
||||
|
||||
const { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||
const { title }: { title?: string } =
|
||||
translations.length > 0 ? getLocalizedMatch(translations) : {};
|
||||
|
||||
const mediaPage = `/images/${id}`;
|
||||
---
|
||||
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
<img src={node.value.url} />
|
||||
<div>
|
||||
{
|
||||
title && (
|
||||
<HeaderTitle header={context.depth + 2}>
|
||||
<Icon name="material-symbols:image-outline" />
|
||||
{title}
|
||||
</HeaderTitle>
|
||||
)
|
||||
}
|
||||
|
||||
<a href={mediaPage}><img src={url} /></a>
|
||||
|
||||
<OpenMediaPageButton url={mediaPage} />
|
||||
</div>
|
||||
|
||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||
|
||||
<style>
|
||||
img {
|
||||
div {
|
||||
margin-block: 4em;
|
||||
|
||||
& > a > img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-block: 3em;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 5px 20px -10px var(--color-shadow);
|
||||
margin-top: 0.4em;
|
||||
margin-bottom: 0.2em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,29 +1,61 @@
|
|||
---
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import { type RichTextUploadVideoNode } from "src/shared/payload/payload-sdk";
|
||||
import { formatLocale } from "src/utils/format";
|
||||
import type { RichTextContext } from "src/utils/richText";
|
||||
import OpenMediaPageButton from "./OpenMediaPageButton.astro";
|
||||
import HeaderTitle from "components/HeaderTitle.astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
||||
interface Props {
|
||||
node: RichTextUploadVideoNode;
|
||||
context: RichTextContext;
|
||||
}
|
||||
|
||||
const { node } = Astro.props;
|
||||
const {
|
||||
node: {
|
||||
value: { id, url, thumbnail, mimeType, subtitles, translations },
|
||||
},
|
||||
context,
|
||||
} = Astro.props;
|
||||
|
||||
const { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||
const { title } = getLocalizedMatch(translations);
|
||||
---
|
||||
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
<video controls>
|
||||
<source src={node.value.url} type={node.value.mimeType} />
|
||||
</video>
|
||||
<div>
|
||||
<HeaderTitle header={context.depth + 2}>
|
||||
<Icon name="material-symbols:movie-outline" />
|
||||
{title}
|
||||
</HeaderTitle>
|
||||
|
||||
<video controls poster={thumbnail?.url}>
|
||||
<source src={url} type={mimeType} />
|
||||
{
|
||||
subtitles.map(({ language, url }) => (
|
||||
<track label={formatLocale(language)} src={url} kind="subtitles" srclang={language} />
|
||||
))
|
||||
}
|
||||
</video>
|
||||
|
||||
<OpenMediaPageButton url={`/videos/${id}`} />
|
||||
</div>
|
||||
|
||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||
|
||||
<style>
|
||||
video {
|
||||
div {
|
||||
margin-block: 4em;
|
||||
|
||||
& > video {
|
||||
margin-top: 0.4em;
|
||||
margin-bottom: 0.2em;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-block: 3em;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 5px 20px -10px var(--color-shadow);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -111,4 +111,5 @@ export type WordingKey =
|
|||
| "global.sources.typeLabel.folder"
|
||||
| "global.sources.typeLabel.collectible.range.page"
|
||||
| "global.sources.typeLabel.collectible.range.timestamp"
|
||||
| "global.sources.typeLabel.collectible.range.custom";
|
||||
| "global.sources.typeLabel.collectible.range.custom"
|
||||
| "global.openMediaPage";
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
import type { EndpointFolderPreview } from "src/shared/payload/payload-sdk";
|
||||
import type { EndpointFolder } from "src/shared/payload/payload-sdk";
|
||||
import FolderCard from "./FolderCard.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
|
||||
interface Props {
|
||||
title?: string | undefined;
|
||||
folders: EndpointFolderPreview[];
|
||||
folders: EndpointFolder[];
|
||||
}
|
||||
|
||||
const { title, folders } = Astro.props;
|
||||
|
|
|
@ -17,10 +17,8 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
|||
openGraph={{ title: t("home.title") }}
|
||||
backgroundImage={{
|
||||
url: "/img/background-image.webp",
|
||||
filename: "background-image",
|
||||
height: 2279,
|
||||
width: 1920,
|
||||
mimeType: "image/webp",
|
||||
}}
|
||||
hideFooterLinks
|
||||
hideHomeButton>
|
||||
|
|
|
@ -21,10 +21,8 @@ const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.cu
|
|||
<AppLayoutBackgroundImg
|
||||
img={{
|
||||
url: "/img/timeline-background.webp",
|
||||
filename: "timeline-background",
|
||||
width: 2478,
|
||||
height: 4110,
|
||||
mimeType: "image/webp",
|
||||
}}
|
||||
/>
|
||||
<AppLayoutTitle title={t("timeline.title")} />
|
||||
|
|
|
@ -551,7 +551,6 @@ export interface Audio {
|
|||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
subfile?: string | VideoSubtitle | null;
|
||||
id?: string | null;
|
||||
}[];
|
||||
tags?: (string | Tag)[] | null;
|
||||
|
@ -597,19 +596,6 @@ export interface MediaThumbnail {
|
|||
};
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "videos-subtitles".
|
||||
*/
|
||||
export interface VideoSubtitle {
|
||||
id: string;
|
||||
url?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "videos".
|
||||
|
@ -617,7 +603,7 @@ export interface VideoSubtitle {
|
|||
export interface Video {
|
||||
id: string;
|
||||
duration: number;
|
||||
thumbnail: string | MediaThumbnail;
|
||||
thumbnail?: string | MediaThumbnail | null;
|
||||
translations: {
|
||||
language: string | Language;
|
||||
title: string;
|
||||
|
@ -658,6 +644,19 @@ export interface Video {
|
|||
width?: number | null;
|
||||
height?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "videos-subtitles".
|
||||
*/
|
||||
export interface VideoSubtitle {
|
||||
id: string;
|
||||
url?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "videos-channels".
|
||||
|
@ -666,7 +665,7 @@ export interface VideosChannel {
|
|||
id: string;
|
||||
url: string;
|
||||
title: string;
|
||||
subscribers?: number | null;
|
||||
subscribers: number;
|
||||
videos?: (string | Video)[] | null;
|
||||
}
|
||||
/**
|
||||
|
@ -1099,17 +1098,17 @@ export interface RichTextUploadNode extends RichTextNode {
|
|||
|
||||
export interface RichTextUploadImageNode extends RichTextUploadNode {
|
||||
relationTo: Collections.Images;
|
||||
value: Image;
|
||||
value: EndpointImage;
|
||||
}
|
||||
|
||||
export interface RichTextUploadVideoNode extends RichTextUploadNode {
|
||||
relationTo: Collections.Videos;
|
||||
value: Video;
|
||||
value: EndpointVideo;
|
||||
}
|
||||
|
||||
export interface RichTextUploadAudioNode extends RichTextUploadNode {
|
||||
relationTo: Collections.Audios;
|
||||
value: Audio;
|
||||
value: EndpointAudio;
|
||||
}
|
||||
|
||||
export interface RichTextTextNode extends RichTextNode {
|
||||
|
@ -1179,10 +1178,10 @@ export const isNodeUploadNode = (node: RichTextNode): node is RichTextUploadNode
|
|||
export const isUploadNodeImageNode = (node: RichTextUploadNode): node is RichTextUploadImageNode =>
|
||||
node.relationTo === Collections.Images;
|
||||
|
||||
export const isUploadNodeVideoNode = (node: RichTextUploadNode): node is RichTextUploadVideoNode =>
|
||||
export const isUploadNodeVideoNode = (node: RichTextUploadNode): node is RichTextUploadVideoNode =>
|
||||
node.relationTo === Collections.Videos;
|
||||
|
||||
export const isUploadNodeAudioNode = (node: RichTextUploadNode): node is RichTextUploadAudioNode =>
|
||||
export const isUploadNodeAudioNode = (node: RichTextUploadNode): node is RichTextUploadAudioNode =>
|
||||
node.relationTo === Collections.Audios;
|
||||
|
||||
export const isNodeListNode = (node: RichTextNode): node is RichTextListNode =>
|
||||
|
@ -1338,7 +1337,7 @@ const request = async (url: string, init?: RequestInit): Promise<Response> => {
|
|||
|
||||
// SDK and Types
|
||||
|
||||
export type EndpointFolderPreview = {
|
||||
export type EndpointFolder = {
|
||||
slug: string;
|
||||
icon?: string;
|
||||
translations: {
|
||||
|
@ -1346,33 +1345,42 @@ export type EndpointFolderPreview = {
|
|||
name: string;
|
||||
description?: RichTextContent;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type EndpointFolder = EndpointFolderPreview & {
|
||||
sections:
|
||||
| { type: "single"; subfolders: EndpointFolderPreview[] }
|
||||
| { type: "single"; subfolders: EndpointFolder[] }
|
||||
| {
|
||||
type: "multiple";
|
||||
sections: {
|
||||
translations: { language: string; name: string }[];
|
||||
subfolders: EndpointFolderPreview[];
|
||||
subfolders: EndpointFolder[];
|
||||
}[];
|
||||
};
|
||||
files: (
|
||||
| {
|
||||
relationTo: "collectibles";
|
||||
value: EndpointCollectiblePreview;
|
||||
relationTo: Collections.Collectibles;
|
||||
value: EndpointCollectible;
|
||||
}
|
||||
| {
|
||||
relationTo: "pages";
|
||||
value: EndpointPagePreview;
|
||||
relationTo: Collections.Pages;
|
||||
value: EndpointPage;
|
||||
}
|
||||
| {
|
||||
relationTo: Collections.Images;
|
||||
value: EndpointImage;
|
||||
}
|
||||
| {
|
||||
relationTo: Collections.Audios;
|
||||
value: EndpointAudio;
|
||||
}
|
||||
| {
|
||||
relationTo: Collections.Videos;
|
||||
value: EndpointVideo;
|
||||
}
|
||||
)[];
|
||||
parentPages: EndpointSource[];
|
||||
};
|
||||
|
||||
export type EndpointWebsiteConfig = {
|
||||
homeFolders: (EndpointFolderPreview & {
|
||||
homeFolders: (EndpointFolder & {
|
||||
lightThumbnail?: PayloadImage;
|
||||
darkThumbnail?: PayloadImage;
|
||||
})[];
|
||||
|
@ -1420,23 +1428,18 @@ export type EndpointTagsGroup = {
|
|||
tags: EndpointTag[];
|
||||
};
|
||||
|
||||
export type EndpointPagePreview = {
|
||||
export type EndpointPage = {
|
||||
slug: string;
|
||||
type: PageType;
|
||||
thumbnail?: PayloadImage;
|
||||
authors: EndpointRecorder[];
|
||||
tagGroups: EndpointTagsGroup[];
|
||||
backgroundImage?: PayloadImage;
|
||||
translations: {
|
||||
language: string;
|
||||
pretitle?: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type EndpointPage = EndpointPagePreview & {
|
||||
backgroundImage?: PayloadImage;
|
||||
translations: (EndpointPagePreview["translations"][number] & {
|
||||
sourceLanguage: string;
|
||||
summary?: RichTextContent;
|
||||
content: RichTextContent;
|
||||
|
@ -1444,11 +1447,11 @@ export type EndpointPage = EndpointPagePreview & {
|
|||
translators: EndpointRecorder[];
|
||||
proofreaders: EndpointRecorder[];
|
||||
toc: TableOfContentEntry[];
|
||||
})[];
|
||||
}[];
|
||||
parentPages: EndpointSource[];
|
||||
};
|
||||
|
||||
export type EndpointCollectiblePreview = {
|
||||
export type EndpointCollectible = {
|
||||
slug: string;
|
||||
thumbnail?: PayloadImage;
|
||||
translations: {
|
||||
|
@ -1461,9 +1464,6 @@ export type EndpointCollectiblePreview = {
|
|||
tagGroups: EndpointTagsGroup[];
|
||||
releaseDate?: string;
|
||||
languages: string[];
|
||||
};
|
||||
|
||||
export type EndpointCollectible = EndpointCollectiblePreview & {
|
||||
backgroundImage?: PayloadImage;
|
||||
nature: CollectibleNature;
|
||||
gallery: PayloadImage[];
|
||||
|
@ -1484,15 +1484,23 @@ export type EndpointCollectible = EndpointCollectiblePreview & {
|
|||
bindingType?: CollectibleBindingTypes;
|
||||
pageOrder?: CollectiblePageOrders;
|
||||
};
|
||||
subitems: EndpointCollectiblePreview[];
|
||||
subitems: EndpointCollectible[];
|
||||
contents: {
|
||||
content:
|
||||
| {
|
||||
relationTo: "pages";
|
||||
value: EndpointPagePreview;
|
||||
relationTo: Collections.Pages;
|
||||
value: EndpointPage;
|
||||
}
|
||||
| {
|
||||
relationTo: "generic-contents";
|
||||
relationTo: Collections.Audios;
|
||||
value: EndpointAudio;
|
||||
}
|
||||
| {
|
||||
relationTo: Collections.Videos;
|
||||
value: EndpointVideo;
|
||||
}
|
||||
| {
|
||||
relationTo: Collections.GenericContents;
|
||||
value: {
|
||||
translations: {
|
||||
language: string;
|
||||
|
@ -1557,21 +1565,72 @@ export type EndpointSource =
|
|||
| { type: "url"; url: string; label: string }
|
||||
| {
|
||||
type: "collectible";
|
||||
collectible: EndpointCollectiblePreview;
|
||||
collectible: EndpointCollectible;
|
||||
range?:
|
||||
| { type: "page"; page: number }
|
||||
| { type: "timestamp"; timestamp: string }
|
||||
| { type: "custom"; translations: { language: string; note: string }[] };
|
||||
}
|
||||
| { type: "page"; page: EndpointPagePreview }
|
||||
| { type: "folder"; folder: EndpointFolderPreview };
|
||||
| { type: "page"; page: EndpointPage }
|
||||
| { type: "folder"; folder: EndpointFolder };
|
||||
|
||||
export type PayloadImage = {
|
||||
export type EndpointMedia = {
|
||||
id: string;
|
||||
url: string;
|
||||
filename: string;
|
||||
mimeType: string;
|
||||
filesize: number;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
tagGroups: EndpointTagsGroup[];
|
||||
translations: {
|
||||
language: string;
|
||||
title: string;
|
||||
description?: RichTextContent;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type EndpointImage = EndpointMedia & {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
export type EndpointAudio = EndpointMedia & {
|
||||
thumbnail?: PayloadImage;
|
||||
duration: number;
|
||||
};
|
||||
|
||||
export type EndpointVideo = EndpointMedia & {
|
||||
thumbnail?: PayloadImage;
|
||||
subtitles: {
|
||||
language: string;
|
||||
url: string;
|
||||
}[];
|
||||
platform?: {
|
||||
channel: {
|
||||
url: string;
|
||||
title: string;
|
||||
subscribers: number;
|
||||
};
|
||||
views?: number;
|
||||
likes?: number;
|
||||
dislikes?: number;
|
||||
url: string;
|
||||
publishedDate: string;
|
||||
};
|
||||
duration: number;
|
||||
};
|
||||
|
||||
export type PayloadMedia = {
|
||||
url: string;
|
||||
mimeType: string;
|
||||
filename: string;
|
||||
filesize: number;
|
||||
};
|
||||
|
||||
export type PayloadImage = PayloadMedia & {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
export const payload = {
|
||||
|
@ -1595,4 +1654,10 @@ export const payload = {
|
|||
await (await request(payloadApiUrl(Collections.ChronologyEvents, `all`))).json(),
|
||||
getChronologyEventByID: async (id: string): Promise<EndpointChronologyEvent> =>
|
||||
await (await request(payloadApiUrl(Collections.ChronologyEvents, `id/${id}`))).json(),
|
||||
getImageByID: async (id: string): Promise<EndpointImage> =>
|
||||
await (await request(payloadApiUrl(Collections.Images, `id/${id}`))).json(),
|
||||
getAudioByID: async (id: string): Promise<EndpointAudio> =>
|
||||
await (await request(payloadApiUrl(Collections.Audios, `id/${id}`))).json(),
|
||||
getVideoByID: async (id: string): Promise<EndpointVideo> =>
|
||||
await (await request(payloadApiUrl(Collections.Videos, `id/${id}`))).json(),
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue