feat: Update navigation structure and add subitems
This commit is contained in:
parent
82258addeb
commit
717ca15a83
@ -50,7 +50,7 @@ function NavigationItem(props: NavigationItemProps) {
|
||||
{isOpened && (
|
||||
<ul
|
||||
role="list"
|
||||
className="mt-2 space-y-2 border-l-2 border-slate-100 lg:mt-4 lg:space-y-4 lg:border-slate-200 dark:border-slate-800 mb-9"
|
||||
className="mt-2 space-y-2 border-l-2 border-slate-100 lg:mt-4 lg:space-y-4 lg:border-slate-200 dark:border-slate-800 mb-4"
|
||||
>
|
||||
{props.section.links.map((link) => (
|
||||
<li key={link.href} className="relative">
|
||||
@ -67,7 +67,9 @@ function NavigationItem(props: NavigationItemProps) {
|
||||
)}
|
||||
>
|
||||
{link.title}
|
||||
{link.subitems && <span className="text-slate-400 dark:text-slate-500"> ({link.subitems.length})</span>}
|
||||
{link.subitems.length > 0 && (
|
||||
<span className="text-slate-400 dark:text-slate-500"> ({link.subitems.length})</span>
|
||||
)}
|
||||
</Link>
|
||||
{link.subitems && (
|
||||
<ul
|
||||
@ -125,11 +127,12 @@ export function Navigation({
|
||||
return (
|
||||
<nav className={clsx("text-base lg:text-sm", className)}>
|
||||
<ul role="list" className="space-y-4">
|
||||
{firstSections.map((section) => (
|
||||
<li key={section.title}>
|
||||
<NavigationItem section={section} onLinkClick={onLinkClick} />
|
||||
</li>
|
||||
))}
|
||||
<li>
|
||||
<h2 className="font-display font-bold text-base text-slate-900 dark:text-white">{firstSections[0]?.type}</h2>
|
||||
{firstSections.map((section) => (
|
||||
<NavigationItem key={section.title} section={section} onLinkClick={onLinkClick} />
|
||||
))}
|
||||
</li>
|
||||
{Object.entries(filteredSections).map(([type, sections]) => (
|
||||
<li key={type}>
|
||||
<h2 className="font-display font-bold text-base text-slate-900 dark:text-white">{type}</h2>
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import { navigation, NavigationLink, type NavigationSubItem } from "@/lib/navigation";
|
||||
import { usePageContext } from "vike-react/usePageContext";
|
||||
import { Link } from "@/components/common/Link";
|
||||
import clsx from "clsx";
|
||||
|
||||
import { navigation } from "@/lib/navigation";
|
||||
|
||||
function ArrowIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 16 16" aria-hidden="true" {...props}>
|
||||
@ -23,8 +22,8 @@ function PageLink({
|
||||
dir?: "previous" | "next";
|
||||
}) {
|
||||
const pageCategory = navigation.find((section) => {
|
||||
return section.links.some((link) => link.href === href);
|
||||
})!;
|
||||
return section.links.some((link) => link.href === href || link.subitems.some((subitem) => subitem.href === href));
|
||||
});
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
@ -40,7 +39,9 @@ function PageLink({
|
||||
)}
|
||||
>
|
||||
<p className="flex flex-col gap-0">
|
||||
<span className="text-violet-600 dark:text-violet-400 text-sm -mb-3">{pageCategory.title}</span>
|
||||
{pageCategory && (
|
||||
<span className="text-violet-600 dark:text-violet-400 text-sm -mb-3">{pageCategory.title}</span>
|
||||
)}
|
||||
<span>{title}</span>
|
||||
</p>
|
||||
<ArrowIcon className={clsx("h-6 w-6 flex-none fill-current", dir === "previous" && "-scale-x-100")} />
|
||||
@ -51,12 +52,45 @@ function PageLink({
|
||||
}
|
||||
|
||||
export function PrevNextLinks() {
|
||||
const allLinks = navigation.flatMap((section) => section.links);
|
||||
const { urlPathname } = usePageContext();
|
||||
|
||||
const allLinks = navigation.flatMap((section) => section.links);
|
||||
const linkIndex = allLinks.findIndex((link) => link.href === urlPathname);
|
||||
const previousPage = linkIndex > -1 ? allLinks[linkIndex - 1] : null;
|
||||
const nextPage = linkIndex > -1 ? allLinks[linkIndex + 1] : null;
|
||||
let subItemElement: undefined | NavigationSubItem;
|
||||
|
||||
const findLinkIndex = (pathname = urlPathname) => {
|
||||
for (let i = 0; i < allLinks.length; i++) {
|
||||
const link = allLinks[i];
|
||||
|
||||
if (link.href === urlPathname) {
|
||||
return i;
|
||||
}
|
||||
|
||||
if (link.subitems) {
|
||||
const subitemIndex = link.subitems.findIndex((subitem) => subitem.href === urlPathname);
|
||||
|
||||
if (subitemIndex !== -1) {
|
||||
subItemElement = link.subitems[subitemIndex];
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const linkIndex = findLinkIndex();
|
||||
if (linkIndex === undefined) return null;
|
||||
|
||||
let previousPage: NavigationSubItem | NavigationLink | null = linkIndex > -1 ? allLinks[linkIndex - 1] : null;
|
||||
let nextPage: NavigationSubItem | NavigationLink | null = linkIndex > -1 ? allLinks[linkIndex + 1] : null;
|
||||
|
||||
if (subItemElement !== undefined) {
|
||||
const subItemIndex = findLinkIndex(subItemElement.href)!;
|
||||
const currentPage = allLinks[subItemIndex];
|
||||
const subItemIndexInLink = currentPage.subitems?.findIndex((subitem) => subitem.href === urlPathname);
|
||||
if (subItemIndexInLink !== undefined && subItemIndexInLink > -1) {
|
||||
previousPage = currentPage.subitems[subItemIndexInLink - 1];
|
||||
nextPage = currentPage.subitems[subItemIndexInLink + 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!nextPage && !previousPage) {
|
||||
return null;
|
||||
|
||||
@ -4,15 +4,42 @@ const navigationsTypes = {
|
||||
DOCUMENTATIONS: "📚 Documentations",
|
||||
};
|
||||
|
||||
export const navigation = [
|
||||
export type NavigationSection = {
|
||||
title: string;
|
||||
type: (typeof navigationsTypes)[keyof typeof navigationsTypes];
|
||||
position: "start" | "auto";
|
||||
links: NavigationLink[];
|
||||
};
|
||||
|
||||
export type NavigationLink = {
|
||||
title: string;
|
||||
href: string;
|
||||
subitems: NavigationSubItem[];
|
||||
};
|
||||
|
||||
export type NavigationSubItem = {
|
||||
title: string;
|
||||
href: string;
|
||||
};
|
||||
|
||||
export const navigation: NavigationSection[] = [
|
||||
{
|
||||
title: "Préambule",
|
||||
type: navigationsTypes.GLOBAL,
|
||||
position: "start",
|
||||
links: [
|
||||
{ title: "Memento Dev", href: "/" },
|
||||
{ title: "Certifications", href: "/certifications" },
|
||||
{ title: "Documentations", href: "/docs" },
|
||||
{ title: "Memento Dev", href: "/", subitems: [] },
|
||||
{ title: "Certifications", href: "/certifications", subitems: [] },
|
||||
{ title: "Documentations", href: "/docs", subitems: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Communauté",
|
||||
type: navigationsTypes.GLOBAL,
|
||||
position: "start",
|
||||
links: [
|
||||
{ title: "Influenceurs", href: "/docs/communaute/influenceurs", subitems: [] },
|
||||
{ title: "Partages et réutilisations", href: "/docs/communaute/partages", subitems: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -20,7 +47,7 @@ export const navigation = [
|
||||
type: navigationsTypes.CERTIFICATIONS,
|
||||
position: "auto",
|
||||
links: [
|
||||
{ title: "Résumé", href: "/certifications/dwwm" },
|
||||
{ title: "Résumé", href: "/certifications/dwwm", subitems: [] },
|
||||
{
|
||||
title: "Activité Type 1",
|
||||
href: "/certifications/dwwm/at1",
|
||||
@ -44,37 +71,38 @@ export const navigation = [
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "React",
|
||||
title: "Front-end",
|
||||
type: navigationsTypes.DOCUMENTATIONS,
|
||||
position: "auto",
|
||||
links: [
|
||||
{ title: "Introduction", href: "/docs/react" },
|
||||
{ title: "Initialisation", href: "/docs/react/initialisation" },
|
||||
{ title: "Syntaxe JSX", href: "/docs/react/jsx" },
|
||||
{ title: "Premier composant", href: "/docs/react/premier-composant" },
|
||||
{ title: "State et cycle de vie", href: "/docs/react/state-et-cycle-de-vie" },
|
||||
{ title: "Hooks", href: "/docs/react/hooks" },
|
||||
{ title: "Le hook useContext", href: "/docs/react/use-context" },
|
||||
{ title: "Le hook useReducer", href: "/docs/react/use-reducer" },
|
||||
{
|
||||
title: "React",
|
||||
href: "/docs/react",
|
||||
subitems: [
|
||||
{ title: "Initialisation", href: "/docs/react/initialisation" },
|
||||
{ title: "Syntaxe JSX", href: "/docs/react/jsx" },
|
||||
{ title: "Premier composant", href: "/docs/react/premier-composant" },
|
||||
{ title: "State et cycle de vie", href: "/docs/react/state-et-cycle-de-vie" },
|
||||
{ title: "Hooks", href: "/docs/react/hooks" },
|
||||
{ title: "Le hook useContext", href: "/docs/react/use-context" },
|
||||
{ title: "Le hook useReducer", href: "/docs/react/use-reducer" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Merise",
|
||||
title: "Base de données",
|
||||
type: navigationsTypes.DOCUMENTATIONS,
|
||||
position: "auto",
|
||||
links: [
|
||||
{ title: "Introduction", href: "/docs/merise" },
|
||||
{ title: "Dictionnaire de données", href: "/docs/merise/dictionnaire-de-donnees" },
|
||||
{ title: "Modèle Conceptuel de Données", href: "/docs/merise/modele-conceptuel-de-donnees" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Communauté",
|
||||
type: navigationsTypes.GLOBAL,
|
||||
position: "start",
|
||||
links: [
|
||||
{ title: "Influenceurs", href: "/docs/communaute/influenceurs" },
|
||||
{ title: "Partages et réutilisations", href: "/docs/communaute/partages" },
|
||||
{
|
||||
title: "Merise",
|
||||
href: "/docs/merise",
|
||||
subitems: [
|
||||
{ title: "Dictionnaire de données", href: "/docs/merise/dictionnaire-de-donnees" },
|
||||
{ title: "Modèle Conceptuel de Données", href: "/docs/merise/modele-conceptuel-de-donnees" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user