Skip to content

Commit

Permalink
feat: add 'works' disclosure menu
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinstadler committed Sep 30, 2024
1 parent 550caff commit 9f263c0
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 38 deletions.
8 changes: 7 additions & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,13 @@ export default function LocaleLayout(props: LocaleLayoutProps): ReactNode {

<Providers
locale={locale}
messages={pick(messages, ["Error", "SearchPage", "PublicationCover"])}
messages={pick(messages, [
"AppHeader",
"BernhardCategories",
"Error",
"SearchPage",
"PublicationCover",
])}
>
<AppLayout>
<AppHeader />
Expand Down
94 changes: 94 additions & 0 deletions components/app-header-nav-menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"use client";
import { useTranslations } from "next-intl";
import { type ReactNode, useId, useState } from "react";

import { AppNavLink } from "@/components/app-nav-link";
import type { LinkProps } from "@/components/link";
import { createHref } from "@/lib/create-href";
import { otherCategories, proseCategories } from "@/lib/model";

import { DisclosureButton } from "./disclosure-button";

export function AppHeaderNavMenu(): ReactNode {
const t = useTranslations("AppHeader");
const catt = useTranslations("BernhardCategories");

const links = {
home: { href: createHref({ pathname: "/" }), label: t("links.home") },
languages: {
href: createHref({ pathname: "/languages" }),
label: t("links.languages"),
},
translators: {
href: createHref({ pathname: "/translators" }),
label: t("links.translators"),
},
search: {
href: createHref({ pathname: "/search" }),
label: t("links.search"),
},
} satisfies Record<string, { href: LinkProps["href"]; label: string }>;

const worksMenu = useId();
const [worksMenuOpen, setWorksMenuOpen] = useState(false);
const proseMenu = useId();
const [proseMenuOpen, setProseMenuOpen] = useState(false);

return (
<nav aria-label={t("navigation-primary")}>
<ul className="flex h-10 items-center gap-4 text-sm" role="list">
{Object.entries(links).map(([id, link]) => {
return (
<li key={id}>
<AppNavLink href={link.href}>{link.label}</AppNavLink>
</li>
);
})}
<li>
<DisclosureButton
controls={worksMenu}
label={t("links.works")}
setState={setWorksMenuOpen}
state={worksMenuOpen}
/>
</li>
</ul>
{worksMenuOpen ? (
<ul className="flex h-10 items-center gap-4 text-sm" id={worksMenu} role="list">
<li>
<DisclosureButton
controls={proseMenu}
label={catt("prose")}
setState={setProseMenuOpen}
state={proseMenuOpen}
/>
</li>
{otherCategories.map((c) => {
return (
<AppNavLink
key={c}
href={`/works/${c}`}
onClick={() => {
setProseMenuOpen(false);
}}
>
{catt(c)}
</AppNavLink>
);
})}
</ul>
) : null}
{worksMenuOpen && proseMenuOpen ? (
<ul className="flex h-10 items-center gap-4 text-sm" id={proseMenu} role="list">
{proseCategories.map((c) => {
return (
<AppNavLink key={c} href={`/works/${c}`}>
{catt(c)}
</AppNavLink>
);
})}
</ul>
) : null}
</nav>
);
}
41 changes: 4 additions & 37 deletions components/app-header.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,11 @@
import { useTranslations } from "next-intl";
import type { ReactNode } from "react";

import { AppNavLink } from "@/components/app-nav-link";
import { ColorSchemeSwitcher } from "@/components/color-scheme-switcher";
import { Link, type LinkProps } from "@/components/link";
import { createHref } from "@/lib/create-href";
import { Link } from "@/components/link";

export function AppHeader(): ReactNode {
const t = useTranslations("AppHeader");

const links = {
home: { href: createHref({ pathname: "/" }), label: t("links.home") },
works: {
href: createHref({ pathname: "/works/novels" }),
label: t("links.works"),
},
languages: {
href: createHref({ pathname: "/languages" }),
label: t("links.languages"),
},
translators: {
href: createHref({ pathname: "/translators" }),
label: t("links.translators"),
},
search: {
href: createHref({ pathname: "/search" }),
label: t("links.search"),
},
} satisfies Record<string, { href: LinkProps["href"]; label: string }>;
import { AppHeaderNavMenu } from "./app-header-nav-menu";

export function AppHeader(): ReactNode {
return (
<header className="border-b">
<div className="container flex items-center justify-between gap-4 py-6">
Expand All @@ -37,17 +14,7 @@ export function AppHeader(): ReactNode {
thomas bernhard in translation
</Link>
</div>
<nav aria-label={t("navigation-primary")}>
<ul className="flex items-center gap-4 text-sm" role="list">
{Object.entries(links).map(([id, link]) => {
return (
<li key={id}>
<AppNavLink href={link.href}>{link.label}</AppNavLink>
</li>
);
})}
</ul>
</nav>
<AppHeaderNavMenu />
<div className="flex items-center gap-4">
<ColorSchemeSwitcher />
</div>
Expand Down
25 changes: 25 additions & 0 deletions components/disclosure-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { ReactNode } from "react";

interface DisclosureButtonProps {
controls: string;
label: string;
state: boolean;
// eslint-disable-next-line @typescript-eslint/ban-types
setState: Function;
}

export function DisclosureButton(props: DisclosureButtonProps): ReactNode {
const toggleState = () => {
props.setState(!props.state);
};
return (
<button
aria-controls={props.controls}
aria-expanded={props.state}
onClick={toggleState}
type="button"
>
{props.label}
</button>
);
}

0 comments on commit 9f263c0

Please sign in to comment.