Limit attributes count on preview cards + fix media pages title
This commit is contained in:
parent
2c2dde250e
commit
6cb971b5a5
4
TODO.md
4
TODO.md
|
@ -9,7 +9,6 @@
|
|||
## Short term
|
||||
|
||||
- [Feat] 404, 500 pages
|
||||
- [Bugs] [iOS] Video doesn't seem to start
|
||||
- [Feat] Add languages to collectibles and pages previews
|
||||
- [Feat] [RichTextContent] Handle relationship
|
||||
- [Bugs] Vollkorn doesn't support many languages
|
||||
|
@ -21,7 +20,6 @@
|
|||
|
||||
## Mid term
|
||||
|
||||
- [Feat] [Payload] Home as parent folders for home folders
|
||||
- [Bugs] [Timeline] Error if collectible not published?
|
||||
- [Feat] [Timeline] display source language
|
||||
- [Feat] [Timeline] Add details button in footer with credits + last updated / created
|
||||
|
@ -32,6 +30,8 @@
|
|||
|
||||
## 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] [WebManifest] Add shortcuts https://web.dev/patterns/web-apps/shortcuts
|
||||
- [Feat] [PWA] Rich install UI https://web.dev/patterns/web-apps/richer-install-ui/
|
||||
|
|
|
@ -701,6 +701,31 @@ const { currentTheme } = Astro.locals;
|
|||
> h5 + h6 {
|
||||
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 {
|
||||
|
|
|
@ -11,27 +11,27 @@ const { header, id } = Astro.props;
|
|||
|
||||
{
|
||||
header === 1 ? (
|
||||
<h1 id={id} class="font-5xl">
|
||||
<h1 id={id}>
|
||||
<slot />
|
||||
</h1>
|
||||
) : header === 2 ? (
|
||||
<h2 id={id} class="font-4xl">
|
||||
<h2 id={id}>
|
||||
<slot />
|
||||
</h2>
|
||||
) : header === 3 ? (
|
||||
<h3 id={id} class="font-3xl">
|
||||
<h3 id={id}>
|
||||
<slot />
|
||||
</h3>
|
||||
) : header === 4 ? (
|
||||
<h4 id={id} class="font-2xl">
|
||||
<h4 id={id}>
|
||||
<slot />
|
||||
</h4>
|
||||
) : header === 5 ? (
|
||||
<h5 id={id} class="font-xl">
|
||||
<h5 id={id}>
|
||||
<slot />
|
||||
</h5>
|
||||
) : (
|
||||
<h6 id={id} class="font-l">
|
||||
<h6 id={id}>
|
||||
<slot />
|
||||
</h6>
|
||||
)
|
||||
|
|
|
@ -27,6 +27,7 @@ interface Props {
|
|||
metaAttributes?: ComponentProps<typeof Attributes>["attributes"] | undefined;
|
||||
credits?: EndpointCredit[] | undefined;
|
||||
filename?: string | undefined;
|
||||
smallTitle?: boolean | undefined;
|
||||
}
|
||||
|
||||
const {
|
||||
|
@ -41,10 +42,9 @@ const {
|
|||
title,
|
||||
subtitle,
|
||||
filename,
|
||||
smallTitle = false,
|
||||
} = Astro.props;
|
||||
|
||||
const smallTitle = !subtitle && !pretitle;
|
||||
|
||||
const hasNavigation = previousImageHref || nextImageHref;
|
||||
---
|
||||
|
||||
|
@ -96,7 +96,7 @@ const hasNavigation = previousImageHref || nextImageHref;
|
|||
<div>
|
||||
{
|
||||
smallTitle ? (
|
||||
<h1 class="font-3xl">{title}</h1>
|
||||
<h1 class="font-4xl">{title}</h1>
|
||||
) : (
|
||||
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
|
||||
)
|
||||
|
|
|
@ -2,18 +2,61 @@
|
|||
import GenericPreview from "components/Previews/GenericPreview.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
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 {
|
||||
collectible: EndpointCollectible;
|
||||
}
|
||||
|
||||
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale);
|
||||
const { getLocalizedMatch, getLocalizedUrl, t, formatPrice, formatDate } = await getI18n(
|
||||
Astro.locals.currentLocale
|
||||
);
|
||||
|
||||
const {
|
||||
collectible: { slug, translations, thumbnail, attributes },
|
||||
collectible: { slug, translations, thumbnail, attributes, languages, price, releaseDate },
|
||||
} = Astro.props;
|
||||
|
||||
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 ------------------------------------------- */}
|
||||
|
@ -24,7 +67,7 @@ const { title, pretitle, subtitle } = getLocalizedMatch(translations);
|
|||
subtitle={subtitle}
|
||||
thumbnail={thumbnail}
|
||||
href={getLocalizedUrl(`/collectibles/${slug}`)}
|
||||
attributes={attributes}
|
||||
attributes={[...attributes, ...additionalAttributes]}
|
||||
icon="material-symbols:category"
|
||||
iconHoverLabel={t("global.previewTypes.collectible")}
|
||||
disableRoundedTop
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
---
|
||||
import type {
|
||||
EndpointImage,
|
||||
EndpointMediaThumbnail,
|
||||
EndpointScanImage,
|
||||
import {
|
||||
AttributeTypes,
|
||||
type EndpointAttribute,
|
||||
type EndpointImage,
|
||||
type EndpointMediaThumbnail,
|
||||
type EndpointScanImage,
|
||||
} from "src/shared/payload/payload-sdk";
|
||||
import Card from "components/Card.astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
@ -10,6 +12,7 @@ import type { ComponentProps } from "astro/types";
|
|||
import { getI18n } from "src/i18n/i18n";
|
||||
import InlineAttributes from "components/InlineAttributes.astro";
|
||||
import { sizesToSrcset, sizesForGridLayout } from "src/utils/img";
|
||||
import type { Attribute } from "src/utils/attributes";
|
||||
|
||||
interface Props {
|
||||
thumbnail?: EndpointImage | EndpointMediaThumbnail | EndpointScanImage | undefined;
|
||||
|
@ -24,7 +27,7 @@ interface Props {
|
|||
iconHoverLabel?: string;
|
||||
}
|
||||
|
||||
const { t } = await getI18n(Astro.locals.currentLocale);
|
||||
const { t, getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||
|
||||
const {
|
||||
thumbnail,
|
||||
|
@ -38,6 +41,37 @@ const {
|
|||
icon = "material-symbols:unknown-document",
|
||||
iconHoverLabel = t("global.previewTypes.unknown"),
|
||||
} = 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 ------------------------------------------- */}
|
||||
|
@ -89,11 +123,11 @@ const {
|
|||
}
|
||||
|
||||
{
|
||||
attributes.length > 0 && (
|
||||
clippedAttributes.length > 0 && (
|
||||
<>
|
||||
{subtitle && <hr />}
|
||||
<div id="tags">
|
||||
<InlineAttributes attributes={attributes} />
|
||||
<InlineAttributes attributes={clippedAttributes} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -2,18 +2,30 @@
|
|||
import GenericPreview from "components/Previews/GenericPreview.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import type { EndpointPage } from "src/shared/payload/payload-sdk";
|
||||
import type { Attribute } from "src/utils/attributes";
|
||||
|
||||
interface Props {
|
||||
page: EndpointPage;
|
||||
}
|
||||
|
||||
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale);
|
||||
const { getLocalizedMatch, getLocalizedUrl, t, formatDate } = await getI18n(
|
||||
Astro.locals.currentLocale
|
||||
);
|
||||
|
||||
const {
|
||||
page: { slug, translations, thumbnail, attributes },
|
||||
page: { slug, translations, thumbnail, attributes, updatedAt },
|
||||
} = Astro.props;
|
||||
|
||||
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 ------------------------------------------- */}
|
||||
|
@ -24,7 +36,7 @@ const { title, pretitle, subtitle } = getLocalizedMatch(translations);
|
|||
subtitle={subtitle}
|
||||
thumbnail={thumbnail}
|
||||
href={getLocalizedUrl(`/pages/${slug}`)}
|
||||
attributes={attributes}
|
||||
attributes={[...attributes, ...metaAttributes]}
|
||||
icon="material-symbols:docs"
|
||||
iconHoverLabel={t("global.previewTypes.page")}
|
||||
/>
|
||||
|
|
|
@ -34,8 +34,6 @@ const {
|
|||
|
||||
const { pretitle, title, subtitle, description } = getLocalizedMatch(translations);
|
||||
|
||||
const smallTitle = !subtitle && !pretitle;
|
||||
|
||||
const metaAttributes = [
|
||||
...(filename && title !== filename
|
||||
? [
|
||||
|
@ -81,13 +79,7 @@ const metaAttributes = [
|
|||
<AudioPlayer audio={audio} class="audio_id-audio-player" />
|
||||
|
||||
<div id="info">
|
||||
{
|
||||
smallTitle ? (
|
||||
<h1>{title}</h1>
|
||||
) : (
|
||||
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
|
||||
)
|
||||
}
|
||||
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
|
||||
{description && <RichText content={description} />}
|
||||
{attributes.length > 0 && <Attributes attributes={attributes} />}
|
||||
{credits.length > 0 && <Credits credits={credits} />}
|
||||
|
|
|
@ -76,5 +76,6 @@ const metaAttributes = [
|
|||
attributes={attributes}
|
||||
metaAttributes={metaAttributes}
|
||||
credits={credits}
|
||||
smallTitle={title === filename}
|
||||
/>
|
||||
</AppLayout>
|
||||
|
|
|
@ -40,5 +40,6 @@ const translation = getLocalizedMatch(translations);
|
|||
? getLocalizedUrl(`/collectibles/${slug}/scans/${nextIndex}`)
|
||||
: undefined}
|
||||
filename={image.filename}
|
||||
smallTitle
|
||||
/>
|
||||
</AppLayout>
|
||||
|
|
|
@ -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>
|
|
@ -64,5 +64,6 @@ const metaAttributes = [
|
|||
attributes={attributes}
|
||||
metaAttributes={metaAttributes}
|
||||
credits={credits}
|
||||
smallTitle={title === filename}
|
||||
/>
|
||||
</AppLayout>
|
||||
|
|
|
@ -24,7 +24,7 @@ const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.cu
|
|||
<div class="card-container">
|
||||
<Card>
|
||||
<div class="card-content prose">
|
||||
<h3 class="font-serif font-3xl">{t("timeline.notes.title")}</h3>
|
||||
<h3>{t("timeline.notes.title")}</h3>
|
||||
|
||||
<p
|
||||
set:html={t("timeline.notes.content", {
|
||||
|
@ -38,7 +38,7 @@ const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.cu
|
|||
|
||||
<Card>
|
||||
<div class="card-content prose">
|
||||
<h3 class="font-serif font-3xl">{t("timeline.priorCataclysmNote.title")}</h3>
|
||||
<h3>{t("timeline.priorCataclysmNote.title")}</h3>
|
||||
|
||||
<p
|
||||
set:html={t("timeline.priorCataclysmNote.content", {
|
||||
|
@ -52,7 +52,7 @@ const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.cu
|
|||
|
||||
<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 }) => (
|
||||
|
|
|
@ -33,7 +33,6 @@ const {
|
|||
} = video;
|
||||
|
||||
const { pretitle, title, subtitle, description } = getLocalizedMatch(translations);
|
||||
const smallTitle = !subtitle && !pretitle;
|
||||
|
||||
const metaAttributes = [
|
||||
...(filename && title !== filename
|
||||
|
@ -80,13 +79,7 @@ const metaAttributes = [
|
|||
<VideoPlayer class="video_id-video-player" video={video} />
|
||||
|
||||
<div id="info">
|
||||
{
|
||||
smallTitle ? (
|
||||
<h1>{title}</h1>
|
||||
) : (
|
||||
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
|
||||
)
|
||||
}
|
||||
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} />
|
||||
{description && <RichText content={description} />}
|
||||
{attributes.length > 0 && <Attributes attributes={attributes} />}
|
||||
{credits.length > 0 && <Credits credits={credits} />}
|
||||
|
|
Loading…
Reference in New Issue