coworking-stream-guide/src/components/blocks/verticalNav.astro
2024-10-03 13:43:28 +10:00

189 lines
4.7 KiB
Text

---
import SearchModal from "../ui/SearchModal.astro";
type Navigation = Record<
string,
{ title: string; url: string; order: number }[]
>;
const currentUrl = Astro.url.pathname;
const isCurrentUrl = (url: string) => currentUrl === url;
export function formatTitle(title: string): string {
return title
.split("-")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ");
}
export async function setup() {
// setup navigation
// Define the order of categories
let categoryOrder = ["Get Started", "Guide", "Tutorials"];
const getStartedFiles = await Astro.glob("../../pages/get-started/*");
const guideFiles = await Astro.glob("../../pages/guide/*");
const tutorialFiles = await Astro.glob("../../pages/tutorials/*");
let markdownFiles = [...getStartedFiles, ...guideFiles, ...tutorialFiles];
let navigation: Navigation = {};
for (const file of markdownFiles) {
let filePath = file.url;
let [_, category] = filePath!.split("/");
let formattedCategory = formatTitle(category).toLowerCase();
let formattedTitle = file.frontmatter.title;
let order = file.frontmatter.order ?? 0;
if (!navigation[formattedCategory]) {
navigation[formattedCategory] = [];
}
navigation[formattedCategory].push({
title: formattedTitle,
url: filePath || "",
order,
});
}
// Create a new navigation object with the desired order
let orderedNavigation: Navigation = {};
for (let category of categoryOrder) {
if (navigation[category.toLowerCase()]) {
orderedNavigation[category] = navigation[
category.toLowerCase()
].sort((a, b) => a.order - b.order);
}
}
return {
navigation: orderedNavigation,
};
}
interface Props {
showHome?: boolean | null;
}
// setup navigation
const { navigation } = await setup();
// show Home link in vertical navbar only on mobile
const { showHome } = Astro.props;
---
<div class="relative">
<nav id="vertical-nav-component" class="flex flex-col" data-pagefind-ignore>
{
showHome && (
<div class="mb-5">
<SearchModal id="vertical" open="Open modal" />
</div>
)
}
{
showHome && (
<div class="mb-2">
<a
href="/"
class={`no-target-blank px-2 rounded-md w-full hover:no-underline hover:text-white text-lg mt-0
${isCurrentUrl("/") ? "text-white" : "text-gray-400"}`}
>
Home
</a>
</div>
)
}
{
Object.entries(navigation).map(([category, links]) => (
<div class="mb-2">
<div class="category no-target-blank rounded-md text-lg font-bold mb-1 mt-0 text-white">
{category}
</div>
<ul class="list-disc list-outside font-normal">
{links.map((link) => (
<li class="mb-1 pl-0">
<a
href={link.url}
class={`no-target-blank px-2 rounded-md w-full transition-colors duration-150 hover:no-underline hover:text-white ${isCurrentUrl(link.url) ? "text-black bg-primary-green" : "text-gray-400 bg-none"}`}
>
{link.title}
</a>
</li>
))}
</ul>
</div>
))
}
<div class="mb-2">
<a
href="/groups"
class={`no-target-blank px-2 rounded-md w-full transition-colors duration-150 hover:no-underline hover:text-white text-lg mt-0
${isCurrentUrl("/groups") ? "text-black bg-primary-green" : "text-gray-400"}`}
>
Groups
</a>
</div>
<div class="mb-2">
<a
href="/credits"
class={`no-target-blank px-2 rounded-md w-full transition-colors duration-150 hover:no-underline hover:text-white text-lg mt-0
${isCurrentUrl("/credits") ? "text-black bg-primary-green" : "text-gray-400"}`}
>
Credits
</a>
</div>
</nav>
</div>
<script>
document.addEventListener("astro:page-load", () => {
const currentUrl = window.location.pathname;
const isCurrentUrl = (url: string) => currentUrl === url;
const links = document.querySelectorAll(
"#vertical-nav-component a:not(.category), #vertical-nav-component a > a:not(.category)"
);
// add active class to current url
links.forEach((link) => {
if (isCurrentUrl(link.getAttribute("href")!)) {
link.classList.add("text-black", "bg-primary-green");
link.classList.remove(
"text-gray-400",
"bg-none",
"hover:text-white"
);
} else {
link.classList.remove("text-black", "bg-primary-green");
link.classList.add(
"text-gray-400",
"bg-none",
"hover:text-white"
);
}
});
// close dialog
const dialog = document.querySelector("dialog");
if (dialog) {
dialog.close();
}
});
// @ts-ignore
new PagefindUI({
element: "#vertical-search",
showSubResults: false,
showEmptyFilters: false,
debounceTimeoutMs: 0,
showImages: false,
autofocus: false,
});
</script>