Compare commits
No commits in common. "d02c0838981acc879fc7b246d3a5db57a9384724" and "a212258c078060299d4e974774508b57f95a94ee" have entirely different histories.
d02c083898
...
a212258c07
@ -3,21 +3,14 @@ import type { IconProps } from "./Icon";
|
|||||||
|
|
||||||
import { Icon } from "./Icon";
|
import { Icon } from "./Icon";
|
||||||
import { Link } from "./Link";
|
import { Link } from "./Link";
|
||||||
import clsx from "clsx";
|
|
||||||
|
|
||||||
type QuickLinksProps = {
|
type QuickLinksProps = {
|
||||||
children: JSXElement;
|
children: JSXElement;
|
||||||
class?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function QuickLinks(props: QuickLinksProps) {
|
export default function QuickLinks(props: QuickLinksProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div class="not-prose my-12 grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||||
class={clsx(
|
|
||||||
"not-prose my-12 grid grid-cols-1 gap-6 sm:grid-cols-2",
|
|
||||||
props.class,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -27,7 +20,6 @@ type QuickLinkProps = {
|
|||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
href: string;
|
href: string;
|
||||||
lastEdited?: Date;
|
|
||||||
icon: IconProps["icon"];
|
icon: IconProps["icon"];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,26 +29,13 @@ QuickLinks.QuickLink = (props: QuickLinkProps) => (
|
|||||||
<div class="relative overflow-hidden rounded-xl p-6">
|
<div class="relative overflow-hidden rounded-xl p-6">
|
||||||
<Icon icon={props.icon} color="blue" class="h-8 w-8" />
|
<Icon icon={props.icon} color="blue" class="h-8 w-8" />
|
||||||
|
|
||||||
<h2 class="mt-4 font-display text-base text-slate-900 leading-5">
|
<h2 class="mt-4 font-display text-base text-slate-900">
|
||||||
<Link href={props.href}>
|
<Link href={props.href}>
|
||||||
<span class="absolute -inset-px rounded-xl" />
|
<span class="absolute -inset-px rounded-xl" />
|
||||||
{props.title}
|
{props.title}
|
||||||
</Link>
|
</Link>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{props.lastEdited && (
|
|
||||||
<p class="mt-2 mb-4 italic text-xs text-slate-500">
|
|
||||||
<span class="font-semibold">Dernière modification :</span>{" "}
|
|
||||||
<time datetime={props.lastEdited.toISOString()}>
|
|
||||||
{props.lastEdited.toLocaleDateString("fr-FR", {
|
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
})}
|
|
||||||
</time>
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<p class="mt-1 text-sm text-slate-700">{props.description}</p>
|
<p class="mt-1 text-sm text-slate-700">{props.description}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import type { JSXElement } from "solid-js";
|
|||||||
|
|
||||||
import { PrevNextLinks } from "@/components/PrevNextLinks";
|
import { PrevNextLinks } from "@/components/PrevNextLinks";
|
||||||
import { usePageContext } from "vike-solid/usePageContext";
|
import { usePageContext } from "vike-solid/usePageContext";
|
||||||
import { LatestDocs } from "@/partials/LatestDocs";
|
|
||||||
import { clientOnly } from "vike-solid/clientOnly";
|
import { clientOnly } from "vike-solid/clientOnly";
|
||||||
import { clock } from "solid-heroicons/outline";
|
import { clock } from "solid-heroicons/outline";
|
||||||
import { navigation } from "@/libs/navigation";
|
import { navigation } from "@/libs/navigation";
|
||||||
@ -22,25 +21,21 @@ export function DocsLayout(props: DocsLayoutProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div class="flex">
|
<main
|
||||||
<main
|
id="article-content"
|
||||||
id="article-content"
|
class="max-w-2xl min-w-0 flex-auto px-4 py-16 lg:max-w-none lg:pr-0 lg:pl-8 xl:px-16 grow"
|
||||||
class="max-w-2xl min-w-0 flex-auto px-4 py-16 lg:max-w-none lg:pr-0 lg:pl-8 xl:px-16 grow"
|
>
|
||||||
>
|
<article>
|
||||||
<article>
|
<DocsHeader
|
||||||
<DocsHeader
|
title={pageContext.exports.frontmatter?.title}
|
||||||
title={pageContext.exports.frontmatter?.title}
|
estimatedReadingTime={pageContext.exports.readingTime?.text}
|
||||||
estimatedReadingTime={pageContext.exports.readingTime?.text}
|
/>
|
||||||
/>
|
<Prose>{props.children}</Prose>
|
||||||
<Prose>{props.children}</Prose>
|
</article>
|
||||||
</article>
|
<PrevNextLinks />
|
||||||
<PrevNextLinks />
|
</main>
|
||||||
</main>
|
|
||||||
|
|
||||||
<TableOfContents />
|
<TableOfContents />
|
||||||
</div>
|
|
||||||
|
|
||||||
<LatestDocs />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import type { JSXElement } from "solid-js";
|
|||||||
import { usePageContext } from "vike-solid/usePageContext";
|
import { usePageContext } from "vike-solid/usePageContext";
|
||||||
import { SmoothScroll } from "@/components/SmoothScroll";
|
import { SmoothScroll } from "@/components/SmoothScroll";
|
||||||
import { HeroSection } from "@/partials/HeroSection";
|
import { HeroSection } from "@/partials/HeroSection";
|
||||||
import { clientOnly } from "vike-solid/clientOnly";
|
|
||||||
import { Navigation } from "@/partials/Navigation";
|
import { Navigation } from "@/partials/Navigation";
|
||||||
|
import { clientOnly } from "vike-solid/clientOnly";
|
||||||
import { Header } from "@/partials/Header";
|
import { Header } from "@/partials/Header";
|
||||||
import { Footer } from "@/partials/Footer";
|
import { Footer } from "@/partials/Footer";
|
||||||
import { DocsLayout } from "./DocsLayout";
|
import { DocsLayout } from "./DocsLayout";
|
||||||
@ -40,10 +40,7 @@ export default function DefaultLayout(props: DefaultLayoutProps) {
|
|||||||
<Navigation />
|
<Navigation />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<DocsLayout>{props.children}</DocsLayout>
|
||||||
<div class="flex flex-col">
|
|
||||||
<DocsLayout>{props.children}</DocsLayout>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
@ -38,10 +38,5 @@ export async function data(pageContext: PageContext) {
|
|||||||
return {
|
return {
|
||||||
sections: doc?.sections || [],
|
sections: doc?.sections || [],
|
||||||
frontmatter,
|
frontmatter,
|
||||||
docs: docCache.orderByLastEdit({
|
|
||||||
limit: 2,
|
|
||||||
includedBasePaths: ["docs", "certifications"],
|
|
||||||
excludedFileNames: [cachePathname],
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
import type { Data } from "@/pages/+data";
|
|
||||||
|
|
||||||
import QuickLinks from "@/components/QuickLinks";
|
|
||||||
import { useData } from "vike-solid/useData";
|
|
||||||
import { For } from "solid-js";
|
|
||||||
|
|
||||||
export function LatestDocs() {
|
|
||||||
const data = useData<Data>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section class="bg-violet-200 rounded-md p-4 m-6">
|
|
||||||
<h2 class="font-display text-3xl tracking-tight text-slate-900 text-center">
|
|
||||||
Dernières documentations
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<QuickLinks class="!mb-0 !mt-6">
|
|
||||||
<For each={data.docs}>
|
|
||||||
{(doc) => (
|
|
||||||
<QuickLinks.QuickLink
|
|
||||||
title={doc.frontmatter?.title || ""}
|
|
||||||
description={doc.frontmatter?.description || ""}
|
|
||||||
lastEdited={doc.lastEdit}
|
|
||||||
href={doc.filePath}
|
|
||||||
icon="presets"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</QuickLinks>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -27,9 +27,7 @@ function NavigationItem(props: NavigationItemProps) {
|
|||||||
return props.section.links.some((link) => checkIsLinkActive(link));
|
return props.section.links.some((link) => checkIsLinkActive(link));
|
||||||
};
|
};
|
||||||
|
|
||||||
const [isOpened, setIsOpened] = createSignal(
|
const [isOpened, setIsOpened] = createSignal(checkIsActive());
|
||||||
checkIsActive() || pageContext.urlPathname === "/",
|
|
||||||
);
|
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
// If the current URL path is the same as the link's href, set isOpened to true
|
// If the current URL path is the same as the link's href, set isOpened to true
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import type { FlexSearchData } from "./FlexSearchService";
|
||||||
|
import type { TableOfContents } from "@/remarkHeadingId";
|
||||||
import type { Node } from "@markdoc/markdoc";
|
import type { Node } from "@markdoc/markdoc";
|
||||||
|
|
||||||
import { slugifyWithCounter } from "@sindresorhus/slugify";
|
import { slugifyWithCounter } from "@sindresorhus/slugify";
|
||||||
@ -14,8 +16,6 @@ export type SectionCache = {
|
|||||||
frontmatter?: SectionFrontmatter;
|
frontmatter?: SectionFrontmatter;
|
||||||
markdocNode: Node;
|
markdocNode: Node;
|
||||||
sections: DocSection[];
|
sections: DocSection[];
|
||||||
lastEdit: Date;
|
|
||||||
filePath: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DocSection = {
|
export type DocSection = {
|
||||||
@ -32,14 +32,6 @@ type SectionFrontmatter = {
|
|||||||
tags: string[];
|
tags: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type OrderConfig = {
|
|
||||||
limit: number;
|
|
||||||
includedBasePaths: string[];
|
|
||||||
excludedBasePaths: string[];
|
|
||||||
includedFileNames: string[];
|
|
||||||
excludedFileNames: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
class DocCache {
|
class DocCache {
|
||||||
private static readonly pagesDir = path.join(__dirname, "pages");
|
private static readonly pagesDir = path.join(__dirname, "pages");
|
||||||
private static instance: DocCache | null = null;
|
private static instance: DocCache | null = null;
|
||||||
@ -170,17 +162,12 @@ class DocCache {
|
|||||||
.replace(/\+Page\.md(x)?$/, "")
|
.replace(/\+Page\.md(x)?$/, "")
|
||||||
.replace(/\/+/, "/")
|
.replace(/\/+/, "/")
|
||||||
.replace(/\/$/, "");
|
.replace(/\/$/, "");
|
||||||
const lastEdit = new Date(
|
|
||||||
(await fs.stat(path.join(DocCache.pagesDir, file))).mtime,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.cache.set(filePath, {
|
this.cache.set(filePath, {
|
||||||
content,
|
content,
|
||||||
frontmatter,
|
frontmatter,
|
||||||
markdocNode,
|
markdocNode,
|
||||||
sections: this.getTableOfContents(markdocNode),
|
sections: this.getTableOfContents(markdocNode),
|
||||||
lastEdit,
|
|
||||||
filePath,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,72 +207,6 @@ class DocCache {
|
|||||||
return this.cache.get(file);
|
return this.cache.get(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public orderByLastEdit(customConfig?: Partial<OrderConfig>): SectionCache[] {
|
|
||||||
const config: OrderConfig = {
|
|
||||||
excludedBasePaths: [],
|
|
||||||
includedBasePaths: [],
|
|
||||||
excludedFileNames: [],
|
|
||||||
includedFileNames: [],
|
|
||||||
limit: 0,
|
|
||||||
...customConfig,
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkIfIncludedBasePath = (doc: SectionCache) => {
|
|
||||||
if (config.includedBasePaths.length > 0) {
|
|
||||||
return config.includedBasePaths.some((basePath) => {
|
|
||||||
return doc.filePath.startsWith(basePath);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkIfExcludedBasePaths = (doc: SectionCache) => {
|
|
||||||
if (config.excludedBasePaths.length > 0) {
|
|
||||||
return !config.excludedBasePaths.some((basePath) => {
|
|
||||||
return doc.filePath.startsWith(basePath);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkIfIncludedFileNames = (doc: SectionCache) => {
|
|
||||||
if (config.includedFileNames.length > 0) {
|
|
||||||
return config.includedFileNames.some((fileName) => {
|
|
||||||
return doc.filePath.includes(fileName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkIfExcludedFileNames = (doc: SectionCache) => {
|
|
||||||
if (config.excludedFileNames.length > 0) {
|
|
||||||
return !config.excludedFileNames.some((fileName) => {
|
|
||||||
return doc.filePath.includes(fileName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const sortedDocs = Array.from(this.cache.values())
|
|
||||||
.sort((a, b) => b.lastEdit.getTime() - a.lastEdit.getTime())
|
|
||||||
.filter((doc) => {
|
|
||||||
return [
|
|
||||||
checkIfIncludedBasePath(doc),
|
|
||||||
checkIfExcludedBasePaths(doc),
|
|
||||||
checkIfIncludedFileNames(doc),
|
|
||||||
checkIfExcludedFileNames(doc),
|
|
||||||
].every((check) => check === true);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (config.limit > 0) return sortedDocs.slice(0, config.limit);
|
|
||||||
|
|
||||||
return sortedDocs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public waitingForCache(timeout: 20000): Promise<void> {
|
public waitingForCache(timeout: 20000): Promise<void> {
|
||||||
const timer = hrtime();
|
const timer = hrtime();
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user