Handle collectible pages
This commit is contained in:
parent
6c1956ce5c
commit
3c7ce915f1
9
TODO.md
Normal file
9
TODO.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Accord's Library v3.0
|
||||||
|
|
||||||
|
## Short term
|
||||||
|
|
||||||
|
- Translate new wording keys
|
||||||
|
|
||||||
|
## Long term
|
||||||
|
|
||||||
|
- Anonymous comments
|
18
package.json
18
package.json
@ -21,27 +21,27 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/check": "^0.5.6",
|
"@astrojs/check": "^0.5.6",
|
||||||
"@astrojs/node": "^8.2.1",
|
"@astrojs/node": "^8.2.3",
|
||||||
"@fontsource-variable/murecho": "^5.0.17",
|
"@fontsource-variable/murecho": "^5.0.18",
|
||||||
"@fontsource-variable/vollkorn": "^5.0.19",
|
"@fontsource-variable/vollkorn": "^5.0.20",
|
||||||
"accept-language": "^3.0.18",
|
"accept-language": "^3.0.18",
|
||||||
"astro": "4.4.6",
|
"astro": "4.4.15",
|
||||||
"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",
|
||||||
"ua-parser-js": "^1.0.37"
|
"ua-parser-js": "^1.0.37"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify-json/material-symbols": "^1.1.73",
|
"@iconify-json/material-symbols": "^1.1.74",
|
||||||
"@types/ua-parser-js": "^0.7.39",
|
"@types/ua-parser-js": "^0.7.39",
|
||||||
"astro-meta-tags": "^0.2.1",
|
"astro-meta-tags": "^0.2.1",
|
||||||
"autoprefixer": "^10.4.17",
|
"autoprefixer": "^10.4.18",
|
||||||
"bun-types": "^1.0.29",
|
"bun-types": "^1.0.30",
|
||||||
"npm-check-updates": "^16.14.15",
|
"npm-check-updates": "^16.14.15",
|
||||||
"postcss-preset-env": "^9.4.0",
|
"postcss-preset-env": "^9.5.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-astro": "^0.13.0",
|
"prettier-plugin-astro": "^0.13.0",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
public/img/background-image.webp
Normal file
BIN
public/img/background-image.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 668 KiB |
Binary file not shown.
Before Width: | Height: | Size: 181 KiB |
Binary file not shown.
Before Width: | Height: | Size: 199 KiB |
@ -10,37 +10,48 @@ interface Props {
|
|||||||
|
|
||||||
const { src, alt } = Astro.props;
|
const { src, alt } = Astro.props;
|
||||||
const uniqueId = getRandomId();
|
const uniqueId = getRandomId();
|
||||||
|
|
||||||
const styleNoScript = `
|
|
||||||
<style>
|
|
||||||
#${uniqueId} {
|
|
||||||
opacity: 1;
|
|
||||||
transition: unset;
|
|
||||||
}
|
|
||||||
</style>`;
|
|
||||||
---
|
---
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
<img id={uniqueId} src={src} alt={alt} class="when-no-print" />
|
<img id={uniqueId} src={src} alt={alt} class="when-no-print when-js" />
|
||||||
<noscript set:html={styleNoScript} />
|
<img src={src} alt={alt} class="when-no-print when-no-js" />
|
||||||
|
|
||||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
img {
|
img {
|
||||||
opacity: 0;
|
|
||||||
transition: 3s opacity;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: -1;
|
bottom: 0;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
object-position: 50% 0;
|
object-position: 50% 0;
|
||||||
width: 100%;
|
|
||||||
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0) 100%);
|
mask-image: linear-gradient(to bottom, rgba(0 0 0 / 30%) 0%, transparent 100%);
|
||||||
|
|
||||||
|
@media (min-width: 110vh) {
|
||||||
|
mask-image: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
rgba(0 0 0 / 30%) 0%,
|
||||||
|
rgba(0 0 0 / 5%) 100vh,
|
||||||
|
transparent 100%
|
||||||
|
);
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&.when-js {
|
||||||
|
opacity: 0;
|
||||||
|
transition: 3s opacity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -38,19 +38,12 @@ const { currentTheme } = Astro.locals;
|
|||||||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#27231e" />
|
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#27231e" />
|
||||||
<link rel="manifest" href="/site.webmanifest" />
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
|
|
||||||
<style is:global>
|
|
||||||
.when-no-js {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<noscript>
|
<noscript>
|
||||||
<style is:global>
|
<style is:global>
|
||||||
.when-js {
|
.when-js {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
visibility: none !important;
|
||||||
.when-no-js {
|
opacity: 0 !important;
|
||||||
display: initial !important;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</noscript>
|
</noscript>
|
||||||
@ -224,10 +217,17 @@ const { currentTheme } = Astro.locals;
|
|||||||
.high-contrast-text {
|
.high-contrast-text {
|
||||||
text-shadow: 0 0 0.6em var(--color-elevation-0);
|
text-shadow: 0 0 0.6em var(--color-elevation-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: clamp(12px, 3vmin, 24px) clamp(24px, 4vw, 64px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
|
position: relative;
|
||||||
color: var(--color-base-1000);
|
color: var(--color-base-1000);
|
||||||
|
min-height: 100vb;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
@media screen {
|
@media screen {
|
||||||
background-color: var(--color-base-150);
|
background-color: var(--color-base-150);
|
||||||
@ -235,8 +235,7 @@ const { currentTheme } = Astro.locals;
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: clamp(12px, 3vmin, 24px) clamp(24px, 4vw, 64px);
|
flex: 1;
|
||||||
min-height: 100vb;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -327,6 +326,24 @@ const { currentTheme } = Astro.locals;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pressable-link {
|
||||||
|
text-decoration: underline dotted 0.1em;
|
||||||
|
text-decoration-color: transparent;
|
||||||
|
|
||||||
|
transition-duration: 150ms;
|
||||||
|
transition-property: text-decoration-color, color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-base-750);
|
||||||
|
text-decoration-color: var(--color-base-650);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: var(--color-base-650);
|
||||||
|
text-decoration-color: var(--color-base-550);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.pressable-label {
|
.pressable-label {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
@ -448,3 +465,13 @@ const { currentTheme } = Astro.locals;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
{/* ------------------------------------------- JS --------------------------------------------- */}
|
||||||
|
|
||||||
|
<script is:inline>
|
||||||
|
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());
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -44,7 +44,7 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
|||||||
<a href="/settings">
|
<a href="/settings">
|
||||||
<Button
|
<Button
|
||||||
icon="material-symbols:settings-outline"
|
icon="material-symbols:settings-outline"
|
||||||
ariaLabel={t("header.topbar.search.tooltip")}
|
ariaLabel={t("header.topbar.settings.tooltip")}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,13 +17,20 @@ switch (parentPage.collection) {
|
|||||||
href = getLocalizedUrl(`/folders/${parentPage.slug}`);
|
href = getLocalizedUrl(`/folders/${parentPage.slug}`);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Collections.Collectibles:
|
||||||
|
href = getLocalizedUrl(`/collectibles/${parentPage.slug}`);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
href = "/404";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
{/* TODO: Not use the tag but actual translation */}
|
||||||
|
|
||||||
<a href={href}><span>{parentPage.tag}</span>{translation.name}</a>
|
<a href={href}><span>{parentPage.tag}</span>{translation.name}</a>
|
||||||
|
|
||||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
@ -18,6 +18,7 @@ const { t } = await getI18n(Astro.locals.currentLocale);
|
|||||||
|
|
||||||
<Tooltip trigger="click">
|
<Tooltip trigger="click">
|
||||||
<div id="tooltip-content" slot="tooltip-content">
|
<div id="tooltip-content" slot="tooltip-content">
|
||||||
|
{/* TODO: Translate */}
|
||||||
<p>This content is part of these pages:</p>
|
<p>This content is part of these pages:</p>
|
||||||
{parentPages.map((parentPage) => <ParentPageLink parentPage={parentPage} />)}
|
{parentPages.map((parentPage) => <ParentPageLink parentPage={parentPage} />)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import type { SpacerBlock } from "src/shared/payload/payload-sdk";
|
import { SpacerSizes, type SpacerBlock } from "src/shared/payload/payload-sdk";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
block: SpacerBlock;
|
block: SpacerBlock;
|
||||||
@ -7,11 +7,11 @@ interface Props {
|
|||||||
|
|
||||||
const { block } = Astro.props;
|
const { block } = Astro.props;
|
||||||
|
|
||||||
const spaceSizeToRem: Record<SpacerBlock["size"], number> = {
|
const spaceSizeToRem: Record<SpacerSizes, number> = {
|
||||||
Small: 1,
|
[SpacerSizes.Small]: 1,
|
||||||
Medium: 2,
|
[SpacerSizes.Medium]: 2,
|
||||||
Large: 4,
|
[SpacerSizes.Large]: 4,
|
||||||
XLarge: 8,
|
[SpacerSizes.XLarge]: 8,
|
||||||
};
|
};
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ if (values.length === 0) return;
|
|||||||
<p>{title}</p>
|
<p>{title}</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="values">
|
<div id="values">
|
||||||
{values.map((value) => <div class="pill">{value}</div>)}
|
{values.map((value) => <div>{value}</div>)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -54,12 +54,13 @@ if (values.length === 0) return;
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|
||||||
& > .pill {
|
& > div {
|
||||||
border: 1px solid var(--color-base-1000);
|
border: 1px solid var(--color-base-1000);
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
padding-top: 0.15em;
|
padding-top: 0.15em;
|
||||||
padding-bottom: 0.25em;
|
padding-bottom: 0.25em;
|
||||||
padding-inline: 0.6em;
|
padding-inline: 0.6em;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
73
src/components/Previews/CollectiblePreview.astro
Normal file
73
src/components/Previews/CollectiblePreview.astro
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
import type { EndpointCollectiblePreview } from "src/shared/payload/payload-sdk";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
collectible: EndpointCollectiblePreview;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { getLocalizedMatch, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
|
||||||
|
const {
|
||||||
|
collectible: { slug, translations, thumbnail },
|
||||||
|
} = Astro.props;
|
||||||
|
|
||||||
|
const { title, pretitle, subtitle } = getLocalizedMatch(translations);
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<a href={getLocalizedUrl(`/collectibles/${slug}`)} class="pressable">
|
||||||
|
{
|
||||||
|
thumbnail && (
|
||||||
|
<img src={thumbnail.url} width={thumbnail.width} height={thumbnail.height} alt="" />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{pretitle && <span id="pretitle">{pretitle} </span>}
|
||||||
|
<span id="title">{title} </span>
|
||||||
|
{subtitle && <span id="subtitle">{subtitle}</span>}
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
padding: 1em;
|
||||||
|
border-radius: 1em;
|
||||||
|
color: var(--color-base-1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height: 0.8;
|
||||||
|
display: grid;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
font-size: clamp(0.5em, 0.35em + 0.75vw, 1em);
|
||||||
|
font-weight: 800;
|
||||||
|
|
||||||
|
& > #pretitle {
|
||||||
|
font-family: var(--font-sans-serifs);
|
||||||
|
font-weight: 400;
|
||||||
|
margin-bottom: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #title {
|
||||||
|
font-family: var(--font-serif);
|
||||||
|
font-size: 200%;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #subtitle {
|
||||||
|
font-family: var(--font-serif);
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
73
src/components/Previews/PagePreview.astro
Normal file
73
src/components/Previews/PagePreview.astro
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
import type { EndpointPagePreview } from "src/shared/payload/payload-sdk";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
page: EndpointPagePreview;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { getLocalizedMatch, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
|
||||||
|
const {
|
||||||
|
page: { slug, translations, thumbnail },
|
||||||
|
} = Astro.props;
|
||||||
|
|
||||||
|
const { title, pretitle, subtitle } = getLocalizedMatch(translations);
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<a href={getLocalizedUrl(`/pages/${slug}`)} class="pressable">
|
||||||
|
{
|
||||||
|
thumbnail && (
|
||||||
|
<img src={thumbnail.url} width={thumbnail.width} height={thumbnail.height} alt="" />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{pretitle && <span id="pretitle">{pretitle} </span>}
|
||||||
|
<span id="title">{title} </span>
|
||||||
|
{subtitle && <span id="subtitle">{subtitle}</span>}
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
padding: 1em;
|
||||||
|
border-radius: 1em;
|
||||||
|
color: var(--color-base-1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height: 0.8;
|
||||||
|
display: grid;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
font-size: clamp(0.5em, 0.35em + 0.75vw, 1em);
|
||||||
|
font-weight: 800;
|
||||||
|
|
||||||
|
& > #pretitle {
|
||||||
|
font-family: var(--font-sans-serifs);
|
||||||
|
font-weight: 400;
|
||||||
|
margin-bottom: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #title {
|
||||||
|
font-family: var(--font-serif);
|
||||||
|
font-size: 200%;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #subtitle {
|
||||||
|
font-family: var(--font-serif);
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -11,7 +11,7 @@ const { entry } = Astro.props;
|
|||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
<li data-prefix={entry.prefix}>
|
<li data-prefix={entry.prefix}>
|
||||||
<a href={`#${entry.prefix}`}>{entry.title}</a>
|
<a href={`#${entry.prefix}`} class="pressable-link">{entry.title}</a>
|
||||||
{
|
{
|
||||||
entry.children.length > 0 && (
|
entry.children.length > 0 && (
|
||||||
<ol>
|
<ol>
|
||||||
@ -28,21 +28,6 @@ const { entry } = Astro.props;
|
|||||||
<style>
|
<style>
|
||||||
a {
|
a {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
text-decoration: underline dotted 0.1em;
|
|
||||||
text-decoration-color: transparent;
|
|
||||||
|
|
||||||
transition-duration: 150ms;
|
|
||||||
transition-property: text-decoration-color, color;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--color-base-750);
|
|
||||||
text-decoration-color: var(--color-base-650);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: var(--color-base-650);
|
|
||||||
text-decoration-color: var(--color-base-550);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
|
@ -10,19 +10,22 @@ const { tagGroups } = Astro.props;
|
|||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
<div>{tagGroups.map((tag) => <TagGroup {...tag} />)}</div>
|
<div>
|
||||||
|
{tagGroups.map((tag) => <TagGroup {...tag} />)}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div {
|
div {
|
||||||
@media (max-width: 35rem) {
|
|
||||||
margin-block: 5em;
|
|
||||||
gap: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
margin-block: 2em;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 1em;
|
gap: 2em;
|
||||||
|
margin-block: 2em;
|
||||||
|
|
||||||
|
@media (max-width: 35rem) {
|
||||||
|
gap: 3.5em;
|
||||||
|
margin-block: 3.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -138,5 +138,48 @@ export const getI18n = async (locale: string) => {
|
|||||||
return getLocalizedMatch(tag.translations).name;
|
return getLocalizedMatch(tag.translations).name;
|
||||||
};
|
};
|
||||||
|
|
||||||
return { t, getLocalizedMatch, getLocalizedUrl, formatTag, formatTagsGroup };
|
const formatPrice = (price: { amount: number; currency: string }): string =>
|
||||||
|
price.amount.toLocaleString(locale, { style: "currency", currency: price.currency });
|
||||||
|
|
||||||
|
const formatDate = (date: Date): string =>
|
||||||
|
date.toLocaleDateString(locale, { dateStyle: "medium" });
|
||||||
|
|
||||||
|
const formatInches = (sizeInMm: number): string => {
|
||||||
|
return (
|
||||||
|
(sizeInMm * 0.039370078740157).toLocaleString(locale, { maximumFractionDigits: 2 }) + " in"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatMillimeters = (sizeInMm: number): string => {
|
||||||
|
return sizeInMm.toLocaleString(locale, { maximumFractionDigits: 0 }) + " mm";
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatPounds = (weightInGrams: number): string => {
|
||||||
|
return (
|
||||||
|
(weightInGrams * 0.002204623).toLocaleString(locale, { maximumFractionDigits: 2 }) + " lb"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatGrams = (weightInGrams: number): string => {
|
||||||
|
return weightInGrams.toLocaleString(locale, { maximumFractionDigits: 0 }) + " g";
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatNumber = (number: number, options?: Intl.NumberFormatOptions): string => {
|
||||||
|
return number.toLocaleString(locale, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
t,
|
||||||
|
getLocalizedMatch,
|
||||||
|
getLocalizedUrl,
|
||||||
|
formatTag,
|
||||||
|
formatTagsGroup,
|
||||||
|
formatPrice,
|
||||||
|
formatDate,
|
||||||
|
formatInches,
|
||||||
|
formatPounds,
|
||||||
|
formatGrams,
|
||||||
|
formatMillimeters,
|
||||||
|
formatNumber,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -50,4 +50,28 @@ export type WordingKey =
|
|||||||
| "footer.license.description"
|
| "footer.license.description"
|
||||||
| "footer.license.icons.tooltip"
|
| "footer.license.icons.tooltip"
|
||||||
| "footer.disclaimer"
|
| "footer.disclaimer"
|
||||||
| "header.nav.parentPages.label";
|
| "header.nav.parentPages.label"
|
||||||
|
| "collectibles.releaseDate"
|
||||||
|
| "collectibles.size"
|
||||||
|
| "collectibles.size.width"
|
||||||
|
| "collectibles.size.height"
|
||||||
|
| "collectibles.size.thickness"
|
||||||
|
| "collectibles.availability.available"
|
||||||
|
| "collectibles.availability.notAvailable.future"
|
||||||
|
| "collectibles.availability.notAvailable.past"
|
||||||
|
| "collectibles.availability.notAvailable.noPrice"
|
||||||
|
| "collectibles.availability.notAvailable"
|
||||||
|
| "collectibles.price"
|
||||||
|
| "collectibles.price.free"
|
||||||
|
| "collectibles.bookFormat"
|
||||||
|
| "collectibles.bookFormat.pageCount"
|
||||||
|
| "collectibles.bookFormat.binding.paperback"
|
||||||
|
| "collectibles.bookFormat.binding.hardcover"
|
||||||
|
| "collectibles.bookFormat.binding.readingDirection.leftToRight"
|
||||||
|
| "collectibles.bookFormat.binding.readingDirection.rightToLeft"
|
||||||
|
| "collectibles.gallery"
|
||||||
|
| "collectibles.scans"
|
||||||
|
| "collectibles.imageCount"
|
||||||
|
| "header.topbar.settings.tooltip"
|
||||||
|
| "collectibles.contents"
|
||||||
|
| "collectibles.weight";
|
||||||
|
@ -76,9 +76,13 @@ const translation = getLocalizedMatch(page.translations);
|
|||||||
<Credits translators={translation.translators} proofreaders={translation.proofreaders} />
|
<Credits translators={translation.translators} proofreaders={translation.proofreaders} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="when-not-large meta-container">
|
{
|
||||||
<TableOfContent toc={translation.toc} />
|
translation.toc.length > 0 && (
|
||||||
</div>
|
<div class="when-not-large meta-container">
|
||||||
|
<TableOfContent toc={translation.toc} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
<div id="text">
|
<div id="text">
|
||||||
@ -110,10 +114,14 @@ const translation = getLocalizedMatch(page.translations);
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<Credits translators={translation.translators} proofreaders={translation.proofreaders} />
|
<Credits
|
||||||
|
translators={translation.translators}
|
||||||
|
transcribers={translation.transcribers}
|
||||||
|
proofreaders={translation.proofreaders}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TableOfContent toc={translation.toc} />
|
{translation.toc.length > 0 && <TableOfContent toc={translation.toc} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</MasoTarget>
|
</MasoTarget>
|
||||||
|
269
src/pages/[locale]/collectibles/[slug].astro
Normal file
269
src/pages/[locale]/collectibles/[slug].astro
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
---
|
||||||
|
import AppEmptyLayout from "components/AppLayout/AppEmptyLayout.astro";
|
||||||
|
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
|
||||||
|
import RichText from "components/RichText/RichText.astro";
|
||||||
|
import TagGroups from "components/TagGroups.astro";
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
import { payload } from "src/shared/payload/payload-sdk";
|
||||||
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
import ImageTile from "./_components/ImageTile.astro";
|
||||||
|
import PriceInfo from "./_components/PriceInfo.astro";
|
||||||
|
import SizeInfo from "./_components/SizeInfo.astro";
|
||||||
|
import ReleaseDateInfo from "./_components/ReleaseDateInfo.astro";
|
||||||
|
import PageInfo from "./_components/PageInfo.astro";
|
||||||
|
import AvailabilityInfo from "./_components/AvailabilityInfo.astro";
|
||||||
|
import WeightInfo from "./_components/WeightInfo.astro";
|
||||||
|
import SubitemSection from "./_components/SubitemSection.astro";
|
||||||
|
import ContentsSection from "./_components/ContentsSection/ContentsSection.astro";
|
||||||
|
|
||||||
|
const { slug } = Astro.params;
|
||||||
|
const { getLocalizedMatch, t } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
|
||||||
|
const collectible = await fetchOr404(() => payload.getCollectible(slug!));
|
||||||
|
if (collectible instanceof Response) {
|
||||||
|
return collectible;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
translations,
|
||||||
|
thumbnail,
|
||||||
|
size,
|
||||||
|
price,
|
||||||
|
releaseDate,
|
||||||
|
pageInfo,
|
||||||
|
urls,
|
||||||
|
weight,
|
||||||
|
backgroundImage,
|
||||||
|
gallery,
|
||||||
|
scans,
|
||||||
|
subitems,
|
||||||
|
parentPages,
|
||||||
|
tagGroups,
|
||||||
|
contents,
|
||||||
|
} = collectible;
|
||||||
|
|
||||||
|
const translation = getLocalizedMatch(translations);
|
||||||
|
|
||||||
|
const galleryFirstImage = gallery[0];
|
||||||
|
const scansFirstImage = scans[0];
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<AppEmptyLayout
|
||||||
|
parentPages={parentPages}
|
||||||
|
backgroundIllustration={backgroundImage?.url ?? thumbnail?.url}>
|
||||||
|
<div id="layout">
|
||||||
|
<div id="left">
|
||||||
|
<AppLayoutTitle
|
||||||
|
title={translation.title}
|
||||||
|
pretitle={translation.pretitle}
|
||||||
|
subtitle={translation.subtitle}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div id="images" class="when-not-large">
|
||||||
|
{
|
||||||
|
thumbnail && (
|
||||||
|
<img
|
||||||
|
id="thumbnail"
|
||||||
|
src={thumbnail.url}
|
||||||
|
width={thumbnail.width}
|
||||||
|
height={thumbnail.height}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
<div id="gallery-scans" class="when-no-print">
|
||||||
|
{
|
||||||
|
galleryFirstImage && (
|
||||||
|
<ImageTile
|
||||||
|
image={galleryFirstImage.url}
|
||||||
|
title="Gallery"
|
||||||
|
subtitle={`${gallery.length} images`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
scansFirstImage && (
|
||||||
|
<ImageTile
|
||||||
|
image={scansFirstImage.url}
|
||||||
|
title="Scans"
|
||||||
|
subtitle={`${scans.length} images`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
translation.description && (
|
||||||
|
<div id="summary" class="high-contrast-text">
|
||||||
|
<RichText content={translation.description} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
<TagGroups tagGroups={tagGroups}>
|
||||||
|
{releaseDate && <ReleaseDateInfo releaseDate={releaseDate} />}
|
||||||
|
|
||||||
|
{price && <PriceInfo price={price} />}
|
||||||
|
|
||||||
|
<AvailabilityInfo urls={urls} price={price !== undefined} releaseDate={releaseDate} />
|
||||||
|
|
||||||
|
{size && <SizeInfo size={size} />}
|
||||||
|
|
||||||
|
{weight && <WeightInfo weight={weight} />}
|
||||||
|
|
||||||
|
{pageInfo && <PageInfo pageInfo={pageInfo} />}
|
||||||
|
</TagGroups>
|
||||||
|
|
||||||
|
{subitems.length > 0 && <SubitemSection subitems={subitems} />}
|
||||||
|
|
||||||
|
{contents.length > 0 && <ContentsSection contents={contents} />}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="right" class="when-large">
|
||||||
|
<div id="images">
|
||||||
|
<div id="gallery-scans" class="when-no-print">
|
||||||
|
{
|
||||||
|
galleryFirstImage && (
|
||||||
|
<ImageTile
|
||||||
|
image={galleryFirstImage.url}
|
||||||
|
title={t("collectibles.gallery")}
|
||||||
|
subtitle={t("collectibles.imageCount", { count: gallery.length })}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
scansFirstImage && (
|
||||||
|
<ImageTile
|
||||||
|
image={scansFirstImage.url}
|
||||||
|
title={t("collectibles.scans")}
|
||||||
|
subtitle={t("collectibles.imageCount", { count: scans.length })}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
thumbnail && (
|
||||||
|
<img
|
||||||
|
id="thumbnail"
|
||||||
|
src={thumbnail.url}
|
||||||
|
width={thumbnail.width}
|
||||||
|
height={thumbnail.height}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AppEmptyLayout>
|
||||||
|
|
||||||
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#layout {
|
||||||
|
display: grid;
|
||||||
|
justify-content: space-between;
|
||||||
|
container-type: inline-size;
|
||||||
|
|
||||||
|
@media (min-width: 80rem) {
|
||||||
|
grid-template-columns: 35rem 35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #left {
|
||||||
|
& > #images {
|
||||||
|
display: grid;
|
||||||
|
place-content: start;
|
||||||
|
place-items: start;
|
||||||
|
margin-block: 2em;
|
||||||
|
gap: clamp(1em, 0.5em + 3vw, 2em);
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
|
@media (max-width: 23rem) {
|
||||||
|
gap: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 52rem) {
|
||||||
|
grid-template-columns: 35rem 10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #thumbnail {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
box-shadow: 0 5px 20px -10px var(--color-shadow);
|
||||||
|
max-width: 35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #gallery-scans {
|
||||||
|
display: flex;
|
||||||
|
max-width: 35rem;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2.5em;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
> :global(div) {
|
||||||
|
aspect-ratio: 2 / 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 23rem) {
|
||||||
|
gap: clamp(1em, 0.5em + 3vw, 2em);
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
> :global(div) {
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 52rem) {
|
||||||
|
max-width: 15rem;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #summary {
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
padding: 1.5em;
|
||||||
|
margin: -1.5em;
|
||||||
|
margin-block: 1em;
|
||||||
|
border-radius: 3em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #right {
|
||||||
|
& > #images {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 10rem 1fr;
|
||||||
|
gap: 1em;
|
||||||
|
|
||||||
|
& > #gallery-scans {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #thumbnail {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
box-shadow: 0 5px 20px -10px var(--color-shadow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.when-large {
|
||||||
|
@media (max-width: 80rem) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.when-not-large {
|
||||||
|
@media (min-width: 80rem) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,106 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
import type { EndpointCollectible } from "src/shared/payload/payload-sdk";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
urls: EndpointCollectible["urls"];
|
||||||
|
releaseDate?: string | undefined;
|
||||||
|
price?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { price = false, urls, releaseDate } = Astro.props;
|
||||||
|
const { t } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
|
||||||
|
const title = (() => {
|
||||||
|
if (urls.length > 0) return t("collectibles.availability.available");
|
||||||
|
|
||||||
|
if (price) {
|
||||||
|
if (!releaseDate) return t("collectibles.availability.notAvailable");
|
||||||
|
const release = new Date(releaseDate);
|
||||||
|
if (release > new Date()) {
|
||||||
|
return t("collectibles.availability.notAvailable.future");
|
||||||
|
} else {
|
||||||
|
return t("collectibles.availability.notAvailable.past");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return t("collectibles.availability.notAvailable.noPrice");
|
||||||
|
})();
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<div id="container">
|
||||||
|
<div id="title">
|
||||||
|
<Icon name="material-symbols:shopping-cart-outline" width={24} height={24} />
|
||||||
|
<p>{title}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
urls.length > 0 && (
|
||||||
|
<div id="values">
|
||||||
|
{urls.map(({ label, url }) => (
|
||||||
|
<a target="_blank" rel="noopener noreferrer" href={url}>
|
||||||
|
{label}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #values {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 0.35em;
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
border: 1px solid var(--color-base-1000);
|
||||||
|
border-radius: 9999px;
|
||||||
|
padding-top: 0.15em;
|
||||||
|
padding-bottom: 0.25em;
|
||||||
|
padding-inline: 0.6em;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
|
||||||
|
transition-duration: 150ms;
|
||||||
|
transition-property: border-color, color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-base-750);
|
||||||
|
border-color: var(--color-base-750);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: var(--color-base-650);
|
||||||
|
border-color: var(--color-base-650);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,93 @@
|
|||||||
|
---
|
||||||
|
import ErrorMessage from "components/ErrorMessage.astro";
|
||||||
|
import RichText from "components/RichText/RichText.astro";
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
import type { EndpointCollectible } from "src/shared/payload/payload-sdk";
|
||||||
|
import { formatInlineTitle } from "src/utils/format";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
content: EndpointCollectible["contents"][number];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { getLocalizedMatch, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
const {
|
||||||
|
content: { content, range },
|
||||||
|
} = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<div id="row">
|
||||||
|
<div id="title">
|
||||||
|
{
|
||||||
|
content.relationTo === "generic-contents" ? (
|
||||||
|
<p>{getLocalizedMatch(content.value.translations).name}</p>
|
||||||
|
) : content.relationTo === "pages" ? (
|
||||||
|
<a href={getLocalizedUrl(`/pages/${content.value.slug}`)} class="pressable-link">
|
||||||
|
{formatInlineTitle(getLocalizedMatch(content.value.translations))}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<ErrorMessage
|
||||||
|
title="Unknown content type"
|
||||||
|
description="Please contact website technical administrator."
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="dots"></div>
|
||||||
|
|
||||||
|
<div id="range">
|
||||||
|
{
|
||||||
|
range && (
|
||||||
|
<>
|
||||||
|
{range.type === "pageRange" ? (
|
||||||
|
range.start
|
||||||
|
) : range.type === "timeRange" ? (
|
||||||
|
range.start
|
||||||
|
) : range.type === "other" ? (
|
||||||
|
<RichText content={getLocalizedMatch(range.translations).note} />
|
||||||
|
) : (
|
||||||
|
<ErrorMessage
|
||||||
|
title="Unknown range type"
|
||||||
|
description="Please contact website technical administrator."
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
gap: 1em;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1em;
|
||||||
|
border-radius: 1em;
|
||||||
|
box-shadow: 0 1px 2px 0 var(--color-shadow-2);
|
||||||
|
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: color-mix(in srgb, var(--color-elevation-2) 50%, transparent);
|
||||||
|
|
||||||
|
border-top: 1px solid var(--color-elevation-2);
|
||||||
|
|
||||||
|
& > #title {
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #dots {
|
||||||
|
width: 100%;
|
||||||
|
min-width: clamp(1em, 0.5em + 5vw, 5em);
|
||||||
|
border-bottom: 0.15em dotted var(--color-base-500);
|
||||||
|
height: 0.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
# > #range {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import type { EndpointCollectible } from "src/shared/payload/payload-sdk";
|
||||||
|
import ContentRow from "./ContentRow.astro";
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
contents: EndpointCollectible["contents"];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { contents } = Astro.props;
|
||||||
|
const { t } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<div id="title">
|
||||||
|
<Icon name="material-symbols:list-alt-outline" width={24} height={24} />
|
||||||
|
<p>{t("collectibles.contents")}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="contents">
|
||||||
|
{contents.map((content) => <ContentRow content={content} />)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#title {
|
||||||
|
margin-top: 6em;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
place-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
& > p {
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#contents {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
58
src/pages/[locale]/collectibles/_components/ImageTile.astro
Normal file
58
src/pages/[locale]/collectibles/_components/ImageTile.astro
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
image: string;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { image, title, subtitle } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<div id="tile">
|
||||||
|
<img src={image} />
|
||||||
|
|
||||||
|
<div class="high-contrast-text">
|
||||||
|
<p class="title">{title}</p>
|
||||||
|
<p>{subtitle}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#tile {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
display: grid;
|
||||||
|
background-color: var(--color-elevation-0);
|
||||||
|
place-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 5px 20px -10px var(--color-shadow);
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
text-align: center;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
padding: 1em;
|
||||||
|
border-radius: 1em;
|
||||||
|
|
||||||
|
& > .title {
|
||||||
|
font-size: 130%;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > img {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0.5;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
87
src/pages/[locale]/collectibles/_components/PageInfo.astro
Normal file
87
src/pages/[locale]/collectibles/_components/PageInfo.astro
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
import {
|
||||||
|
CollectibleBindingTypes,
|
||||||
|
CollectiblePageOrders,
|
||||||
|
type EndpointCollectible,
|
||||||
|
} from "src/shared/payload/payload-sdk";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
pageInfo: NonNullable<EndpointCollectible["pageInfo"]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
pageInfo: { pageCount, bindingType, pageOrder },
|
||||||
|
} = Astro.props;
|
||||||
|
|
||||||
|
const { t } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<div id="container">
|
||||||
|
<div id="title">
|
||||||
|
<Icon name="material-symbols:note-stack-outline" width={24} height={24} />
|
||||||
|
<p>{t("collectibles.bookFormat")}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="values">
|
||||||
|
<p>{t("collectibles.bookFormat.pageCount", { count: pageCount })}</p>
|
||||||
|
{
|
||||||
|
bindingType && (
|
||||||
|
<p>
|
||||||
|
{t(
|
||||||
|
bindingType === CollectibleBindingTypes.Hardcover
|
||||||
|
? "collectibles.bookFormat.binding.hardcover"
|
||||||
|
: "collectibles.bookFormat.binding.paperback"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
pageOrder && (
|
||||||
|
<p>
|
||||||
|
{t(
|
||||||
|
pageOrder === CollectiblePageOrders.LeftToRight
|
||||||
|
? "collectibles.bookFormat.binding.readingDirection.leftToRight"
|
||||||
|
: "collectibles.bookFormat.binding.readingDirection.rightToLeft"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #values {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
70
src/pages/[locale]/collectibles/_components/PriceInfo.astro
Normal file
70
src/pages/[locale]/collectibles/_components/PriceInfo.astro
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
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>
|
@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
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>
|
91
src/pages/[locale]/collectibles/_components/SizeInfo.astro
Normal file
91
src/pages/[locale]/collectibles/_components/SizeInfo.astro
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
size: {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
thickness?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { size } = Astro.props;
|
||||||
|
|
||||||
|
const { formatInches, formatMillimeters, t } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<div id="size">
|
||||||
|
<div id="title">
|
||||||
|
<Icon name="material-symbols:measuring-tape-outline" width={24} height={24} />
|
||||||
|
<p>{t("collectibles.size")}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="values">
|
||||||
|
<div>
|
||||||
|
<p>{t("collectibles.size.width")}</p>
|
||||||
|
<p>{formatMillimeters(size.width)}</p>
|
||||||
|
<p>{formatInches(size.width)}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>{t("collectibles.size.height")}</p>
|
||||||
|
<p>{formatMillimeters(size.height)}</p>
|
||||||
|
<p>{formatInches(size.height)}</p>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
size.thickness && (
|
||||||
|
<div>
|
||||||
|
<p>{t("collectibles.size.thickness")}</p>
|
||||||
|
<p>{formatMillimeters(size.thickness)}</p>
|
||||||
|
<p>{formatInches(size.thickness)}</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#size {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
gap: 1em 2em;
|
||||||
|
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;
|
||||||
|
translate: 0px -0.1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #values {
|
||||||
|
display: flex;
|
||||||
|
gap: 1em 1.5em;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.6em;
|
||||||
|
|
||||||
|
& > p:first-child {
|
||||||
|
font-size: 120%;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import CollectiblePreview from "components/Previews/CollectiblePreview.astro";
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
import type { EndpointCollectible } from "src/shared/payload/payload-sdk";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
subitems: EndpointCollectible["subitems"];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { subitems } = Astro.props;
|
||||||
|
const { t } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<div id="title">
|
||||||
|
<Icon name="material-symbols:box-outline" width={24} height={24} />
|
||||||
|
<p>{t("collectibles.contents")}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="values">
|
||||||
|
{subitems.map((subitem) => <CollectiblePreview collectible={subitem} />)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#title {
|
||||||
|
margin-top: 6em;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
place-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
& > p {
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#values {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
|
gap: clamp(6px, 2vmin, 16px);
|
||||||
|
}
|
||||||
|
</style>
|
52
src/pages/[locale]/collectibles/_components/WeightInfo.astro
Normal file
52
src/pages/[locale]/collectibles/_components/WeightInfo.astro
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
weight: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { weight } = Astro.props;
|
||||||
|
const { formatPounds, formatGrams, t } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
|
<div id="container">
|
||||||
|
<div id="title">
|
||||||
|
<Icon name="material-symbols:scale-outline" width={24} height={24} />
|
||||||
|
<p>{t("collectibles.weight")}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>{formatGrams(weight)}{" "}({formatPounds(weight)})</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>
|
@ -6,9 +6,11 @@ import FoldersSection from "./_components/FoldersSection.astro";
|
|||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
import ErrorMessage from "components/ErrorMessage.astro";
|
import ErrorMessage from "components/ErrorMessage.astro";
|
||||||
import { getI18n } from "src/i18n/i18n";
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
import CollectiblePreview from "components/Previews/CollectiblePreview.astro";
|
||||||
|
import PagePreview from "components/Previews/PagePreview.astro";
|
||||||
|
|
||||||
const { slug } = Astro.params;
|
const { slug } = Astro.params;
|
||||||
const { getLocalizedMatch, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
const { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
|
||||||
const folder = await fetchOr404(() => payload.getFolder(slug!));
|
const folder = await fetchOr404(() => payload.getFolder(slug!));
|
||||||
if (folder instanceof Response) {
|
if (folder instanceof Response) {
|
||||||
@ -50,19 +52,15 @@ const meta = getLocalizedMatch(folder.translations);
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
<div>
|
<div id="files">
|
||||||
{
|
{
|
||||||
folder.files.map(({ relationTo, value }) => {
|
folder.files.map(({ relationTo, value }) => {
|
||||||
switch (relationTo) {
|
switch (relationTo) {
|
||||||
case "library-items":
|
case "collectibles":
|
||||||
return <p>Library item not supported yet! {value.slug}</p>;
|
return <CollectiblePreview collectible={value} />;
|
||||||
|
|
||||||
case "pages":
|
case "pages":
|
||||||
return (
|
return <PagePreview page={value} />;
|
||||||
<a class="pressable" href={getLocalizedUrl(`/pages/${value.slug}`)}>
|
|
||||||
{value.slug}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
@ -85,9 +83,16 @@ const meta = getLocalizedMatch(folder.translations);
|
|||||||
display: grid;
|
display: grid;
|
||||||
gap: 4em;
|
gap: 4em;
|
||||||
|
|
||||||
#sections {
|
& > #sections {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 2.5em;
|
gap: 2.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& > #files {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||||
|
gap: clamp(6px, 2vmin, 16px);
|
||||||
|
place-items: start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -14,7 +14,7 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
|||||||
|
|
||||||
<AppLayout
|
<AppLayout
|
||||||
title="Accord’s Library"
|
title="Accord’s Library"
|
||||||
backgroundIllustration="/img/bg-home2.webp"
|
backgroundIllustration="/img/background-image.webp"
|
||||||
hideFooterLinks
|
hideFooterLinks
|
||||||
hideHomeButton>
|
hideHomeButton>
|
||||||
<div id="title" slot="header-title">
|
<div id="title" slot="header-title">
|
||||||
|
@ -14,6 +14,8 @@ if (page instanceof Response) {
|
|||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||||
|
|
||||||
<AppEmptyLayout parentPages={page.parentPages} backgroundIllustration={page.thumbnail?.url}>
|
<AppEmptyLayout
|
||||||
|
parentPages={page.parentPages}
|
||||||
|
backgroundIllustration={page.backgroundImage?.url ?? page.thumbnail?.url}>
|
||||||
<Page slug={page.slug} lang={Astro.locals.currentLocale} page={page} />
|
<Page slug={page.slug} lang={Astro.locals.currentLocale} page={page} />
|
||||||
</AppEmptyLayout>
|
</AppEmptyLayout>
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
import AppLayout from "components/AppLayout/AppLayout.astro";
|
import AppLayout from "components/AppLayout/AppLayout.astro";
|
||||||
import { getI18n } from "src/i18n/i18n";
|
import { getI18n } from "src/i18n/i18n";
|
||||||
import { cache } from "src/utils/cachedPayload";
|
import { cache } from "src/utils/cachedPayload";
|
||||||
|
import { formatCurrency } from "src/utils/currencies";
|
||||||
|
import { formatLocale } from "src/utils/format";
|
||||||
|
|
||||||
const { currentLocale, currentTheme, currentCurrency } = Astro.locals;
|
const { currentLocale, currentTheme, currentCurrency } = Astro.locals;
|
||||||
const { t } = await getI18n(currentLocale);
|
const { t } = await getI18n(currentLocale);
|
||||||
@ -20,7 +22,7 @@ const { t } = await getI18n(currentLocale);
|
|||||||
class:list={{ current: currentLocale === id }}
|
class:list={{ current: currentLocale === id }}
|
||||||
href={`?action-lang=${id}`}
|
href={`?action-lang=${id}`}
|
||||||
data-astro-prefetch="tap">
|
data-astro-prefetch="tap">
|
||||||
{id}
|
{formatLocale(id)}
|
||||||
</a>
|
</a>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -50,15 +52,15 @@ const { t } = await getI18n(currentLocale);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h2>{t("settings.theme.title")}</h2>
|
<h2>{t("settings.currency.title")}</h2>
|
||||||
<p>{t("settings.theme.description")}</p><br />
|
<p>{t("settings.currency.description")}</p><br />
|
||||||
{
|
{
|
||||||
cache.currencies.map((id) => (
|
cache.currencies.map((id) => (
|
||||||
<a
|
<a
|
||||||
class:list={{ current: currentCurrency === id }}
|
class:list={{ current: currentCurrency === id }}
|
||||||
href={`?action-currency=${id}`}
|
href={`?action-currency=${id}`}
|
||||||
data-astro-prefetch="tap">
|
data-astro-prefetch="tap">
|
||||||
{id}
|
{`${id} (${formatCurrency(id)})`}
|
||||||
</a>
|
</a>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -72,6 +74,7 @@ const { t } = await getI18n(currentLocale);
|
|||||||
.section {
|
.section {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
align-items: start;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
|
|
||||||
& > .current {
|
& > .current {
|
||||||
|
@ -35,41 +35,35 @@ export type RecorderBiographies =
|
|||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "CategoryTranslations".
|
* via the `definition` "CategoryTranslations".
|
||||||
*/
|
*/
|
||||||
export type CategoryTranslations =
|
export type CategoryTranslations = {
|
||||||
| {
|
language: string | Language;
|
||||||
language: string | Language;
|
name: string;
|
||||||
name: string;
|
id?: string | null;
|
||||||
id?: string | null;
|
}[];
|
||||||
}[]
|
|
||||||
| null;
|
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
collections: {
|
collections: {
|
||||||
folders: Folder;
|
folders: Folder;
|
||||||
'folders-thumbnails': FoldersThumbnail;
|
'folders-thumbnails': FoldersThumbnail;
|
||||||
'library-items': LibraryItem;
|
|
||||||
pages: Page;
|
pages: Page;
|
||||||
'chronology-items': ChronologyItem;
|
'chronology-items': ChronologyItem;
|
||||||
'chronology-eras': ChronologyEra;
|
'chronology-eras': ChronologyEra;
|
||||||
weapons: Weapon;
|
weapons: Weapon;
|
||||||
'weapons-groups': WeaponsGroup;
|
'weapons-groups': WeaponsGroup;
|
||||||
'weapons-thumbnails': WeaponsThumbnail;
|
'weapons-thumbnails': WeaponsThumbnail;
|
||||||
'library-items-thumbnails': LibraryItemThumbnail;
|
|
||||||
'library-items-scans': LibraryItemScans;
|
|
||||||
'library-items-gallery': LibraryItemGallery;
|
|
||||||
'recorders-thumbnails': RecordersThumbnail;
|
'recorders-thumbnails': RecordersThumbnail;
|
||||||
files: File;
|
|
||||||
notes: Note;
|
notes: Note;
|
||||||
videos: Video;
|
videos: Video;
|
||||||
'videos-channels': VideosChannel;
|
'videos-channels': VideosChannel;
|
||||||
languages: Language;
|
languages: Language;
|
||||||
currencies: Currency;
|
currencies: Currency;
|
||||||
recorders: Recorder;
|
recorders: Recorder;
|
||||||
keys: Key;
|
|
||||||
tags: Tag;
|
tags: Tag;
|
||||||
'tags-groups': TagsGroup;
|
'tags-groups': TagsGroup;
|
||||||
images: Image;
|
images: Image;
|
||||||
wordings: Wording;
|
wordings: Wording;
|
||||||
|
collectibles: Collectible;
|
||||||
|
'generic-contents': GenericContent;
|
||||||
'payload-preferences': PayloadPreference;
|
'payload-preferences': PayloadPreference;
|
||||||
'payload-migrations': PayloadMigration;
|
'payload-migrations': PayloadMigration;
|
||||||
};
|
};
|
||||||
@ -123,8 +117,8 @@ export interface Folder {
|
|||||||
files?:
|
files?:
|
||||||
| (
|
| (
|
||||||
| {
|
| {
|
||||||
relationTo: 'library-items';
|
relationTo: 'collectibles';
|
||||||
value: string | LibraryItem;
|
value: string | Collectible;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
relationTo: 'pages';
|
relationTo: 'pages';
|
||||||
@ -170,21 +164,41 @@ export interface Language {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "library-items".
|
* via the `definition` "collectibles".
|
||||||
*/
|
*/
|
||||||
export interface LibraryItem {
|
export interface Collectible {
|
||||||
id: string;
|
id: string;
|
||||||
itemType?: ('Textual' | 'Audio' | 'Video' | 'Game' | 'Other') | null;
|
|
||||||
language: string | Language;
|
|
||||||
slug: string;
|
slug: string;
|
||||||
thumbnail?: string | LibraryItemThumbnail | null;
|
thumbnail?: string | Image | null;
|
||||||
pretitle?: string | null;
|
nature: 'Physical' | 'Digital';
|
||||||
title: string;
|
languages?: (string | Language)[] | null;
|
||||||
subtitle?: string | null;
|
tags?: (string | Tag)[] | null;
|
||||||
digital: boolean;
|
translations: {
|
||||||
|
language: string | Language;
|
||||||
|
pretitle?: string | null;
|
||||||
|
title: string;
|
||||||
|
subtitle?: string | null;
|
||||||
|
description?: {
|
||||||
|
root: {
|
||||||
|
children: {
|
||||||
|
type: string;
|
||||||
|
version: number;
|
||||||
|
[k: string]: unknown;
|
||||||
|
}[];
|
||||||
|
direction: ('ltr' | 'rtl') | null;
|
||||||
|
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||||
|
indent: number;
|
||||||
|
type: string;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
[k: string]: unknown;
|
||||||
|
} | null;
|
||||||
|
id?: string | null;
|
||||||
|
}[];
|
||||||
|
backgroundImage?: string | Image | null;
|
||||||
gallery?:
|
gallery?:
|
||||||
| {
|
| {
|
||||||
image?: string | LibraryItemGallery | null;
|
image: string | Image;
|
||||||
id?: string | null;
|
id?: string | null;
|
||||||
}[]
|
}[]
|
||||||
| null;
|
| null;
|
||||||
@ -195,141 +209,136 @@ export interface LibraryItem {
|
|||||||
typesetters?: (string | Recorder)[] | null;
|
typesetters?: (string | Recorder)[] | null;
|
||||||
coverEnabled?: boolean | null;
|
coverEnabled?: boolean | null;
|
||||||
cover?: {
|
cover?: {
|
||||||
front?: string | LibraryItemScans | null;
|
front?: string | Image | null;
|
||||||
spine?: string | LibraryItemScans | null;
|
spine?: string | Image | null;
|
||||||
back?: string | LibraryItemScans | null;
|
back?: string | Image | null;
|
||||||
insideFront?: string | LibraryItemScans | null;
|
insideFront?: string | Image | null;
|
||||||
insideBack?: string | LibraryItemScans | null;
|
insideBack?: string | Image | null;
|
||||||
flapFront?: string | LibraryItemScans | null;
|
flapFront?: string | Image | null;
|
||||||
flapBack?: string | LibraryItemScans | null;
|
flapBack?: string | Image | null;
|
||||||
insideFlapFront?: string | LibraryItemScans | null;
|
insideFlapFront?: string | Image | null;
|
||||||
insideFlapBack?: string | LibraryItemScans | null;
|
insideFlapBack?: string | Image | null;
|
||||||
};
|
};
|
||||||
dustjacketEnabled?: boolean | null;
|
dustjacketEnabled?: boolean | null;
|
||||||
dustjacket?: {
|
dustjacket?: {
|
||||||
front?: string | LibraryItemScans | null;
|
front?: string | Image | null;
|
||||||
spine?: string | LibraryItemScans | null;
|
spine?: string | Image | null;
|
||||||
back?: string | LibraryItemScans | null;
|
back?: string | Image | null;
|
||||||
insideFront?: string | LibraryItemScans | null;
|
insideFront?: string | Image | null;
|
||||||
insideSpine?: string | LibraryItemScans | null;
|
insideSpine?: string | Image | null;
|
||||||
insideBack?: string | LibraryItemScans | null;
|
insideBack?: string | Image | null;
|
||||||
flapFront?: string | LibraryItemScans | null;
|
flapFront?: string | Image | null;
|
||||||
flapBack?: string | LibraryItemScans | null;
|
flapBack?: string | Image | null;
|
||||||
insideFlapFront?: string | LibraryItemScans | null;
|
insideFlapFront?: string | Image | null;
|
||||||
insideFlapBack?: string | LibraryItemScans | null;
|
insideFlapBack?: string | Image | null;
|
||||||
};
|
};
|
||||||
obiEnabled?: boolean | null;
|
obiEnabled?: boolean | null;
|
||||||
obi?: {
|
obi?: {
|
||||||
front?: string | LibraryItemScans | null;
|
front?: string | Image | null;
|
||||||
spine?: string | LibraryItemScans | null;
|
spine?: string | Image | null;
|
||||||
back?: string | LibraryItemScans | null;
|
back?: string | Image | null;
|
||||||
insideFront?: string | LibraryItemScans | null;
|
insideFront?: string | Image | null;
|
||||||
insideSpine?: string | LibraryItemScans | null;
|
insideSpine?: string | Image | null;
|
||||||
insideBack?: string | LibraryItemScans | null;
|
insideBack?: string | Image | null;
|
||||||
flapFront?: string | LibraryItemScans | null;
|
flapFront?: string | Image | null;
|
||||||
flapBack?: string | LibraryItemScans | null;
|
flapBack?: string | Image | null;
|
||||||
insideFlapFront?: string | LibraryItemScans | null;
|
insideFlapFront?: string | Image | null;
|
||||||
insideFlapBack?: string | LibraryItemScans | null;
|
insideFlapBack?: string | Image | null;
|
||||||
};
|
};
|
||||||
pages?:
|
pages?:
|
||||||
| {
|
| {
|
||||||
page: number;
|
page: number;
|
||||||
image: string | LibraryItemScans;
|
image: string | Image;
|
||||||
id?: string | null;
|
|
||||||
}[]
|
|
||||||
| null;
|
|
||||||
archiveFile?: (string | null) | File;
|
|
||||||
};
|
|
||||||
textual?: {
|
|
||||||
subtype?: (string | null) | Key;
|
|
||||||
pageCount?: number | null;
|
|
||||||
bindingType?: ('Paperback' | 'Hardcover') | null;
|
|
||||||
pageOrder?: ('LeftToRight' | 'RightToLeft') | null;
|
|
||||||
};
|
|
||||||
audio?: {
|
|
||||||
audioSubtype?: (string | null) | Key;
|
|
||||||
tracks?:
|
|
||||||
| {
|
|
||||||
title: string;
|
|
||||||
file: string | File;
|
|
||||||
id?: string | null;
|
id?: string | null;
|
||||||
}[]
|
}[]
|
||||||
| null;
|
| null;
|
||||||
};
|
};
|
||||||
video?: {
|
|
||||||
subtype?: (string | null) | Key;
|
|
||||||
};
|
|
||||||
game?: {
|
|
||||||
demo?: boolean | null;
|
|
||||||
platform?: (string | null) | Key;
|
|
||||||
audioLanguages?: (string | Language)[] | null;
|
|
||||||
subtitleLanguages?: (string | Language)[] | null;
|
|
||||||
interfacesLanguages?: (string | Language)[] | null;
|
|
||||||
};
|
|
||||||
releaseDate?: string | null;
|
|
||||||
categories?: (string | Key)[] | null;
|
|
||||||
sizeEnabled?: boolean | null;
|
|
||||||
size?: {
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
thickness?: number | null;
|
|
||||||
};
|
|
||||||
priceEnabled?: boolean | null;
|
|
||||||
price?: {
|
|
||||||
amount: number;
|
|
||||||
currency: string | Currency;
|
|
||||||
};
|
|
||||||
translations?:
|
|
||||||
| {
|
|
||||||
language: string | Language;
|
|
||||||
description: {
|
|
||||||
root: {
|
|
||||||
children: {
|
|
||||||
type: string;
|
|
||||||
version: number;
|
|
||||||
[k: string]: unknown;
|
|
||||||
}[];
|
|
||||||
direction: ('ltr' | 'rtl') | null;
|
|
||||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
|
||||||
indent: number;
|
|
||||||
type: string;
|
|
||||||
version: number;
|
|
||||||
};
|
|
||||||
[k: string]: unknown;
|
|
||||||
};
|
|
||||||
id?: string | null;
|
|
||||||
}[]
|
|
||||||
| null;
|
|
||||||
urls?:
|
urls?:
|
||||||
| {
|
| {
|
||||||
url: string;
|
url: string;
|
||||||
id?: string | null;
|
id?: string | null;
|
||||||
}[]
|
}[]
|
||||||
| null;
|
| null;
|
||||||
parentItems?: (string | LibraryItem)[] | null;
|
releaseDate?: string | null;
|
||||||
subitems?: (string | LibraryItem)[] | null;
|
priceEnabled?: boolean | null;
|
||||||
|
price?: {
|
||||||
|
amount: number;
|
||||||
|
currency: string | Currency;
|
||||||
|
};
|
||||||
|
sizeEnabled?: boolean | null;
|
||||||
|
size?: {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
thickness?: number | null;
|
||||||
|
};
|
||||||
|
weightEnabled?: boolean | null;
|
||||||
|
weight?: {
|
||||||
|
amount: number;
|
||||||
|
};
|
||||||
|
pageInfoEnabled?: boolean | null;
|
||||||
|
pageInfo?: {
|
||||||
|
pageCount: number;
|
||||||
|
bindingType?: ('Paperback' | 'Hardcover') | null;
|
||||||
|
pageOrder?: ('Left to right' | 'Right to left') | null;
|
||||||
|
};
|
||||||
|
folders?: (string | Folder)[] | null;
|
||||||
|
parentItems?: (string | Collectible)[] | null;
|
||||||
|
subitems?: (string | Collectible)[] | null;
|
||||||
contents?:
|
contents?:
|
||||||
| {
|
| {
|
||||||
content: string | Page;
|
content:
|
||||||
pageStart?: number | null;
|
| {
|
||||||
pageEnd?: number | null;
|
relationTo: 'pages';
|
||||||
timeStart?: number | null;
|
value: string | Page;
|
||||||
timeEnd?: number | null;
|
}
|
||||||
note?: {
|
| {
|
||||||
root: {
|
relationTo: 'generic-contents';
|
||||||
children: {
|
value: string | GenericContent;
|
||||||
type: string;
|
};
|
||||||
version: number;
|
range?:
|
||||||
[k: string]: unknown;
|
| (
|
||||||
}[];
|
| {
|
||||||
direction: ('ltr' | 'rtl') | null;
|
start: number;
|
||||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
end: number;
|
||||||
indent: number;
|
id?: string | null;
|
||||||
type: string;
|
blockName?: string | null;
|
||||||
version: number;
|
blockType: 'pageRange';
|
||||||
};
|
}
|
||||||
[k: string]: unknown;
|
| {
|
||||||
} | null;
|
start: string;
|
||||||
|
end: string;
|
||||||
|
id?: string | null;
|
||||||
|
blockName?: string | null;
|
||||||
|
blockType: 'timeRange';
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
translations?:
|
||||||
|
| {
|
||||||
|
language: string | Language;
|
||||||
|
note: {
|
||||||
|
root: {
|
||||||
|
children: {
|
||||||
|
type: string;
|
||||||
|
version: number;
|
||||||
|
[k: string]: unknown;
|
||||||
|
}[];
|
||||||
|
direction: ('ltr' | 'rtl') | null;
|
||||||
|
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||||
|
indent: number;
|
||||||
|
type: string;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
[k: string]: unknown;
|
||||||
|
};
|
||||||
|
id?: string | null;
|
||||||
|
}[]
|
||||||
|
| null;
|
||||||
|
id?: string | null;
|
||||||
|
blockName?: string | null;
|
||||||
|
blockType: 'other';
|
||||||
|
}
|
||||||
|
)[]
|
||||||
|
| null;
|
||||||
id?: string | null;
|
id?: string | null;
|
||||||
}[]
|
}[]
|
||||||
| null;
|
| null;
|
||||||
@ -340,11 +349,10 @@ export interface LibraryItem {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "library-items-thumbnails".
|
* via the `definition` "images".
|
||||||
*/
|
*/
|
||||||
export interface LibraryItemThumbnail {
|
export interface Image {
|
||||||
id: string;
|
id: string;
|
||||||
libraryItem?: (string | LibraryItem)[] | null;
|
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
url?: string | null;
|
url?: string | null;
|
||||||
@ -370,48 +378,40 @@ export interface LibraryItemThumbnail {
|
|||||||
filesize?: number | null;
|
filesize?: number | null;
|
||||||
filename?: string | null;
|
filename?: string | null;
|
||||||
};
|
};
|
||||||
square?: {
|
|
||||||
url?: string | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
filename?: string | null;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "library-items-gallery".
|
* via the `definition` "tags".
|
||||||
*/
|
*/
|
||||||
export interface LibraryItemGallery {
|
export interface Tag {
|
||||||
id: string;
|
id: string;
|
||||||
|
name?: string | null;
|
||||||
|
slug: string;
|
||||||
|
translations: {
|
||||||
|
language: string | Language;
|
||||||
|
name: string;
|
||||||
|
id?: string | null;
|
||||||
|
}[];
|
||||||
|
group: string | TagsGroup;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "tags-groups".
|
||||||
|
*/
|
||||||
|
export interface TagsGroup {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
icon?: string | null;
|
||||||
|
translations: {
|
||||||
|
language: string | Language;
|
||||||
|
name: string;
|
||||||
|
id?: string | null;
|
||||||
|
}[];
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
url?: string | null;
|
|
||||||
filename?: string | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
sizes?: {
|
|
||||||
thumb?: {
|
|
||||||
url?: string | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
filename?: string | null;
|
|
||||||
};
|
|
||||||
small?: {
|
|
||||||
url?: string | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
filename?: string | null;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
@ -468,86 +468,6 @@ export interface RecordersThumbnail {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "library-items-scans".
|
|
||||||
*/
|
|
||||||
export interface LibraryItemScans {
|
|
||||||
id: string;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
url?: string | null;
|
|
||||||
filename?: string | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
sizes?: {
|
|
||||||
thumb?: {
|
|
||||||
url?: string | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
filename?: string | null;
|
|
||||||
};
|
|
||||||
og?: {
|
|
||||||
url?: string | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
filename?: string | null;
|
|
||||||
};
|
|
||||||
medium?: {
|
|
||||||
url?: string | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
filename?: string | null;
|
|
||||||
};
|
|
||||||
large?: {
|
|
||||||
url?: string | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
filename?: string | null;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "files".
|
|
||||||
*/
|
|
||||||
export interface File {
|
|
||||||
id: string;
|
|
||||||
filename: string;
|
|
||||||
type: 'LibraryScans' | 'LibrarySoundtracks' | 'ContentVideo' | 'ContentAudio';
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "keys".
|
|
||||||
*/
|
|
||||||
export interface Key {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
type:
|
|
||||||
| 'Contents'
|
|
||||||
| 'LibraryAudio'
|
|
||||||
| 'LibraryVideo'
|
|
||||||
| 'LibraryTextual'
|
|
||||||
| 'LibraryGroup'
|
|
||||||
| 'Library'
|
|
||||||
| 'Weapons'
|
|
||||||
| 'GamePlatforms'
|
|
||||||
| 'Categories'
|
|
||||||
| 'Wordings';
|
|
||||||
translations?: CategoryTranslations;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "currencies".
|
* via the `definition` "currencies".
|
||||||
@ -561,9 +481,10 @@ export interface Currency {
|
|||||||
*/
|
*/
|
||||||
export interface Page {
|
export interface Page {
|
||||||
id: string;
|
id: string;
|
||||||
type: 'Content' | 'Article' | 'Generic';
|
|
||||||
slug: string;
|
slug: string;
|
||||||
|
type: 'Content' | 'Post' | 'Generic';
|
||||||
thumbnail?: string | Image | null;
|
thumbnail?: string | Image | null;
|
||||||
|
backgroundImage?: string | Image | null;
|
||||||
tags?: (string | Tag)[] | null;
|
tags?: (string | Tag)[] | null;
|
||||||
authors?: (string | Recorder)[] | null;
|
authors?: (string | Recorder)[] | null;
|
||||||
translations: {
|
translations: {
|
||||||
@ -608,7 +529,7 @@ export interface Page {
|
|||||||
id?: string | null;
|
id?: string | null;
|
||||||
}[];
|
}[];
|
||||||
folders?: (string | Folder)[] | null;
|
folders?: (string | Folder)[] | null;
|
||||||
collectibles?: (string | LibraryItem)[] | null;
|
collectibles?: (string | Collectible)[] | null;
|
||||||
updatedBy: string | Recorder;
|
updatedBy: string | Recorder;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
@ -616,71 +537,16 @@ export interface Page {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "images".
|
* via the `definition` "generic-contents".
|
||||||
*/
|
*/
|
||||||
export interface Image {
|
export interface GenericContent {
|
||||||
id: string;
|
id: string;
|
||||||
updatedAt: string;
|
name: string;
|
||||||
createdAt: string;
|
translations: {
|
||||||
url?: string | null;
|
language: string | Language;
|
||||||
filename?: string | null;
|
name: string;
|
||||||
mimeType?: string | null;
|
id?: string | null;
|
||||||
filesize?: number | null;
|
}[];
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
sizes?: {
|
|
||||||
thumb?: {
|
|
||||||
url?: string | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
filename?: string | null;
|
|
||||||
};
|
|
||||||
og?: {
|
|
||||||
url?: string | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
filename?: string | null;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "tags".
|
|
||||||
*/
|
|
||||||
export interface Tag {
|
|
||||||
id: string;
|
|
||||||
name?: string | null;
|
|
||||||
slug: string;
|
|
||||||
translations?:
|
|
||||||
| {
|
|
||||||
language: string | Language;
|
|
||||||
name: string;
|
|
||||||
id?: string | null;
|
|
||||||
}[]
|
|
||||||
| null;
|
|
||||||
group: string | TagsGroup;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "tags-groups".
|
|
||||||
*/
|
|
||||||
export interface TagsGroup {
|
|
||||||
id: string;
|
|
||||||
slug: string;
|
|
||||||
icon?: string | null;
|
|
||||||
translations?:
|
|
||||||
| {
|
|
||||||
language: string | Language;
|
|
||||||
name: string;
|
|
||||||
id?: string | null;
|
|
||||||
}[]
|
|
||||||
| null;
|
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
@ -786,10 +652,8 @@ export interface Weapon {
|
|||||||
id: string;
|
id: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
thumbnail?: string | WeaponsThumbnail | null;
|
thumbnail?: string | WeaponsThumbnail | null;
|
||||||
type: string | Key;
|
|
||||||
group?: (string | null) | WeaponsGroup;
|
group?: (string | null) | WeaponsGroup;
|
||||||
appearances: {
|
appearances: {
|
||||||
categories: (string | Key)[];
|
|
||||||
translations: {
|
translations: {
|
||||||
language: string | Language;
|
language: string | Language;
|
||||||
sourceLanguage: string | Language;
|
sourceLanguage: string | Language;
|
||||||
@ -1004,7 +868,7 @@ export interface VideosChannel {
|
|||||||
export interface Wording {
|
export interface Wording {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
translations?: CategoryTranslations;
|
translations: CategoryTranslations;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
@ -1047,7 +911,7 @@ export interface PayloadMigration {
|
|||||||
* via the `definition` "SpacerBlock".
|
* via the `definition` "SpacerBlock".
|
||||||
*/
|
*/
|
||||||
export interface SpacerBlock {
|
export interface SpacerBlock {
|
||||||
size: 'Small' | 'Medium' | 'Large' | 'XLarge';
|
size: 'Small' | 'Medium' | 'Large' | 'Extra Large';
|
||||||
blockType: 'spacerBlock';
|
blockType: 'spacerBlock';
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -1139,12 +1003,7 @@ export enum Collections {
|
|||||||
ChronologyItems = "chronology-items",
|
ChronologyItems = "chronology-items",
|
||||||
Currencies = "currencies",
|
Currencies = "currencies",
|
||||||
Files = "files",
|
Files = "files",
|
||||||
Keys = "keys",
|
|
||||||
Languages = "languages",
|
Languages = "languages",
|
||||||
LibraryItems = "library-items",
|
|
||||||
LibraryItemsThumbnails = "library-items-thumbnails",
|
|
||||||
LibraryItemsScans = "library-items-scans",
|
|
||||||
LibraryItemsGallery = "library-items-gallery",
|
|
||||||
Notes = "notes",
|
Notes = "notes",
|
||||||
Pages = "pages",
|
Pages = "pages",
|
||||||
PagesThumbnails = "pages-thumbnails",
|
PagesThumbnails = "pages-thumbnails",
|
||||||
@ -1160,7 +1019,9 @@ export enum Collections {
|
|||||||
Tags = "tags",
|
Tags = "tags",
|
||||||
TagsGroups = "tags-groups",
|
TagsGroups = "tags-groups",
|
||||||
Images = "images",
|
Images = "images",
|
||||||
Wordings = "wordings"
|
Wordings = "wordings",
|
||||||
|
Collectibles = "collectibles",
|
||||||
|
GenericContents = "generic-contents",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CollectionGroups {
|
export enum CollectionGroups {
|
||||||
@ -1169,19 +1030,6 @@ export enum CollectionGroups {
|
|||||||
Meta = "Meta",
|
Meta = "Meta",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum KeysTypes {
|
|
||||||
Contents = "Contents",
|
|
||||||
LibraryAudio = "Library / Audio",
|
|
||||||
LibraryVideo = "Library / Video",
|
|
||||||
LibraryTextual = "Library / Textual",
|
|
||||||
LibraryGroup = "Library / Group",
|
|
||||||
Library = "Library",
|
|
||||||
Weapons = "Weapons",
|
|
||||||
GamePlatforms = "Game Platforms",
|
|
||||||
Categories = "Categories",
|
|
||||||
Wordings = "Wordings",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum LanguageCodes {
|
export enum LanguageCodes {
|
||||||
en = "English",
|
en = "English",
|
||||||
fr = "French",
|
fr = "French",
|
||||||
@ -1191,31 +1039,27 @@ export enum LanguageCodes {
|
|||||||
"zh" = "Chinese",
|
"zh" = "Chinese",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum FileTypes {
|
export enum CollectibleBindingTypes {
|
||||||
LibraryScans = "Library / Scans",
|
|
||||||
LibrarySoundtracks = "Library / Soundtracks",
|
|
||||||
ContentVideo = "Content / Video",
|
|
||||||
ContentAudio = "Content / Audio",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum LibraryItemsTypes {
|
|
||||||
Textual = "Textual",
|
|
||||||
Audio = "Audio",
|
|
||||||
Video = "Video",
|
|
||||||
Game = "Game",
|
|
||||||
Other = "Other",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum LibraryItemsTextualBindingTypes {
|
|
||||||
Paperback = "Paperback",
|
Paperback = "Paperback",
|
||||||
Hardcover = "Hardcover",
|
Hardcover = "Hardcover",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum LibraryItemsTextualPageOrders {
|
export enum CollectiblePageOrders {
|
||||||
LeftToRight = "Left to right",
|
LeftToRight = "Left to right",
|
||||||
RightToLeft = "Right to left",
|
RightToLeft = "Right to left",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CollectibleNature {
|
||||||
|
Physical = "Physical",
|
||||||
|
Digital = "Digital",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum CollectibleContentType {
|
||||||
|
None = "None",
|
||||||
|
Indexes = "Index-based",
|
||||||
|
Pages = "Page-based",
|
||||||
|
}
|
||||||
|
|
||||||
export enum RecordersRoles {
|
export enum RecordersRoles {
|
||||||
Admin = "Admin",
|
Admin = "Admin",
|
||||||
Recorder = "Recorder",
|
Recorder = "Recorder",
|
||||||
@ -1235,7 +1079,7 @@ export enum VideoSources {
|
|||||||
|
|
||||||
export enum PageType {
|
export enum PageType {
|
||||||
Content = "Content",
|
Content = "Content",
|
||||||
Article = "Article",
|
Post = "Post",
|
||||||
Generic = "Generic",
|
Generic = "Generic",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1583,12 +1427,12 @@ export type EndpointFolder = EndpointFolderPreview & {
|
|||||||
};
|
};
|
||||||
files: (
|
files: (
|
||||||
| {
|
| {
|
||||||
relationTo: "library-items";
|
relationTo: "collectibles";
|
||||||
value: LibraryItem;
|
value: EndpointCollectiblePreview;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
relationTo: "pages";
|
relationTo: "pages";
|
||||||
value: Page;
|
value: EndpointPagePreview;
|
||||||
}
|
}
|
||||||
)[];
|
)[];
|
||||||
};
|
};
|
||||||
@ -1616,17 +1460,6 @@ export type EndpointRecorder = {
|
|||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointKey = {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
type: Key["type"];
|
|
||||||
translations: {
|
|
||||||
language: string;
|
|
||||||
name: string;
|
|
||||||
short: string;
|
|
||||||
}[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type EndpointWording = {
|
export type EndpointWording = {
|
||||||
name: string;
|
name: string;
|
||||||
translations: {
|
translations: {
|
||||||
@ -1654,7 +1487,7 @@ export type EndpointTagsGroup = {
|
|||||||
tags: EndpointTag[];
|
tags: EndpointTag[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointPage = {
|
export type EndpointPagePreview = {
|
||||||
slug: string;
|
slug: string;
|
||||||
type: PageType;
|
type: PageType;
|
||||||
thumbnail?: PayloadImage;
|
thumbnail?: PayloadImage;
|
||||||
@ -1662,18 +1495,24 @@ export type EndpointPage = {
|
|||||||
tagGroups: TagGroup[];
|
tagGroups: TagGroup[];
|
||||||
translations: {
|
translations: {
|
||||||
language: string;
|
language: string;
|
||||||
sourceLanguage: string;
|
|
||||||
pretitle?: string;
|
pretitle?: string;
|
||||||
title: string;
|
title: string;
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
|
}[];
|
||||||
|
status: "draft" | "published";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EndpointPage = EndpointPagePreview & {
|
||||||
|
backgroundImage?: PayloadImage;
|
||||||
|
translations: (EndpointPagePreview["translations"][number] & {
|
||||||
|
sourceLanguage: string;
|
||||||
summary?: RichTextContent;
|
summary?: RichTextContent;
|
||||||
content: RichTextContent;
|
content: RichTextContent;
|
||||||
transcribers: string[];
|
transcribers: string[];
|
||||||
translators: string[];
|
translators: string[];
|
||||||
proofreaders: string[];
|
proofreaders: string[];
|
||||||
toc: TableOfContentEntry[];
|
toc: TableOfContentEntry[];
|
||||||
}[];
|
})[];
|
||||||
status: "draft" | "published";
|
|
||||||
parentPages: ParentPage[];
|
parentPages: ParentPage[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1684,6 +1523,82 @@ export type ParentPage = {
|
|||||||
tag: string;
|
tag: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type EndpointCollectiblePreview = {
|
||||||
|
slug: string;
|
||||||
|
thumbnail?: PayloadImage;
|
||||||
|
translations: {
|
||||||
|
language: string;
|
||||||
|
pretitle?: string;
|
||||||
|
title: string;
|
||||||
|
subtitle?: string;
|
||||||
|
description?: RichTextContent;
|
||||||
|
}[];
|
||||||
|
tagGroups: TagGroup[];
|
||||||
|
status: "draft" | "published";
|
||||||
|
releaseDate?: string;
|
||||||
|
languages: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EndpointCollectible = EndpointCollectiblePreview & {
|
||||||
|
backgroundImage?: PayloadImage;
|
||||||
|
nature: CollectibleNature;
|
||||||
|
gallery: PayloadImage[];
|
||||||
|
scans: PayloadImage[];
|
||||||
|
urls: { url: string; label: string }[];
|
||||||
|
price?: {
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
};
|
||||||
|
size?: {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
thickness?: number;
|
||||||
|
};
|
||||||
|
weight?: number;
|
||||||
|
pageInfo?: {
|
||||||
|
pageCount: number;
|
||||||
|
bindingType?: CollectibleBindingTypes;
|
||||||
|
pageOrder?: CollectiblePageOrders;
|
||||||
|
};
|
||||||
|
subitems: EndpointCollectiblePreview[];
|
||||||
|
contents: {
|
||||||
|
content:
|
||||||
|
| {
|
||||||
|
relationTo: "pages";
|
||||||
|
value: EndpointPagePreview;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
relationTo: "generic-contents";
|
||||||
|
value: {
|
||||||
|
translations: {
|
||||||
|
language: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
range?:
|
||||||
|
| {
|
||||||
|
type: "pageRange";
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "timeRange";
|
||||||
|
start: string;
|
||||||
|
end: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "other";
|
||||||
|
translations: {
|
||||||
|
language: string;
|
||||||
|
note: RichTextContent;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
parentPages: ParentPage[];
|
||||||
|
};
|
||||||
|
|
||||||
export type TagGroup = { slug: string; icon: string; values: string[] };
|
export type TagGroup = { slug: string; icon: string; values: string[] };
|
||||||
|
|
||||||
export type TableOfContentEntry = {
|
export type TableOfContentEntry = {
|
||||||
@ -1723,4 +1638,6 @@ export const payload = {
|
|||||||
await (await request(payloadApiUrl(Collections.TagsGroups, `all`))).json(),
|
await (await request(payloadApiUrl(Collections.TagsGroups, `all`))).json(),
|
||||||
getPage: async (slug: string): Promise<EndpointPage> =>
|
getPage: async (slug: string): Promise<EndpointPage> =>
|
||||||
await (await request(payloadApiUrl(Collections.Pages, `slug/${slug}`))).json(),
|
await (await request(payloadApiUrl(Collections.Pages, `slug/${slug}`))).json(),
|
||||||
|
getCollectible: async (slug: string): Promise<EndpointCollectible> =>
|
||||||
|
await (await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}`))).json(),
|
||||||
};
|
};
|
||||||
|
@ -12,3 +12,23 @@ export const formatRecorder = (recorderId: string): string => {
|
|||||||
|
|
||||||
return result.username;
|
return result.username;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const formatInlineTitle = ({
|
||||||
|
pretitle,
|
||||||
|
title,
|
||||||
|
subtitle,
|
||||||
|
}: {
|
||||||
|
pretitle?: string | undefined;
|
||||||
|
title: string;
|
||||||
|
subtitle?: string | undefined;
|
||||||
|
}): string => {
|
||||||
|
let result = "";
|
||||||
|
if (pretitle) {
|
||||||
|
result += `${pretitle}: `;
|
||||||
|
}
|
||||||
|
result += title;
|
||||||
|
if (subtitle) {
|
||||||
|
result += ` — ${subtitle}`;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user