summaryrefslogtreecommitdiffstats
path: root/src/ui/components/SiteHeader.tsx
blob: 17831a1cd1995963df7f50ed1d4c31268ed4d993 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import type { HTMLAttributes } from "corvos/plugins/jsx.ts";

import { Icon } from "$/ui/objects/Icon.tsx";

import { nav } from "../../data/nav.ts";
import { ActionButton } from "../objects/ActionButton.tsx";
import { Navbar } from "../objects/Navbar.tsx";
import { NavbarItem } from "../objects/NavbarItem.tsx";
import { Logo } from "./Logo.tsx";

export type Props = HTMLAttributes<"header"> & {
	"url": string;
	"mode"?: "compact" | "none";
	"at-end"?: boolean;
	"hidden"?: boolean;
	"sm"?: JSX.Element;
	"end"?: JSX.Element;
	"children"?: JSX.Element;
};

export const SiteHeader = ({
	children,
	sm,
	url,
	mode,
	"at-end": atEnd,
	hidden,
	end,
	class: cls,
	...props
}: Props) => {
	const navItems = nav.map((item) => ({
		...item,
		selected: new RegExp(`^${item.url.replace("/#", "/")}`).test(url),
	}));

	const parent = navItems
		.filter((item) => item.url !== url)
		.reduce(
			(parent: (typeof navItems)[number] | undefined, item) =>
				item.selected && item.url.length > (parent?.url.length ?? 0) ? item : parent,
			undefined,
		);
	const selected = navItems.reduce(
		(sel, item) => (item.selected && item.url.length > sel.url.length ? item : sel),
		{
			icon: "",
			label: "Back",
			selected: true,
			url: "/",
		},
	);

	const variant = atEnd ? "static-white" : undefined;

	return (
		<header
			class:list={[
				"c-site-header",
				"l-media",
				{ "c-site-header--end": atEnd, "c-site-header--hidden": hidden },
				cls,
			]}
			{...props}
		>
			<Logo class="c-site-header__logo l-media__block" variant={variant} />

			{mode !== "none" && (
				<>
					<Navbar aria-label="Mainmenu" class="c-site-header__nav l-media__block" variant={variant}>
						{mode === "compact" ? (
							<NavbarItem
								href={selected.url}
								pre={<Icon icon="arrow-left" variant="bold" />}
								selected
							>
								{selected.label}
							</NavbarItem>
						) : (
							navItems
								.filter((item) => item.url !== "/" && !item.hidden)
								.map((item) => (
									<NavbarItem as="a" href={item.url} selected={item.selected}>
										{item.label}
									</NavbarItem>
								))
						)}
					</Navbar>

					{parent && (
						<ActionButton
							align-block
							class="c-site-header__back l-media__block"
							href={parent.url}
							icon={<Icon icon="arrow-left" variant="bold" />}
							level="quiet"
							pill
						/>
					)}
				</>
			)}

			{children}

			{sm && <div class="c-site-header__slot c-site-header__slot--sm">{sm}</div>}

			{end && (
				<>
					<div class="c-site-header__spacer" />
					<div class="c-site-header__slot c-site-header__slot--end">{end}</div>
				</>
			)}

			<Logo
				class="c-site-header__logo c-site-header__logo--sm l-media__block"
				size="sm"
				variant={variant}
			/>
		</header>
	);
};