Skip to content

Commit

Permalink
feat: basic pages
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinstadler committed Jul 30, 2024
1 parent 57b7574 commit 20a387d
Show file tree
Hide file tree
Showing 14 changed files with 509 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
echo "APP_NAME_SUFFIX=$APP_NAME_SUFFIX" >> $GITHUB_OUTPUT
outputs:
environment: "${{ steps.environment.outputs.ENVIRONMENT }}"
app_name: "frontend${{ steps.environment.outputs.APP_NAME_SUFFIX }}"
app_name: "thomas-bernhard-global${{ steps.environment.outputs.APP_NAME_SUFFIX }}"
registry: "ghcr.io"
image: "${{ github.repository }}"

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ jobs:

build-deploy:
if: ${{ github.event_name == 'push' }}
needs: [validate]
# needs: [validate]
uses: ./.github/workflows/build-deploy.yml
secrets: inherit
# https://docs.github.com/en/actions/using-workflows/reusing-workflows#access-and-permissions
Expand Down
31 changes: 14 additions & 17 deletions app/(index)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { Metadata, ResolvingMetadata } from "next";
import { useTranslations } from "next-intl";
import { getTranslations } from "next-intl/server";
import type { ReactNode } from "react";

import { Logo } from "@/components/logo";
import { MainContent } from "@/components/main-content";
import { ClickablePublicationThumbnail } from "@/components/publication-cover";

import { getPublications } from "../data";

interface IndexPageProps extends EmptyObject {}

Expand All @@ -27,22 +27,19 @@ export async function generateMetadata(
}

export default function IndexPage(_props: IndexPageProps): ReactNode {
const t = useTranslations("IndexPage");
// const t = useTranslations("IndexPage");

const pubs = getPublications({ erstpublikation: true }, undefined, "RANDOM()", 0, 12);

return (
<MainContent className="container py-8">
<section className="mx-auto grid w-full max-w-screen-lg items-start justify-items-center gap-3 px-4 py-8 text-center md:py-12">
<div className="flex items-center gap-2 rounded-lg bg-muted px-3 py-1 text-sm font-medium leading-tight">
<Logo className="size-4 shrink-0" />
<span>{t("badge")}</span>
</div>
<h1 className="text-balance text-3xl font-bold leading-tight tracking-tighter md:text-5xl lg:text-6xl">
{t("title")}
</h1>
<div className="mx-auto w-full max-w-screen-md text-pretty text-lg text-on-muted sm:text-xl">
{t("lead-in")}
<section className="mx-auto grid w-full max-w-screen-lg items-start justify-items-center gap-3 px-4 py-8 text-center md:py-12">
<div className="mx-auto w-full max-w-screen-md text-pretty text-lg text-on-muted sm:text-xl">
<div className="grid grid-cols-3 gap-4 lg:grid-cols-4">
{pubs.map((p) => {
return <ClickablePublicationThumbnail key={p.signatur} publication={p} />;
})}
</div>
</section>
</MainContent>
</div>
</section>
);
}
1 change: 1 addition & 0 deletions app/data.json

Large diffs are not rendered by default.

123 changes: 123 additions & 0 deletions app/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import type {
BernhardWork,
Publication,
publicationTypes,
Translation,
Translator,
} from "@/types/model";

import data from "./data.json";

const publications = data.publications as unknown as Record<string, Publication>;
const bernhardworks = data.bernhardworks as unknown as Array<BernhardWork>;
const translators = data.translators as unknown as Array<Translator>;
const translations = data.translations as unknown as Array<Translation>;

const languages = Array.from(
new Set(
Object.values(publications).map((e) => {
return e.language;
}),
),
).sort();

export function getChildren(pub: Publication): Array<Publication> | undefined {
return pub.parents
?.flatMap((ps) => {
return getPublication(ps.signatur);
})
.filter((p) => {
return p !== undefined;
});
}
export function getLanguages(): Array<string> {
return languages;
}

export function getPublication(signatur: string): Publication | undefined {
return publications[signatur];
}

export function getPublications(
filter?: { [key in keyof Publication]?: Publication[key] },
category?: typeof publicationTypes,
sort?: string,
offset = 0,
limit = 10,
): Array<Publication> {
let pubs = Object.values(publications);

if (category) {
pubs = pubs.filter((p) => {
return p.categories.includes(category);
});
}
if (filter) {
for (const key in filter) {
pubs = pubs.filter((p) => {
return p[key as keyof Publication] === filter[key as keyof Publication];
});
}
}

if (sort) {
// TODO sort by actual key if given
pubs.sort(() => {
return Math.random() - 0.5;
});
}

return limit ? pubs.slice(offset, offset + limit) : pubs.slice(offset);
}

// get 4 publications, ideally in the same language but excluding the publication
export function getSameLanguagePublications(pub: Publication) {
return Object.values(publications)
.filter((p) => {
return p.language === pub.language && p.signatur !== pub.signatur;
})
.sort(() => {
return Math.random() - 0.5;
})
.slice(0, 3);
}

export function getTranslation(id: number): Translation | undefined {
return translations[id - 1];
}

export function getTranslator(id: number): Translator | undefined {
return translators[id - 1];
}

export function getTranslators(): Array<Translator> | undefined {
return translators;
}

export function getWork(gndOrId: string): BernhardWork | undefined {
return bernhardworks.find((w) => {
return w.gnd === gndOrId || w.id === gndOrId;
});
}

// get list of works but actually by way of publications of that category...
export function getWorks(category?: typeof publicationTypes): Array<BernhardWork> {
const pubs: Array<Publication> = getPublications({}, category, undefined, 0, 0);
const translations = pubs.flatMap((p) => {
return p.contains;
});
const works = [
...new Set(
translations.map((t) => {
return t.work;
}),
),
];
return works
.map((i) => {
return bernhardworks[(i as unknown as number) - 1];
})
.filter((w) => {
return w !== undefined;
});
}
10 changes: 10 additions & 0 deletions app/language/[language]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import LanguagesPage from "../page";

interface LanguagePageProps {
params: {
language?: string;
};
}
export default function LanguagePage(props: LanguagePageProps) {
return <LanguagesPage language={props.params.language} />;
}
47 changes: 47 additions & 0 deletions app/language/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// eslint-disable-next-line no-restricted-imports
import Link from "next/link";
import { useTranslations } from "next-intl";

import { getLanguages, getPublications } from "@/app/data";
import { ClickablePublicationThumbnail } from "@/components/publication-cover";

interface LanguagesPageProps {
language?: string;
}
export default function LanguagesPage(props: LanguagesPageProps) {
const t = useTranslations("LanguagesPage");

const ls = getLanguages();
const filter = props.language ? { language: props.language } : undefined;

const pubs = getPublications(filter);
// TODO throw error if empty

return (
<div className="flex">
<div className="w-44">
<span className="font-bold">{t("languages")}</span>
<ul>
{ls.map((l) => {
return (
<li key={l}>
<Link href={`/language/${l}`}>{l}</Link>
</li>
);
})}
</ul>
</div>
<div>
<select>
<option>all works</option>
<option>what&apos;s this dropdown??</option>
</select>
<div className="grid grid-cols-3">
{pubs.map((p) => {
return <ClickablePublicationThumbnail key={p.signatur} publication={p} />;
})}
</div>
</div>
</div>
);
}
9 changes: 6 additions & 3 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Providers } from "@/app/providers";
import { AppFooter } from "@/components/app-footer";
import { AppHeader } from "@/components/app-header";
import { AppLayout } from "@/components/app-layout";
import { id } from "@/components/main-content";
import { id, MainContent } from "@/components/main-content";
import { SkipLink } from "@/components/skip-link";
import { env } from "@/config/env.config";
import { AnalyticsScript } from "@/lib/analytics-script";
Expand Down Expand Up @@ -73,7 +73,6 @@ export async function generateMetadata(

export default function LocaleLayout(props: LocaleLayoutProps): ReactNode {
const { children } = props;

const locale = useLocale();

const t = useTranslations("LocaleLayout");
Expand Down Expand Up @@ -118,11 +117,15 @@ export default function LocaleLayout(props: LocaleLayoutProps): ReactNode {
<Providers locale={locale} messages={pick(messages, ["Error"])}>
<AppLayout>
<AppHeader />
{children}
<MainContent className="container flex justify-center py-8">
<div className="mx-auto max-w-xl">{children}</div>
</MainContent>
<AppFooter />
</AppLayout>
</Providers>
</body>
</html>
);
}

// return (<html lang={locale}><body className="flex flex-col gap-16 p-10">
68 changes: 68 additions & 0 deletions app/publication/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { notFound } from "next/navigation";
import { useTranslations } from "next-intl";

import { getChildren, getPublication, getSameLanguagePublications, getWork } from "@/app/data";
import { ClickablePublicationThumbnail, PublicationCover } from "@/components/publication-cover";

interface PublicationPageProps {
params: {
id: string;
};
}

export default function PublicationPage(props: PublicationPageProps) {
const t = useTranslations("PublicationPage");
const pub = getPublication(props.params.id);
if (!pub) {
return notFound();
}
const later = getChildren(pub);
return (
<>
<h1 className="font-bold">{pub.title}</h1>
<h2 className="italic">{pub.categories.join(", ")}</h2>
<div className="flex flex-initial">
<div className="relative w-40 flex-auto">
<PublicationCover publication={pub} />
</div>
<div className="flex-auto">
<p className="italic">{pub.language}</p>
<p>{t("translated_by")} ...</p>
{/* TODO map over all works, find unique translators? */}
<p>{pub.year}</p>
<p className="italic">{t("contains")}</p>
<p>
{pub.contains
.map((t) => {
return t.title; // title of the translation
})
.join(" / ")}
</p>
<p>
{pub.contains
.map((t) => {
return getWork(String(t.work))?.title;
})
.join(" / ")}
</p>

{later ? (
<>
<p className="font-bold">{t("later_editions")}</p>
<div className="flex">...</div>
</>
) : null}

<p className="font-bold">
{t("more_in")} {pub.language}
</p>
<div className="flex">
{getSameLanguagePublications(pub).map((p) => {
return <ClickablePublicationThumbnail key={p.signatur} publication={p} />;
})}
</div>
</div>
</div>
</>
);
}
Loading

0 comments on commit 20a387d

Please sign in to comment.