Support for responsive images
This commit is contained in:
parent
bb86a5238b
commit
d25e6ba711
8
TODO.md
8
TODO.md
|
@ -1,16 +1,18 @@
|
||||||
# Accord's Library v3.0
|
# Accord's Library v3.0
|
||||||
|
|
||||||
|
## Ongoing
|
||||||
|
|
||||||
|
- [Analytics] Add analytics
|
||||||
|
|
||||||
## Short term
|
## Short term
|
||||||
|
|
||||||
- Number of audio players seems limited (on Chrome and Firefox)
|
- Number of audio players seems limited (on Chrome and Firefox)
|
||||||
- Automatically generate different sizes of images
|
|
||||||
- [RichTextContent] Handle relationship
|
- [RichTextContent] Handle relationship
|
||||||
- [RichTextContent] Add autolink block support
|
- [RichTextContent] Add autolink block support
|
||||||
|
|
||||||
## Mid term
|
## Mid term
|
||||||
|
|
||||||
- Save cookies for longer than just the session
|
- Save cookies for longer than just the session
|
||||||
- [Folders] Support for nameless section
|
|
||||||
- [Timeline] Error if collectible not published?
|
- [Timeline] Error if collectible not published?
|
||||||
- [Timeline] display source language
|
- [Timeline] display source language
|
||||||
- [Timeline] Add details button in footer with credits + last updated / created
|
- [Timeline] Add details button in footer with credits + last updated / created
|
||||||
|
@ -18,10 +20,10 @@
|
||||||
- [Videos] Display platform info + channel page
|
- [Videos] Display platform info + channel page
|
||||||
- [JSLess] Provide JS-less alternative for timeline card footers
|
- [JSLess] Provide JS-less alternative for timeline card footers
|
||||||
- [JSLess] Provide JS-less alternative for parent pages
|
- [JSLess] Provide JS-less alternative for parent pages
|
||||||
- [Analytics] Add analytics
|
|
||||||
|
|
||||||
## Long term
|
## Long term
|
||||||
|
|
||||||
|
- [Folders] Support for nameless section
|
||||||
- [Scripts] Can't run the scripts using node (ts-node?)
|
- [Scripts] Can't run the scripts using node (ts-node?)
|
||||||
- [Scans] Adapt size of obi based on cover/dustjacket
|
- [Scans] Adapt size of obi based on cover/dustjacket
|
||||||
- [Scans] Order of cover/dustjacket/obi should be based on the book's page order.
|
- [Scans] Order of cover/dustjacket/obi should be based on the book's page order.
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"@fontsource-variable/murecho": "^5.0.19",
|
"@fontsource-variable/murecho": "^5.0.19",
|
||||||
"@fontsource-variable/vollkorn": "^5.0.21",
|
"@fontsource-variable/vollkorn": "^5.0.21",
|
||||||
"accept-language": "^3.0.18",
|
"accept-language": "^3.0.18",
|
||||||
"astro": "4.8.7",
|
"astro": "4.9.0",
|
||||||
"astro-icon": "^1.1.0",
|
"astro-icon": "^1.1.0",
|
||||||
"node-cache": "^5.1.2",
|
"node-cache": "^5.1.2",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
|
@ -3166,9 +3166,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/astro": {
|
"node_modules/astro": {
|
||||||
"version": "4.8.7",
|
"version": "4.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/astro/-/astro-4.8.7.tgz",
|
"resolved": "https://registry.npmjs.org/astro/-/astro-4.9.0.tgz",
|
||||||
"integrity": "sha512-bTtv6zv94+U5cQdwy89LWTnocEfJ2Tfy6vpYYSUthfj12HtOpk0ykGW7YBe9a69NHqPwivSOvRjXOxGKigL9qA==",
|
"integrity": "sha512-beb3go5Oh5QDjns7YVxG1r40Flt/cuXB+YFTnVRqbh2NuMpYRoXZqIT+ZNaorleEfrLjLFXfsn1AAKVP+XZ2KA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/compiler": "^2.8.0",
|
"@astrojs/compiler": "^2.8.0",
|
||||||
"@astrojs/internal-helpers": "0.4.0",
|
"@astrojs/internal-helpers": "0.4.0",
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"script:download-currencies": "npm run scripts/download-currencies.ts",
|
"script:download-currencies": "npm run scripts/download-currencies.ts",
|
||||||
"script:download-wording-keys": "npm run scripts/download-wording-keys.ts",
|
"script:download-wording-keys": "npm run scripts/download-wording-keys.ts",
|
||||||
"prettier": "prettier --write --list-different --plugin=prettier-plugin-astro .",
|
"prettier": "prettier --write --list-different --plugin=prettier-plugin-astro .",
|
||||||
"precommit": "npm run script:download-wording-keys && npm run script:download-payload-sdk && npm run prettier && npm run astro check"
|
"precommit": "npm run script:download-payload-sdk && npm run script:download-wording-keys && npm run prettier && npm run astro check"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"npm": ">=10.0.0",
|
"npm": ">=10.0.0",
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
"@fontsource-variable/murecho": "^5.0.19",
|
"@fontsource-variable/murecho": "^5.0.19",
|
||||||
"@fontsource-variable/vollkorn": "^5.0.21",
|
"@fontsource-variable/vollkorn": "^5.0.21",
|
||||||
"accept-language": "^3.0.18",
|
"accept-language": "^3.0.18",
|
||||||
"astro": "4.8.7",
|
"astro": "4.9.0",
|
||||||
"astro-icon": "^1.1.0",
|
"astro-icon": "^1.1.0",
|
||||||
"node-cache": "^5.1.2",
|
"node-cache": "^5.1.2",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 668 KiB |
Binary file not shown.
Before Width: | Height: | Size: 86 KiB |
Binary file not shown.
Before Width: | Height: | Size: 455 KiB |
|
@ -1,14 +1,20 @@
|
||||||
---
|
---
|
||||||
import type { PayloadImage } from "src/shared/payload/payload-sdk";
|
import type {
|
||||||
|
EndpointImage,
|
||||||
|
EndpointMediaThumbnail,
|
||||||
|
EndpointScanImage,
|
||||||
|
} from "src/shared/payload/payload-sdk";
|
||||||
import { getRandomId } from "src/utils/random";
|
import { getRandomId } from "src/utils/random";
|
||||||
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
img: Pick<PayloadImage, "url" | "width" | "height">;
|
img: EndpointImage | EndpointMediaThumbnail | EndpointScanImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
img: { url, width, height },
|
img: { url, width, height, sizes },
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
const uniqueId = getRandomId();
|
const uniqueId = getRandomId();
|
||||||
|
|
||||||
const style = `
|
const style = `
|
||||||
|
@ -22,8 +28,24 @@ const style = `
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
<img id={uniqueId} src={url} class="when-no-print when-js" />
|
<img
|
||||||
<img id={uniqueId} src={url} class="when-no-print when-no-js" />
|
id={uniqueId}
|
||||||
|
src={url}
|
||||||
|
srcset={sizesToSrcset(sizes)}
|
||||||
|
sizes="100vw"
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
class="when-no-print when-js"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
id={uniqueId}
|
||||||
|
src={url}
|
||||||
|
srcset={sizesToSrcset(sizes)}
|
||||||
|
sizes="100vw"
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
class="when-no-print when-no-js"
|
||||||
|
/>
|
||||||
|
|
||||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,20 @@ import "@fontsource-variable/vollkorn";
|
||||||
import "@fontsource-variable/murecho";
|
import "@fontsource-variable/murecho";
|
||||||
import { getI18n } from "src/i18n/i18n";
|
import { getI18n } from "src/i18n/i18n";
|
||||||
import AppLayoutSpinner from "./AppLayoutSpinner.astro";
|
import AppLayoutSpinner from "./AppLayoutSpinner.astro";
|
||||||
import type { EndpointAudio, EndpointVideo, PayloadImage } from "src/shared/payload/payload-sdk";
|
import type {
|
||||||
|
EndpointAudio,
|
||||||
|
EndpointImage,
|
||||||
|
EndpointMediaThumbnail,
|
||||||
|
EndpointVideo,
|
||||||
|
} from "src/shared/payload/payload-sdk";
|
||||||
|
import { cache } from "src/utils/payload";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
openGraph?:
|
openGraph?:
|
||||||
| {
|
| {
|
||||||
title?: string | undefined;
|
title?: string | undefined;
|
||||||
description?: string | undefined;
|
description?: string | undefined;
|
||||||
thumbnail?: PayloadImage | undefined;
|
thumbnail?: EndpointImage | EndpointMediaThumbnail | undefined;
|
||||||
audio?: EndpointAudio | undefined;
|
audio?: EndpointAudio | undefined;
|
||||||
video?: EndpointVideo | undefined;
|
video?: EndpointVideo | undefined;
|
||||||
}
|
}
|
||||||
|
@ -23,19 +29,10 @@ const { currentLocale } = Astro.locals;
|
||||||
const { t } = await getI18n(currentLocale);
|
const { t } = await getI18n(currentLocale);
|
||||||
|
|
||||||
const { openGraph = {} } = Astro.props;
|
const { openGraph = {} } = Astro.props;
|
||||||
const {
|
const { description = t("global.meta.description"), audio, video } = openGraph;
|
||||||
description = t("global.meta.description"),
|
|
||||||
thumbnail = {
|
const thumbnail =
|
||||||
filename: "default_og.jpg",
|
openGraph.thumbnail?.openGraph ?? openGraph.thumbnail ?? cache.config.defaultOpenGraphImage;
|
||||||
filesize: 0,
|
|
||||||
height: 630,
|
|
||||||
width: 1200,
|
|
||||||
mimeType: "image/jpeg",
|
|
||||||
url: "/img/default_og.jpg",
|
|
||||||
},
|
|
||||||
audio,
|
|
||||||
video,
|
|
||||||
} = openGraph;
|
|
||||||
|
|
||||||
const title = openGraph.title
|
const title = openGraph.title
|
||||||
? `${openGraph.title} – ${t("global.siteName")}`
|
? `${openGraph.title} – ${t("global.siteName")}`
|
||||||
|
@ -76,8 +73,6 @@ const { currentTheme } = Astro.locals;
|
||||||
<meta name="twitter:site" content="@AccordsLibrary" />
|
<meta name="twitter:site" content="@AccordsLibrary" />
|
||||||
<meta name="twitter:title" content={title} />
|
<meta name="twitter:title" content={title} />
|
||||||
<meta name="twitter:description" content={description} />
|
<meta name="twitter:description" content={description} />
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
|
||||||
<meta name="twitter:image" content={thumbnail.url} />
|
|
||||||
|
|
||||||
<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:locale" content={currentLocale} />
|
||||||
|
@ -86,11 +81,20 @@ const { currentTheme } = Astro.locals;
|
||||||
<meta property="og:title" content={title} />
|
<meta property="og:title" content={title} />
|
||||||
<meta property="og:description" content={description} />
|
<meta property="og:description" content={description} />
|
||||||
|
|
||||||
<meta property="og:image" content={thumbnail.url} />
|
{
|
||||||
<meta property="og:image:secure_url" content={thumbnail.url} />
|
thumbnail && (
|
||||||
<meta property="og:image:width" content={thumbnail.width.toString()} />
|
<>
|
||||||
<meta property="og:image:height" content={thumbnail.height.toString()} />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta property="og:image:type" content={thumbnail.mimeType} />
|
<meta name="twitter:image" content={thumbnail.url} />
|
||||||
|
|
||||||
|
<meta property="og:image" content={thumbnail.url} />
|
||||||
|
<meta property="og:image:secure_url" content={thumbnail.url} />
|
||||||
|
<meta property="og:image:width" content={thumbnail.width.toString()} />
|
||||||
|
<meta property="og:image:height" content={thumbnail.height.toString()} />
|
||||||
|
<meta property="og:image:type" content={thumbnail.mimeType} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
audio && (
|
audio && (
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
import Button from "components/Button.astro";
|
import Button from "components/Button.astro";
|
||||||
import {
|
import {
|
||||||
type EndpointCredit,
|
type EndpointCredit,
|
||||||
type PayloadImage,
|
type EndpointImage,
|
||||||
|
type EndpointMediaThumbnail,
|
||||||
|
type EndpointScanImage,
|
||||||
type RichTextContent,
|
type RichTextContent,
|
||||||
} from "src/shared/payload/payload-sdk";
|
} from "src/shared/payload/payload-sdk";
|
||||||
import Credits from "./Credits.astro";
|
import Credits from "./Credits.astro";
|
||||||
|
@ -11,11 +13,12 @@ import AppLayoutTitle from "./AppLayout/components/AppLayoutTitle.astro";
|
||||||
import type { ComponentProps } from "astro/types";
|
import type { ComponentProps } from "astro/types";
|
||||||
import AppLayoutDescription from "./AppLayout/components/AppLayoutDescription.astro";
|
import AppLayoutDescription from "./AppLayout/components/AppLayoutDescription.astro";
|
||||||
import Attributes from "./Attributes.astro";
|
import Attributes from "./Attributes.astro";
|
||||||
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
previousImageHref?: string | undefined;
|
previousImageHref?: string | undefined;
|
||||||
nextImageHref?: string | undefined;
|
nextImageHref?: string | undefined;
|
||||||
image: PayloadImage;
|
image: EndpointImage | EndpointScanImage | EndpointMediaThumbnail;
|
||||||
pretitle?: string | undefined;
|
pretitle?: string | undefined;
|
||||||
title: string;
|
title: string;
|
||||||
subtitle?: string | undefined;
|
subtitle?: string | undefined;
|
||||||
|
@ -29,7 +32,7 @@ interface Props {
|
||||||
const {
|
const {
|
||||||
nextImageHref,
|
nextImageHref,
|
||||||
previousImageHref,
|
previousImageHref,
|
||||||
image: { url, width, height },
|
image: { url, width, height, sizes },
|
||||||
attributes = [],
|
attributes = [],
|
||||||
metaAttributes = [],
|
metaAttributes = [],
|
||||||
credits = [],
|
credits = [],
|
||||||
|
@ -41,24 +44,45 @@ const {
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
const smallTitle = !subtitle && !pretitle;
|
const smallTitle = !subtitle && !pretitle;
|
||||||
|
|
||||||
|
const hasNavigation = previousImageHref || nextImageHref;
|
||||||
---
|
---
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<div id="image-viewer" class:list={{ "with-buttons": previousImageHref || nextImageHref }}>
|
<div id="image-viewer" class:list={{ "with-buttons": hasNavigation }}>
|
||||||
<a
|
{
|
||||||
class:list={{ hidden: !previousImageHref }}
|
hasNavigation && (
|
||||||
href={previousImageHref}
|
<a
|
||||||
data-astro-history="replace">
|
class:list={{ hidden: !previousImageHref }}
|
||||||
<Button icon="material-symbols:chevron-left" />
|
href={previousImageHref}
|
||||||
|
data-astro-history="replace">
|
||||||
|
<Button icon="material-symbols:chevron-left" />
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
<a href={url} target="_blank">
|
||||||
|
<img
|
||||||
|
src={url}
|
||||||
|
srcset={sizesToSrcset(sizes)}
|
||||||
|
sizes={`(max-aspect-ratio: ${width / 0.9}/${height / 0.7}) 90vw, ${(width / height) * 70}vh`}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href={url} target="_blank"><img src={url} width={width} height={height} /></a>
|
{
|
||||||
|
hasNavigation && (
|
||||||
<a class:list={{ hidden: !nextImageHref }} href={nextImageHref} data-astro-history="replace">
|
<a
|
||||||
<Button icon="material-symbols:chevron-right" />
|
class:list={{ hidden: !nextImageHref }}
|
||||||
</a>
|
href={nextImageHref}
|
||||||
|
data-astro-history="replace">
|
||||||
|
<Button icon="material-symbols:chevron-right" />
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -128,11 +152,11 @@ const smallTitle = !subtitle && !pretitle;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 2em;
|
gap: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > h1 {
|
|
||||||
max-width: 35em;
|
|
||||||
overflow-wrap: anywhere;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
max-width: 35em;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
---
|
---
|
||||||
import type { PayloadImage } from "src/shared/payload/payload-sdk";
|
import type {
|
||||||
|
EndpointImage,
|
||||||
|
EndpointMediaThumbnail,
|
||||||
|
EndpointScanImage,
|
||||||
|
} from "src/shared/payload/payload-sdk";
|
||||||
import Card from "components/Card.astro";
|
import Card from "components/Card.astro";
|
||||||
import { Icon } from "astro-icon/components";
|
import { Icon } from "astro-icon/components";
|
||||||
import type { ComponentProps } from "astro/types";
|
import type { ComponentProps } from "astro/types";
|
||||||
import { getI18n } from "src/i18n/i18n";
|
import { getI18n } from "src/i18n/i18n";
|
||||||
import InlineAttributes from "components/InlineAttributes.astro";
|
import InlineAttributes from "components/InlineAttributes.astro";
|
||||||
|
import { sizesToSrcset, sizesForGridLayout } from "src/utils/img";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
thumbnail?: PayloadImage | undefined;
|
thumbnail?: EndpointImage | EndpointMediaThumbnail | EndpointScanImage | undefined;
|
||||||
pretitle?: string | undefined;
|
pretitle?: string | undefined;
|
||||||
title: string;
|
title: string;
|
||||||
subtitle?: string | undefined;
|
subtitle?: string | undefined;
|
||||||
|
@ -41,7 +46,13 @@ const {
|
||||||
<div id="card">
|
<div id="card">
|
||||||
{
|
{
|
||||||
thumbnail && (
|
thumbnail && (
|
||||||
<img src={thumbnail.url} width={thumbnail.width} height={thumbnail.height} alt="" />
|
<img
|
||||||
|
src={thumbnail.url}
|
||||||
|
srcset={sizesToSrcset(thumbnail.sizes)}
|
||||||
|
sizes={sizesForGridLayout(250, 1.15)}
|
||||||
|
width={thumbnail.width}
|
||||||
|
height={thumbnail.height}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import OpenMediaPageButton from "./OpenMediaPageButton.astro";
|
||||||
import { getI18n } from "src/i18n/i18n";
|
import { getI18n } from "src/i18n/i18n";
|
||||||
import HeaderTitle from "components/HeaderTitle.astro";
|
import HeaderTitle from "components/HeaderTitle.astro";
|
||||||
import { Icon } from "astro-icon/components";
|
import { Icon } from "astro-icon/components";
|
||||||
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
node: RichTextUploadImageNode;
|
node: RichTextUploadImageNode;
|
||||||
|
@ -13,7 +14,7 @@ interface Props {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
node: {
|
node: {
|
||||||
value: { id, url, width, height, translations },
|
value: { id, url, width, height, translations, sizes },
|
||||||
},
|
},
|
||||||
context,
|
context,
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
@ -36,7 +37,15 @@ const mediaPage = getLocalizedUrl(`/images/${id}`);
|
||||||
</HeaderTitle>
|
</HeaderTitle>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<a href={mediaPage}><img src={url} width={width} height={height} /></a>
|
<a href={mediaPage}>
|
||||||
|
<img
|
||||||
|
src={url}
|
||||||
|
srcset={sizesToSrcset(sizes)}
|
||||||
|
sizes={`(max-width: 550px) 90vw, 550px`}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
<OpenMediaPageButton url={mediaPage} />
|
<OpenMediaPageButton url={mediaPage} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
---
|
---
|
||||||
|
import type { EndpointImage } from "src/shared/payload/payload-sdk";
|
||||||
|
import { sizesForGridLayout, sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
img?: { light: string; dark: string } | undefined;
|
img?: { light: EndpointImage; dark: EndpointImage } | undefined;
|
||||||
name: string;
|
name: string;
|
||||||
href: string;
|
href: string;
|
||||||
}
|
}
|
||||||
|
@ -14,8 +17,26 @@ const { img, name, href } = Astro.props;
|
||||||
{
|
{
|
||||||
img ? (
|
img ? (
|
||||||
<>
|
<>
|
||||||
<img src={img.light} class="when-light-theme" alt={name} title={name} />
|
<img
|
||||||
<img src={img.dark} class="when-dark-theme" alt={name} title={name} />
|
src={img.light.url}
|
||||||
|
srcset={sizesToSrcset(img.light.sizes)}
|
||||||
|
sizes={sizesForGridLayout(250, 1.15)}
|
||||||
|
width={img.light.width}
|
||||||
|
height={img.light.height}
|
||||||
|
class="when-light-theme"
|
||||||
|
alt={name}
|
||||||
|
title={name}
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src={img.dark.url}
|
||||||
|
srcset={sizesToSrcset(img.dark.sizes)}
|
||||||
|
sizes={sizesForGridLayout(250, 1.15)}
|
||||||
|
width={img.dark.width}
|
||||||
|
height={img.dark.height}
|
||||||
|
class="when-dark-theme"
|
||||||
|
alt={name}
|
||||||
|
title={name}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -9,12 +9,10 @@ const { getLocalizedUrl, getLocalizedMatch } = await getI18n(Astro.locals.curren
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
{
|
{
|
||||||
cache.config.homeFolders.map(({ slug, translations, darkThumbnail, lightThumbnail }) => (
|
cache.config.home.folders.map(({ slug, translations, darkThumbnail, lightThumbnail }) => (
|
||||||
<CategoryCard
|
<CategoryCard
|
||||||
img={
|
img={
|
||||||
darkThumbnail && lightThumbnail
|
darkThumbnail && lightThumbnail ? { dark: darkThumbnail, light: lightThumbnail } : undefined
|
||||||
? { dark: darkThumbnail.url, light: lightThumbnail.url }
|
|
||||||
: undefined
|
|
||||||
}
|
}
|
||||||
name={getLocalizedMatch(translations).name}
|
name={getLocalizedMatch(translations).name}
|
||||||
href={getLocalizedUrl(`/folders/${slug}`)}
|
href={getLocalizedUrl(`/folders/${slug}`)}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import AppLayoutDescription from "components/AppLayout/components/AppLayoutDescr
|
||||||
import Attributes from "components/Attributes.astro";
|
import Attributes from "components/Attributes.astro";
|
||||||
import type { Attribute } from "src/utils/attributes";
|
import type { Attribute } from "src/utils/attributes";
|
||||||
import { payload } from "src/utils/payload";
|
import { payload } from "src/utils/payload";
|
||||||
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
export const partial = true;
|
export const partial = true;
|
||||||
|
|
||||||
|
@ -71,6 +72,8 @@ if (updatedBy) {
|
||||||
<img
|
<img
|
||||||
id="thumbnail"
|
id="thumbnail"
|
||||||
src={thumbnail.url}
|
src={thumbnail.url}
|
||||||
|
srcset={sizesToSrcset(thumbnail.sizes)}
|
||||||
|
sizes={`(max-width: 550px) 90vw, 550px`}
|
||||||
width={thumbnail.width}
|
width={thumbnail.width}
|
||||||
height={thumbnail.height}
|
height={thumbnail.height}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -11,8 +11,8 @@ import { payload } from "src/utils/payload";
|
||||||
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
|
||||||
const { id } = Astro.params;
|
const id = Astro.params.id!;
|
||||||
const audio = await fetchOr404(() => payload.getAudioByID(id!));
|
const audio = await fetchOr404(() => payload.getAudioByID(id));
|
||||||
if (audio instanceof Response) {
|
if (audio instanceof Response) {
|
||||||
return audio;
|
return audio;
|
||||||
}
|
}
|
||||||
|
@ -72,10 +72,10 @@ const metaAttributes = [
|
||||||
|
|
||||||
<AppLayout
|
<AppLayout
|
||||||
openGraph={{
|
openGraph={{
|
||||||
|
title: formatInlineTitle({ pretitle, title, subtitle }),
|
||||||
|
description: description && formatRichTextToString(description),
|
||||||
thumbnail,
|
thumbnail,
|
||||||
audio,
|
audio,
|
||||||
description: description ? formatRichTextToString(description) : undefined,
|
|
||||||
title: formatInlineTitle({ pretitle, title, subtitle }),
|
|
||||||
}}>
|
}}>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<AudioPlayer audio={audio} />
|
<AudioPlayer audio={audio} />
|
||||||
|
|
|
@ -1,18 +1,39 @@
|
||||||
---
|
---
|
||||||
|
import type {
|
||||||
|
EndpointImage,
|
||||||
|
EndpointMediaThumbnail,
|
||||||
|
EndpointScanImage,
|
||||||
|
} from "src/shared/payload/payload-sdk";
|
||||||
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
image: string;
|
image: EndpointImage | EndpointScanImage | EndpointMediaThumbnail;
|
||||||
title: string;
|
title: string;
|
||||||
subtitle: string;
|
subtitle: string;
|
||||||
href: string;
|
href: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { image, title, subtitle, href } = Astro.props;
|
const {
|
||||||
|
image: { url, width, height, sizes },
|
||||||
|
title,
|
||||||
|
subtitle,
|
||||||
|
href,
|
||||||
|
} = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
<a href={href}>
|
<a href={href}>
|
||||||
<img src={image} />
|
<img
|
||||||
|
src={url}
|
||||||
|
srcset={sizesToSrcset(sizes)}
|
||||||
|
sizes=`
|
||||||
|
(max-width: 400px) 90vw,
|
||||||
|
(max-width: 850px) 50vw,
|
||||||
|
200px`
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="high-contrast-text">
|
<div class="high-contrast-text">
|
||||||
<p class="title">{title}</p>
|
<p class="title">{title}</p>
|
||||||
|
|
|
@ -55,9 +55,9 @@ const metaAttributes = [
|
||||||
|
|
||||||
<AppLayout
|
<AppLayout
|
||||||
openGraph={{
|
openGraph={{
|
||||||
thumbnail: image,
|
|
||||||
description: description ? formatRichTextToString(description) : undefined,
|
|
||||||
title: formatInlineTitle({ pretitle, title, subtitle }),
|
title: formatInlineTitle({ pretitle, title, subtitle }),
|
||||||
|
description: description && formatRichTextToString(description),
|
||||||
|
thumbnail: image,
|
||||||
}}
|
}}
|
||||||
parentPages={parentPages}>
|
parentPages={parentPages}>
|
||||||
<Lightbox
|
<Lightbox
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { getI18n } from "src/i18n/i18n";
|
||||||
import { payload } from "src/utils/payload";
|
import { payload } from "src/utils/payload";
|
||||||
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
const slug = Astro.params.slug!;
|
const slug = Astro.params.slug!;
|
||||||
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale);
|
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
@ -38,9 +39,17 @@ const translation = getLocalizedMatch(translations);
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
images.map((image, index) => (
|
images.map(({ url, width, height, sizes }, index) => (
|
||||||
<a href={getLocalizedUrl(`/collectibles/${slug}/gallery/${index}`)}>
|
<a href={getLocalizedUrl(`/collectibles/${slug}/gallery/${index}`)}>
|
||||||
<img src={image.url} />
|
<img
|
||||||
|
src={url}
|
||||||
|
srcset={sizesToSrcset(sizes)}
|
||||||
|
sizes={`
|
||||||
|
(max-width: ${(width / height) * 320}px) 90vw,
|
||||||
|
${(width / height) * 320}px`}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -70,7 +79,7 @@ const translation = getLocalizedMatch(translations);
|
||||||
}
|
}
|
||||||
|
|
||||||
& > img {
|
& > img {
|
||||||
max-height: 20em;
|
max-height: 320px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|
|
@ -18,13 +18,14 @@ import { convert } from "src/utils/currencies";
|
||||||
import Attributes from "components/Attributes.astro";
|
import Attributes from "components/Attributes.astro";
|
||||||
import type { Attribute } from "src/utils/attributes";
|
import type { Attribute } from "src/utils/attributes";
|
||||||
import { payload } from "src/utils/payload";
|
import { payload } from "src/utils/payload";
|
||||||
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
const { slug } = Astro.params;
|
const slug = Astro.params.slug!;
|
||||||
const { getLocalizedMatch, getLocalizedUrl, t, formatDate, formatPrice } = await getI18n(
|
const { getLocalizedMatch, getLocalizedUrl, t, formatDate, formatPrice } = await getI18n(
|
||||||
Astro.locals.currentLocale
|
Astro.locals.currentLocale
|
||||||
);
|
);
|
||||||
|
|
||||||
const collectible = await fetchOr404(() => payload.getCollectible(slug!));
|
const collectible = await fetchOr404(() => payload.getCollectible(slug));
|
||||||
if (collectible instanceof Response) {
|
if (collectible instanceof Response) {
|
||||||
return collectible;
|
return collectible;
|
||||||
}
|
}
|
||||||
|
@ -158,6 +159,8 @@ if (price) {
|
||||||
<img
|
<img
|
||||||
id="thumbnail"
|
id="thumbnail"
|
||||||
src={thumbnail.url}
|
src={thumbnail.url}
|
||||||
|
srcset={sizesToSrcset(thumbnail.sizes)}
|
||||||
|
sizes={`(max-width: 550px) 90vw, 550px`}
|
||||||
width={thumbnail.width}
|
width={thumbnail.width}
|
||||||
height={thumbnail.height}
|
height={thumbnail.height}
|
||||||
/>
|
/>
|
||||||
|
@ -169,7 +172,7 @@ if (price) {
|
||||||
{
|
{
|
||||||
gallery && (
|
gallery && (
|
||||||
<ImageTile
|
<ImageTile
|
||||||
image={gallery.thumbnail.url}
|
image={gallery.thumbnail}
|
||||||
title={t("collectibles.gallery.title")}
|
title={t("collectibles.gallery.title")}
|
||||||
subtitle={t("collectibles.gallery.subtitle", { count: gallery.count })}
|
subtitle={t("collectibles.gallery.subtitle", { count: gallery.count })}
|
||||||
href={getLocalizedUrl(`/collectibles/${slug}/gallery`)}
|
href={getLocalizedUrl(`/collectibles/${slug}/gallery`)}
|
||||||
|
@ -180,7 +183,7 @@ if (price) {
|
||||||
{
|
{
|
||||||
scans && (
|
scans && (
|
||||||
<ImageTile
|
<ImageTile
|
||||||
image={scans.thumbnail.url}
|
image={scans.thumbnail}
|
||||||
title={t("collectibles.scans.title")}
|
title={t("collectibles.scans.title")}
|
||||||
subtitle={t("collectibles.scans.subtitle", { count: scans.count })}
|
subtitle={t("collectibles.scans.subtitle", { count: scans.count })}
|
||||||
href={getLocalizedUrl(`/collectibles/${slug}/scans`)}
|
href={getLocalizedUrl(`/collectibles/${slug}/scans`)}
|
||||||
|
|
|
@ -17,7 +17,7 @@ if (scanPage instanceof Response) {
|
||||||
return scanPage;
|
return scanPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { parentPages, previousIndex, nextIndex, image, translations } = scanPage;
|
const { parentPages, previousIndex, nextIndex, image, translations, thumbnail } = scanPage;
|
||||||
const translation = getLocalizedMatch(translations);
|
const translation = getLocalizedMatch(translations);
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ const translation = getLocalizedMatch(translations);
|
||||||
openGraph={{
|
openGraph={{
|
||||||
title: `${formatInlineTitle(translation)} (${index})`,
|
title: `${formatInlineTitle(translation)} (${index})`,
|
||||||
description: translation.description && formatRichTextToString(translation.description),
|
description: translation.description && formatRichTextToString(translation.description),
|
||||||
thumbnail: image,
|
thumbnail,
|
||||||
}}
|
}}
|
||||||
parentPages={parentPages}>
|
parentPages={parentPages}>
|
||||||
<Lightbox
|
<Lightbox
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
---
|
---
|
||||||
import { getI18n } from "src/i18n/i18n";
|
import { getI18n } from "src/i18n/i18n";
|
||||||
import type { EndpointScanImage } from "src/shared/payload/payload-sdk";
|
import type { EndpointScanImage } from "src/shared/payload/payload-sdk";
|
||||||
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
scan: EndpointScanImage;
|
scan: EndpointScanImage;
|
||||||
|
@ -8,7 +9,7 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
scan: { url, index, width, height },
|
scan: { url, index, width, height, sizes },
|
||||||
collectibleSlug,
|
collectibleSlug,
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
|
@ -18,7 +19,15 @@ const { getLocalizedUrl, formatScanIndexShort } = await getI18n(Astro.locals.cur
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
<a href={getLocalizedUrl(`/collectibles/${collectibleSlug}/scans/${index}`)}>
|
<a href={getLocalizedUrl(`/collectibles/${collectibleSlug}/scans/${index}`)}>
|
||||||
<img width={width} height={height} src={url} alt={index} />
|
<img
|
||||||
|
src={url}
|
||||||
|
srcset={sizesToSrcset(sizes)}
|
||||||
|
sizes={`
|
||||||
|
(max-width: ${(width / height) * 320}px) 90vw,
|
||||||
|
${(width / height) * 320}px`}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
/>
|
||||||
<p>{formatScanIndexShort(index)}</p>
|
<p>{formatScanIndexShort(index)}</p>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
@ -39,10 +48,11 @@ const { getLocalizedUrl, formatScanIndexShort } = await getI18n(Astro.locals.cur
|
||||||
}
|
}
|
||||||
|
|
||||||
& > img {
|
& > img {
|
||||||
max-height: 20em;
|
max-height: 320px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
aspect-ratio: auto 21/29.7;
|
||||||
box-shadow: 0 5px 20px -10px var(--color-shadow);
|
box-shadow: 0 5px 20px -10px var(--color-shadow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,9 @@ import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro
|
||||||
import AppLayoutDescription from "components/AppLayout/components/AppLayoutDescription.astro";
|
import AppLayoutDescription from "components/AppLayout/components/AppLayoutDescription.astro";
|
||||||
import { payload } from "src/utils/payload";
|
import { payload } from "src/utils/payload";
|
||||||
|
|
||||||
const { slug } = Astro.params;
|
const slug = Astro.params.slug!;
|
||||||
|
|
||||||
const folder = await fetchOr404(() => payload.getFolder(slug!));
|
const folder = await fetchOr404(() => payload.getFolder(slug));
|
||||||
if (folder instanceof Response) {
|
if (folder instanceof Response) {
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { payload } from "src/utils/payload";
|
||||||
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
|
||||||
const { id } = Astro.params;
|
const id = Astro.params.id!;
|
||||||
const image = await fetchOr404(() => payload.getImageByID(id!));
|
const image = await fetchOr404(() => payload.getImageByID(id));
|
||||||
if (image instanceof Response) {
|
if (image instanceof Response) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,9 @@ const metaAttributes = [
|
||||||
|
|
||||||
<AppLayout
|
<AppLayout
|
||||||
openGraph={{
|
openGraph={{
|
||||||
thumbnail: image,
|
|
||||||
description: description ? formatRichTextToString(description) : undefined,
|
|
||||||
title: formatInlineTitle({ pretitle, title, subtitle }),
|
title: formatInlineTitle({ pretitle, title, subtitle }),
|
||||||
|
description: description && formatRichTextToString(description),
|
||||||
|
thumbnail: image,
|
||||||
}}>
|
}}>
|
||||||
<Lightbox
|
<Lightbox
|
||||||
image={image}
|
image={image}
|
||||||
|
|
|
@ -16,11 +16,7 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
|
||||||
<AppLayout
|
<AppLayout
|
||||||
openGraph={{ title: t("home.title") }}
|
openGraph={{ title: t("home.title") }}
|
||||||
backgroundImage={{
|
backgroundImage={cache.config.home.backgroundImage}
|
||||||
url: "/img/background-image.webp",
|
|
||||||
height: 2279,
|
|
||||||
width: 1920,
|
|
||||||
}}
|
|
||||||
hideFooterLinks
|
hideFooterLinks
|
||||||
hideHomeButton>
|
hideHomeButton>
|
||||||
<div id="title">
|
<div id="title">
|
||||||
|
|
|
@ -6,15 +6,17 @@ import { payload } from "src/utils/payload";
|
||||||
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
|
||||||
const { slug } = Astro.params;
|
const slug = Astro.params.slug!;
|
||||||
|
|
||||||
const page = await fetchOr404(() => payload.getPage(slug!));
|
const page = await fetchOr404(() => payload.getPage(slug));
|
||||||
if (page instanceof Response) {
|
if (page instanceof Response) {
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { parentPages, thumbnail, translations, backgroundImage } = page;
|
||||||
|
|
||||||
const { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
const { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||||
const meta = getLocalizedMatch(page.translations);
|
const meta = getLocalizedMatch(translations);
|
||||||
---
|
---
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
@ -23,9 +25,9 @@ const meta = getLocalizedMatch(page.translations);
|
||||||
openGraph={{
|
openGraph={{
|
||||||
title: formatInlineTitle(meta),
|
title: formatInlineTitle(meta),
|
||||||
description: meta.summary && formatRichTextToString(meta.summary),
|
description: meta.summary && formatRichTextToString(meta.summary),
|
||||||
thumbnail: page.thumbnail,
|
thumbnail: thumbnail,
|
||||||
}}
|
}}
|
||||||
parentPages={page.parentPages}
|
parentPages={parentPages}
|
||||||
backgroundImage={page.backgroundImage ?? page.thumbnail}>
|
backgroundImage={backgroundImage ?? thumbnail}>
|
||||||
<Page slug={page.slug} lang={Astro.locals.currentLocale} page={page} />
|
<Page slug={slug} lang={Astro.locals.currentLocale} page={page} />
|
||||||
</AppLayout>
|
</AppLayout>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { payload } from "src/utils/payload";
|
||||||
import type { Attribute } from "src/utils/attributes";
|
import type { Attribute } from "src/utils/attributes";
|
||||||
import { formatLocale } from "src/utils/format";
|
import { formatLocale } from "src/utils/format";
|
||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
const id = Astro.params.id!;
|
const id = Astro.params.id!;
|
||||||
const recorder = await fetchOr404(() => payload.getRecorderByID(id));
|
const recorder = await fetchOr404(() => payload.getRecorderByID(id));
|
||||||
|
@ -46,7 +47,13 @@ if (languages.length > 0) {
|
||||||
{
|
{
|
||||||
avatar && (
|
avatar && (
|
||||||
<Fragment slot="header-aside">
|
<Fragment slot="header-aside">
|
||||||
<img src={avatar.url} width={avatar.width} height={avatar.height} />
|
<img
|
||||||
|
src={avatar.url}
|
||||||
|
srcset={sizesToSrcset(avatar.sizes)}
|
||||||
|
sizes={`(max-width: 550px) 90vw, 550px`}
|
||||||
|
width={avatar.width}
|
||||||
|
height={avatar.height}
|
||||||
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import AppLayout from "components/AppLayout/AppLayout.astro";
|
||||||
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
|
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
|
||||||
import Card from "components/Card.astro";
|
import Card from "components/Card.astro";
|
||||||
import { getI18n } from "src/i18n/i18n";
|
import { getI18n } from "src/i18n/i18n";
|
||||||
import AppLayoutBackgroundImg from "components/AppLayout/components/AppLayoutBackgroundImg.astro";
|
|
||||||
import { cache } from "src/utils/payload";
|
import { cache } from "src/utils/payload";
|
||||||
import type { WordingKey } from "src/i18n/wordings-keys";
|
import type { WordingKey } from "src/i18n/wordings-keys";
|
||||||
import AppLayoutDescription from "components/AppLayout/components/AppLayoutDescription.astro";
|
import AppLayoutDescription from "components/AppLayout/components/AppLayoutDescription.astro";
|
||||||
|
@ -18,14 +17,7 @@ const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.cu
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
<AppLayout>
|
<AppLayout backgroundImage={cache.config.timeline.backgroundImage}>
|
||||||
<AppLayoutBackgroundImg
|
|
||||||
img={{
|
|
||||||
url: "/img/timeline-background.webp",
|
|
||||||
width: 2478,
|
|
||||||
height: 4110,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<AppLayoutTitle title={t("timeline.title")} />
|
<AppLayoutTitle title={t("timeline.title")} />
|
||||||
<AppLayoutDescription description={t("timeline.description")} />
|
<AppLayoutDescription description={t("timeline.description")} />
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ import { payload } from "src/utils/payload";
|
||||||
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
|
||||||
const { id } = Astro.params;
|
const id = Astro.params.id!;
|
||||||
const video = await fetchOr404(() => payload.getVideoByID(id!));
|
const video = await fetchOr404(() => payload.getVideoByID(id));
|
||||||
if (video instanceof Response) {
|
if (video instanceof Response) {
|
||||||
return video;
|
return video;
|
||||||
}
|
}
|
||||||
|
@ -71,10 +71,10 @@ const metaAttributes = [
|
||||||
|
|
||||||
<AppLayout
|
<AppLayout
|
||||||
openGraph={{
|
openGraph={{
|
||||||
|
title: formatInlineTitle({ pretitle, title, subtitle }),
|
||||||
|
description: description && formatRichTextToString(description),
|
||||||
thumbnail,
|
thumbnail,
|
||||||
video,
|
video,
|
||||||
description: description ? formatRichTextToString(description) : undefined,
|
|
||||||
title: formatInlineTitle({ pretitle, title, subtitle }),
|
|
||||||
}}>
|
}}>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<VideoPlayer video={video} />
|
<VideoPlayer video={video} />
|
||||||
|
|
|
@ -55,7 +55,6 @@ export interface Page {
|
||||||
slug: string;
|
slug: string;
|
||||||
thumbnail?: string | Image | null;
|
thumbnail?: string | Image | null;
|
||||||
backgroundImage?: string | Image | null;
|
backgroundImage?: string | Image | null;
|
||||||
tags?: (string | Tag)[] | null;
|
|
||||||
attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null;
|
attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null;
|
||||||
translations: {
|
translations: {
|
||||||
language: string | Language;
|
language: string | Language;
|
||||||
|
@ -133,7 +132,6 @@ export interface Image {
|
||||||
id?: string | null;
|
id?: string | null;
|
||||||
}[]
|
}[]
|
||||||
| null;
|
| null;
|
||||||
tags?: (string | Tag)[] | null;
|
|
||||||
attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null;
|
attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null;
|
||||||
credits?: Credits;
|
credits?: Credits;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
|
@ -161,6 +159,62 @@ export interface Image {
|
||||||
filesize?: number | null;
|
filesize?: number | null;
|
||||||
filename?: string | null;
|
filename?: string | null;
|
||||||
};
|
};
|
||||||
|
"200w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"320w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"480w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"800w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"1280w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"1920w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"2560w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -171,22 +225,6 @@ export interface Language {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "tags".
|
|
||||||
*/
|
|
||||||
export interface Tag {
|
|
||||||
id: string;
|
|
||||||
slug: string;
|
|
||||||
page?: (string | null) | Page;
|
|
||||||
translations: {
|
|
||||||
language: string | Language;
|
|
||||||
name: string;
|
|
||||||
id?: string | null;
|
|
||||||
}[];
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "TagsBlock".
|
* via the `definition` "TagsBlock".
|
||||||
|
@ -215,6 +253,22 @@ export interface Attribute {
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "tags".
|
||||||
|
*/
|
||||||
|
export interface Tag {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
page?: (string | null) | Page;
|
||||||
|
translations: {
|
||||||
|
language: string | Language;
|
||||||
|
name: string;
|
||||||
|
id?: string | null;
|
||||||
|
}[];
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "NumberBlock".
|
* via the `definition` "NumberBlock".
|
||||||
|
@ -373,7 +427,6 @@ export interface Collectible {
|
||||||
thumbnail?: string | Image | null;
|
thumbnail?: string | Image | null;
|
||||||
nature: "Physical" | "Digital";
|
nature: "Physical" | "Digital";
|
||||||
languages?: (string | Language)[] | null;
|
languages?: (string | Language)[] | null;
|
||||||
tags?: (string | Tag)[] | null;
|
|
||||||
attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null;
|
attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null;
|
||||||
translations: {
|
translations: {
|
||||||
language: string | Language;
|
language: string | Language;
|
||||||
|
@ -576,7 +629,31 @@ export interface Scan {
|
||||||
filesize?: number | null;
|
filesize?: number | null;
|
||||||
filename?: string | null;
|
filename?: string | null;
|
||||||
};
|
};
|
||||||
og?: {
|
"200w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"320w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"480w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"800w"?: {
|
||||||
url?: string | null;
|
url?: string | null;
|
||||||
width?: number | null;
|
width?: number | null;
|
||||||
height?: number | null;
|
height?: number | null;
|
||||||
|
@ -638,7 +715,6 @@ export interface Audio {
|
||||||
} | null;
|
} | null;
|
||||||
id?: string | null;
|
id?: string | null;
|
||||||
}[];
|
}[];
|
||||||
tags?: (string | Tag)[] | null;
|
|
||||||
attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null;
|
attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null;
|
||||||
credits?: Credits;
|
credits?: Credits;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
|
@ -681,6 +757,62 @@ export interface MediaThumbnail {
|
||||||
filesize?: number | null;
|
filesize?: number | null;
|
||||||
filename?: string | null;
|
filename?: string | null;
|
||||||
};
|
};
|
||||||
|
"200w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"320w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"480w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"800w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"1280w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"1920w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
"2560w"?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -714,7 +846,6 @@ export interface Video {
|
||||||
subfile?: string | VideoSubtitle | null;
|
subfile?: string | VideoSubtitle | null;
|
||||||
id?: string | null;
|
id?: string | null;
|
||||||
}[];
|
}[];
|
||||||
tags?: (string | Tag)[] | null;
|
|
||||||
attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null;
|
attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null;
|
||||||
credits?: Credits;
|
credits?: Credits;
|
||||||
platformEnabled?: boolean | null;
|
platformEnabled?: boolean | null;
|
||||||
|
@ -928,6 +1059,9 @@ export interface PayloadMigration {
|
||||||
*/
|
*/
|
||||||
export interface WebsiteConfig {
|
export interface WebsiteConfig {
|
||||||
id: string;
|
id: string;
|
||||||
|
homeBackgroundImage: string | Image;
|
||||||
|
timelineBackgroundImage: string | Image;
|
||||||
|
defaultOpenGraphImage: string | Image;
|
||||||
homeFolders?:
|
homeFolders?:
|
||||||
| {
|
| {
|
||||||
lightThumbnail?: string | Image | null;
|
lightThumbnail?: string | Image | null;
|
||||||
|
@ -1393,11 +1527,15 @@ export type EndpointFolder = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointWebsiteConfig = {
|
export type EndpointWebsiteConfig = {
|
||||||
homeFolders: (EndpointFolder & {
|
home: {
|
||||||
lightThumbnail?: EndpointImage;
|
backgroundImage?: EndpointImage;
|
||||||
darkThumbnail?: EndpointImage;
|
folders: (EndpointFolder & {
|
||||||
})[];
|
lightThumbnail?: EndpointImage;
|
||||||
|
darkThumbnail?: EndpointImage;
|
||||||
|
})[];
|
||||||
|
};
|
||||||
timeline: {
|
timeline: {
|
||||||
|
backgroundImage?: EndpointImage;
|
||||||
breaks: number[];
|
breaks: number[];
|
||||||
eventCount: number;
|
eventCount: number;
|
||||||
eras: {
|
eras: {
|
||||||
|
@ -1406,6 +1544,7 @@ export type EndpointWebsiteConfig = {
|
||||||
name: string;
|
name: string;
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
defaultOpenGraphImage?: EndpointImage;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointRecorder = {
|
export type EndpointRecorder = {
|
||||||
|
@ -1516,7 +1655,7 @@ export type EndpointCollectible = {
|
||||||
backgroundImage?: EndpointImage;
|
backgroundImage?: EndpointImage;
|
||||||
nature: CollectibleNature;
|
nature: CollectibleNature;
|
||||||
gallery?: { count: number; thumbnail: EndpointImage };
|
gallery?: { count: number; thumbnail: EndpointImage };
|
||||||
scans?: { count: number; thumbnail: PayloadImage };
|
scans?: { count: number; thumbnail: EndpointScanImage };
|
||||||
urls: { url: string; label: string }[];
|
urls: { url: string; label: string }[];
|
||||||
price?: {
|
price?: {
|
||||||
amount: number;
|
amount: number;
|
||||||
|
@ -1681,6 +1820,7 @@ export type EndpointCollectibleScanPage = {
|
||||||
|
|
||||||
export type EndpointScanImage = PayloadImage & {
|
export type EndpointScanImage = PayloadImage & {
|
||||||
index: string;
|
index: string;
|
||||||
|
sizes: PayloadImage[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TableOfContentEntry = {
|
export type TableOfContentEntry = {
|
||||||
|
@ -1748,15 +1888,17 @@ export type EndpointMedia = {
|
||||||
export type EndpointImage = EndpointMedia & {
|
export type EndpointImage = EndpointMedia & {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
sizes: PayloadImage[];
|
||||||
|
openGraph?: PayloadImage;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointAudio = EndpointMedia & {
|
export type EndpointAudio = EndpointMedia & {
|
||||||
thumbnail?: PayloadImage;
|
thumbnail?: EndpointMediaThumbnail;
|
||||||
duration: number;
|
duration: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointVideo = EndpointMedia & {
|
export type EndpointVideo = EndpointMedia & {
|
||||||
thumbnail?: PayloadImage;
|
thumbnail?: EndpointMediaThumbnail;
|
||||||
subtitles: {
|
subtitles: {
|
||||||
language: string;
|
language: string;
|
||||||
url: string;
|
url: string;
|
||||||
|
@ -1776,6 +1918,11 @@ export type EndpointVideo = EndpointMedia & {
|
||||||
duration: number;
|
duration: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type EndpointMediaThumbnail = PayloadImage & {
|
||||||
|
sizes: PayloadImage[];
|
||||||
|
openGraph?: PayloadImage;
|
||||||
|
};
|
||||||
|
|
||||||
export type PayloadMedia = {
|
export type PayloadMedia = {
|
||||||
url: string;
|
url: string;
|
||||||
mimeType: string;
|
mimeType: string;
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import type { PayloadImage } from "src/shared/payload/payload-sdk";
|
||||||
|
|
||||||
|
export const sizesToSrcset = (sizes: PayloadImage[]): string =>
|
||||||
|
sizes.map(({ url, width }) => `${encodeURI(url)} ${width}w`).join(", ");
|
||||||
|
|
||||||
|
export const sizesForGridLayout = (targetSize: number, marginMultiplier: number) => `
|
||||||
|
(max-width: ${targetSize * 2 * marginMultiplier}px) ${100 / 1}vw,
|
||||||
|
(max-width: ${targetSize * 3 * marginMultiplier}px) ${100 / 2}vw,
|
||||||
|
(max-width: ${targetSize * 4 * marginMultiplier}px) ${100 / 3}vw,
|
||||||
|
${targetSize}px`;
|
Loading…
Reference in New Issue