Updated credit + language switcher on pages
This commit is contained in:
parent
591ea6b976
commit
5f70ca4b92
3
TODO.md
3
TODO.md
|
@ -9,15 +9,12 @@
|
||||||
|
|
||||||
## Short term
|
## Short term
|
||||||
|
|
||||||
- [Bugs] On android Chrome, the setting button in the header flashes for a few ms when the page is loading
|
|
||||||
- [Bugs] Make sure uploads name are slug-like and with an extension.
|
- [Bugs] Make sure uploads name are slug-like and with an extension.
|
||||||
- [Bugs] Nyupun can't upload subtitles files
|
- [Bugs] Nyupun can't upload subtitles files
|
||||||
- [Bugs] https://v3.accords-library.com/en/collectibles/dod-original-soundtrack/scans obi is way too big
|
- [Bugs] https://v3.accords-library.com/en/collectibles/dod-original-soundtrack/scans obi is way too big
|
||||||
- [Feat] 404, 500 pages
|
- [Feat] 404, 500 pages
|
||||||
- [Feat] [RichTextContent] Handle relationship
|
- [Feat] [RichTextContent] Handle relationship
|
||||||
- [Feat] [Timeline] Improve layout/spacing on mobile
|
- [Feat] [Timeline] Improve layout/spacing on mobile
|
||||||
- [Feat] Display if a content has a source language
|
|
||||||
- [Feat] [JSLess] Display if a content is available in more than one language
|
|
||||||
- [Bugs] Number of audio players seems limited (on Chrome and Firefox)
|
- [Bugs] Number of audio players seems limited (on Chrome and Firefox)
|
||||||
- [Feat] [RichTextContent] Add autolink block support
|
- [Feat] [RichTextContent] Add autolink block support
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,8 @@ const { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div {
|
div {
|
||||||
display: grid;
|
display: flex;
|
||||||
gap: 2em;
|
flex-direction: column;
|
||||||
|
gap: 0.5em;
|
||||||
@media (max-width: 35rem) {
|
|
||||||
gap: 3em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
---
|
|
||||||
import MasoActor from "components/Maso/MasoActor.astro";
|
|
||||||
import Tooltip from "components/Tooltip.astro";
|
|
||||||
import Button from "components/Button.astro";
|
|
||||||
import { formatLocale } from "src/utils/format";
|
|
||||||
import { getI18n } from "src/i18n/i18n";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
currentLanguage: string;
|
|
||||||
currentSourceLanguage: string;
|
|
||||||
getPartialUrl: (locale: string) => string;
|
|
||||||
availableLanguages: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const { currentLanguage, currentSourceLanguage, getPartialUrl, availableLanguages } = Astro.props;
|
|
||||||
const { t } = await getI18n(Astro.locals.currentLocale);
|
|
||||||
---
|
|
||||||
|
|
||||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
|
||||||
|
|
||||||
<div id="lang-selector" class="when-js when-no-print">
|
|
||||||
<Tooltip trigger="click">
|
|
||||||
<Button
|
|
||||||
icon="material-symbols:translate"
|
|
||||||
title={`${currentLanguage !== currentSourceLanguage ? `${currentSourceLanguage.toUpperCase()} → ` : ""}${currentLanguage.toUpperCase()}`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div id="tooltip-content" slot="tooltip-content">
|
|
||||||
{
|
|
||||||
availableLanguages.map((id) => (
|
|
||||||
<MasoActor href={getPartialUrl(id)}>
|
|
||||||
<p class:list={{ current: id === currentLanguage, "pressable-link": true }}>
|
|
||||||
{formatLocale(id)}
|
|
||||||
</p>
|
|
||||||
</MasoActor>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
<p>
|
|
||||||
{
|
|
||||||
t("global.languageOverride.availableLanguages", {
|
|
||||||
count: availableLanguages.length,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
#lang-selector {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1em;
|
|
||||||
|
|
||||||
#tooltip-content {
|
|
||||||
display: grid;
|
|
||||||
gap: 0.5em;
|
|
||||||
|
|
||||||
& .current {
|
|
||||||
color: var(--color-base-750);
|
|
||||||
text-decoration: underline 0.08em var(--color-base-650);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -18,9 +18,11 @@ const { href, method = "get", class: className, id } = Astro.props;
|
||||||
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@media (scripting: enabled) {
|
||||||
maso-actor {
|
maso-actor {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{/* ------------------------------------------- JS --------------------------------------------- */}
|
{/* ------------------------------------------- JS --------------------------------------------- */}
|
||||||
|
|
|
@ -69,8 +69,6 @@ export type WordingKey =
|
||||||
| "collectibles.bookFormat.binding.hardcover"
|
| "collectibles.bookFormat.binding.hardcover"
|
||||||
| "collectibles.bookFormat.binding.readingDirection.leftToRight"
|
| "collectibles.bookFormat.binding.readingDirection.leftToRight"
|
||||||
| "collectibles.bookFormat.binding.readingDirection.rightToLeft"
|
| "collectibles.bookFormat.binding.readingDirection.rightToLeft"
|
||||||
| "collectibles.gallery"
|
|
||||||
| "collectibles.scans"
|
|
||||||
| "collectibles.imageCount"
|
| "collectibles.imageCount"
|
||||||
| "header.topbar.settings.tooltip"
|
| "header.topbar.settings.tooltip"
|
||||||
| "collectibles.contents"
|
| "collectibles.contents"
|
||||||
|
@ -87,31 +85,31 @@ export type WordingKey =
|
||||||
| "global.loading"
|
| "global.loading"
|
||||||
| "pages.tableOfContent.sceneBreak"
|
| "pages.tableOfContent.sceneBreak"
|
||||||
| "pages.tableOfContent.break"
|
| "pages.tableOfContent.break"
|
||||||
| "global.languageOverride.availableLanguages"
|
| "pages.credits.availableLanguages"
|
||||||
| "timeline.title"
|
| "timeline.title"
|
||||||
| "timeline.eras.drakengard3"
|
| "timeline.description"
|
||||||
|
| "timeline.eras.cataclysm"
|
||||||
| "timeline.eras.drakengard"
|
| "timeline.eras.drakengard"
|
||||||
| "timeline.eras.drakengard2"
|
| "timeline.eras.drakengard2"
|
||||||
|
| "timeline.eras.drakengard3"
|
||||||
| "timeline.eras.nier"
|
| "timeline.eras.nier"
|
||||||
| "timeline.eras.nierAutomata"
|
| "timeline.eras.nierAutomata"
|
||||||
| "timeline.eras.cataclysm"
|
| "timeline.jumpTo"
|
||||||
| "timeline.description"
|
|
||||||
| "timeline.notes.title"
|
|
||||||
| "timeline.notes.content"
|
| "timeline.notes.content"
|
||||||
|
| "timeline.notes.title"
|
||||||
| "timeline.priorCataclysmNote.title"
|
| "timeline.priorCataclysmNote.title"
|
||||||
| "timeline.priorCataclysmNote.content"
|
| "timeline.priorCataclysmNote.content"
|
||||||
| "timeline.jumpTo"
|
|
||||||
| "timeline.year.during"
|
| "timeline.year.during"
|
||||||
| "timeline.eventFooter.languages"
|
|
||||||
| "timeline.eventFooter.sources"
|
| "timeline.eventFooter.sources"
|
||||||
|
| "timeline.eventFooter.languages"
|
||||||
| "timeline.eventFooter.note"
|
| "timeline.eventFooter.note"
|
||||||
| "global.sources.typeLabel.url"
|
|
||||||
| "global.sources.typeLabel.page"
|
|
||||||
| "global.sources.typeLabel.collectible"
|
| "global.sources.typeLabel.collectible"
|
||||||
| "global.sources.typeLabel.folder"
|
| "global.sources.typeLabel.collectible.range.custom"
|
||||||
| "global.sources.typeLabel.collectible.range.page"
|
| "global.sources.typeLabel.collectible.range.page"
|
||||||
| "global.sources.typeLabel.collectible.range.timestamp"
|
| "global.sources.typeLabel.collectible.range.timestamp"
|
||||||
| "global.sources.typeLabel.collectible.range.custom"
|
| "global.sources.typeLabel.folder"
|
||||||
|
| "global.sources.typeLabel.page"
|
||||||
|
| "global.sources.typeLabel.url"
|
||||||
| "global.openMediaPage"
|
| "global.openMediaPage"
|
||||||
| "global.downloadButton"
|
| "global.downloadButton"
|
||||||
| "global.previewTypes.video"
|
| "global.previewTypes.video"
|
||||||
|
@ -121,6 +119,8 @@ export type WordingKey =
|
||||||
| "global.previewTypes.collectible"
|
| "global.previewTypes.collectible"
|
||||||
| "global.previewTypes.unknown"
|
| "global.previewTypes.unknown"
|
||||||
| "collectibles.scans.title"
|
| "collectibles.scans.title"
|
||||||
|
| "collectibles.gallery.title"
|
||||||
|
| "collectibles.gallery.subtitle"
|
||||||
| "collectibles.scans.subtitle"
|
| "collectibles.scans.subtitle"
|
||||||
| "collectibles.scans.shortIndex.flapFront"
|
| "collectibles.scans.shortIndex.flapFront"
|
||||||
| "collectibles.scans.shortIndex.front"
|
| "collectibles.scans.shortIndex.front"
|
||||||
|
@ -134,11 +134,9 @@ export type WordingKey =
|
||||||
| "collectibles.scans.obi"
|
| "collectibles.scans.obi"
|
||||||
| "collectibles.scans.obiInside"
|
| "collectibles.scans.obiInside"
|
||||||
| "collectibles.scans.pages"
|
| "collectibles.scans.pages"
|
||||||
| "collectibles.gallery.title"
|
|
||||||
| "collectibles.gallery.subtitle"
|
|
||||||
| "global.sources.typeLabel.scans"
|
|
||||||
| "collectibles.scans.dustjacket.description"
|
| "collectibles.scans.dustjacket.description"
|
||||||
| "collectibles.scans.obi.description"
|
| "collectibles.scans.obi.description"
|
||||||
|
| "global.sources.typeLabel.scans"
|
||||||
| "global.sources.typeLabel.gallery"
|
| "global.sources.typeLabel.gallery"
|
||||||
| "global.media.attributes.filename"
|
| "global.media.attributes.filename"
|
||||||
| "global.media.attributes.duration"
|
| "global.media.attributes.duration"
|
||||||
|
@ -152,5 +150,6 @@ export type WordingKey =
|
||||||
| "collectibles.nature.digital"
|
| "collectibles.nature.digital"
|
||||||
| "global.previewTypes.zip"
|
| "global.previewTypes.zip"
|
||||||
| "global.previewTypes.pdf"
|
| "global.previewTypes.pdf"
|
||||||
| "files.thumbnail.noPreview"
|
| "collectibles.files"
|
||||||
| "collectibles.files";
|
| "pages.credits.translationLabel"
|
||||||
|
| "pages.credits.currentLocale";
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
---
|
||||||
|
import Card from "components/Card.astro";
|
||||||
|
import Credits from "components/Credits.astro";
|
||||||
|
import InlineCredits from "components/InlineCredits.astro";
|
||||||
|
import MasoActor from "components/Maso/MasoActor.astro";
|
||||||
|
import { getI18n } from "src/i18n/i18n";
|
||||||
|
import type { EndpointCredit, EndpointPage } from "src/shared/payload/payload-sdk";
|
||||||
|
import { formatLocale } from "src/utils/format";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
slug: string;
|
||||||
|
currentLocale: string;
|
||||||
|
sourceLanguage: string;
|
||||||
|
credits: EndpointCredit[];
|
||||||
|
otherTranslations: EndpointPage["translations"];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { slug, currentLocale, sourceLanguage, credits, otherTranslations } = Astro.props;
|
||||||
|
|
||||||
|
const { t, getLocalizedUrl } = await getI18n(currentLocale);
|
||||||
|
---
|
||||||
|
|
||||||
|
<div id="credits">
|
||||||
|
<Card class="partial_page-card">
|
||||||
|
<p>{t("pages.credits.currentLocale")}</p>
|
||||||
|
<p class="font-2xl">
|
||||||
|
{formatLocale(currentLocale)}
|
||||||
|
{
|
||||||
|
sourceLanguage !== currentLocale && (
|
||||||
|
<span class="font-m">
|
||||||
|
{t("pages.credits.translationLabel", {
|
||||||
|
locale: formatLocale(sourceLanguage),
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{credits.length > 0 && <Credits credits={credits} />}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{
|
||||||
|
otherTranslations.length > 0 && (
|
||||||
|
<div id="translations">
|
||||||
|
<p>{t("pages.credits.availableLanguages", { count: otherTranslations.length })}</p>
|
||||||
|
|
||||||
|
{otherTranslations.map((translation) => (
|
||||||
|
<MasoActor
|
||||||
|
href={getLocalizedUrl(`/api/pages/partial?lang=${translation.language}&slug=${slug}`)}>
|
||||||
|
<Card class="partial_page-card-other">
|
||||||
|
<p class="font-xl">
|
||||||
|
{formatLocale(translation.language)}
|
||||||
|
{translation.sourceLanguage !== translation.language && (
|
||||||
|
<span class="font-m">
|
||||||
|
{t("pages.credits.translationLabel", {
|
||||||
|
locale: formatLocale(translation.sourceLanguage),
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{translation.credits.length > 0 && <InlineCredits credits={translation.credits} />}
|
||||||
|
</Card>
|
||||||
|
</MasoActor>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#credits {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
@media (max-width: 35rem) {
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partial_page-card {
|
||||||
|
padding: 1.5em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5em;
|
||||||
|
max-width: 35em;
|
||||||
|
|
||||||
|
p > span {
|
||||||
|
margin-left: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
margin-top: 1.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.partial_page-card-other {
|
||||||
|
padding: 1.5em;
|
||||||
|
padding-top: 1.75em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1em;
|
||||||
|
max-width: 35em;
|
||||||
|
|
||||||
|
@media (scripting: enabled) {
|
||||||
|
transition-duration: 150ms;
|
||||||
|
transition-property: border-color, box-shadow, background-color;
|
||||||
|
|
||||||
|
& > p {
|
||||||
|
transition: 150ms color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus-visible {
|
||||||
|
border-color: var(--color-base-650);
|
||||||
|
outline-color: var(--color-base-650);
|
||||||
|
box-shadow: 0 2px 2px var(--color-shadow-2);
|
||||||
|
background-color: color-mix(in srgb, var(--color-elevation-2) 80%, transparent);
|
||||||
|
|
||||||
|
& > p {
|
||||||
|
color: var(--color-base-750);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
border-color: var(--color-base-1000);
|
||||||
|
box-shadow: 0 6px 12px 2px var(--color-shadow-2);
|
||||||
|
background-color: var(--color-elevation-2);
|
||||||
|
outline-color: var(--color-base-1000);
|
||||||
|
|
||||||
|
& > p {
|
||||||
|
color: var(--color-base-1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > #translations {
|
||||||
|
margin-top: 2em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -4,14 +4,13 @@ import type { EndpointPage } from "src/shared/payload/payload-sdk";
|
||||||
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
|
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
|
||||||
import MasoTarget from "components/Maso/MasoTarget.astro";
|
import MasoTarget from "components/Maso/MasoTarget.astro";
|
||||||
import TableOfContent from "components/TableOfContent/TableOfContent.astro";
|
import TableOfContent from "components/TableOfContent/TableOfContent.astro";
|
||||||
import LanguageOverride from "components/LanguageOverride.astro";
|
|
||||||
import Credits from "components/Credits.astro";
|
|
||||||
import { getI18n } from "src/i18n/i18n";
|
import { getI18n } from "src/i18n/i18n";
|
||||||
import AsideLayout from "components/AppLayout/AsideLayout.astro";
|
import AsideLayout from "components/AppLayout/AsideLayout.astro";
|
||||||
import Attributes from "components/Attributes.astro";
|
import Attributes from "components/Attributes.astro";
|
||||||
import type { Attribute } from "src/utils/attributes";
|
import type { Attribute } from "src/utils/attributes";
|
||||||
import { payload } from "src/utils/payload";
|
import { payload } from "src/utils/payload";
|
||||||
import { sizesToSrcset } from "src/utils/img";
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
import PageCredits from "./_components/PageCredits.astro";
|
||||||
|
|
||||||
export const partial = true;
|
export const partial = true;
|
||||||
|
|
||||||
|
@ -103,17 +102,16 @@ if (updatedBy) {
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|
||||||
<Fragment slot="aside">
|
<Fragment slot="aside">
|
||||||
<div id="credits">
|
<PageCredits
|
||||||
<LanguageOverride
|
slug={slug}
|
||||||
currentLanguage={language}
|
currentLocale={lang}
|
||||||
currentSourceLanguage={sourceLanguage}
|
sourceLanguage={sourceLanguage}
|
||||||
availableLanguages={translations.map(({ language }) => language)}
|
credits={credits}
|
||||||
getPartialUrl={(lang) => getLocalizedUrl(`/api/pages/partial?lang=${lang}&slug=${slug}`)}
|
otherTranslations={translations.filter(
|
||||||
|
(otherTranslation) => otherTranslation.language !== language
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{credits.length > 0 && <Credits credits={credits} />}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{metaAttributes.length > 0 && <Attributes attributes={metaAttributes} />}
|
{metaAttributes.length > 0 && <Attributes attributes={metaAttributes} />}
|
||||||
|
|
||||||
{toc.length > 0 && <TableOfContent toc={toc} lang={language} />}
|
{toc.length > 0 && <TableOfContent toc={toc} lang={language} />}
|
||||||
|
@ -136,16 +134,6 @@ if (updatedBy) {
|
||||||
width: min(100%, 35rem);
|
width: min(100%, 35rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#credits {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 16px;
|
|
||||||
|
|
||||||
@media (max-width: 35rem) {
|
|
||||||
gap: 32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#summary {
|
#summary {
|
||||||
@media (max-width: 1280.5px) {
|
@media (max-width: 1280.5px) {
|
||||||
margin-top: -2em;
|
margin-top: -2em;
|
||||||
|
|
|
@ -1566,7 +1566,7 @@ export type EndpointFolderPreview = {
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointFolder = EndpointFolderPreview & {
|
export type EndpointFolder = Omit<EndpointFolderPreview, "translations"> & {
|
||||||
translations: (EndpointFolderPreview["translations"][number] & {
|
translations: (EndpointFolderPreview["translations"][number] & {
|
||||||
description?: RichTextContent;
|
description?: RichTextContent;
|
||||||
})[];
|
})[];
|
||||||
|
@ -1719,7 +1719,7 @@ export type EndpointPagePreview = {
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointPage = EndpointPagePreview & {
|
export type EndpointPage = Omit<EndpointPagePreview, "translations"> & {
|
||||||
backgroundImage?: EndpointPayloadImage;
|
backgroundImage?: EndpointPayloadImage;
|
||||||
translations: (EndpointPagePreview["translations"][number] & {
|
translations: (EndpointPagePreview["translations"][number] & {
|
||||||
sourceLanguage: string;
|
sourceLanguage: string;
|
||||||
|
@ -1752,7 +1752,7 @@ export type EndpointCollectiblePreview = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointCollectible = EndpointCollectiblePreview & {
|
export type EndpointCollectible = Omit<EndpointCollectiblePreview, "translations"> & {
|
||||||
translations: (EndpointCollectiblePreview["translations"][number] & {
|
translations: (EndpointCollectiblePreview["translations"][number] & {
|
||||||
description?: RichTextContent;
|
description?: RichTextContent;
|
||||||
})[];
|
})[];
|
||||||
|
@ -1985,7 +1985,7 @@ export type EndpointMediaPreview = {
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointMedia = EndpointMediaPreview & {
|
export type EndpointMedia = Omit<EndpointMediaPreview, "translations"> & {
|
||||||
filesize: number;
|
filesize: number;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
|
Loading…
Reference in New Issue