Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
DrMint | 67de6b0b6a |
|
@ -5,6 +5,8 @@ import { capitalize, formatInlineTitle } from "src/utils/format";
|
||||||
|
|
||||||
export const defaultLocale = "en";
|
export const defaultLocale = "en";
|
||||||
|
|
||||||
|
export type I18n = Awaited<ReturnType<typeof getI18n>>;
|
||||||
|
|
||||||
export const getI18n = async (locale: string) => {
|
export const getI18n = async (locale: string) => {
|
||||||
const formatWithValues = (
|
const formatWithValues = (
|
||||||
templateName: string,
|
templateName: string,
|
||||||
|
|
|
@ -0,0 +1,257 @@
|
||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
import {
|
||||||
|
Collections,
|
||||||
|
type EndpointFolder,
|
||||||
|
type EndpointImage,
|
||||||
|
} from "src/shared/payload/payload-sdk";
|
||||||
|
import { type Attribute, convertEndpointAttributeToAttribute } from "src/utils/attributes";
|
||||||
|
import { formatLocale } from "src/utils/format";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
files: EndpointFolder["files"];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { files } = Astro.props;
|
||||||
|
|
||||||
|
type Row = {
|
||||||
|
thumbnail?: EndpointImage | undefined;
|
||||||
|
pretitle?: string | undefined;
|
||||||
|
title: string;
|
||||||
|
lang?: string | undefined;
|
||||||
|
subtitle?: string | undefined;
|
||||||
|
icon?: string;
|
||||||
|
iconHoverLabel?: string;
|
||||||
|
attributes: Attribute[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const i18n = await getI18n(Astro.locals.currentLocale);
|
||||||
|
const { t, getLocalizedMatch } = i18n;
|
||||||
|
|
||||||
|
const rows = files.map<Row>(({ relationTo, value }) => {
|
||||||
|
switch (relationTo) {
|
||||||
|
case Collections.Collectibles: {
|
||||||
|
const { title, pretitle, subtitle, language } = getLocalizedMatch(value.translations);
|
||||||
|
|
||||||
|
const attributes = value.attributes.map((attribute) =>
|
||||||
|
convertEndpointAttributeToAttribute(attribute, i18n)
|
||||||
|
);
|
||||||
|
|
||||||
|
const additionalAttributes: Attribute[] = [];
|
||||||
|
|
||||||
|
if (value.languages.length > 0) {
|
||||||
|
additionalAttributes.push({
|
||||||
|
title: t("collectibles.languages"),
|
||||||
|
icon: "material-symbols:translate",
|
||||||
|
values: value.languages.map((lang) => ({ name: formatLocale(lang) })),
|
||||||
|
withBorder: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
thumbnail: value.thumbnail,
|
||||||
|
title,
|
||||||
|
pretitle,
|
||||||
|
subtitle,
|
||||||
|
lang: language,
|
||||||
|
icon: "material-symbols:category",
|
||||||
|
iconHoverLabel: t("global.previewTypes.collectible"),
|
||||||
|
attributes: [...attributes, ...additionalAttributes],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { title: "Error", attributes: [] };
|
||||||
|
});
|
||||||
|
|
||||||
|
const commomAttributes = [
|
||||||
|
...new Map<string, Omit<Attribute, "values" | "withBorder">>(
|
||||||
|
rows.flatMap(({ attributes }) => attributes.map((attribute) => [attribute.title, attribute]))
|
||||||
|
).values(),
|
||||||
|
];
|
||||||
|
---
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
{
|
||||||
|
commomAttributes.map(({ title, icon }) => (
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<Icon name={icon} width={20} height={20} />
|
||||||
|
<p class="font-l">{title}</p>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{
|
||||||
|
rows.map(
|
||||||
|
({ thumbnail, pretitle, title, subtitle, lang, icon, iconHoverLabel, attributes }) => (
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{thumbnail ? (
|
||||||
|
<img src={thumbnail.url} />
|
||||||
|
) : (
|
||||||
|
<div title={iconHoverLabel} class="thumbnail-alt">
|
||||||
|
<Icon name={icon} width={32} height={32} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p lang={lang}>
|
||||||
|
{pretitle && (
|
||||||
|
<span id="pretitle" class="font-s">
|
||||||
|
{pretitle}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span class="font-serif font-2xl">{title}</span>
|
||||||
|
{subtitle && (
|
||||||
|
<span id="subtitle" class="font-serif font-m">
|
||||||
|
{subtitle}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
{commomAttributes.map((attributeToFind) => {
|
||||||
|
const attribute = attributes.find(({ title }) => title === attributeToFind.title);
|
||||||
|
if (!attribute) return <td class="center">–</td>;
|
||||||
|
return (
|
||||||
|
<td>
|
||||||
|
<div id="values" class:list={{ "with-border": attribute.withBorder }}>
|
||||||
|
{attribute.values.map(({ name }) => (
|
||||||
|
<div class="pill" lang={lang}>
|
||||||
|
{name}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
table {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
/* TODO: stop using this stupid hack */
|
||||||
|
max-width: calc(100vw - clamp(24px, 4vw, 64px) * 2);
|
||||||
|
|
||||||
|
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: 2px solid var(--color-base-400);
|
||||||
|
|
||||||
|
& > thead {
|
||||||
|
background-color: var(--color-elevation-1);
|
||||||
|
|
||||||
|
& > tr > th {
|
||||||
|
padding: 1em 1.5em;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
place-content: center;
|
||||||
|
place-items: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
& > svg {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > tbody {
|
||||||
|
& > tr {
|
||||||
|
img,
|
||||||
|
.thumbnail-alt {
|
||||||
|
height: 5em;
|
||||||
|
width: 5em;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > td:nth-child(1) {
|
||||||
|
padding-right: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail-alt {
|
||||||
|
background-color: var(--color-elevation-2);
|
||||||
|
color: var(--color-base-400);
|
||||||
|
display: grid;
|
||||||
|
place-content: center;
|
||||||
|
border-radius: 0.7em;
|
||||||
|
|
||||||
|
& > svg {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
transition: 150ms color;
|
||||||
|
line-height: 0.9;
|
||||||
|
|
||||||
|
& > #pretitle {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #subtitle {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
border-block: 1px solid var(--color-base-400);
|
||||||
|
|
||||||
|
& > #values {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
place-items: center;
|
||||||
|
place-content: center;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&.with-border {
|
||||||
|
& > div,
|
||||||
|
& > a {
|
||||||
|
border-radius: 9999px;
|
||||||
|
padding-bottom: 0.25em;
|
||||||
|
padding-top: 0.15em;
|
||||||
|
padding-inline: 0.6em;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
border: 1px solid var(--color-base-1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
padding: 0.5em 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,3 +1,6 @@
|
||||||
|
import type { I18n } from "src/i18n/i18n";
|
||||||
|
import { AttributeTypes, type EndpointAttribute } from "src/shared/payload/payload-sdk";
|
||||||
|
|
||||||
export type Attribute = {
|
export type Attribute = {
|
||||||
icon: string;
|
icon: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -5,3 +8,34 @@ export type Attribute = {
|
||||||
values: { name: string; href?: string | undefined; lang?: string | undefined }[];
|
values: { name: string; href?: string | undefined; lang?: string | undefined }[];
|
||||||
withBorder?: boolean | undefined;
|
withBorder?: boolean | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const convertEndpointAttributeToAttribute = (
|
||||||
|
endpointAttribute: EndpointAttribute,
|
||||||
|
{ getLocalizedMatch, getLocalizedUrl, formatNumber }: I18n
|
||||||
|
): Attribute => {
|
||||||
|
const { icon, translations, value, type } = endpointAttribute;
|
||||||
|
const { language: lang, name: title } = getLocalizedMatch(translations);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case AttributeTypes.Number:
|
||||||
|
return { icon, title, lang, values: [{ name: formatNumber(value) }] };
|
||||||
|
|
||||||
|
case AttributeTypes.Text:
|
||||||
|
return { icon, title, lang, values: [{ name: value }] };
|
||||||
|
|
||||||
|
case AttributeTypes.Tags:
|
||||||
|
return {
|
||||||
|
icon,
|
||||||
|
title,
|
||||||
|
lang,
|
||||||
|
values: value.map(({ translations, page }) => {
|
||||||
|
const { name, language } = getLocalizedMatch(translations);
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
lang: language,
|
||||||
|
...(page ? { href: getLocalizedUrl(`/pages/${page.slug}`) } : {}),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue