Added basic row view

This commit is contained in:
DrMint 2024-06-15 09:43:11 +02:00
parent 4f23b02097
commit 67de6b0b6a
3 changed files with 293 additions and 0 deletions

View File

@ -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,

View File

@ -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>

View File

@ -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}`) } : {}),
};
}),
};
}
};