diff --git a/app/components/syntax/Navigation.tsx b/app/components/syntax/Navigation.tsx
index f543071..1ae09f1 100644
--- a/app/components/syntax/Navigation.tsx
+++ b/app/components/syntax/Navigation.tsx
@@ -2,7 +2,7 @@ import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/solid";
import { usePageContext } from "vike-react/usePageContext";
import { Link } from "@/components/common/Link";
import { navigation } from "@/lib/navigation";
-import { useState } from "react";
+import { useEffect, useState } from "react";
import clsx from "clsx";
type NavigationItemProps = {
@@ -50,50 +50,101 @@ function NavigationItem(props: NavigationItemProps) {
{isOpened && (
{props.section.links.map((link) => (
-
+ subitem.href === urlPathname)}
+ />
+
+ ))}
+
+ )}
+ >
+ );
+}
+
+type NavigationSubItemProps = {
+ link: (typeof navigation)[number]["links"][number];
+ onLinkClick?: React.MouseEventHandler;
+ isOpened?: boolean;
+};
+
+function NavigationSubItem(props: NavigationSubItemProps) {
+ const [isOpened, setIsOpened] = useState(props.isOpened);
+ const { urlPathname } = usePageContext();
+
+ useEffect(() => {
+ setIsOpened(
+ props.link.href === urlPathname || props.link.subitems?.some((subitem) => subitem.href === urlPathname),
+ );
+ }, [urlPathname, props.link]);
+
+ return (
+ <>
+
+ {props.link.subitems.length > 0 && (
+ {
+ if (e.key === "Enter" || e.key === " ") {
+ setIsOpened((prev) => !prev);
+ e.preventDefault();
+ }
+ }}
+ onClick={() => setIsOpened((prev) => !prev)}
+ >
+ {isOpened ? (
+
+ ) : (
+
+ )}
+ {isOpened ? "Masquer" : "Afficher"}
+
+ )}
+
+
+ {props.link.title}
+ {props.link.subitems.length > 0 && (
+ ({props.link.subitems.length})
+ )}
+
+
+ {props.link.subitems && isOpened && (
+
+ {props.link.subitems.map((subitem) => (
+ -
subitem.href === urlPathname)
+ "block w-full pl-3.5 before:pointer-events-none before:absolute before:top-1/2 before:-left-1 before:h-1.5 before:w-1.5 before:-translate-y-1/2 before:rounded-full",
+ subitem.href === urlPathname
? "font-semibold text-violet-500 before:bg-violet-500"
: "text-slate-500 before:hidden before:bg-slate-300 hover:text-slate-600 hover:before:block dark:text-slate-400 dark:before:bg-slate-700 dark:hover:text-slate-300",
)}
>
- {link.title}
- {link.subitems.length > 0 && (
- ({link.subitems.length})
- )}
+ {subitem.title}
- {link.subitems && (
-
- {link.subitems.map((subitem) => (
- -
-
- {subitem.title}
-
-
- ))}
-
- )}
))}
diff --git a/app/lib/navigation.ts b/app/lib/navigation.ts
index da9785d..3add153 100644
--- a/app/lib/navigation.ts
+++ b/app/lib/navigation.ts
@@ -11,9 +11,14 @@ export type NavigationSection = {
links: NavigationLink[];
};
+export type NavigationOG = Partial<{
+ image: string;
+}>;
+
export type NavigationLink = {
title: string;
href: string;
+ og?: NavigationOG;
subitems: NavigationSubItem[];
};
@@ -101,6 +106,7 @@ export const navigation: NavigationSection[] = [
{
title: "Merise",
href: "/docs/merise",
+ og: { image: "/merise/og.webp" },
subitems: [
{ title: "Introduction", href: "/docs/merise" },
{ title: "Dictionnaire de données", href: "/docs/merise/dictionnaire-de-donnees" },
@@ -112,3 +118,16 @@ export const navigation: NavigationSection[] = [
],
},
];
+
+export function findNavigationLink(namespace: string, href: string) {
+ const currentUrl = `/${namespace}/${href}`.replace(/\/+/g, "/").replace(/\/$/, "");
+
+ const links = navigation.flatMap((section) => section.links);
+ const subitems = links.flatMap((link) => link.subitems);
+ const allLinks = new Set([...links, ...subitems]);
+ const foundLink = Array.from(allLinks).find((link) => link.href === currentUrl);
+
+ console.log({ allLinks, currentUrl });
+
+ return foundLink;
+}
diff --git a/app/pages/+Head.tsx b/app/pages/+Head.tsx
index 429fd8a..48371af 100644
--- a/app/pages/+Head.tsx
+++ b/app/pages/+Head.tsx
@@ -1,4 +1,4 @@
-import logoUrl from "../assets/logo.svg";
+import logoUrl from "@/assets/logo.svg";
export default function HeadDefault() {
return (
diff --git a/app/pages/+config.ts b/app/pages/+config.ts
index 80c7eee..ac63eef 100644
--- a/app/pages/+config.ts
+++ b/app/pages/+config.ts
@@ -23,6 +23,8 @@ export default {
class: "flex min-h-full bg-white dark:bg-slate-900",
},
+ image: null,
+
// prerender: true,
prefetchStaticAssets: "hover",
diff --git a/app/pages/docs/+data.ts b/app/pages/docs/+data.ts
index 68da945..abfc020 100644
--- a/app/pages/docs/+data.ts
+++ b/app/pages/docs/+data.ts
@@ -1,6 +1,7 @@
import type { PageContext } from "vike/types";
import { snippetsService } from "@/services/SnippetsService";
+import { findNavigationLink } from "@/lib/navigation";
import { docsService } from "@/services/DocsService";
import { readingTime } from "reading-time-estimator";
import { useConfig } from "vike-react/useConfig";
@@ -15,6 +16,7 @@ export async function data(pageContext: PageContext) {
const { key } = pageContext.routeParams;
const doc = await docsService.getDoc("docs", key);
+ const link = findNavigationLink("docs", key);
if (!doc) {
throw render(404);
@@ -25,6 +27,7 @@ export async function data(pageContext: PageContext) {
config({
title: buildTitle(doc.title),
description: doc.description,
+ image: link?.og?.image || "notfound",
});
docsService.transform(doc);
diff --git a/app/public/merise/og.webp b/app/public/merise/og.webp
new file mode 100644
index 0000000..8dfbe5e
Binary files /dev/null and b/app/public/merise/og.webp differ