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