Improve metadata info on most pages
This commit is contained in:
parent
cb3ba888dd
commit
b1561c1b74
|
@ -31,11 +31,9 @@ const { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||||
div {
|
div {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 2em;
|
gap: 2em;
|
||||||
margin-block: 2em;
|
|
||||||
|
|
||||||
@media (max-width: 35rem) {
|
@media (max-width: 35rem) {
|
||||||
gap: 3.5em;
|
gap: 3em;
|
||||||
margin-block: 3.5em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,12 +5,12 @@ import {
|
||||||
type PayloadImage,
|
type PayloadImage,
|
||||||
type RichTextContent,
|
type RichTextContent,
|
||||||
} from "src/shared/payload/payload-sdk";
|
} from "src/shared/payload/payload-sdk";
|
||||||
import RichText from "./RichText/RichText.astro";
|
|
||||||
import TagGroups from "./TagGroups.astro";
|
import TagGroups from "./TagGroups.astro";
|
||||||
import Credits from "./Credits.astro";
|
import Credits from "./Credits.astro";
|
||||||
import DownloadButton from "./DownloadButton.astro";
|
import DownloadButton from "./DownloadButton.astro";
|
||||||
import AppLayoutTitle from "./AppLayout/components/AppLayoutTitle.astro";
|
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";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
previousImageHref?: string | undefined;
|
previousImageHref?: string | undefined;
|
||||||
|
@ -65,15 +65,16 @@ const smallTitle = !subtitle && !pretitle;
|
||||||
complex:
|
complex:
|
||||||
(tagGroups && tagGroups.length > 0) || (credits && credits.length > 0) || description,
|
(tagGroups && tagGroups.length > 0) || (credits && credits.length > 0) || description,
|
||||||
}}>
|
}}>
|
||||||
{
|
<div>
|
||||||
smallTitle ? (
|
{
|
||||||
<h1>{title}</h1>
|
smallTitle ? (
|
||||||
) : (
|
<h1>{title}</h1>
|
||||||
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
|
) : (
|
||||||
)
|
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
|
||||||
}
|
)
|
||||||
|
}
|
||||||
{description && <RichText content={description} />}
|
{description && <AppLayoutDescription description={description} />}
|
||||||
|
</div>
|
||||||
{tagGroups && tagGroups.length > 0 && <TagGroups tagGroups={tagGroups} />}
|
{tagGroups && tagGroups.length > 0 && <TagGroups tagGroups={tagGroups} />}
|
||||||
{credits && credits.length > 0 && <Credits credits={credits} />}
|
{credits && credits.length > 0 && <Credits credits={credits} />}
|
||||||
{filename && <DownloadButton href={url} filename={filename} />}
|
{filename && <DownloadButton href={url} filename={filename} />}
|
||||||
|
@ -113,12 +114,16 @@ const smallTitle = !subtitle && !pretitle;
|
||||||
& > #info {
|
& > #info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1em;
|
gap: 4em;
|
||||||
align-items: center;
|
align-items: start;
|
||||||
|
|
||||||
&.complex {
|
@media (max-width: 35rem) {
|
||||||
|
gap: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.complex) {
|
||||||
|
align-items: center;
|
||||||
gap: 2em;
|
gap: 2em;
|
||||||
align-items: start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
& > h1 {
|
& > h1 {
|
||||||
|
|
|
@ -41,13 +41,12 @@ const groups = tagGroups.map((group) => {
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div {
|
div {
|
||||||
display: grid;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
gap: 2em;
|
gap: 2em;
|
||||||
margin-block: 2em;
|
|
||||||
|
|
||||||
@media (max-width: 35rem) {
|
@media (max-width: 35rem) {
|
||||||
gap: 3.5em;
|
gap: 3em;
|
||||||
margin-block: 3.5em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -144,4 +144,7 @@ export type WordingKey =
|
||||||
| "global.media.attributes.duration"
|
| "global.media.attributes.duration"
|
||||||
| "global.media.attributes.filesize"
|
| "global.media.attributes.filesize"
|
||||||
| "global.media.attributes.createdAt"
|
| "global.media.attributes.createdAt"
|
||||||
| "global.media.attributes.updatedAt";
|
| "global.media.attributes.updatedAt"
|
||||||
|
| "global.media.attributes.updatedBy"
|
||||||
|
| "collectibles.nature"
|
||||||
|
| "collectibles.languages";
|
||||||
|
|
|
@ -22,13 +22,38 @@ interface Props {
|
||||||
const reqUrl = new URL(Astro.request.url);
|
const reqUrl = new URL(Astro.request.url);
|
||||||
const lang = Astro.props.lang ?? reqUrl.searchParams.get("lang")!;
|
const lang = Astro.props.lang ?? reqUrl.searchParams.get("lang")!;
|
||||||
const slug = Astro.props.slug ?? reqUrl.searchParams.get("slug")!;
|
const slug = Astro.props.slug ?? reqUrl.searchParams.get("slug")!;
|
||||||
const { translations, thumbnail, tagGroups } = Astro.props.page ?? (await payload.getPage(slug));
|
const { translations, thumbnail, tagGroups, createdAt, updatedAt, updatedBy } =
|
||||||
|
Astro.props.page ?? (await payload.getPage(slug));
|
||||||
|
|
||||||
const { getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
const { getLocalizedUrl, t, formatDate } = await getI18n(Astro.locals.currentLocale);
|
||||||
const { getLocalizedMatch } = await getI18n(lang);
|
const { getLocalizedMatch } = await getI18n(lang);
|
||||||
|
|
||||||
const { pretitle, title, subtitle, summary, content, credits, toc, language, sourceLanguage } =
|
const { pretitle, title, subtitle, summary, content, credits, toc, language, sourceLanguage } =
|
||||||
getLocalizedMatch(translations);
|
getLocalizedMatch(translations);
|
||||||
|
|
||||||
|
const attributes = [
|
||||||
|
{
|
||||||
|
title: t("global.media.attributes.createdAt"),
|
||||||
|
icon: "material-symbols:calendar-add-on-outline",
|
||||||
|
values: [formatDate(new Date(createdAt))],
|
||||||
|
withBorder: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("global.media.attributes.updatedAt"),
|
||||||
|
icon: "material-symbols:edit-calendar",
|
||||||
|
values: [formatDate(new Date(updatedAt))],
|
||||||
|
withBorder: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (updatedBy) {
|
||||||
|
attributes.push({
|
||||||
|
title: t("global.media.attributes.updatedBy"),
|
||||||
|
icon: "material-symbols:person-edit-outline",
|
||||||
|
values: [updatedBy?.username],
|
||||||
|
withBorder: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
@ -56,27 +81,37 @@ const { pretitle, title, subtitle, summary, content, credits, toc, language, sou
|
||||||
|
|
||||||
<Fragment slot="meta">
|
<Fragment slot="meta">
|
||||||
{summary && <AppLayoutDescription description={summary} />}
|
{summary && <AppLayoutDescription description={summary} />}
|
||||||
{tagGroups.length > 0 && <TagGroups tagGroups={tagGroups} />}
|
|
||||||
</Fragment>
|
|
||||||
|
|
||||||
<Fragment slot="aside">
|
|
||||||
{
|
{
|
||||||
translations.length > 1 && (
|
tagGroups.length > 0 && (
|
||||||
<LanguageOverride
|
<div id="tags">
|
||||||
currentLanguage={language}
|
<TagGroups tagGroups={tagGroups} />
|
||||||
currentSourceLanguage={sourceLanguage}
|
</div>
|
||||||
availableLanguages={translations.map(({ language }) => language)}
|
|
||||||
getPartialUrl={(lang) =>
|
|
||||||
getLocalizedUrl(`/api/pages/partial?lang=${lang}&slug=${slug}`)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
</Fragment>
|
||||||
|
|
||||||
{credits.length > 0 && <Credits credits={credits} />}
|
<div id="aside" slot="aside">
|
||||||
|
<div id="credits">
|
||||||
|
{
|
||||||
|
translations.length > 1 && (
|
||||||
|
<LanguageOverride
|
||||||
|
currentLanguage={language}
|
||||||
|
currentSourceLanguage={sourceLanguage}
|
||||||
|
availableLanguages={translations.map(({ language }) => language)}
|
||||||
|
getPartialUrl={(lang) =>
|
||||||
|
getLocalizedUrl(`/api/pages/partial?lang=${lang}&slug=${slug}`)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
{credits.length > 0 && <Credits credits={credits} />}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{attributes.length > 0 && <TagGroups tagGroups={attributes} />}
|
||||||
|
|
||||||
{toc.length > 0 && <TableOfContent toc={toc} />}
|
{toc.length > 0 && <TableOfContent toc={toc} />}
|
||||||
</Fragment>
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
<div id="text">
|
<div id="text">
|
||||||
|
@ -94,6 +129,39 @@ const { pretitle, title, subtitle, summary, content, credits, toc, language, sou
|
||||||
margin-block: 3em;
|
margin-block: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#aside {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4em;
|
||||||
|
|
||||||
|
@media (max-width: 35rem) {
|
||||||
|
gap: 6em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#tags {
|
||||||
|
margin-block: 2em;
|
||||||
|
|
||||||
|
@media (max-width: 1280.5px) {
|
||||||
|
margin-bottom: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 35rem) {
|
||||||
|
margin-top: 4em;
|
||||||
|
margin-bottom: 6em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#credits {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1em;
|
||||||
|
|
||||||
|
@media (max-width: 35rem) {
|
||||||
|
gap: 2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#thumbnail {
|
#thumbnail {
|
||||||
max-width: 35rem;
|
max-width: 35rem;
|
||||||
max-height: 60vh;
|
max-height: 60vh;
|
||||||
|
|
|
@ -36,8 +36,7 @@ const { pretitle, title, subtitle, description } = getLocalizedMatch(translation
|
||||||
|
|
||||||
const smallTitle = !subtitle && !pretitle;
|
const smallTitle = !subtitle && !pretitle;
|
||||||
|
|
||||||
const tagsAndAttributes = [
|
const attributes = [
|
||||||
...tagGroups,
|
|
||||||
...(filename && title !== filename
|
...(filename && title !== filename
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
|
@ -81,7 +80,7 @@ const tagsAndAttributes = [
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<AudioPlayer audio={audio} />
|
<AudioPlayer audio={audio} />
|
||||||
|
|
||||||
<div>
|
<div id="info">
|
||||||
{
|
{
|
||||||
smallTitle ? (
|
smallTitle ? (
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
|
@ -90,10 +89,9 @@ const tagsAndAttributes = [
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{description && <RichText content={description} />}
|
{description && <RichText content={description} />}
|
||||||
<div>
|
{tagGroups.length > 0 && <TagGroups tagGroups={tagGroups} />}
|
||||||
{tagsAndAttributes.length > 0 && <TagGroups tagGroups={tagsAndAttributes} />}
|
{credits.length > 0 && <Credits credits={credits} />}
|
||||||
{credits.length > 0 && <Credits credits={credits} />}
|
{attributes.length > 0 && <TagGroups tagGroups={attributes} />}
|
||||||
</div>
|
|
||||||
<DownloadButton href={url} filename={filename} />
|
<DownloadButton href={url} filename={filename} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -117,18 +115,14 @@ const tagsAndAttributes = [
|
||||||
max-width: 35em;
|
max-width: 35em;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > div {
|
& > #info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2em;
|
gap: 4em;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
|
|
||||||
& > div {
|
@media (max-width: 35rem) {
|
||||||
display: flex;
|
gap: 6em;
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 2em 6em;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
---
|
|
||||||
import { Icon } from "astro-icon/components";
|
|
||||||
import { getI18n } from "src/i18n/i18n";
|
|
||||||
import { convert } from "src/utils/currencies";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
price: {
|
|
||||||
amount: number;
|
|
||||||
currency: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const { price } = Astro.props;
|
|
||||||
|
|
||||||
const { formatPrice, t } = await getI18n(Astro.locals.currentLocale);
|
|
||||||
|
|
||||||
const preferredCurrency = Astro.locals.currentCurrency;
|
|
||||||
|
|
||||||
const convertedPrice: Props["price"] = {
|
|
||||||
amount: convert(price.currency, preferredCurrency, price.amount),
|
|
||||||
currency: preferredCurrency,
|
|
||||||
};
|
|
||||||
|
|
||||||
let priceText = price.amount === 0 ? t("collectibles.price.free") : formatPrice(price);
|
|
||||||
|
|
||||||
if (price.amount > 0 && price.currency !== convertedPrice.currency) {
|
|
||||||
priceText += ` (${formatPrice(convertedPrice)})`;
|
|
||||||
}
|
|
||||||
---
|
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
|
||||||
|
|
||||||
<div id="container">
|
|
||||||
<div id="title">
|
|
||||||
<Icon name="material-symbols:sell-outline" width={24} height={24} />
|
|
||||||
<p>{t("collectibles.price")}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{(<p>{priceText}</p>)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
#container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: auto 1fr;
|
|
||||||
gap: 0.5em 1em;
|
|
||||||
align-items: start;
|
|
||||||
|
|
||||||
@media (max-width: 35em) {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > #title {
|
|
||||||
display: flex;
|
|
||||||
place-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
|
|
||||||
& > p {
|
|
||||||
font-size: 1.5em;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > p {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,53 +0,0 @@
|
||||||
---
|
|
||||||
import { Icon } from "astro-icon/components";
|
|
||||||
import { getI18n } from "src/i18n/i18n";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
releaseDate: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { releaseDate } = Astro.props;
|
|
||||||
|
|
||||||
const { formatDate, t } = await getI18n(Astro.locals.currentLocale);
|
|
||||||
---
|
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
|
||||||
|
|
||||||
<div id="container">
|
|
||||||
<div id="title">
|
|
||||||
<Icon name="material-symbols:calendar-month-outline" width={24} height={24} />
|
|
||||||
<p>{t("collectibles.releaseDate")}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>{formatDate(new Date(releaseDate))}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
#container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: auto 1fr;
|
|
||||||
gap: 0.5em 1em;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
@media (max-width: 35em) {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > #title {
|
|
||||||
display: flex;
|
|
||||||
place-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
|
|
||||||
& > p {
|
|
||||||
font-size: 1.5em;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > p {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -3,23 +3,24 @@ import AppLayout from "components/AppLayout/AppLayout.astro";
|
||||||
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
|
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
|
||||||
import TagGroups from "components/TagGroups.astro";
|
import TagGroups from "components/TagGroups.astro";
|
||||||
import { getI18n } from "src/i18n/i18n";
|
import { getI18n } from "src/i18n/i18n";
|
||||||
import { payload } from "src/shared/payload/payload-sdk";
|
import { CollectibleNature, payload } from "src/shared/payload/payload-sdk";
|
||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
import ImageTile from "./_components/ImageTile.astro";
|
import ImageTile from "./_components/ImageTile.astro";
|
||||||
import PriceInfo from "./_components/PriceInfo.astro";
|
|
||||||
import SizeInfo from "./_components/SizeInfo.astro";
|
import SizeInfo from "./_components/SizeInfo.astro";
|
||||||
import ReleaseDateInfo from "./_components/ReleaseDateInfo.astro";
|
|
||||||
import PageInfo from "./_components/PageInfo.astro";
|
import PageInfo from "./_components/PageInfo.astro";
|
||||||
import AvailabilityInfo from "./_components/AvailabilityInfo.astro";
|
import AvailabilityInfo from "./_components/AvailabilityInfo.astro";
|
||||||
import WeightInfo from "./_components/WeightInfo.astro";
|
import WeightInfo from "./_components/WeightInfo.astro";
|
||||||
import SubitemSection from "./_components/SubitemSection.astro";
|
import SubitemSection from "./_components/SubitemSection.astro";
|
||||||
import ContentsSection from "./_components/ContentsSection/ContentsSection.astro";
|
import ContentsSection from "./_components/ContentsSection/ContentsSection.astro";
|
||||||
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
import { formatInlineTitle, formatLocale, formatRichTextToString } from "src/utils/format";
|
||||||
import AsideLayout from "components/AppLayout/AsideLayout.astro";
|
import AsideLayout from "components/AppLayout/AsideLayout.astro";
|
||||||
import AppLayoutDescription from "components/AppLayout/components/AppLayoutDescription.astro";
|
import AppLayoutDescription from "components/AppLayout/components/AppLayoutDescription.astro";
|
||||||
|
import { convert } from "src/utils/currencies";
|
||||||
|
|
||||||
const { slug } = Astro.params;
|
const { slug } = Astro.params;
|
||||||
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale);
|
const { getLocalizedMatch, getLocalizedUrl, t, formatDate, formatPrice } = await getI18n(
|
||||||
|
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) {
|
||||||
|
@ -42,9 +43,89 @@ const {
|
||||||
parentPages,
|
parentPages,
|
||||||
tagGroups,
|
tagGroups,
|
||||||
contents,
|
contents,
|
||||||
|
createdAt,
|
||||||
|
updatedAt,
|
||||||
|
updatedBy,
|
||||||
|
languages,
|
||||||
|
nature,
|
||||||
} = collectible;
|
} = collectible;
|
||||||
|
|
||||||
const translation = getLocalizedMatch(translations);
|
const translation = getLocalizedMatch(translations);
|
||||||
|
const { pretitle, title, subtitle, description } = translation;
|
||||||
|
|
||||||
|
const attributes = [
|
||||||
|
{
|
||||||
|
title: t("global.media.attributes.createdAt"),
|
||||||
|
icon: "material-symbols:calendar-add-on-outline",
|
||||||
|
values: [formatDate(new Date(createdAt))],
|
||||||
|
withBorder: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("global.media.attributes.updatedAt"),
|
||||||
|
icon: "material-symbols:edit-calendar",
|
||||||
|
values: [formatDate(new Date(updatedAt))],
|
||||||
|
withBorder: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (updatedBy) {
|
||||||
|
attributes.push({
|
||||||
|
title: t("global.media.attributes.updatedBy"),
|
||||||
|
icon: "material-symbols:person-edit-outline",
|
||||||
|
values: [updatedBy?.username],
|
||||||
|
withBorder: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const tagGroupWithAttributes = [
|
||||||
|
...tagGroups,
|
||||||
|
{
|
||||||
|
title: t("collectibles.nature"),
|
||||||
|
icon: "material-symbols:leaf-spark-outline",
|
||||||
|
values: [nature === CollectibleNature.Physical ? "Physical" : "Digital"],
|
||||||
|
withBorder: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (releaseDate) {
|
||||||
|
tagGroupWithAttributes.push({
|
||||||
|
title: t("collectibles.releaseDate"),
|
||||||
|
icon: "material-symbols:calendar-month-outline",
|
||||||
|
values: [formatDate(new Date(releaseDate))],
|
||||||
|
withBorder: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (languages.length > 0) {
|
||||||
|
tagGroupWithAttributes.push({
|
||||||
|
title: t("collectibles.languages"),
|
||||||
|
icon: "material-symbols:translate",
|
||||||
|
values: languages.map((lang) => formatLocale(lang)),
|
||||||
|
withBorder: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (price) {
|
||||||
|
const preferredCurrency = Astro.locals.currentCurrency;
|
||||||
|
|
||||||
|
const convertedPrice = {
|
||||||
|
amount: convert(price.currency, preferredCurrency, price.amount),
|
||||||
|
currency: preferredCurrency,
|
||||||
|
};
|
||||||
|
|
||||||
|
let priceText = price.amount === 0 ? t("collectibles.price.free") : formatPrice(price);
|
||||||
|
|
||||||
|
if (price.amount > 0 && price.currency !== convertedPrice.currency) {
|
||||||
|
priceText += ` (${formatPrice(convertedPrice)})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
tagGroupWithAttributes.push({
|
||||||
|
title: t("collectibles.price"),
|
||||||
|
icon: "material-symbols:sell-outline",
|
||||||
|
values: [priceText],
|
||||||
|
withBorder: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
@ -52,18 +133,14 @@ const translation = getLocalizedMatch(translations);
|
||||||
<AppLayout
|
<AppLayout
|
||||||
openGraph={{
|
openGraph={{
|
||||||
title: formatInlineTitle(translation),
|
title: formatInlineTitle(translation),
|
||||||
description: translation.description && formatRichTextToString(translation.description),
|
description: description && formatRichTextToString(description),
|
||||||
thumbnail,
|
thumbnail,
|
||||||
}}
|
}}
|
||||||
parentPages={parentPages}
|
parentPages={parentPages}
|
||||||
backgroundImage={backgroundImage ?? thumbnail}>
|
backgroundImage={backgroundImage ?? thumbnail}>
|
||||||
<AsideLayout>
|
<AsideLayout>
|
||||||
<Fragment slot="header">
|
<Fragment slot="header">
|
||||||
<AppLayoutTitle
|
<AppLayoutTitle title={title} pretitle={pretitle} subtitle={subtitle} />
|
||||||
title={translation.title}
|
|
||||||
pretitle={translation.pretitle}
|
|
||||||
subtitle={translation.subtitle}
|
|
||||||
/>
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|
||||||
<Fragment slot="header-aside">
|
<Fragment slot="header-aside">
|
||||||
|
@ -107,21 +184,31 @@ const translation = getLocalizedMatch(translations);
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|
||||||
{translation.description && <AppLayoutDescription description={translation.description} />}
|
<Fragment slot="aside">
|
||||||
|
{
|
||||||
|
attributes.length > 0 && (
|
||||||
|
<div id="attributes">
|
||||||
|
<TagGroups tagGroups={attributes} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Fragment>
|
||||||
|
|
||||||
<TagGroups tagGroups={tagGroups}>
|
<Fragment slot="meta">
|
||||||
{releaseDate && <ReleaseDateInfo releaseDate={releaseDate} />}
|
{description && <AppLayoutDescription description={description} />}
|
||||||
|
|
||||||
{price && <PriceInfo price={price} />}
|
<div id="tags">
|
||||||
|
<TagGroups tagGroups={tagGroupWithAttributes}>
|
||||||
|
<AvailabilityInfo urls={urls} price={price !== undefined} releaseDate={releaseDate} />
|
||||||
|
|
||||||
<AvailabilityInfo urls={urls} price={price !== undefined} releaseDate={releaseDate} />
|
{size && <SizeInfo size={size} />}
|
||||||
|
|
||||||
{size && <SizeInfo size={size} />}
|
{weight && <WeightInfo weight={weight} />}
|
||||||
|
|
||||||
{weight && <WeightInfo weight={weight} />}
|
{pageInfo && <PageInfo pageInfo={pageInfo} />}
|
||||||
|
</TagGroups>
|
||||||
{pageInfo && <PageInfo pageInfo={pageInfo} />}
|
</div>
|
||||||
</TagGroups>
|
</Fragment>
|
||||||
|
|
||||||
{subitems.length > 0 && <SubitemSection subitems={subitems} />}
|
{subitems.length > 0 && <SubitemSection subitems={subitems} />}
|
||||||
|
|
||||||
|
@ -195,4 +282,24 @@ const translation = getLocalizedMatch(translations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tags {
|
||||||
|
margin-block: 2em;
|
||||||
|
|
||||||
|
@media (max-width: 1280.5px) {
|
||||||
|
margin-bottom: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 35rem) {
|
||||||
|
margin-top: 4em;
|
||||||
|
margin-bottom: 6em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#attributes {
|
||||||
|
@media (min-width: 1280.5px) {
|
||||||
|
margin-left: 12em;
|
||||||
|
margin-top: 3em;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -33,7 +33,7 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
|
||||||
<AppLayoutDescription description={t("home.description")} />
|
<AppLayoutDescription description={t("home.description")} />
|
||||||
|
|
||||||
<a href={getLocalizedUrl("/about")}>
|
<a href={getLocalizedUrl("/about")} class="DEV_TODO">
|
||||||
<Button title={t("home.aboutUsButton")} icon="material-symbols:left-click" />
|
<Button title={t("home.aboutUsButton")} icon="material-symbols:left-click" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,7 @@ const {
|
||||||
const { pretitle, title, subtitle, description } = getLocalizedMatch(translations);
|
const { pretitle, title, subtitle, description } = getLocalizedMatch(translations);
|
||||||
const smallTitle = !subtitle && !pretitle;
|
const smallTitle = !subtitle && !pretitle;
|
||||||
|
|
||||||
const tagsAndAttributes = [
|
const attributes = [
|
||||||
...tagGroups,
|
|
||||||
...(filename && title !== filename
|
...(filename && title !== filename
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
|
@ -80,7 +79,7 @@ const tagsAndAttributes = [
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<VideoPlayer video={video} />
|
<VideoPlayer video={video} />
|
||||||
|
|
||||||
<div>
|
<div id="info">
|
||||||
{
|
{
|
||||||
smallTitle ? (
|
smallTitle ? (
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
|
@ -89,10 +88,9 @@ const tagsAndAttributes = [
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{description && <RichText content={description} />}
|
{description && <RichText content={description} />}
|
||||||
<div>
|
{tagGroups.length > 0 && <TagGroups tagGroups={tagGroups} />}
|
||||||
{tagsAndAttributes.length > 0 && <TagGroups tagGroups={tagsAndAttributes} />}
|
{credits.length > 0 && <Credits credits={credits} />}
|
||||||
{credits.length > 0 && <Credits credits={credits} />}
|
{attributes.length > 0 && <TagGroups tagGroups={attributes} />}
|
||||||
</div>
|
|
||||||
<DownloadButton href={url} filename={filename} />
|
<DownloadButton href={url} filename={filename} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -118,18 +116,14 @@ const tagsAndAttributes = [
|
||||||
max-width: 35em;
|
max-width: 35em;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > div {
|
& > #info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2em;
|
gap: 4em;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
|
|
||||||
& > div {
|
@media (max-width: 35rem) {
|
||||||
display: flex;
|
gap: 6em;
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 2em 6em;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1482,6 +1482,9 @@ export type EndpointPage = {
|
||||||
credits: EndpointCredit[];
|
credits: EndpointCredit[];
|
||||||
toc: TableOfContentEntry[];
|
toc: TableOfContentEntry[];
|
||||||
}[];
|
}[];
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
updatedBy?: EndpointRecorder;
|
||||||
parentPages: EndpointSource[];
|
parentPages: EndpointSource[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1562,6 +1565,9 @@ export type EndpointCollectible = {
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
}[];
|
}[];
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
updatedBy?: EndpointRecorder;
|
||||||
parentPages: EndpointSource[];
|
parentPages: EndpointSource[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue