Limit attributes count on preview cards + fix media pages title

This commit is contained in:
DrMint 2024-06-02 09:59:03 +02:00
parent 2c2dde250e
commit 6cb971b5a5
14 changed files with 181 additions and 44 deletions

View File

@ -9,7 +9,6 @@
## Short term ## Short term
- [Feat] 404, 500 pages - [Feat] 404, 500 pages
- [Bugs] [iOS] Video doesn't seem to start
- [Feat] Add languages to collectibles and pages previews - [Feat] Add languages to collectibles and pages previews
- [Feat] [RichTextContent] Handle relationship - [Feat] [RichTextContent] Handle relationship
- [Bugs] Vollkorn doesn't support many languages - [Bugs] Vollkorn doesn't support many languages
@ -21,7 +20,6 @@
## Mid term ## Mid term
- [Feat] [Payload] Home as parent folders for home folders
- [Bugs] [Timeline] Error if collectible not published? - [Bugs] [Timeline] Error if collectible not published?
- [Feat] [Timeline] display source language - [Feat] [Timeline] display source language
- [Feat] [Timeline] Add details button in footer with credits + last updated / created - [Feat] [Timeline] Add details button in footer with credits + last updated / created
@ -32,6 +30,8 @@
## Long term ## Long term
- [Bugs] [iOS] Video doesn't seem to start
- [Feat] [Folders] Provide a list view, and a list/grid toggle
- [Feat] [Payload] Endpoints should provide a simple text-based version of the content (for OG purposes) - [Feat] [Payload] Endpoints should provide a simple text-based version of the content (for OG purposes)
- [Feat] [WebManifest] Add shortcuts https://web.dev/patterns/web-apps/shortcuts - [Feat] [WebManifest] Add shortcuts https://web.dev/patterns/web-apps/shortcuts
- [Feat] [PWA] Rich install UI https://web.dev/patterns/web-apps/richer-install-ui/ - [Feat] [PWA] Rich install UI https://web.dev/patterns/web-apps/richer-install-ui/

View File

@ -701,6 +701,31 @@ const { currentTheme } = Astro.locals;
> h5 + h6 { > h5 + h6 {
margin-top: -0.75em; margin-top: -0.75em;
} }
h2 {
font-size: var(--font-size-4xl);
font-variation-settings: "wght" 800;
}
h3 {
font-size: var(--font-size-3xl);
font-variation-settings: "wght" 750;
}
h4 {
font-size: var(--font-size-2xl);
font-variation-settings: "wght" 700;
}
h5 {
font-size: var(--font-size-xl);
font-variation-settings: "wght" 600;
}
h6 {
font-size: var(--font-size-l);
font-variation-settings: "wght" 500;
}
} }
@view-transition { @view-transition {

View File

@ -11,27 +11,27 @@ const { header, id } = Astro.props;
{ {
header === 1 ? ( header === 1 ? (
<h1 id={id} class="font-5xl"> <h1 id={id}>
<slot /> <slot />
</h1> </h1>
) : header === 2 ? ( ) : header === 2 ? (
<h2 id={id} class="font-4xl"> <h2 id={id}>
<slot /> <slot />
</h2> </h2>
) : header === 3 ? ( ) : header === 3 ? (
<h3 id={id} class="font-3xl"> <h3 id={id}>
<slot /> <slot />
</h3> </h3>
) : header === 4 ? ( ) : header === 4 ? (
<h4 id={id} class="font-2xl"> <h4 id={id}>
<slot /> <slot />
</h4> </h4>
) : header === 5 ? ( ) : header === 5 ? (
<h5 id={id} class="font-xl"> <h5 id={id}>
<slot /> <slot />
</h5> </h5>
) : ( ) : (
<h6 id={id} class="font-l"> <h6 id={id}>
<slot /> <slot />
</h6> </h6>
) )

View File

@ -27,6 +27,7 @@ interface Props {
metaAttributes?: ComponentProps<typeof Attributes>["attributes"] | undefined; metaAttributes?: ComponentProps<typeof Attributes>["attributes"] | undefined;
credits?: EndpointCredit[] | undefined; credits?: EndpointCredit[] | undefined;
filename?: string | undefined; filename?: string | undefined;
smallTitle?: boolean | undefined;
} }
const { const {
@ -41,10 +42,9 @@ const {
title, title,
subtitle, subtitle,
filename, filename,
smallTitle = false,
} = Astro.props; } = Astro.props;
const smallTitle = !subtitle && !pretitle;
const hasNavigation = previousImageHref || nextImageHref; const hasNavigation = previousImageHref || nextImageHref;
--- ---
@ -96,7 +96,7 @@ const hasNavigation = previousImageHref || nextImageHref;
<div> <div>
{ {
smallTitle ? ( smallTitle ? (
<h1 class="font-3xl">{title}</h1> <h1 class="font-4xl">{title}</h1>
) : ( ) : (
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} /> <AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
) )

View File

@ -2,18 +2,61 @@
import GenericPreview from "components/Previews/GenericPreview.astro"; import GenericPreview from "components/Previews/GenericPreview.astro";
import { getI18n } from "src/i18n/i18n"; import { getI18n } from "src/i18n/i18n";
import type { EndpointCollectible } from "src/shared/payload/payload-sdk"; import type { EndpointCollectible } from "src/shared/payload/payload-sdk";
import type { Attribute } from "src/utils/attributes";
import { convert } from "src/utils/currencies";
import { formatLocale } from "src/utils/format";
interface Props { interface Props {
collectible: EndpointCollectible; collectible: EndpointCollectible;
} }
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale); const { getLocalizedMatch, getLocalizedUrl, t, formatPrice, formatDate } = await getI18n(
Astro.locals.currentLocale
);
const { const {
collectible: { slug, translations, thumbnail, attributes }, collectible: { slug, translations, thumbnail, attributes, languages, price, releaseDate },
} = Astro.props; } = Astro.props;
const { title, pretitle, subtitle } = getLocalizedMatch(translations); const { title, pretitle, subtitle } = getLocalizedMatch(translations);
const additionalAttributes: Attribute[] = [];
if (languages.length > 0) {
additionalAttributes.push({
title: t("collectibles.languages"),
icon: "material-symbols:translate",
values: languages.map((lang) => ({ name: formatLocale(lang) })),
withBorder: true,
});
}
if (releaseDate) {
additionalAttributes.push({
title: t("collectibles.releaseDate"),
icon: "material-symbols:calendar-month",
values: [{ name: formatDate(new Date(releaseDate)) }],
withBorder: false,
});
}
if (price) {
const preferredCurrency = Astro.locals.currentCurrency;
const convertedPrice = {
amount: convert(price.currency, preferredCurrency, price.amount),
currency: preferredCurrency,
};
additionalAttributes.push({
title: t("collectibles.price"),
icon: "material-symbols:sell",
values: [
{ name: price.amount === 0 ? t("collectibles.price.free") : formatPrice(convertedPrice) },
],
withBorder: false,
});
}
--- ---
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
@ -24,7 +67,7 @@ const { title, pretitle, subtitle } = getLocalizedMatch(translations);
subtitle={subtitle} subtitle={subtitle}
thumbnail={thumbnail} thumbnail={thumbnail}
href={getLocalizedUrl(`/collectibles/${slug}`)} href={getLocalizedUrl(`/collectibles/${slug}`)}
attributes={attributes} attributes={[...attributes, ...additionalAttributes]}
icon="material-symbols:category" icon="material-symbols:category"
iconHoverLabel={t("global.previewTypes.collectible")} iconHoverLabel={t("global.previewTypes.collectible")}
disableRoundedTop disableRoundedTop

View File

@ -1,8 +1,10 @@
--- ---
import type { import {
EndpointImage, AttributeTypes,
EndpointMediaThumbnail, type EndpointAttribute,
EndpointScanImage, type EndpointImage,
type EndpointMediaThumbnail,
type EndpointScanImage,
} from "src/shared/payload/payload-sdk"; } from "src/shared/payload/payload-sdk";
import Card from "components/Card.astro"; import Card from "components/Card.astro";
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
@ -10,6 +12,7 @@ import type { ComponentProps } from "astro/types";
import { getI18n } from "src/i18n/i18n"; import { getI18n } from "src/i18n/i18n";
import InlineAttributes from "components/InlineAttributes.astro"; import InlineAttributes from "components/InlineAttributes.astro";
import { sizesToSrcset, sizesForGridLayout } from "src/utils/img"; import { sizesToSrcset, sizesForGridLayout } from "src/utils/img";
import type { Attribute } from "src/utils/attributes";
interface Props { interface Props {
thumbnail?: EndpointImage | EndpointMediaThumbnail | EndpointScanImage | undefined; thumbnail?: EndpointImage | EndpointMediaThumbnail | EndpointScanImage | undefined;
@ -24,7 +27,7 @@ interface Props {
iconHoverLabel?: string; iconHoverLabel?: string;
} }
const { t } = await getI18n(Astro.locals.currentLocale); const { t, getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
const { const {
thumbnail, thumbnail,
@ -38,6 +41,37 @@ const {
icon = "material-symbols:unknown-document", icon = "material-symbols:unknown-document",
iconHoverLabel = t("global.previewTypes.unknown"), iconHoverLabel = t("global.previewTypes.unknown"),
} = Astro.props; } = Astro.props;
/* Clip the number of attributes such that the card isn't ridiculously long */
let metaLength = 0;
const maxMetaLength = 230;
metaLength += (pretitle?.length ?? 0) * 1.5;
metaLength += (title?.length ?? 0) * 3;
metaLength += (subtitle?.length ?? 0) * 3;
const clippedAttributes: (Attribute | EndpointAttribute)[] = [];
for (const attribute of attributes) {
if (metaLength > maxMetaLength) {
clippedAttributes.pop();
break;
}
if ("title" in attribute) {
metaLength += attribute.title.length;
metaLength += attribute.values.join(", ").length;
clippedAttributes.push(attribute);
} else {
metaLength += getLocalizedMatch(attribute.translations).name.length;
if (attribute.type === AttributeTypes.Tags) {
metaLength += attribute.value
.map(({ translations }) => getLocalizedMatch(translations).name)
.join(", ").length;
metaLength += clippedAttributes.push(attribute);
}
// TODO: Handle other attribute types
}
metaLength += 8;
}
--- ---
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
@ -89,11 +123,11 @@ const {
} }
{ {
attributes.length > 0 && ( clippedAttributes.length > 0 && (
<> <>
{subtitle && <hr />} {subtitle && <hr />}
<div id="tags"> <div id="tags">
<InlineAttributes attributes={attributes} /> <InlineAttributes attributes={clippedAttributes} />
</div> </div>
</> </>
) )

View File

@ -2,18 +2,30 @@
import GenericPreview from "components/Previews/GenericPreview.astro"; import GenericPreview from "components/Previews/GenericPreview.astro";
import { getI18n } from "src/i18n/i18n"; import { getI18n } from "src/i18n/i18n";
import type { EndpointPage } from "src/shared/payload/payload-sdk"; import type { EndpointPage } from "src/shared/payload/payload-sdk";
import type { Attribute } from "src/utils/attributes";
interface Props { interface Props {
page: EndpointPage; page: EndpointPage;
} }
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale); const { getLocalizedMatch, getLocalizedUrl, t, formatDate } = await getI18n(
Astro.locals.currentLocale
);
const { const {
page: { slug, translations, thumbnail, attributes }, page: { slug, translations, thumbnail, attributes, updatedAt },
} = Astro.props; } = Astro.props;
const { title, pretitle, subtitle } = getLocalizedMatch(translations); const { title, pretitle, subtitle } = getLocalizedMatch(translations);
const metaAttributes: Attribute[] = [
{
title: t("global.media.attributes.updatedAt"),
icon: "material-symbols:edit-calendar",
values: [{ name: formatDate(new Date(updatedAt)) }],
withBorder: false,
},
];
--- ---
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
@ -24,7 +36,7 @@ const { title, pretitle, subtitle } = getLocalizedMatch(translations);
subtitle={subtitle} subtitle={subtitle}
thumbnail={thumbnail} thumbnail={thumbnail}
href={getLocalizedUrl(`/pages/${slug}`)} href={getLocalizedUrl(`/pages/${slug}`)}
attributes={attributes} attributes={[...attributes, ...metaAttributes]}
icon="material-symbols:docs" icon="material-symbols:docs"
iconHoverLabel={t("global.previewTypes.page")} iconHoverLabel={t("global.previewTypes.page")}
/> />

View File

@ -34,8 +34,6 @@ const {
const { pretitle, title, subtitle, description } = getLocalizedMatch(translations); const { pretitle, title, subtitle, description } = getLocalizedMatch(translations);
const smallTitle = !subtitle && !pretitle;
const metaAttributes = [ const metaAttributes = [
...(filename && title !== filename ...(filename && title !== filename
? [ ? [
@ -81,13 +79,7 @@ const metaAttributes = [
<AudioPlayer audio={audio} class="audio_id-audio-player" /> <AudioPlayer audio={audio} class="audio_id-audio-player" />
<div id="info"> <div id="info">
{ <AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
smallTitle ? (
<h1>{title}</h1>
) : (
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
)
}
{description && <RichText content={description} />} {description && <RichText content={description} />}
{attributes.length > 0 && <Attributes attributes={attributes} />} {attributes.length > 0 && <Attributes attributes={attributes} />}
{credits.length > 0 && <Credits credits={credits} />} {credits.length > 0 && <Credits credits={credits} />}

View File

@ -76,5 +76,6 @@ const metaAttributes = [
attributes={attributes} attributes={attributes}
metaAttributes={metaAttributes} metaAttributes={metaAttributes}
credits={credits} credits={credits}
smallTitle={title === filename}
/> />
</AppLayout> </AppLayout>

View File

@ -40,5 +40,6 @@ const translation = getLocalizedMatch(translations);
? getLocalizedUrl(`/collectibles/${slug}/scans/${nextIndex}`) ? getLocalizedUrl(`/collectibles/${slug}/scans/${nextIndex}`)
: undefined} : undefined}
filename={image.filename} filename={image.filename}
smallTitle
/> />
</AppLayout> </AppLayout>

View File

@ -0,0 +1,35 @@
---
import AppLayout from "components/AppLayout/AppLayout.astro";
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
import { getI18n } from "src/i18n/i18n";
const { getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
---
{/* ------------------------------------------- HTML ------------------------------------------- */}
<AppLayout>
<AppLayoutTitle pretitle="Welcome to" title="The Dev Room" />
<ul>
<li>
<a href={getLocalizedUrl("/dev/design-system")} class="pressable-link">Design System</a>
</li>
<li>
<a href={getLocalizedUrl("/dev/rich-text")} class="pressable-link">
Guide to the Rich Text Editor
</a>
</li>
</ul>
</AppLayout>
{/* ------------------------------------------- CSS -------------------------------------------- */}
<style>
ul {
margin-block: 2em;
}
li {
margin-block: 0.5em;
}
</style>

View File

@ -64,5 +64,6 @@ const metaAttributes = [
attributes={attributes} attributes={attributes}
metaAttributes={metaAttributes} metaAttributes={metaAttributes}
credits={credits} credits={credits}
smallTitle={title === filename}
/> />
</AppLayout> </AppLayout>

View File

@ -24,7 +24,7 @@ const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.cu
<div class="card-container"> <div class="card-container">
<Card> <Card>
<div class="card-content prose"> <div class="card-content prose">
<h3 class="font-serif font-3xl">{t("timeline.notes.title")}</h3> <h3>{t("timeline.notes.title")}</h3>
<p <p
set:html={t("timeline.notes.content", { set:html={t("timeline.notes.content", {
@ -38,7 +38,7 @@ const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.cu
<Card> <Card>
<div class="card-content prose"> <div class="card-content prose">
<h3 class="font-serif font-3xl">{t("timeline.priorCataclysmNote.title")}</h3> <h3>{t("timeline.priorCataclysmNote.title")}</h3>
<p <p
set:html={t("timeline.priorCataclysmNote.content", { set:html={t("timeline.priorCataclysmNote.content", {
@ -52,7 +52,7 @@ const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.cu
<Card> <Card>
<div class="card-content prose jump-card"> <div class="card-content prose jump-card">
<h3 class="font-serif font-3xl">{t("timeline.jumpTo")}</h3> <h3>{t("timeline.jumpTo")}</h3>
{ {
cache.config.timeline.eras.map(({ name, startingYear, endingYear }) => ( cache.config.timeline.eras.map(({ name, startingYear, endingYear }) => (

View File

@ -33,7 +33,6 @@ const {
} = video; } = video;
const { pretitle, title, subtitle, description } = getLocalizedMatch(translations); const { pretitle, title, subtitle, description } = getLocalizedMatch(translations);
const smallTitle = !subtitle && !pretitle;
const metaAttributes = [ const metaAttributes = [
...(filename && title !== filename ...(filename && title !== filename
@ -80,13 +79,7 @@ const metaAttributes = [
<VideoPlayer class="video_id-video-player" video={video} /> <VideoPlayer class="video_id-video-player" video={video} />
<div id="info"> <div id="info">
{ <AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
smallTitle ? (
<h1>{title}</h1>
) : (
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
)
}
{description && <RichText content={description} />} {description && <RichText content={description} />}
{attributes.length > 0 && <Attributes attributes={attributes} />} {attributes.length > 0 && <Attributes attributes={attributes} />}
{credits.length > 0 && <Credits credits={credits} />} {credits.length > 0 && <Credits credits={credits} />}