From dd541e6be5e23f52f63e159b26632939eea39f3e Mon Sep 17 00:00:00 2001 From: GauthierWebDev Date: Fri, 18 Apr 2025 10:49:07 +0200 Subject: [PATCH 1/8] refactor: Remove unused Mermaid component and imports --- app/components/common/Mermaid.tsx | 41 ------------------------------- app/layouts/LayoutDefault.tsx | 18 ++++++++------ app/markdoc/tags.tsx | 17 ++----------- 3 files changed, 13 insertions(+), 63 deletions(-) delete mode 100644 app/components/common/Mermaid.tsx diff --git a/app/components/common/Mermaid.tsx b/app/components/common/Mermaid.tsx deleted file mode 100644 index ccd2021..0000000 --- a/app/components/common/Mermaid.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import MermaidRenderer from "react-mermaid2"; - -type MermaidProps = { - path: string; -}; - -export function Mermaid(props: MermaidProps) { - return ( - >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é - `} - /> - ); -} diff --git a/app/layouts/LayoutDefault.tsx b/app/layouts/LayoutDefault.tsx index 63a98f7..ca4e96e 100644 --- a/app/layouts/LayoutDefault.tsx +++ b/app/layouts/LayoutDefault.tsx @@ -1,20 +1,22 @@ import { MobileNavigation } from "@syntax/MobileNavigation"; import { usePageContext } from "vike-react/usePageContext"; import { ThemeProvider } from "@/providers/ThemeProvider"; +import { useEffect, useState, Suspense } from "react"; import { ThemeSelector } from "@syntax/ThemeSelector"; +import { clientOnly } from "vike-react/clientOnly"; +import { ToastContainer } from "react-toastify"; import { Navigation } from "@syntax/Navigation"; import { Link } from "@/components/common/Link"; -import { useEffect, useState } from "react"; -import { Search } from "@syntax/Search"; import { Hero } from "@syntax/Hero"; -import { Logo, LogoWithText } from "@syntax/Logo"; +import { Logo } from "@syntax/Logo"; import clsx from "clsx"; import "./style.css"; import "./tailwind.css"; import "./prism.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">) { return ( @@ -58,9 +60,11 @@ function Header() { -
- -
+ }> +
+ +
+
diff --git a/app/markdoc/tags.tsx b/app/markdoc/tags.tsx index 8cd4757..e3098b8 100644 --- a/app/markdoc/tags.tsx +++ b/app/markdoc/tags.tsx @@ -1,16 +1,9 @@ import { QuickLink, QuickLinks } from "@syntax/QuickLinks"; 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 { Iframe } from "@/components/common/Iframe"; -import { Mermaid } from "@/components/common/Mermaid"; -// import path from "path"; - -// const __dirname = path.resolve(); +import { Callout } from "@syntax/Callout"; +import React from "react"; const tags = { callout: { @@ -91,12 +84,6 @@ const tags = { }, }, }, - mermaid: { - render: Mermaid, - attributes: { - path: { type: String }, - }, - }, img: { render: ({ src, alt = "", className = "" }: { src: string; alt: string; className: string }) => ( {alt} From d0bc4a4eb0d9a23df033084b43bd30594956df80 Mon Sep 17 00:00:00 2001 From: GauthierWebDev Date: Fri, 18 Apr 2025 11:05:17 +0200 Subject: [PATCH 2/8] style: Update code formatting in LayoutDefault --- app/layouts/LayoutDefault.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/layouts/LayoutDefault.tsx b/app/layouts/LayoutDefault.tsx index ca4e96e..0cd38ce 100644 --- a/app/layouts/LayoutDefault.tsx +++ b/app/layouts/LayoutDefault.tsx @@ -1,12 +1,12 @@ import { MobileNavigation } from "@syntax/MobileNavigation"; import { usePageContext } from "vike-react/usePageContext"; import { ThemeProvider } from "@/providers/ThemeProvider"; -import { useEffect, useState, Suspense } from "react"; import { ThemeSelector } from "@syntax/ThemeSelector"; import { clientOnly } from "vike-react/clientOnly"; import { ToastContainer } from "react-toastify"; import { Navigation } from "@syntax/Navigation"; import { Link } from "@/components/common/Link"; +import { useEffect, useState } from "react"; import { Hero } from "@syntax/Hero"; import { Logo } from "@syntax/Logo"; import clsx from "clsx"; @@ -60,11 +60,9 @@ function Header() {
- }> -
- -
-
+
+ } /> +
From a02916d76a07b07654ac1c9d7899f5e4de08eff1 Mon Sep 17 00:00:00 2001 From: GauthierWebDev Date: Fri, 18 Apr 2025 11:21:28 +0200 Subject: [PATCH 3/8] refactor: Use super() in Tag class constructor --- app/markdoc/Tag.ts | 22 ++++++---------------- app/markdoc/nodes.tsx | 11 +++++------ 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/app/markdoc/Tag.ts b/app/markdoc/Tag.ts index a02caaf..8f5dc84 100644 --- a/app/markdoc/Tag.ts +++ b/app/markdoc/Tag.ts @@ -1,21 +1,11 @@ -// Workaround about undefined import only in production build - import type { RenderableTreeNode } from "@markdoc/markdoc"; +import type { ReactNode } from "react"; -export class Tag = Record> { - readonly $$mdtype = "Tag" as const; +import { Tag as MarkdocTag } from "@markdoc/markdoc"; - static isTag = (tag: any): tag is Tag => { - return !!(tag?.$$mdtype === "Tag"); - }; - - name: N; - attributes: A; - children: RenderableTreeNode[]; - - constructor(name = "div" as N, attributes = {} as A, children: RenderableTreeNode[] = []) { - this.name = name; - this.attributes = attributes; - this.children = children; +export class Tag extends MarkdocTag { + constructor(name: string | ReactNode, attributes: Record, children: RenderableTreeNode[]) { + // Workaround for TypeScript's type system + super(name as unknown as string, attributes, children); } } diff --git a/app/markdoc/nodes.tsx b/app/markdoc/nodes.tsx index 6287a2b..7c1c656 100644 --- a/app/markdoc/nodes.tsx +++ b/app/markdoc/nodes.tsx @@ -1,13 +1,12 @@ import type { Config, Node } from "@markdoc/markdoc"; import { slugifyWithCounter } from "@sindresorhus/slugify"; +import { nodes as defaultNodes } from "@markdoc/markdoc"; 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"; - -const { nodes: defaultNodes, Tag } = Markdoc; +import { Fence } from "@syntax/Fence"; +import { Tag } from "./Tag"; +import yaml from "js-yaml"; let documentSlugifyMap = new Map(); @@ -19,7 +18,7 @@ const nodes = { documentSlugifyMap.set(config, slugifyWithCounter()); return new Tag( - this.render, + this.render as unknown as string, { frontmatter: yaml.load(node.attributes.frontmatter), estimatedReadingTime: config?.variables?.estimatedReadingTime, From bf9c64da68d01732490d4006612025dd7a1d5270 Mon Sep 17 00:00:00 2001 From: GauthierWebDev Date: Fri, 18 Apr 2025 11:41:24 +0200 Subject: [PATCH 4/8] refactor: Rearrange import statements in eslint.config.js --- app/eslint.config.js | 16 ++++++-------- app/hooks/useAutoComplete.ts | 37 --------------------------------- app/layouts/LayoutDefault.tsx | 2 +- app/lib/search.ts | 26 +++++++++++++---------- app/lib/sections.ts | 3 ++- app/markdoc/Tag.ts | 8 ++++++- app/markdoc/nodes.tsx | 2 +- app/markdoc/tags.tsx | 10 ++++----- app/pages/+Head.tsx | 1 + app/pages/_error/+Page.tsx | 4 +++- app/pages/index/+data.ts | 2 +- app/providers/ThemeProvider.tsx | 2 +- app/services/SnippetsService.ts | 2 -- 13 files changed, 43 insertions(+), 72 deletions(-) delete mode 100644 app/hooks/useAutoComplete.ts diff --git a/app/eslint.config.js b/app/eslint.config.js index 1ba6c0c..23320c6 100644 --- a/app/eslint.config.js +++ b/app/eslint.config.js @@ -1,10 +1,10 @@ // @ts-nocheck -import eslint from "@eslint/js"; -import prettier from "eslint-plugin-prettier/recommended"; 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 eslint from "@eslint/js"; +import globals from "globals"; export default tseslint.config( { @@ -33,14 +33,10 @@ export default tseslint.config( }, { rules: { - "@typescript-eslint/no-unused-vars": [ - 1, - { - argsIgnorePattern: "^_", - }, - ], + "@typescript-eslint/no-unused-vars": [1, { argsIgnorePattern: "^_" }], "@typescript-eslint/no-namespace": 0, - "react/react-in-jsx-scope": false, + "react/react-in-jsx-scope": "warn", + "react/jsx-filename-extension": [1, { extensions: [".tsx"] }], }, }, diff --git a/app/hooks/useAutoComplete.ts b/app/hooks/useAutoComplete.ts deleted file mode 100644 index 41dafa9..0000000 --- a/app/hooks/useAutoComplete.ts +++ /dev/null @@ -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) { - const [results, setResults] = useState([]); - 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, - }; -} diff --git a/app/layouts/LayoutDefault.tsx b/app/layouts/LayoutDefault.tsx index 0cd38ce..24227b3 100644 --- a/app/layouts/LayoutDefault.tsx +++ b/app/layouts/LayoutDefault.tsx @@ -27,7 +27,7 @@ function GitHubIcon(props: React.ComponentPropsWithoutRef<"svg">) { } function Header() { - let [isScrolled, setIsScrolled] = useState(false); + const [isScrolled, setIsScrolled] = useState(false); useEffect(() => { function onScroll() { diff --git a/app/lib/search.ts b/app/lib/search.ts index d8d79ff..bb3ad9e 100644 --- a/app/lib/search.ts +++ b/app/lib/search.ts @@ -5,6 +5,8 @@ import glob from "fast-glob"; import * as path from "path"; import * as fs from "fs"; +type SearchOptionValue = string | number | boolean | null | undefined | object | unknown; + const slugify = slugifyWithCounter(); interface Node { @@ -32,20 +34,22 @@ export interface SearchResult { function toString(node: Node): string { let str = node.type === "text" && typeof node.attributes?.content === "string" ? node.attributes.content : ""; + if ("children" in node) { - for (let child of node.children!) { + for (const child of node.children!) { str += toString(child); } } + return str; } function extractSections(node: Node, sections: Section[], isRoot: boolean = true): void { - if (isRoot) { - slugify.reset(); - } + if (isRoot) slugify.reset(); + 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); sections.push({ content, hash, subsections: [] }); @@ -53,7 +57,7 @@ function extractSections(node: Node, sections: Section[], isRoot: boolean = true sections[sections.length - 1].subsections.push(content); } } else if ("children" in node) { - for (let child of node.children!) { + for (const child of node.children!) { extractSections(child, sections, false); } } @@ -111,18 +115,18 @@ export function buildSearchIndex(pagesDir: string): FlexSearch.Document, query: string, - options: Record = {}, + options: Record = {}, ): SearchResult[] { const results = sectionIndex.search(query, { ...options, enrich: true, }); - if (results.length === 0) { - return []; - } + if (results.length === 0) 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, title: item.doc.title, pageTitle: item.doc.pageTitle, diff --git a/app/lib/sections.ts b/app/lib/sections.ts index 76d2a7a..2006737 100644 --- a/app/lib/sections.ts +++ b/app/lib/sections.ts @@ -41,7 +41,8 @@ function isH3Node(node: Node): node is H3Node { function getNodeText(node: Node) { let text = ""; - for (let child of node.children ?? []) { + + for (const child of node.children ?? []) { if (child.type === "text") { text += child.attributes.content; } diff --git a/app/markdoc/Tag.ts b/app/markdoc/Tag.ts index 8f5dc84..e50b59d 100644 --- a/app/markdoc/Tag.ts +++ b/app/markdoc/Tag.ts @@ -3,8 +3,14 @@ import type { ReactNode } from "react"; import { Tag as MarkdocTag } from "@markdoc/markdoc"; +type TagAttributesValue = string | number | boolean | null | undefined | object | unknown; + export class Tag extends MarkdocTag { - constructor(name: string | ReactNode, attributes: Record, children: RenderableTreeNode[]) { + constructor( + name: string | ReactNode, + attributes: Record, + children: RenderableTreeNode[], + ) { // Workaround for TypeScript's type system super(name as unknown as string, attributes, children); } diff --git a/app/markdoc/nodes.tsx b/app/markdoc/nodes.tsx index 7c1c656..3c32b0f 100644 --- a/app/markdoc/nodes.tsx +++ b/app/markdoc/nodes.tsx @@ -8,7 +8,7 @@ import { Fence } from "@syntax/Fence"; import { Tag } from "./Tag"; import yaml from "js-yaml"; -let documentSlugifyMap = new Map(); +const documentSlugifyMap = new Map(); const nodes = { document: { diff --git a/app/markdoc/tags.tsx b/app/markdoc/tags.tsx index e3098b8..9abbbb8 100644 --- a/app/markdoc/tags.tsx +++ b/app/markdoc/tags.tsx @@ -36,10 +36,10 @@ const tags = { alt: { type: String }, caption: { type: String }, }, - render: ({ src, alt = "", caption }: { src: string; alt: string; caption: string }) => ( + render: (props: { src: string; alt: string; caption: string }) => (
- {alt} -
{caption}
+ {props.alt} +
{props.caption}
), }, @@ -85,8 +85,8 @@ const tags = { }, }, img: { - render: ({ src, alt = "", className = "" }: { src: string; alt: string; className: string }) => ( - {alt} + render: (props: { src: string; alt: string; className: string }) => ( + {props.alt} ), attributes: { src: { type: String }, diff --git a/app/pages/+Head.tsx b/app/pages/+Head.tsx index 48371af..cb6c941 100644 --- a/app/pages/+Head.tsx +++ b/app/pages/+Head.tsx @@ -1,4 +1,5 @@ import logoUrl from "@/assets/logo.svg"; +import React from "react"; export default function HeadDefault() { return ( diff --git a/app/pages/_error/+Page.tsx b/app/pages/_error/+Page.tsx index b8448b0..92d0fa7 100644 --- a/app/pages/_error/+Page.tsx +++ b/app/pages/_error/+Page.tsx @@ -1,8 +1,10 @@ import { usePageContext } from "vike-react/usePageContext"; import { Link } from "@/components/common/Link"; +import React from "react"; export default function Page() { const { is404 } = usePageContext(); + if (is404) { return ( <> @@ -16,7 +18,7 @@ export default function Page() { Désolé, nous ne pouvons pas trouver la page que vous recherchez.

- Retour à l'accueil + Retour à l'accueil
diff --git a/app/pages/index/+data.ts b/app/pages/index/+data.ts index d96d7f3..1cc024d 100644 --- a/app/pages/index/+data.ts +++ b/app/pages/index/+data.ts @@ -9,7 +9,7 @@ import { render } from "vike/abort"; export type Data = Awaited>; -export async function data(pageContext: PageContext) { +export async function data(_pageContext: PageContext) { const config = useConfig(); const doc = await docsService.getDoc("docs", "index"); diff --git a/app/providers/ThemeProvider.tsx b/app/providers/ThemeProvider.tsx index cabcac4..9d248f4 100644 --- a/app/providers/ThemeProvider.tsx +++ b/app/providers/ThemeProvider.tsx @@ -1,5 +1,5 @@ import { ThemeContext, type Theme } from "@/contexts/ThemeContext"; -import { useEffect, useState } from "react"; +import React, { useEffect, useState } from "react"; type ThemeProviderProps = { children: React.ReactNode; diff --git a/app/services/SnippetsService.ts b/app/services/SnippetsService.ts index a91393f..5d47b0d 100644 --- a/app/services/SnippetsService.ts +++ b/app/services/SnippetsService.ts @@ -1,5 +1,3 @@ -import path from "path"; - type SnippetsCache = Map; class SnippetsService { From bc4729a5de8cc2b44af8f779add4a833865dc803 Mon Sep 17 00:00:00 2001 From: GauthierWebDev Date: Fri, 18 Apr 2025 11:48:19 +0200 Subject: [PATCH 5/8] style: Import React in multiple components --- app/components/syntax/Prose.tsx | 1 + app/components/syntax/QuickLinks.tsx | 1 + app/components/syntax/SSRSnippet.tsx | 2 +- app/components/syntax/Search.tsx | 2 +- app/components/syntax/Snippet.tsx | 1 + app/components/syntax/TableOfContents.tsx | 32 +++++++------------ app/components/syntax/ThemeSelector.tsx | 6 ++-- .../syntax/icons/InstallationIcon.tsx | 1 + app/components/syntax/icons/LightbulbIcon.tsx | 1 + app/components/syntax/icons/PluginsIcon.tsx | 1 + app/components/syntax/icons/PresetsIcon.tsx | 1 + app/components/syntax/icons/QuestionIcon.tsx | 1 + app/components/syntax/icons/ThemingIcon.tsx | 1 + app/components/syntax/icons/WarningIcon.tsx | 1 + app/layouts/LayoutDefault.tsx | 2 +- app/lib/navigation.ts | 9 +++--- app/lib/search.ts | 4 +-- 17 files changed, 35 insertions(+), 32 deletions(-) diff --git a/app/components/syntax/Prose.tsx b/app/components/syntax/Prose.tsx index 01bd70b..3a3e982 100644 --- a/app/components/syntax/Prose.tsx +++ b/app/components/syntax/Prose.tsx @@ -1,3 +1,4 @@ +import React from "react"; import clsx from "clsx"; export function Prose({ diff --git a/app/components/syntax/QuickLinks.tsx b/app/components/syntax/QuickLinks.tsx index ac0b39f..4d6d551 100644 --- a/app/components/syntax/QuickLinks.tsx +++ b/app/components/syntax/QuickLinks.tsx @@ -1,5 +1,6 @@ import { Link } from "@/components/common/Link"; import { Icon } from "@syntax/Icon"; +import React from "react"; export function QuickLinks({ children }: { children: React.ReactNode }) { return
{children}
; diff --git a/app/components/syntax/SSRSnippet.tsx b/app/components/syntax/SSRSnippet.tsx index c623496..876e295 100644 --- a/app/components/syntax/SSRSnippet.tsx +++ b/app/components/syntax/SSRSnippet.tsx @@ -1,7 +1,7 @@ import { Highlight, Prism } from "prism-react-renderer"; import { prismThemes } from "@/data/themes/prism"; +import React, { Fragment, useMemo } from "react"; import { useTheme } from "@/hooks/useTheme"; -import { Fragment, useMemo } from "react"; import clsx from "clsx"; export function SSRSnippet({ diff --git a/app/components/syntax/Search.tsx b/app/components/syntax/Search.tsx index 1bfde89..80c3d5c 100644 --- a/app/components/syntax/Search.tsx +++ b/app/components/syntax/Search.tsx @@ -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 { Dialog, DialogPanel } from "@headlessui/react"; import { useDebounce } from "@/hooks/useDebounce"; diff --git a/app/components/syntax/Snippet.tsx b/app/components/syntax/Snippet.tsx index 76b58df..c9050de 100644 --- a/app/components/syntax/Snippet.tsx +++ b/app/components/syntax/Snippet.tsx @@ -3,6 +3,7 @@ import type { Data } from "@/pages/docs/+data"; import { clientOnly } from "vike-react/clientOnly"; import { useData } from "vike-react/useData"; import { SSRSnippet } from "./SSRSnippet"; +import React from "react"; const CSRSnippet = clientOnly(() => import("./CSRSnippet")); diff --git a/app/components/syntax/TableOfContents.tsx b/app/components/syntax/TableOfContents.tsx index 4c94268..ff0fa6a 100644 --- a/app/components/syntax/TableOfContents.tsx +++ b/app/components/syntax/TableOfContents.tsx @@ -1,25 +1,23 @@ -"use client"; - -import { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { Link } from "@/components/common/Link"; import clsx from "clsx"; import { type Section, type Subsection } from "@/lib/sections"; export function TableOfContents({ tableOfContents }: { tableOfContents: Array
}) { - let [currentSection, setCurrentSection] = useState(tableOfContents[0]?.id); + const [currentSection, setCurrentSection] = useState(tableOfContents[0]?.id); - let getHeadings = useCallback((tableOfContents: Array
) => { + const getHeadings = useCallback((tableOfContents: Array
) => { return tableOfContents .flatMap((node) => [node.id, ...node.children.map((child) => child.id)]) .map((id) => { - let el = document.getElementById(id); + const el = document.getElementById(id); if (!el) return null; - let style = window.getComputedStyle(el); - let scrollMt = parseFloat(style.scrollMarginTop); + const style = window.getComputedStyle(el); + const scrollMt = parseFloat(style.scrollMarginTop); - let top = window.scrollY + el.getBoundingClientRect().top - scrollMt; + const top = window.scrollY + el.getBoundingClientRect().top - scrollMt; return { id, top }; }) .filter((x): x is { id: string; top: number } => x !== null); @@ -35,11 +33,8 @@ export function TableOfContents({ tableOfContents }: { tableOfContents: Array= heading.top - 10) { - current = heading.id; - } else { - break; - } + if (top < heading.top - 10) break; + current = heading.id; } setCurrentSection(current); } @@ -51,12 +46,9 @@ export function TableOfContents({ tableOfContents }: { tableOfContents: Array -1; } diff --git a/app/components/syntax/ThemeSelector.tsx b/app/components/syntax/ThemeSelector.tsx index a100e94..e067857 100644 --- a/app/components/syntax/ThemeSelector.tsx +++ b/app/components/syntax/ThemeSelector.tsx @@ -1,5 +1,5 @@ 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 clsx from "clsx"; @@ -33,8 +33,8 @@ function DarkIcon(props: React.ComponentPropsWithoutRef<"svg">) { } export function ThemeSelector(props: React.ComponentPropsWithoutRef>) { - let [mounted, setMounted] = useState(false); - let { theme, setTheme } = useTheme(); + const [mounted, setMounted] = useState(false); + const { theme, setTheme } = useTheme(); useEffect(() => { setMounted(true); diff --git a/app/components/syntax/icons/InstallationIcon.tsx b/app/components/syntax/icons/InstallationIcon.tsx index 20c1bc7..f9ed190 100644 --- a/app/components/syntax/icons/InstallationIcon.tsx +++ b/app/components/syntax/icons/InstallationIcon.tsx @@ -1,4 +1,5 @@ import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; +import React from "react"; export function InstallationIcon({ id, diff --git a/app/components/syntax/icons/LightbulbIcon.tsx b/app/components/syntax/icons/LightbulbIcon.tsx index f0e2439..137f02e 100644 --- a/app/components/syntax/icons/LightbulbIcon.tsx +++ b/app/components/syntax/icons/LightbulbIcon.tsx @@ -1,4 +1,5 @@ import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; +import React from "react"; export function LightbulbIcon({ id, color }: { id: string; color?: React.ComponentProps["color"] }) { return ( diff --git a/app/components/syntax/icons/PluginsIcon.tsx b/app/components/syntax/icons/PluginsIcon.tsx index 4797471..5dd5de1 100644 --- a/app/components/syntax/icons/PluginsIcon.tsx +++ b/app/components/syntax/icons/PluginsIcon.tsx @@ -1,4 +1,5 @@ import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; +import React from "react"; export function PluginsIcon({ id, color }: { id: string; color?: React.ComponentProps["color"] }) { return ( diff --git a/app/components/syntax/icons/PresetsIcon.tsx b/app/components/syntax/icons/PresetsIcon.tsx index d6e29b2..4342463 100644 --- a/app/components/syntax/icons/PresetsIcon.tsx +++ b/app/components/syntax/icons/PresetsIcon.tsx @@ -1,4 +1,5 @@ import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; +import React from "react"; export function PresetsIcon({ id, color }: { id: string; color?: React.ComponentProps["color"] }) { return ( diff --git a/app/components/syntax/icons/QuestionIcon.tsx b/app/components/syntax/icons/QuestionIcon.tsx index 2f89f4c..002f853 100644 --- a/app/components/syntax/icons/QuestionIcon.tsx +++ b/app/components/syntax/icons/QuestionIcon.tsx @@ -1,4 +1,5 @@ import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; +import React from "react"; export function QuestionIcon({ id, color }: { id: string; color?: React.ComponentProps["color"] }) { return ( diff --git a/app/components/syntax/icons/ThemingIcon.tsx b/app/components/syntax/icons/ThemingIcon.tsx index 15a6960..e68d30c 100644 --- a/app/components/syntax/icons/ThemingIcon.tsx +++ b/app/components/syntax/icons/ThemingIcon.tsx @@ -1,4 +1,5 @@ import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; +import React from "react"; export function ThemingIcon({ id, color }: { id: string; color?: React.ComponentProps["color"] }) { return ( diff --git a/app/components/syntax/icons/WarningIcon.tsx b/app/components/syntax/icons/WarningIcon.tsx index 091536f..24e12df 100644 --- a/app/components/syntax/icons/WarningIcon.tsx +++ b/app/components/syntax/icons/WarningIcon.tsx @@ -1,4 +1,5 @@ import { DarkMode, Gradient, LightMode } from "@syntax/Icon"; +import React from "react"; export function WarningIcon({ id, color }: { id: string; color?: React.ComponentProps["color"] }) { return ( diff --git a/app/layouts/LayoutDefault.tsx b/app/layouts/LayoutDefault.tsx index 24227b3..b7c9760 100644 --- a/app/layouts/LayoutDefault.tsx +++ b/app/layouts/LayoutDefault.tsx @@ -3,10 +3,10 @@ import { usePageContext } from "vike-react/usePageContext"; import { ThemeProvider } from "@/providers/ThemeProvider"; 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 { Link } from "@/components/common/Link"; -import { useEffect, useState } from "react"; import { Hero } from "@syntax/Hero"; import { Logo } from "@syntax/Logo"; import clsx from "clsx"; diff --git a/app/lib/navigation.ts b/app/lib/navigation.ts index b3e4200..c584b75 100644 --- a/app/lib/navigation.ts +++ b/app/lib/navigation.ts @@ -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 { const currentUrl = `/${namespace}/${href}`.replace(/\/+/g, "/").replace(/\/$/, ""); const foundLink = navigation .flatMap((section) => section.links) .find((link) => { - link.href === currentUrl || - link.subitems.some((subitem) => { - subitem.href === currentUrl; - }); + return link.href === currentUrl || doesLinkSubitemExist(link, currentUrl); }); return foundLink; diff --git a/app/lib/search.ts b/app/lib/search.ts index bb3ad9e..d56e1e9 100644 --- a/app/lib/search.ts +++ b/app/lib/search.ts @@ -50,8 +50,8 @@ function extractSections(node: Node, sections: Section[], isRoot: boolean = true if (node.type === "heading" || node.type === "paragraph") { 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: [] }); } else { sections[sections.length - 1].subsections.push(content); From ebd8eec3563ffaf2ebe525939e90be1c553310f7 Mon Sep 17 00:00:00 2001 From: GauthierWebDev Date: Fri, 18 Apr 2025 11:49:54 +0200 Subject: [PATCH 6/8] style: Update variable declarations to use const --- app/components/syntax/HeroBackground.tsx | 2 +- app/components/syntax/Icon.tsx | 2 +- app/components/syntax/Logo.tsx | 28 ++-------------------- app/components/syntax/MobileNavigation.tsx | 9 +++---- app/components/syntax/Navigation.tsx | 2 +- app/components/syntax/PrevNextLinks.tsx | 1 + app/components/syntax/Prose.tsx | 2 +- 7 files changed, 12 insertions(+), 34 deletions(-) diff --git a/app/components/syntax/HeroBackground.tsx b/app/components/syntax/HeroBackground.tsx index 82a7688..5385d69 100644 --- a/app/components/syntax/HeroBackground.tsx +++ b/app/components/syntax/HeroBackground.tsx @@ -1,4 +1,4 @@ -import { useId } from "react"; +import React, { useId } from "react"; export function HeroBackground(props: React.ComponentPropsWithoutRef<"svg">) { const id = useId(); diff --git a/app/components/syntax/Icon.tsx b/app/components/syntax/Icon.tsx index e5c3fde..2af0a22 100644 --- a/app/components/syntax/Icon.tsx +++ b/app/components/syntax/Icon.tsx @@ -5,7 +5,7 @@ import { PluginsIcon } from "@syntax/icons/PluginsIcon"; import { PresetsIcon } from "@syntax/icons/PresetsIcon"; import { ThemingIcon } from "@syntax/icons/ThemingIcon"; import { WarningIcon } from "@syntax/icons/WarningIcon"; -import { useId } from "react"; +import React, { useId } from "react"; import clsx from "clsx"; const icons = { diff --git a/app/components/syntax/Logo.tsx b/app/components/syntax/Logo.tsx index c7e787e..174c2d3 100644 --- a/app/components/syntax/Logo.tsx +++ b/app/components/syntax/Logo.tsx @@ -1,11 +1,6 @@ -function LogomarkPaths() { - // return ( - // - // - // - // - // ); +import React from "react"; +function LogomarkPaths() { return ( <> @@ -33,25 +28,6 @@ function LogomarkPaths() { ); } -export function LogoWithText(props: React.ComponentPropsWithoutRef<"svg">) { - return ( - - - - Memento Dev - - - ); -} - export function Logo(props: React.ComponentPropsWithoutRef<"svg">) { return ( diff --git a/app/components/syntax/MobileNavigation.tsx b/app/components/syntax/MobileNavigation.tsx index e120858..dc8734d 100644 --- a/app/components/syntax/MobileNavigation.tsx +++ b/app/components/syntax/MobileNavigation.tsx @@ -1,4 +1,4 @@ -import { Suspense, useCallback, useEffect, useState } from "react"; +import React, { Suspense, useCallback, useEffect, useState } from "react"; import { usePageContext } from "vike-react/usePageContext"; import { Dialog, DialogPanel } from "@headlessui/react"; import { Navigation } from "@syntax/Navigation"; @@ -32,11 +32,12 @@ function CloseOnNavigation({ close }: { close: () => void }) { } export function MobileNavigation() { - let [isOpen, setIsOpen] = useState(false); - let close = useCallback(() => setIsOpen(false), [setIsOpen]); + const [isOpen, setIsOpen] = useState(false); + const close = useCallback(() => setIsOpen(false), [setIsOpen]); function onLinkClick(event: React.MouseEvent) { - let link = event.currentTarget; + const link = event.currentTarget; + if ( link.pathname + link.search + link.hash === window.location.pathname + window.location.search + window.location.hash diff --git a/app/components/syntax/Navigation.tsx b/app/components/syntax/Navigation.tsx index 1ae09f1..0793c25 100644 --- a/app/components/syntax/Navigation.tsx +++ b/app/components/syntax/Navigation.tsx @@ -1,8 +1,8 @@ import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/solid"; import { usePageContext } from "vike-react/usePageContext"; +import React, { useEffect, useState } from "react"; import { Link } from "@/components/common/Link"; import { navigation } from "@/lib/navigation"; -import { useEffect, useState } from "react"; import clsx from "clsx"; type NavigationItemProps = { diff --git a/app/components/syntax/PrevNextLinks.tsx b/app/components/syntax/PrevNextLinks.tsx index df886aa..5cabe56 100644 --- a/app/components/syntax/PrevNextLinks.tsx +++ b/app/components/syntax/PrevNextLinks.tsx @@ -1,6 +1,7 @@ import { usePageContext } from "vike-react/usePageContext"; import { Link } from "@/components/common/Link"; import { navigation } from "@/lib/navigation"; +import React from "react"; import clsx from "clsx"; function ArrowIcon(props: React.ComponentPropsWithoutRef<"svg">) { diff --git a/app/components/syntax/Prose.tsx b/app/components/syntax/Prose.tsx index 3a3e982..a071e13 100644 --- a/app/components/syntax/Prose.tsx +++ b/app/components/syntax/Prose.tsx @@ -8,7 +8,7 @@ export function Prose({ }: React.ComponentPropsWithoutRef & { as?: T; }) { - let Component = as ?? "div"; + const Component = as ?? "div"; return ( Date: Fri, 18 Apr 2025 11:50:59 +0200 Subject: [PATCH 7/8] style: Remove redundant React imports --- app/components/syntax/Button.tsx | 1 + app/components/syntax/CSRSnippet.tsx | 2 +- app/components/syntax/Callout.tsx | 1 + app/components/syntax/DocsHeader.tsx | 1 + app/components/syntax/DocsLayout.tsx | 1 + app/components/syntax/Fence.tsx | 1 + app/components/syntax/Hero.tsx | 2 +- app/components/syntax/Icon.tsx | 4 ++-- 8 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/components/syntax/Button.tsx b/app/components/syntax/Button.tsx index fb0a7f2..6b5234d 100644 --- a/app/components/syntax/Button.tsx +++ b/app/components/syntax/Button.tsx @@ -1,4 +1,5 @@ import { Link } from "@/components/common/Link"; +import React from "react"; import clsx from "clsx"; const variantStyles = { diff --git a/app/components/syntax/CSRSnippet.tsx b/app/components/syntax/CSRSnippet.tsx index bd23808..bd388dd 100644 --- a/app/components/syntax/CSRSnippet.tsx +++ b/app/components/syntax/CSRSnippet.tsx @@ -1,8 +1,8 @@ import { ClipboardDocumentIcon } from "@heroicons/react/24/outline"; import { prismThemes } from "@/data/themes/prism"; +import React, { Fragment, useMemo } from "react"; import { Highlight } from "prism-react-renderer"; import { useTheme } from "@/hooks/useTheme"; -import { Fragment, useMemo } from "react"; import { toast } from "react-toastify"; import { Button } from "./Button"; import Prism from "prismjs"; diff --git a/app/components/syntax/Callout.tsx b/app/components/syntax/Callout.tsx index e933547..4084dac 100644 --- a/app/components/syntax/Callout.tsx +++ b/app/components/syntax/Callout.tsx @@ -1,4 +1,5 @@ import { Icon } from "@syntax/Icon"; +import React from "react"; import clsx from "clsx"; const styles = { diff --git a/app/components/syntax/DocsHeader.tsx b/app/components/syntax/DocsHeader.tsx index 7ab57ea..bab4ce6 100644 --- a/app/components/syntax/DocsHeader.tsx +++ b/app/components/syntax/DocsHeader.tsx @@ -1,6 +1,7 @@ import { usePageContext } from "vike-react/usePageContext"; import { ClockIcon } from "@heroicons/react/24/outline"; import { navigation } from "@/lib/navigation"; +import React from "react"; type DocsHeaderProps = { title?: string; diff --git a/app/components/syntax/DocsLayout.tsx b/app/components/syntax/DocsLayout.tsx index 0e2f85a..b0bf80a 100644 --- a/app/components/syntax/DocsLayout.tsx +++ b/app/components/syntax/DocsLayout.tsx @@ -5,6 +5,7 @@ import { PrevNextLinks } from "@syntax/PrevNextLinks"; import { collectSections } from "@/lib/sections"; import { DocsHeader } from "@syntax/DocsHeader"; import { Prose } from "@syntax/Prose"; +import React from "react"; export function DocsLayout({ children, diff --git a/app/components/syntax/Fence.tsx b/app/components/syntax/Fence.tsx index 6a138f6..6af6507 100644 --- a/app/components/syntax/Fence.tsx +++ b/app/components/syntax/Fence.tsx @@ -1,5 +1,6 @@ import { clientOnly } from "vike-react/clientOnly"; import { SSRSnippet } from "./SSRSnippet"; +import React from "react"; const CSRSnippet = clientOnly(() => import("./CSRSnippet")); diff --git a/app/components/syntax/Hero.tsx b/app/components/syntax/Hero.tsx index d30aa1f..39ce8c2 100644 --- a/app/components/syntax/Hero.tsx +++ b/app/components/syntax/Hero.tsx @@ -3,8 +3,8 @@ import blurIndigoImage from "@/images/blur-indigo.webp"; import blurCyanImage from "@/images/blur-cyan.webp"; import { Image } from "@/components/common/Image"; import { Highlight } from "prism-react-renderer"; +import React, { Fragment } from "react"; import { Button } from "@syntax/Button"; -import { Fragment } from "react"; import clsx from "clsx"; const codeLanguage = "javascript"; diff --git a/app/components/syntax/Icon.tsx b/app/components/syntax/Icon.tsx index 2af0a22..fd916da 100644 --- a/app/components/syntax/Icon.tsx +++ b/app/components/syntax/Icon.tsx @@ -32,8 +32,8 @@ export function Icon({ color?: keyof typeof iconStyles; icon: keyof typeof icons; } & Omit, "color">) { - let id = useId(); - let IconComponent = icons[icon]; + const id = useId(); + const IconComponent = icons[icon]; return ( {props.alt}; } diff --git a/app/components/common/Link.tsx b/app/components/common/Link.tsx index a9c00ea..0221c40 100644 --- a/app/components/common/Link.tsx +++ b/app/components/common/Link.tsx @@ -1,8 +1,9 @@ import { usePageContext } from "vike-react/usePageContext"; import { prefetch } from "vike/client/router"; +import React from "react"; import clsx from "clsx"; -export function Link(props: React.AnchorHTMLAttributes & { href: string }) { +export function Link(props: React.AnchorHTMLAttributes & { href: string; className?: string }) { const { urlPathname } = usePageContext(); const isActive = props.href === "/" ? urlPathname === props.href : urlPathname.startsWith(props.href); const isSameDomain = !(props.href.startsWith("http") || props.href.startsWith("mailto")); diff --git a/app/components/md/Tabs.tsx b/app/components/md/Tabs.tsx index 84a23f6..4eed3b1 100644 --- a/app/components/md/Tabs.tsx +++ b/app/components/md/Tabs.tsx @@ -1,6 +1,6 @@ import type { Dispatch, SetStateAction } from "react"; -import { createContext, useContext, useEffect, useState } from "react"; +import React, { createContext, useContext, useEffect, useState } from "react"; import { Button } from "@syntax/Button"; import clsx from "clsx"; diff --git a/app/components/syntax/CSRSnippet.tsx b/app/components/syntax/CSRSnippet.tsx index bd388dd..2361fe8 100644 --- a/app/components/syntax/CSRSnippet.tsx +++ b/app/components/syntax/CSRSnippet.tsx @@ -40,7 +40,7 @@ export default function CSRSnippet({ {label} )} -
+            
               
                 {tokens.map((line, lineIndex) => (
                   
@@ -69,7 +69,7 @@ export default function CSRSnippet({