Compare commits

...

5 Commits

29 changed files with 95 additions and 184 deletions

View File

@ -1,41 +0,0 @@
import MermaidRenderer from "react-mermaid2";
type MermaidProps = {
path: string;
};
export function Mermaid(props: MermaidProps) {
return (
<MermaidRenderer
chart={`
sequenceDiagram
autonumber
box rgba(139,92,246,.1) Navigateur
actor Utilisateur
end
box rgba(139,92,246,.1) Serveur
participant Routeur
participant Contrôleur
participant Modèle
participant Vue
end
participant Base de données
Utilisateur->>Routeur: Je veux voir la page d'accueil
Routeur->>Contrôleur: Appelle la méthode \`home\`
alt Si des données sont nécessaires
Contrôleur->>Modèle: Demande les données
Modèle->>Base de données: Récupère les données
Base de données-->>Modèle: Retourne les données
Modèle-->>Contrôleur: Retourne les données
end
Contrôleur->>Vue: Demande le HTML
Vue-->>Contrôleur: Retourne le HTML généré
Contrôleur->>Utilisateur: Retourne le HTML généré
`}
/>
);
}

View File

@ -1,3 +1,4 @@
import React from "react";
import clsx from "clsx"; import clsx from "clsx";
export function Prose<T extends React.ElementType = "div">({ export function Prose<T extends React.ElementType = "div">({

View File

@ -1,5 +1,6 @@
import { Link } from "@/components/common/Link"; import { Link } from "@/components/common/Link";
import { Icon } from "@syntax/Icon"; import { Icon } from "@syntax/Icon";
import React from "react";
export function QuickLinks({ children }: { children: React.ReactNode }) { export function QuickLinks({ children }: { children: React.ReactNode }) {
return <div className="not-prose my-12 grid grid-cols-1 gap-6 sm:grid-cols-2">{children}</div>; return <div className="not-prose my-12 grid grid-cols-1 gap-6 sm:grid-cols-2">{children}</div>;

View File

@ -1,7 +1,7 @@
import { Highlight, Prism } from "prism-react-renderer"; import { Highlight, Prism } from "prism-react-renderer";
import { prismThemes } from "@/data/themes/prism"; import { prismThemes } from "@/data/themes/prism";
import React, { Fragment, useMemo } from "react";
import { useTheme } from "@/hooks/useTheme"; import { useTheme } from "@/hooks/useTheme";
import { Fragment, useMemo } from "react";
import clsx from "clsx"; import clsx from "clsx";
export function SSRSnippet({ export function SSRSnippet({

View File

@ -1,4 +1,4 @@
import { useId, useState, useEffect, createContext, useContext, Fragment } from "react"; import React, { useId, useState, useEffect, createContext, useContext, Fragment } from "react";
import { SearchResult } from "@/services/FlexSearchService"; import { SearchResult } from "@/services/FlexSearchService";
import { Dialog, DialogPanel } from "@headlessui/react"; import { Dialog, DialogPanel } from "@headlessui/react";
import { useDebounce } from "@/hooks/useDebounce"; import { useDebounce } from "@/hooks/useDebounce";

View File

@ -3,6 +3,7 @@ import type { Data } from "@/pages/docs/+data";
import { clientOnly } from "vike-react/clientOnly"; import { clientOnly } from "vike-react/clientOnly";
import { useData } from "vike-react/useData"; import { useData } from "vike-react/useData";
import { SSRSnippet } from "./SSRSnippet"; import { SSRSnippet } from "./SSRSnippet";
import React from "react";
const CSRSnippet = clientOnly(() => import("./CSRSnippet")); const CSRSnippet = clientOnly(() => import("./CSRSnippet"));

View File

@ -1,25 +1,23 @@
"use client"; import React, { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { Link } from "@/components/common/Link"; import { Link } from "@/components/common/Link";
import clsx from "clsx"; import clsx from "clsx";
import { type Section, type Subsection } from "@/lib/sections"; import { type Section, type Subsection } from "@/lib/sections";
export function TableOfContents({ tableOfContents }: { tableOfContents: Array<Section> }) { export function TableOfContents({ tableOfContents }: { tableOfContents: Array<Section> }) {
let [currentSection, setCurrentSection] = useState(tableOfContents[0]?.id); const [currentSection, setCurrentSection] = useState(tableOfContents[0]?.id);
let getHeadings = useCallback((tableOfContents: Array<Section>) => { const getHeadings = useCallback((tableOfContents: Array<Section>) => {
return tableOfContents return tableOfContents
.flatMap((node) => [node.id, ...node.children.map((child) => child.id)]) .flatMap((node) => [node.id, ...node.children.map((child) => child.id)])
.map((id) => { .map((id) => {
let el = document.getElementById(id); const el = document.getElementById(id);
if (!el) return null; if (!el) return null;
let style = window.getComputedStyle(el); const style = window.getComputedStyle(el);
let scrollMt = parseFloat(style.scrollMarginTop); const scrollMt = parseFloat(style.scrollMarginTop);
let top = window.scrollY + el.getBoundingClientRect().top - scrollMt; const top = window.scrollY + el.getBoundingClientRect().top - scrollMt;
return { id, top }; return { id, top };
}) })
.filter((x): x is { id: string; top: number } => x !== null); .filter((x): x is { id: string; top: number } => x !== null);
@ -35,11 +33,8 @@ export function TableOfContents({ tableOfContents }: { tableOfContents: Array<Se
let current = headings[0]?.id; let current = headings[0]?.id;
for (const heading of headings) { for (const heading of headings) {
if (top >= heading.top - 10) { if (top < heading.top - 10) break;
current = heading.id; current = heading.id;
} else {
break;
}
} }
setCurrentSection(current); setCurrentSection(current);
} }
@ -51,12 +46,9 @@ export function TableOfContents({ tableOfContents }: { tableOfContents: Array<Se
}, [getHeadings, tableOfContents]); }, [getHeadings, tableOfContents]);
function isActive(section: Section | Subsection) { function isActive(section: Section | Subsection) {
if (section.id === currentSection) { if (section.id === currentSection) return true;
return true; if (!section.children) return false;
}
if (!section.children) {
return false;
}
return section.children.findIndex(isActive) > -1; return section.children.findIndex(isActive) > -1;
} }

View File

@ -1,5 +1,5 @@
import { Label, Listbox, ListboxButton, ListboxOption, ListboxOptions } from "@headlessui/react"; import { Label, Listbox, ListboxButton, ListboxOption, ListboxOptions } from "@headlessui/react";
import { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTheme } from "@/hooks/useTheme"; import { useTheme } from "@/hooks/useTheme";
import clsx from "clsx"; import clsx from "clsx";
@ -33,8 +33,8 @@ function DarkIcon(props: React.ComponentPropsWithoutRef<"svg">) {
} }
export function ThemeSelector(props: React.ComponentPropsWithoutRef<typeof Listbox<"div">>) { export function ThemeSelector(props: React.ComponentPropsWithoutRef<typeof Listbox<"div">>) {
let [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
let { theme, setTheme } = useTheme(); const { theme, setTheme } = useTheme();
useEffect(() => { useEffect(() => {
setMounted(true); setMounted(true);

View File

@ -1,4 +1,5 @@
import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; import { DarkMode, Gradient, LightMode } from "@syntax/Icon";
import React from "react";
export function InstallationIcon({ export function InstallationIcon({
id, id,

View File

@ -1,4 +1,5 @@
import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; import { DarkMode, Gradient, LightMode } from "@syntax/Icon";
import React from "react";
export function LightbulbIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) { export function LightbulbIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) {
return ( return (

View File

@ -1,4 +1,5 @@
import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; import { DarkMode, Gradient, LightMode } from "@syntax/Icon";
import React from "react";
export function PluginsIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) { export function PluginsIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) {
return ( return (

View File

@ -1,4 +1,5 @@
import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; import { DarkMode, Gradient, LightMode } from "@syntax/Icon";
import React from "react";
export function PresetsIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) { export function PresetsIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) {
return ( return (

View File

@ -1,4 +1,5 @@
import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; import { DarkMode, Gradient, LightMode } from "@syntax/Icon";
import React from "react";
export function QuestionIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) { export function QuestionIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) {
return ( return (

View File

@ -1,4 +1,5 @@
import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; import { DarkMode, Gradient, LightMode } from "@syntax/Icon";
import React from "react";
export function ThemingIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) { export function ThemingIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) {
return ( return (

View File

@ -1,4 +1,5 @@
import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; import { DarkMode, Gradient, LightMode } from "@syntax/Icon";
import React from "react";
export function WarningIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) { export function WarningIcon({ id, color }: { id: string; color?: React.ComponentProps<typeof Gradient>["color"] }) {
return ( return (

View File

@ -1,10 +1,10 @@
// @ts-nocheck // @ts-nocheck
import eslint from "@eslint/js";
import prettier from "eslint-plugin-prettier/recommended";
import react from "eslint-plugin-react/configs/recommended.js"; import react from "eslint-plugin-react/configs/recommended.js";
import globals from "globals"; import prettier from "eslint-plugin-prettier/recommended";
import tseslint from "typescript-eslint"; import tseslint from "typescript-eslint";
import eslint from "@eslint/js";
import globals from "globals";
export default tseslint.config( export default tseslint.config(
{ {
@ -33,14 +33,10 @@ export default tseslint.config(
}, },
{ {
rules: { rules: {
"@typescript-eslint/no-unused-vars": [ "@typescript-eslint/no-unused-vars": [1, { argsIgnorePattern: "^_" }],
1,
{
argsIgnorePattern: "^_",
},
],
"@typescript-eslint/no-namespace": 0, "@typescript-eslint/no-namespace": 0,
"react/react-in-jsx-scope": false, "react/react-in-jsx-scope": "warn",
"react/jsx-filename-extension": [1, { extensions: [".tsx"] }],
}, },
}, },

View File

@ -1,37 +0,0 @@
import type { SearchResult } from "@/lib/search";
import { useDebounce } from "./useDebounce";
import { useState, useEffect, use } from "react";
export function useAutoComplete(onSearch: (query: string) => Promise<SearchResult[]>) {
const [results, setResults] = useState<SearchResult[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [isOpened, setIsOpened] = useState(false);
const [query, setQuery] = useDebounce();
useEffect(() => {
// Attach the event listener to the window
function handleKeyDown(event: KeyboardEvent) {
if (event.key === "Escape") {
setIsOpened(false);
} else if (event.key === "K" && (event.ctrlKey || event.metaKey)) {
event.preventDefault();
setIsOpened(true);
}
}
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, []);
return {
results,
isLoading,
isOpened,
query,
setQuery,
};
}

View File

@ -2,19 +2,21 @@ import { MobileNavigation } from "@syntax/MobileNavigation";
import { usePageContext } from "vike-react/usePageContext"; import { usePageContext } from "vike-react/usePageContext";
import { ThemeProvider } from "@/providers/ThemeProvider"; import { ThemeProvider } from "@/providers/ThemeProvider";
import { ThemeSelector } from "@syntax/ThemeSelector"; import { ThemeSelector } from "@syntax/ThemeSelector";
import { clientOnly } from "vike-react/clientOnly";
import React, { useEffect, useState } from "react";
import { ToastContainer } from "react-toastify";
import { Navigation } from "@syntax/Navigation"; import { Navigation } from "@syntax/Navigation";
import { Link } from "@/components/common/Link"; import { Link } from "@/components/common/Link";
import { useEffect, useState } from "react";
import { Search } from "@syntax/Search";
import { Hero } from "@syntax/Hero"; import { Hero } from "@syntax/Hero";
import { Logo, LogoWithText } from "@syntax/Logo"; import { Logo } from "@syntax/Logo";
import clsx from "clsx"; import clsx from "clsx";
import "./style.css"; import "./style.css";
import "./tailwind.css"; import "./tailwind.css";
import "./prism.css"; import "./prism.css";
import "unfonts.css"; import "unfonts.css";
import { ToastContainer } from "react-toastify";
const Search = clientOnly(() => import("@syntax/Search").then((module) => module.Search));
function GitHubIcon(props: React.ComponentPropsWithoutRef<"svg">) { function GitHubIcon(props: React.ComponentPropsWithoutRef<"svg">) {
return ( return (
@ -25,7 +27,7 @@ function GitHubIcon(props: React.ComponentPropsWithoutRef<"svg">) {
} }
function Header() { function Header() {
let [isScrolled, setIsScrolled] = useState(false); const [isScrolled, setIsScrolled] = useState(false);
useEffect(() => { useEffect(() => {
function onScroll() { function onScroll() {
@ -59,7 +61,7 @@ function Header() {
</div> </div>
<div className="-my-5 mr-6 sm:mr-8 md:mr-0"> <div className="-my-5 mr-6 sm:mr-8 md:mr-0">
<Search /> <Search fallback={<div className="h-6 w-6 animate-pulse rounded-full bg-slate-200 dark:bg-slate-700" />} />
</div> </div>
<div className="relative flex basis-0 justify-end gap-6 sm:gap-8 md:grow"> <div className="relative flex basis-0 justify-end gap-6 sm:gap-8 md:grow">

View File

@ -119,16 +119,17 @@ export const navigation: NavigationSection[] = [
}, },
]; ];
export function doesLinkSubitemExist(link: NavigationLink, subitemHref: string): boolean {
return link.subitems.some((subitem) => subitem.href === subitemHref);
}
export function findNavigationLink(namespace: string, href: string): NavigationLink | undefined { export function findNavigationLink(namespace: string, href: string): NavigationLink | undefined {
const currentUrl = `/${namespace}/${href}`.replace(/\/+/g, "/").replace(/\/$/, ""); const currentUrl = `/${namespace}/${href}`.replace(/\/+/g, "/").replace(/\/$/, "");
const foundLink = navigation const foundLink = navigation
.flatMap((section) => section.links) .flatMap((section) => section.links)
.find((link) => { .find((link) => {
link.href === currentUrl || return link.href === currentUrl || doesLinkSubitemExist(link, currentUrl);
link.subitems.some((subitem) => {
subitem.href === currentUrl;
});
}); });
return foundLink; return foundLink;

View File

@ -5,6 +5,8 @@ import glob from "fast-glob";
import * as path from "path"; import * as path from "path";
import * as fs from "fs"; import * as fs from "fs";
type SearchOptionValue = string | number | boolean | null | undefined | object | unknown;
const slugify = slugifyWithCounter(); const slugify = slugifyWithCounter();
interface Node { interface Node {
@ -32,28 +34,30 @@ export interface SearchResult {
function toString(node: Node): string { function toString(node: Node): string {
let str = node.type === "text" && typeof node.attributes?.content === "string" ? node.attributes.content : ""; let str = node.type === "text" && typeof node.attributes?.content === "string" ? node.attributes.content : "";
if ("children" in node) { if ("children" in node) {
for (let child of node.children!) { for (const child of node.children!) {
str += toString(child); str += toString(child);
} }
} }
return str; return str;
} }
function extractSections(node: Node, sections: Section[], isRoot: boolean = true): void { function extractSections(node: Node, sections: Section[], isRoot: boolean = true): void {
if (isRoot) { if (isRoot) slugify.reset();
slugify.reset();
}
if (node.type === "heading" || node.type === "paragraph") { if (node.type === "heading" || node.type === "paragraph") {
let content = toString(node).trim(); const content = toString(node).trim();
if (node.type === "heading" && node.attributes?.level! <= 2) {
let hash = node.attributes?.id ?? slugify(content); if (node.attributes?.level && node.type === "heading" && node.attributes.level <= 2) {
const hash = node.attributes?.id ?? slugify(content);
sections.push({ content, hash, subsections: [] }); sections.push({ content, hash, subsections: [] });
} else { } else {
sections[sections.length - 1].subsections.push(content); sections[sections.length - 1].subsections.push(content);
} }
} else if ("children" in node) { } else if ("children" in node) {
for (let child of node.children!) { for (const child of node.children!) {
extractSections(child, sections, false); extractSections(child, sections, false);
} }
} }
@ -111,18 +115,18 @@ export function buildSearchIndex(pagesDir: string): FlexSearch.Document<SearchRe
export function search( export function search(
sectionIndex: FlexSearch.Document<SearchResult>, sectionIndex: FlexSearch.Document<SearchResult>,
query: string, query: string,
options: Record<string, any> = {}, options: Record<string, SearchOptionValue> = {},
): SearchResult[] { ): SearchResult[] {
const results = sectionIndex.search(query, { const results = sectionIndex.search(query, {
...options, ...options,
enrich: true, enrich: true,
}); });
if (results.length === 0) { if (results.length === 0) return [];
return [];
}
return results[0].result.map((item: any) => ({ const searchResults = results[0].result as unknown as { id: string; doc: { title: string; pageTitle: string } }[];
return searchResults.map((item) => ({
url: item.id, url: item.id,
title: item.doc.title, title: item.doc.title,
pageTitle: item.doc.pageTitle, pageTitle: item.doc.pageTitle,

View File

@ -41,7 +41,8 @@ function isH3Node(node: Node): node is H3Node {
function getNodeText(node: Node) { function getNodeText(node: Node) {
let text = ""; let text = "";
for (let child of node.children ?? []) {
for (const child of node.children ?? []) {
if (child.type === "text") { if (child.type === "text") {
text += child.attributes.content; text += child.attributes.content;
} }

View File

@ -1,21 +1,17 @@
// Workaround about undefined import only in production build
import type { RenderableTreeNode } from "@markdoc/markdoc"; import type { RenderableTreeNode } from "@markdoc/markdoc";
import type { ReactNode } from "react";
export class Tag<N extends string = string, A extends Record<string, any> = Record<string, any>> { import { Tag as MarkdocTag } from "@markdoc/markdoc";
readonly $$mdtype = "Tag" as const;
static isTag = (tag: any): tag is Tag => { type TagAttributesValue = string | number | boolean | null | undefined | object | unknown;
return !!(tag?.$$mdtype === "Tag");
};
name: N; export class Tag extends MarkdocTag {
attributes: A; constructor(
children: RenderableTreeNode[]; name: string | ReactNode,
attributes: Record<string, TagAttributesValue>,
constructor(name = "div" as N, attributes = {} as A, children: RenderableTreeNode[] = []) { children: RenderableTreeNode[],
this.name = name; ) {
this.attributes = attributes; // Workaround for TypeScript's type system
this.children = children; super(name as unknown as string, attributes, children);
} }
} }

View File

@ -1,15 +1,14 @@
import type { Config, Node } from "@markdoc/markdoc"; import type { Config, Node } from "@markdoc/markdoc";
import { slugifyWithCounter } from "@sindresorhus/slugify"; import { slugifyWithCounter } from "@sindresorhus/slugify";
import { nodes as defaultNodes } from "@markdoc/markdoc";
import { DocsLayout } from "@syntax/DocsLayout"; import { DocsLayout } from "@syntax/DocsLayout";
import Markdoc from "@markdoc/markdoc";
import { Fence } from "@syntax/Fence";
import yaml from "js-yaml";
import { Link } from "@/components/common/Link"; import { Link } from "@/components/common/Link";
import { Fence } from "@syntax/Fence";
import { Tag } from "./Tag";
import yaml from "js-yaml";
const { nodes: defaultNodes, Tag } = Markdoc; const documentSlugifyMap = new Map();
let documentSlugifyMap = new Map();
const nodes = { const nodes = {
document: { document: {
@ -19,7 +18,7 @@ const nodes = {
documentSlugifyMap.set(config, slugifyWithCounter()); documentSlugifyMap.set(config, slugifyWithCounter());
return new Tag( return new Tag(
this.render, this.render as unknown as string,
{ {
frontmatter: yaml.load(node.attributes.frontmatter), frontmatter: yaml.load(node.attributes.frontmatter),
estimatedReadingTime: config?.variables?.estimatedReadingTime, estimatedReadingTime: config?.variables?.estimatedReadingTime,

View File

@ -1,16 +1,9 @@
import { QuickLink, QuickLinks } from "@syntax/QuickLinks"; import { QuickLink, QuickLinks } from "@syntax/QuickLinks";
import { TabContent, Tabs } from "@/components/md/Tabs"; import { TabContent, Tabs } from "@/components/md/Tabs";
// import { Fence2 } from "@/components/syntax/Fence2";
import { Callout } from "@syntax/Callout";
// import fs from "fs/promises";
// import { Tag } from "./Tag";
import React from "react";
import { Snippet } from "@/components/syntax/Snippet"; import { Snippet } from "@/components/syntax/Snippet";
import { Iframe } from "@/components/common/Iframe"; import { Iframe } from "@/components/common/Iframe";
import { Mermaid } from "@/components/common/Mermaid"; import { Callout } from "@syntax/Callout";
// import path from "path"; import React from "react";
// const __dirname = path.resolve();
const tags = { const tags = {
callout: { callout: {
@ -43,10 +36,10 @@ const tags = {
alt: { type: String }, alt: { type: String },
caption: { type: String }, caption: { type: String },
}, },
render: ({ src, alt = "", caption }: { src: string; alt: string; caption: string }) => ( render: (props: { src: string; alt: string; caption: string }) => (
<figure> <figure>
<img src={src} alt={alt} loading="lazy" /> <img src={props.src} alt={props.alt} loading="lazy" />
<figcaption>{caption}</figcaption> <figcaption>{props.caption}</figcaption>
</figure> </figure>
), ),
}, },
@ -91,15 +84,9 @@ const tags = {
}, },
}, },
}, },
mermaid: {
render: Mermaid,
attributes: {
path: { type: String },
},
},
img: { img: {
render: ({ src, alt = "", className = "" }: { src: string; alt: string; className: string }) => ( render: (props: { src: string; alt: string; className: string }) => (
<img src={src} alt={alt} className={className} loading="lazy" /> <img src={props.src} alt={props.alt} className={props.className} loading="lazy" />
), ),
attributes: { attributes: {
src: { type: String }, src: { type: String },

View File

@ -1,4 +1,5 @@
import logoUrl from "@/assets/logo.svg"; import logoUrl from "@/assets/logo.svg";
import React from "react";
export default function HeadDefault() { export default function HeadDefault() {
return ( return (

View File

@ -1,8 +1,10 @@
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 React from "react";
export default function Page() { export default function Page() {
const { is404 } = usePageContext(); const { is404 } = usePageContext();
if (is404) { if (is404) {
return ( return (
<> <>
@ -16,7 +18,7 @@ export default function Page() {
Désolé, nous ne pouvons pas trouver la page que vous recherchez. Désolé, nous ne pouvons pas trouver la page que vous recherchez.
</p> </p>
<Link href="/" className="mt-8 text-sm font-medium text-slate-900 dark:text-white"> <Link href="/" className="mt-8 text-sm font-medium text-slate-900 dark:text-white">
Retour à l'accueil Retour à l&apos;accueil
</Link> </Link>
</div> </div>
</div> </div>

View File

@ -9,7 +9,7 @@ import { render } from "vike/abort";
export type Data = Awaited<ReturnType<typeof data>>; export type Data = Awaited<ReturnType<typeof data>>;
export async function data(pageContext: PageContext) { export async function data(_pageContext: PageContext) {
const config = useConfig(); const config = useConfig();
const doc = await docsService.getDoc("docs", "index"); const doc = await docsService.getDoc("docs", "index");

View File

@ -1,5 +1,5 @@
import { ThemeContext, type Theme } from "@/contexts/ThemeContext"; import { ThemeContext, type Theme } from "@/contexts/ThemeContext";
import { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
type ThemeProviderProps = { type ThemeProviderProps = {
children: React.ReactNode; children: React.ReactNode;

View File

@ -1,5 +1,3 @@
import path from "path";
type SnippetsCache = Map<string, string>; type SnippetsCache = Map<string, string>;
class SnippetsService { class SnippetsService {