improve sources and parent pages

This commit is contained in:
DrMint 2024-03-22 23:14:47 +01:00
parent 0c4d5e4007
commit 1d5e34f1a6
10 changed files with 131 additions and 99 deletions

View File

@ -8,6 +8,7 @@
## Mid term ## Mid term
- Support for nameless section - Support for nameless section
- [Timeline] Error if collectible not published?
- [Collectibles] Create page for gallery - [Collectibles] Create page for gallery
- [Collectibles] Create page for scans - [Collectibles] Create page for scans
- When the tags overflow, the tag group name should be align start (see http://localhost:12499/en/pages/magnitude-negative-chapter-1) - When the tags overflow, the tag group name should be align start (see http://localhost:12499/en/pages/magnitude-negative-chapter-1)

View File

@ -2,13 +2,13 @@
import Html from "./components/Html.astro"; import Html from "./components/Html.astro";
import Topbar from "./components/Topbar/Topbar.astro"; import Topbar from "./components/Topbar/Topbar.astro";
import Footer from "./components/Footer.astro"; import Footer from "./components/Footer.astro";
import type { ParentPage, PayloadImage } from "src/shared/payload/payload-sdk"; import type { EndpointSource, PayloadImage } from "src/shared/payload/payload-sdk";
import AppLayoutBackgroundImg from "./components/AppLayoutBackgroundImg.astro"; import AppLayoutBackgroundImg from "./components/AppLayoutBackgroundImg.astro";
import type { ComponentProps } from "astro/types"; import type { ComponentProps } from "astro/types";
interface Props { interface Props {
openGraph?: ComponentProps<typeof Html>["openGraph"]; openGraph?: ComponentProps<typeof Html>["openGraph"];
parentPages?: ParentPage[]; parentPages?: EndpointSource[];
hideFooterLinks?: boolean; hideFooterLinks?: boolean;
backgroundImage?: PayloadImage | undefined; backgroundImage?: PayloadImage | undefined;
} }

View File

@ -4,12 +4,12 @@ import Button from "components/Button.astro";
import ThemeSelector from "./components/ThemeSelector.astro"; import ThemeSelector from "./components/ThemeSelector.astro";
import LanguageSelector from "./components/LanguageSelector.astro"; import LanguageSelector from "./components/LanguageSelector.astro";
import CurrencySelector from "./components/CurrencySelector.astro"; import CurrencySelector from "./components/CurrencySelector.astro";
import type { ParentPage } from "src/shared/payload/payload-sdk";
import ParentPagesButton from "./components/ParentPagesButton.astro"; import ParentPagesButton from "./components/ParentPagesButton.astro";
import { getI18n } from "src/i18n/i18n"; import { getI18n } from "src/i18n/i18n";
import type { EndpointSource } from "src/shared/payload/payload-sdk";
interface Props { interface Props {
parentPages?: ParentPage[] | undefined; parentPages?: EndpointSource[] | undefined;
hideHomeButton?: boolean; hideHomeButton?: boolean;
} }

View File

@ -1,13 +1,13 @@
--- ---
import Tooltip from "components/Tooltip.astro"; import Tooltip from "components/Tooltip.astro";
import type { ParentPage } from "src/shared/payload/payload-sdk";
import ParentPageLink from "./ParentPageLink.astro";
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import { getI18n } from "src/i18n/i18n"; import { getI18n } from "src/i18n/i18n";
import ReturnToButton from "./ReturnToButton.astro"; import ReturnToButton from "./ReturnToButton.astro";
import type { EndpointSource } from "src/shared/payload/payload-sdk";
import SourceRow from "components/SourceRow.astro";
interface Props { interface Props {
parentPages: ParentPage[]; parentPages: EndpointSource[];
} }
const { parentPages } = Astro.props; const { parentPages } = Astro.props;
@ -24,10 +24,12 @@ 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">
<p>{t("header.nav.parentPages.tooltip")}</p> <p>{t("header.nav.parentPages.tooltip")}</p>
<div>
{parentPages.map((parentPage) => ( {parentPages.map((parentPage) => (
<ParentPageLink parentPage={parentPage} /> <SourceRow source={parentPage} />
))} ))}
</div> </div>
</div>
<div class="pressable-label"> <div class="pressable-label">
<Icon name="material-symbols:keyboard-return" /> <Icon name="material-symbols:keyboard-return" />
<p> <p>
@ -44,7 +46,14 @@ const { t } = await getI18n(Astro.locals.currentLocale);
<style> <style>
#tooltip-content { #tooltip-content {
display: grid; > p {
gap: 1em; margin-bottom: 1em;
}
> div {
display: flex;
flex-direction: column;
gap: 0.5em;
}
} }
</style> </style>

View File

@ -1,44 +1,32 @@
--- ---
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import { getI18n } from "src/i18n/i18n"; import { getI18n } from "src/i18n/i18n";
import { Collections, type ParentPage } from "src/shared/payload/payload-sdk"; import type { EndpointSource } from "src/shared/payload/payload-sdk";
interface Props { interface Props {
parentPage: ParentPage; parentPage: EndpointSource;
} }
const { parentPage } = Astro.props; const { parentPage } = Astro.props;
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale); const { formatEndpointSource } = await getI18n(Astro.locals.currentLocale);
const translation = getLocalizedMatch(parentPage.translations); const {
href,
let href = ""; typeLabel,
let collectionLabel = ""; label,
switch (parentPage.collection) { target = undefined,
case Collections.Folders: rel = undefined,
href = getLocalizedUrl(`/folders/${parentPage.slug}`); } = formatEndpointSource(parentPage);
collectionLabel = t("header.nav.parentPages.collections.folder");
break;
case Collections.Collectibles:
href = getLocalizedUrl(`/collectibles/${parentPage.slug}`);
collectionLabel = t("header.nav.parentPages.collections.collectible");
break;
default:
href = "/404";
break;
}
--- ---
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
<a href={href}> <a href={href} target={target} rel={rel}>
<div class="pressable-label"> <div class="pressable-label">
<Icon name="material-symbols:keyboard-return" /> <Icon name="material-symbols:keyboard-return" />
<p> <p>
<span>{collectionLabel}</span> <span>{typeLabel}</span>
{translation.name} {label}
</p> </p>
</div> </div>
</a> </a>

View File

@ -1,38 +1,26 @@
--- ---
import { getI18n } from "src/i18n/i18n"; import { getI18n } from "src/i18n/i18n";
import { Collections, type ParentPage } from "src/shared/payload/payload-sdk"; import type { EndpointSource } from "src/shared/payload/payload-sdk";
interface Props { interface Props {
parentPage: ParentPage; source: EndpointSource;
} }
const { parentPage } = Astro.props; const { source } = Astro.props;
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale); const { formatEndpointSource } = await getI18n(Astro.locals.currentLocale);
const translation = getLocalizedMatch(parentPage.translations); const {
href,
let href = ""; typeLabel,
let collectionLabel = ""; label,
switch (parentPage.collection) { target = undefined,
case Collections.Folders: rel = undefined,
href = getLocalizedUrl(`/folders/${parentPage.slug}`); } = formatEndpointSource(source);
collectionLabel = t("header.nav.parentPages.collections.folder");
break;
case Collections.Collectibles:
href = getLocalizedUrl(`/collectibles/${parentPage.slug}`);
collectionLabel = t("header.nav.parentPages.collections.collectible");
break;
default:
href = "/404";
break;
}
--- ---
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
<a href={href}><div>{collectionLabel}</div><p>{translation.name}</p></a> <a href={href} target={target} rel={rel}><div>{typeLabel}</div><p>{label}</p></a>
{/* ------------------------------------------- CSS -------------------------------------------- */} {/* ------------------------------------------- CSS -------------------------------------------- */}

View File

@ -1,7 +1,7 @@
import type { WordingKey } from "src/i18n/wordings-keys"; import type { WordingKey } from "src/i18n/wordings-keys";
import type { ChronologyEvent } from "src/shared/payload/payload-sdk"; import type { ChronologyEvent, EndpointSource } from "src/shared/payload/payload-sdk";
import { cache } from "src/utils/cachedPayload"; import { cache } from "src/utils/cachedPayload";
import { capitalize } from "src/utils/format"; import { capitalize, formatInlineTitle } from "src/utils/format";
export const defaultLocale = "en"; export const defaultLocale = "en";
@ -173,6 +173,70 @@ export const getI18n = async (locale: string) => {
); );
}; };
const formatEndpointSource = (source: EndpointSource) => {
switch (source.type) {
case "url":
return {
href: source.url,
typeLabel: t("global.sources.typeLabel.url"),
label: source.label,
target: "_blank",
rel: "noopener noreferrer",
};
case "collectible":
const rangeLabel = (() => {
switch (source.range?.type) {
case "timestamp":
return t("global.sources.typeLabel.collectible.range.timestamp", {
page: source.range.timestamp,
});
case "page":
return t("global.sources.typeLabel.collectible.range.page", {
page: source.range.page,
});
case "custom":
return t("global.sources.typeLabel.collectible.range.custom", {
note: getLocalizedMatch(source.range.translations).note,
});
case undefined:
default:
return "";
}
})();
return {
href: getLocalizedUrl(`/collectibles/${source.collectible.slug}`),
typeLabel: t("global.sources.typeLabel.collectible"),
label: formatInlineTitle(getLocalizedMatch(source.collectible.translations)) + rangeLabel,
};
case "page":
return {
href: getLocalizedUrl(`/pages/${source.page.slug}`),
typeLabel: t("global.sources.typeLabel.page"),
label: formatInlineTitle(getLocalizedMatch(source.page.translations)),
};
case "folder":
return {
href: getLocalizedUrl(`/folders/${source.folder.slug}`),
typeLabel: t("global.sources.typeLabel.folder"),
label: getLocalizedMatch(source.folder.translations).name,
};
default:
return {
href: "/404",
label: `Invalid type ${source["type"]}`,
typeLabel: "Error",
};
}
};
return { return {
t, t,
getLocalizedMatch, getLocalizedMatch,
@ -185,5 +249,6 @@ export const getI18n = async (locale: string) => {
formatMillimeters, formatMillimeters,
formatNumber, formatNumber,
formatTimelineDate, formatTimelineDate,
formatEndpointSource,
}; };
}; };

View File

@ -104,4 +104,11 @@ export type WordingKey =
| "timeline.year.during" | "timeline.year.during"
| "timeline.eventFooter.languages" | "timeline.eventFooter.languages"
| "timeline.eventFooter.sources" | "timeline.eventFooter.sources"
| "timeline.eventFooter.note"; | "timeline.eventFooter.note"
| "global.sources.typeLabel.url"
| "global.sources.typeLabel.page"
| "global.sources.typeLabel.collectible"
| "global.sources.typeLabel.folder"
| "global.sources.typeLabel.collectible.range.page"
| "global.sources.typeLabel.collectible.range.timestamp"
| "global.sources.typeLabel.collectible.range.custom";

View File

@ -1,9 +1,9 @@
--- ---
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import SourceRow from "components/SourceRow.astro";
import Tooltip from "components/Tooltip.astro"; import Tooltip from "components/Tooltip.astro";
import { getI18n } from "src/i18n/i18n"; import { getI18n } from "src/i18n/i18n";
import type { EndpointSource } from "src/shared/payload/payload-sdk"; import type { EndpointSource } from "src/shared/payload/payload-sdk";
import { formatInlineTitle } from "src/utils/format";
interface Props { interface Props {
sources: EndpointSource[]; sources: EndpointSource[];
@ -11,30 +11,12 @@ interface Props {
const { sources } = Astro.props; const { sources } = Astro.props;
const { getLocalizedUrl, getLocalizedMatch, t } = await getI18n(Astro.locals.currentLocale); 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">
{ {sources.map((source) => <SourceRow source={source} />)}
sources.map((source) =>
source.type === "url" ? (
<a class="pressable-link" href={source.url} target={"_blank"} rel={"noopener noreferrer"}>
{source.label}
</a>
) : source.type === "collectible" ? (
<a
class="pressable-link"
href={getLocalizedUrl(`/collectibles/${source.collectible.slug}`)}>
{formatInlineTitle(getLocalizedMatch(source.collectible.translations))}
</a>
) : (
<a class="pressable-link" href={getLocalizedUrl(`/pages/${source.page.slug}`)}>
{formatInlineTitle(getLocalizedMatch(source.page.translations))}
</a>
)
)
}
</div> </div>
<div class="pressable-label"> <div class="pressable-label">
<Icon name="material-symbols:edit-note" /> <Icon name="material-symbols:edit-note" />

View File

@ -862,9 +862,6 @@ export interface SectionBlock {
blockType: "sectionBlock"; blockType: "sectionBlock";
} }
declare module "payload" {
export interface GeneratedTypes extends Config {}
}
/////////////// CONSTANTS /////////////// /////////////// CONSTANTS ///////////////
@ -1299,7 +1296,7 @@ export type EndpointFolder = EndpointFolderPreview & {
value: EndpointPagePreview; value: EndpointPagePreview;
} }
)[]; )[];
parentPages: ParentPage[]; parentPages: EndpointSource[];
}; };
export type EndpointHomeFolder = EndpointFolderPreview & { export type EndpointHomeFolder = EndpointFolderPreview & {
@ -1369,13 +1366,7 @@ export type EndpointPage = EndpointPagePreview & {
proofreaders: EndpointRecorder[]; proofreaders: EndpointRecorder[];
toc: TableOfContentEntry[]; toc: TableOfContentEntry[];
})[]; })[];
parentPages: ParentPage[]; parentPages: EndpointSource[];
};
export type ParentPage = {
slug: string;
collection: Collections;
translations: { language: string; name: string }[];
}; };
export type EndpointCollectiblePreview = { export type EndpointCollectiblePreview = {
@ -1450,7 +1441,7 @@ export type EndpointCollectible = EndpointCollectiblePreview & {
}[]; }[];
}; };
}[]; }[];
parentPages: ParentPage[]; parentPages: EndpointSource[];
}; };
export type TableOfContentEntry = { export type TableOfContentEntry = {
@ -1493,7 +1484,8 @@ export type EndpointSource =
| { type: "timestamp"; timestamp: string } | { type: "timestamp"; timestamp: string }
| { type: "custom"; translations: { language: string; note: string }[] }; | { type: "custom"; translations: { language: string; note: string }[] };
} }
| { type: "page"; page: EndpointPagePreview }; | { type: "page"; page: EndpointPagePreview }
| { type: "folder"; folder: EndpointFolderPreview };
export type PayloadImage = { export type PayloadImage = {
url: string; url: string;
@ -1523,5 +1515,5 @@ export const payload = {
getChronologyEvents: async (): Promise<EndpointChronologyEvent[]> => getChronologyEvents: async (): Promise<EndpointChronologyEvent[]> =>
await (await request(payloadApiUrl(Collections.ChronologyEvents, `all`))).json(), await (await request(payloadApiUrl(Collections.ChronologyEvents, `all`))).json(),
getChronologyEventByID: async (id: string): Promise<EndpointChronologyEvent> => getChronologyEventByID: async (id: string): Promise<EndpointChronologyEvent> =>
await (await request(payloadApiUrl(Collections.ChronologyEvents, id))).json(), await (await request(payloadApiUrl(Collections.ChronologyEvents, `id/${id}`))).json(),
}; };