@hgdc/docs 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs.schema.json +21 -0
- package/package.json +3 -1
- package/src/build/auto-import.ts +5 -24
- package/src/build/content.ts +82 -0
- package/src/build/markdown.ts +10 -5
- package/src/components/Accordion.astro +3 -1
- package/src/components/Callout.astro +31 -0
- package/src/components/Card.astro +3 -1
- package/src/components/Check.astro +2 -3
- package/src/components/CodeGroup.astro +9 -1
- package/src/components/Danger.astro +2 -3
- package/src/components/Info.astro +2 -3
- package/src/components/Note.astro +2 -3
- package/src/components/Tip.astro +2 -3
- package/src/components/Warning.astro +2 -3
- package/src/core/components.ts +166 -0
- package/src/core/config.ts +42 -0
- package/src/core/feedback-api.ts +27 -0
- package/src/core/theme.ts +6 -3
- package/src/core/validate.ts +276 -0
- package/src/integration.ts +102 -30
- package/src/overrides/Assistant.astro +17 -39
- package/src/overrides/Footer.astro +107 -0
- package/src/overrides/Head.astro +14 -14
- package/src/overrides/Header.astro +92 -0
- package/src/overrides/Icon.astro +65 -0
- package/src/overrides/PageFrame.astro +55 -8
- package/src/overrides/PageSidebar.astro +7 -0
- package/src/overrides/PageTitle.astro +126 -95
- package/src/overrides/Search.astro +54 -0
- package/src/overrides/Sidebar.astro +105 -60
- package/src/overrides/SidebarList.astro +52 -0
- package/src/overrides/SiteFooter.astro +51 -0
- package/src/overrides/ThemeProvider.astro +23 -0
- package/src/overrides/ThemeToggle.astro +90 -0
- package/src/overrides/TwoColumnContent.astro +45 -0
- package/src/overrides/sections.ts +29 -0
- package/src/styles/theme.css +2137 -511
- package/src/widget/client.ts +51 -19
- package/src/widget/code.ts +218 -0
- package/src/widget/excerpt.ts +5 -0
- package/src/widget/search.ts +222 -0
- package/template/.astro/collections/docs.schema.json +3 -0
- package/template/.astro/content-modules.mjs +35 -15
- package/template/.astro/data-store.json +1 -0
- package/template/.astro/settings.json +5 -0
- package/template/.build/.well-known/llms.txt +51 -34
- package/template/.build/404.html +16 -42
- package/template/.build/_astro/Assistant.astro_astro_type_script_index_0_lang.C1pz7yK1.js +4 -0
- package/template/.build/_astro/CodeGroup.astro_astro_type_script_index_0_lang.-eM8maAX.js +1 -0
- package/template/.build/_astro/Footer.astro_astro_type_script_index_0_lang.DzCnn3OT.js +1 -0
- package/template/.build/_astro/Search.astro_astro_type_script_index_0_lang.D7EcezBU.js +1 -0
- package/template/.build/_astro/code.smqv0zhe.js +9 -0
- package/template/.build/_astro/common.Dx3aBIS0.css +3 -0
- package/template/.build/_astro/{ec.8nqtp.css → ec.t9qpe.css} +1 -1
- package/template/.build/_astro/logo.BPu921Tp.svg +1 -0
- package/template/.build/_hgdc/corpus.json +1 -1
- package/template/.build/concepts/confidentialite/index.html +50 -0
- package/template/.build/concepts/confidentialite.md +38 -0
- package/template/.build/concepts/deploiements/index.html +106 -0
- package/template/.build/concepts/deploiements.md +70 -0
- package/template/.build/concepts/organisations-et-roles/index.html +83 -0
- package/template/.build/concepts/organisations-et-roles.md +39 -0
- package/template/.build/concepts/preversion/index.html +49 -0
- package/template/.build/concepts/preversion.md +52 -0
- package/template/.build/concepts/secrets-et-coffre/index.html +70 -0
- package/template/.build/concepts/secrets-et-coffre.md +54 -0
- package/template/.build/demarrer/depuis-github/index.html +34 -0
- package/template/.build/demarrer/depuis-github.md +68 -0
- package/template/.build/demarrer/premier-site/index.html +28 -0
- package/template/.build/demarrer/premier-site.md +94 -0
- package/template/.build/guides/brancher-un-domaine/index.html +91 -0
- package/template/.build/guides/brancher-un-domaine.md +81 -0
- package/template/.build/guides/cle-d-api/index.html +62 -0
- package/template/.build/guides/cle-d-api.md +78 -0
- package/template/.build/guides/depannage/index.html +64 -0
- package/template/.build/guides/depannage.md +69 -0
- package/template/.build/guides/deployer-depuis-github/index.html +45 -0
- package/template/.build/guides/deployer-depuis-github.md +70 -0
- package/template/.build/guides/deployer-un-framework/index.html +81 -0
- package/template/.build/guides/deployer-un-framework.md +74 -0
- package/template/.build/guides/github-actions-sans-application/index.html +53 -0
- package/template/.build/guides/github-actions-sans-application.md +95 -0
- package/template/.build/guides/inviter-une-personne/index.html +28 -0
- package/template/.build/guides/inviter-une-personne.md +38 -0
- package/template/.build/guides/lire-les-logs/index.html +37 -0
- package/template/.build/guides/lire-les-logs.md +48 -0
- package/template/.build/guides/migrer-depuis-vercel/index.html +25 -0
- package/template/.build/guides/migrer-depuis-vercel.md +51 -0
- package/template/.build/guides/monorepo/index.html +40 -0
- package/template/.build/guides/monorepo.md +42 -0
- package/template/.build/guides/revenir-en-arriere/index.html +39 -0
- package/template/.build/guides/revenir-en-arriere.md +50 -0
- package/template/.build/guides/site-statique/index.html +41 -0
- package/template/.build/guides/site-statique.md +59 -0
- package/template/.build/guides/synchroniser-doppler/index.html +46 -0
- package/template/.build/guides/synchroniser-doppler.md +63 -0
- package/template/.build/guides/variables-d-environnement/index.html +73 -0
- package/template/.build/guides/variables-d-environnement.md +92 -0
- package/template/.build/images/famille/account.svg +1 -0
- package/template/.build/images/famille/analytics.svg +1 -0
- package/template/.build/images/famille/docs.svg +1 -0
- package/template/.build/images/famille/host.svg +1 -0
- package/template/.build/images/famille/mail.svg +1 -0
- package/template/.build/images/famille/portal.svg +1 -0
- package/template/.build/images/famille/status.svg +1 -0
- package/template/.build/images/logo.svg +1 -0
- package/template/.build/index.html +30 -86
- package/template/.build/index.md +59 -21
- package/template/.build/llms-full.txt +2330 -518
- package/template/.build/llms.txt +51 -34
- package/template/.build/pagefind/fragment/fr-ch_16987e2.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_2b4c97b.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_3294a5c.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_34858c9.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_39ddba1.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_4ab1899.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_4d3a52a.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_506c187.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_5aa255a.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_6841c7d.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_6dc7a2d.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_847edff.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_8745af7.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_8aac5e6.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_916b233.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_9fd014a.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_a0808f8.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_a4e1f69.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_a80a53d.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_a9e725b.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_ac3f64c.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_af292f1.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_af3e716.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_b0689a4.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_baed996.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_c89e27a.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_cd6ca13.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_d09af09.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_d4bcea8.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_dc2a134.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_ded7ddc.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_e2528cb.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_e3cbb4e.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_e7902d9.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_f48ca47.pf_fragment +0 -0
- package/template/.build/pagefind/index/fr-ch_8a5f905.pf_index +0 -0
- package/template/.build/pagefind/index/fr-ch_fbd9c96.pf_index +0 -0
- package/template/.build/pagefind/pagefind-entry.json +1 -1
- package/template/.build/pagefind/pagefind.fr-ch_211aacbfa7f0e.pf_meta +0 -0
- package/template/.build/reference/api/deploiements/index.html +326 -0
- package/template/.build/reference/api/deploiements.md +170 -0
- package/template/.build/reference/api/erreurs/index.html +102 -0
- package/template/.build/reference/api/erreurs.md +50 -0
- package/template/.build/reference/api/fichiers/index.html +82 -0
- package/template/.build/reference/api/fichiers.md +62 -0
- package/template/.build/reference/api/introduction/index.html +126 -0
- package/template/.build/reference/api/introduction.md +84 -0
- package/template/.build/reference/api/projets/index.html +184 -0
- package/template/.build/reference/api/projets.md +102 -0
- package/template/.build/reference/api/utilisateur/index.html +96 -0
- package/template/.build/reference/api/utilisateur.md +89 -0
- package/template/.build/reference/api/variables/index.html +75 -0
- package/template/.build/reference/api/variables.md +58 -0
- package/template/.build/reference/cli/index.html +165 -82
- package/template/.build/reference/cli.md +159 -23
- package/template/.build/reference/compatibilite/index.html +196 -0
- package/template/.build/reference/compatibilite.md +64 -0
- package/template/.build/reference/domaines/index.html +171 -0
- package/template/.build/reference/domaines.md +76 -0
- package/template/.build/reference/limites/index.html +159 -0
- package/template/.build/reference/limites.md +56 -0
- package/template/.build/reference/variables/index.html +164 -0
- package/template/.build/reference/variables.md +63 -0
- package/template/.build/reference/vercel-json/index.html +65 -0
- package/template/.build/reference/vercel-json.md +51 -0
- package/template/node_modules/.vite/deps/_metadata.json +8 -8
- package/template/src/content.config.ts +8 -2
- package/template/.build/_astro/Assistant.astro_astro_type_script_index_0_lang.DWgmlr85.js +0 -4
- package/template/.build/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.C3fM4Kra.js +0 -1
- package/template/.build/_astro/Search.astro_astro_type_script_index_0_lang.Cn3-p701.js +0 -1
- package/template/.build/_astro/TableOfContents.astro_astro_type_script_index_0_lang.BpJaGz7G.js +0 -1
- package/template/.build/_astro/common.C-MpX45O.css +0 -3
- package/template/.build/_astro/logo-clair.BqNh6JNi.svg +0 -1
- package/template/.build/_astro/logo-sombre.BkgsFXxh.svg +0 -1
- package/template/.build/_astro/starlight-toc.D4UDIxQL.js +0 -1
- package/template/.build/_astro/ui-core.CrG20ya_.js +0 -2
- package/template/.build/demarrer/premiere-doc/index.html +0 -84
- package/template/.build/demarrer/premiere-doc.md +0 -65
- package/template/.build/explications/donnees/index.html +0 -114
- package/template/.build/explications/donnees.md +0 -28
- package/template/.build/explications/fonctionnement/index.html +0 -93
- package/template/.build/explications/fonctionnement.md +0 -32
- package/template/.build/guides/agents/index.html +0 -118
- package/template/.build/guides/agents.md +0 -54
- package/template/.build/guides/assistant/index.html +0 -119
- package/template/.build/guides/assistant.md +0 -46
- package/template/.build/guides/composants/index.html +0 -97
- package/template/.build/guides/composants.md +0 -101
- package/template/.build/guides/ecrire/index.html +0 -116
- package/template/.build/guides/ecrire.md +0 -63
- package/template/.build/guides/navigation/index.html +0 -90
- package/template/.build/guides/navigation.md +0 -63
- package/template/.build/guides/publier/index.html +0 -95
- package/template/.build/guides/publier.md +0 -65
- package/template/.build/guides/theme/index.html +0 -87
- package/template/.build/guides/theme.md +0 -33
- package/template/.build/images/favicon.svg +0 -1
- package/template/.build/images/logo-clair.svg +0 -1
- package/template/.build/images/logo-sombre.svg +0 -1
- package/template/.build/pagefind/fragment/fr-ch_2a431a9.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_456586a.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_4f8575c.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_68e734b.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_72b91f4.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_8f256dd.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_95a15cc.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_aa80c55.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_ab79738.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_cfa4336.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_dab8f5e.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_de60b43.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_e02aa49.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_e254a54.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_e2c46e3.pf_fragment +0 -0
- package/template/.build/pagefind/index/fr-ch_a71411b.pf_index +0 -0
- package/template/.build/pagefind/pagefind.fr-ch_2f3ea8fccf961.pf_meta +0 -0
- package/template/.build/reference/api-assistant/index.html +0 -161
- package/template/.build/reference/api-assistant.md +0 -70
- package/template/.build/reference/docs-json/index.html +0 -192
- package/template/.build/reference/docs-json.md +0 -43
- package/template/.build/reference/mcp/index.html +0 -151
- package/template/.build/reference/mcp.md +0 -49
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { compile } from "@mdx-js/mdx"
|
|
2
|
+
import type { Root } from "mdast"
|
|
3
|
+
import remarkGfm from "remark-gfm"
|
|
4
|
+
import { parse as parseYaml } from "yaml"
|
|
5
|
+
|
|
6
|
+
import { isMdxComponent } from "./components.ts"
|
|
7
|
+
import { parseDocsConfig } from "./config.ts"
|
|
8
|
+
import { missingPages, normalizeNavigation, pageToSlug } from "./navigation.ts"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Ce que le build refuserait, vérifié avant de publier : l'éditeur de la console bloque
|
|
12
|
+
* la publication sur la moindre erreur, avec la ligne à corriger. Même compilateur MDX
|
|
13
|
+
* que le build (`@mdx-js/mdx`, GFM), même schéma de `docs.json`, même règle de pages.
|
|
14
|
+
*/
|
|
15
|
+
export type Problem = { file: string; line: number | null; column: number | null; message: string }
|
|
16
|
+
|
|
17
|
+
/** Une page de la doc : `.mdx` ou `.md` à l'intérieur du dossier. */
|
|
18
|
+
export const PAGE_FILE = /\.(mdx|md)$/i
|
|
19
|
+
|
|
20
|
+
const IMAGE_FILE = /\.(png|jpe?g|gif|svg|webp|avif|ico)$/i
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Fichier que l'éditeur peut écrire, relatif au dossier de la doc : `docs.json`, pages et
|
|
24
|
+
* images. Jamais un dossier caché ni la configuration du build (même règle que Host,
|
|
25
|
+
* `isEditablePath` d'agenthost, qui revérifie).
|
|
26
|
+
*/
|
|
27
|
+
export function isDocFile(path: string): boolean {
|
|
28
|
+
if (path.length === 0 || path.length > 300) return false
|
|
29
|
+
if (path.startsWith("/") || path.endsWith("/") || path.includes("\\")) return false
|
|
30
|
+
const segments = path.split("/")
|
|
31
|
+
if (segments.some((s) => s === "" || s === "." || s === ".." || s.startsWith("."))) return false
|
|
32
|
+
if (segments.includes("node_modules") || segments[0] === "dist") return false
|
|
33
|
+
if (!/^[\p{L}\p{N} ._/()+@-]+$/u.test(path)) return false
|
|
34
|
+
return path === "docs.json" || PAGE_FILE.test(path) || IMAGE_FILE.test(path)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function isImageFile(path: string): boolean {
|
|
38
|
+
return IMAGE_FILE.test(path)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Fichiers Markdown du dossier qui ne sont pas des pages (`template/src/content.config.ts`). */
|
|
42
|
+
const NOT_PAGES = new Set(["README.md", "CHANGELOG.md"])
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Une page du site : `.mdx` ou `.md`, sauf un extrait (`_nom.mdx`, inclus par d'autres pages)
|
|
46
|
+
* et le README ou le CHANGELOG à la racine, que le build ignore.
|
|
47
|
+
*/
|
|
48
|
+
export function isPageFile(file: string): boolean {
|
|
49
|
+
return PAGE_FILE.test(file) && !NOT_PAGES.has(file) && !(file.split("/").at(-1) ?? "").startsWith("_")
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** `guides/publier.mdx` → `guides/publier` : le chemin de page de `docs.json` ; `null` pour un autre fichier. */
|
|
53
|
+
export function pageOfFile(file: string): string | null {
|
|
54
|
+
return isPageFile(file) ? file.replace(PAGE_FILE, "") : null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n?---[ \t]*(?:\r?\n|$)/
|
|
58
|
+
|
|
59
|
+
export type Frontmatter = { raw: string | null; body: string; lines: number }
|
|
60
|
+
|
|
61
|
+
/** En-tête YAML d'une page et corps, avec le nombre de lignes de l'en-tête (pour garder les numéros de ligne). */
|
|
62
|
+
export function splitFrontmatter(source: string): Frontmatter {
|
|
63
|
+
const match = FRONTMATTER.exec(source)
|
|
64
|
+
if (!match) return { raw: null, body: source, lines: 0 }
|
|
65
|
+
const header = match[0]
|
|
66
|
+
const lines = header.split("\n").length - (header.endsWith("\n") ? 1 : 0)
|
|
67
|
+
return { raw: match[1] ?? "", body: source.slice(header.length), lines }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Lit l'en-tête d'une page : objet YAML, ou `null` s'il manque ou ne se lit pas. */
|
|
71
|
+
export function readFrontmatter(source: string): Record<string, unknown> | null {
|
|
72
|
+
const { raw } = splitFrontmatter(source)
|
|
73
|
+
if (raw === null) return null
|
|
74
|
+
try {
|
|
75
|
+
const data: unknown = parseYaml(raw)
|
|
76
|
+
return data && typeof data === "object" && !Array.isArray(data) ? (data as Record<string, unknown>) : null
|
|
77
|
+
} catch {
|
|
78
|
+
return null
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
type Position = { start?: { line?: number; column?: number } }
|
|
83
|
+
type MdxNode = { type: string; name?: string | null; position?: Position; children?: Array<MdxNode> }
|
|
84
|
+
|
|
85
|
+
/** Composants appelés par la page sans exister : le build échouerait au rendu. */
|
|
86
|
+
function unknownComponents(problems: Array<Problem>, file: string) {
|
|
87
|
+
return () => (tree: Root) => {
|
|
88
|
+
const declared = new Set<string>()
|
|
89
|
+
const walk = (node: MdxNode) => {
|
|
90
|
+
if (node.type === "mdxjsEsm") {
|
|
91
|
+
const value = (node as unknown as { value: string }).value
|
|
92
|
+
for (const match of value.matchAll(/import\s+(?:\{([^}]*)\}|([A-Za-z_$][\w$]*))/g)) {
|
|
93
|
+
for (const name of (match[1] ?? match[2] ?? "").split(","))
|
|
94
|
+
declared.add(
|
|
95
|
+
name
|
|
96
|
+
.split(/\s+as\s+/)
|
|
97
|
+
.pop()!
|
|
98
|
+
.trim(),
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
for (const match of value.matchAll(/export\s+(?:const|function)\s+([A-Za-z_$][\w$]*)/g)) declared.add(match[1]!)
|
|
102
|
+
}
|
|
103
|
+
for (const child of node.children ?? []) walk(child)
|
|
104
|
+
}
|
|
105
|
+
walk(tree as unknown as MdxNode)
|
|
106
|
+
const check = (node: MdxNode) => {
|
|
107
|
+
if ((node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") && node.name) {
|
|
108
|
+
const root = node.name.split(".")[0]!
|
|
109
|
+
if (/^[A-Z]/.test(root) && !isMdxComponent(root) && !declared.has(root))
|
|
110
|
+
problems.push({
|
|
111
|
+
file,
|
|
112
|
+
line: node.position?.start?.line ?? null,
|
|
113
|
+
column: node.position?.start?.column ?? null,
|
|
114
|
+
message: `Le composant <${node.name}> n'existe pas. Composants disponibles : <Note>, <Tip>, <Card>, <Steps>…`,
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
for (const child of node.children ?? []) check(child)
|
|
118
|
+
}
|
|
119
|
+
check(tree as unknown as MdxNode)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const TRANSLATIONS: Array<[RegExp, (m: RegExpMatchArray) => string]> = [
|
|
124
|
+
[/Expected a closing tag for `<([^>]+)>`/, (m) => `La balise <${m[1]}> n'est jamais fermée.`],
|
|
125
|
+
[
|
|
126
|
+
/Unexpected closing slash `\/` in tag, expected an open tag first/,
|
|
127
|
+
() => "Balise fermante sans balise ouvrante correspondante.",
|
|
128
|
+
],
|
|
129
|
+
[
|
|
130
|
+
/Unexpected closing tag `<\/([^>]+)>`, expected corresponding closing tag for `<([^>]+)>`/,
|
|
131
|
+
(m) => `</${m[1]}> ferme la mauvaise balise : <${m[2]}> est encore ouverte.`,
|
|
132
|
+
],
|
|
133
|
+
[
|
|
134
|
+
/Expected the closing tag `<\/([^>]+)>` either after the end of/,
|
|
135
|
+
(m) =>
|
|
136
|
+
`</${m[1]}> est mal placée : ouvre et ferme <${m[1]}> sur leurs propres lignes, ou sur la même ligne que le texte.`,
|
|
137
|
+
],
|
|
138
|
+
[
|
|
139
|
+
/Could not parse expression with acorn/,
|
|
140
|
+
() => "Expression entre accolades illisible : échappe « { » par « \\{ » si c'est du texte.",
|
|
141
|
+
],
|
|
142
|
+
[/Could not parse import\/exports with acorn/, () => "Ligne import ou export illisible."],
|
|
143
|
+
[
|
|
144
|
+
/Unexpected end of file in expression, expected a corresponding closing brace for `\{`/,
|
|
145
|
+
() => "Accolade « { » jamais fermée : échappe-la par « \\{ » si c'est du texte.",
|
|
146
|
+
],
|
|
147
|
+
[
|
|
148
|
+
/Unexpected character `(.)` \(U\+[0-9A-F]+\) before name/,
|
|
149
|
+
(m) => `Caractère « ${m[1]} » inattendu après « < » : écris « < » pour un chevron dans le texte.`,
|
|
150
|
+
],
|
|
151
|
+
[/Unexpected lazy line in/, () => "Ligne mal indentée à l'intérieur d'un bloc (citation, liste ou composant)."],
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
function translate(reason: string): string {
|
|
155
|
+
for (const [pattern, render] of TRANSLATIONS) {
|
|
156
|
+
const match = reason.match(pattern)
|
|
157
|
+
if (match) return render(match)
|
|
158
|
+
}
|
|
159
|
+
return `Syntaxe MDX invalide : ${reason}`
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
type Point = { line?: number; column?: number }
|
|
163
|
+
type VFileMessageLike = {
|
|
164
|
+
reason?: string
|
|
165
|
+
message?: string
|
|
166
|
+
line?: number | null
|
|
167
|
+
column?: number | null
|
|
168
|
+
place?: (Point & { start?: Point }) | null
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Position d'une erreur de MDX : son point, sinon celui cité dans le message (`(7:1-7:7)`). */
|
|
172
|
+
function positionOf(failure: VFileMessageLike, reason: string): { line: number | null; column: number | null } {
|
|
173
|
+
const point = failure.place?.start ?? failure.place
|
|
174
|
+
if (failure.line) return { line: failure.line, column: failure.column ?? null }
|
|
175
|
+
if (point?.line) return { line: point.line, column: point.column ?? null }
|
|
176
|
+
const cited = reason.match(/\((\d+):(\d+)/)
|
|
177
|
+
return cited ? { line: Number(cited[1]), column: Number(cited[2]) } : { line: null, column: null }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** En-tête lu ; `undefined` (et une erreur notée) s'il ne se lit pas. */
|
|
181
|
+
function checkYaml(problems: Array<Problem>, file: string, raw: string): unknown {
|
|
182
|
+
try {
|
|
183
|
+
return parseYaml(raw)
|
|
184
|
+
} catch (error) {
|
|
185
|
+
const position = (error as { linePos?: Array<{ line: number; col: number }> }).linePos?.[0]
|
|
186
|
+
problems.push({
|
|
187
|
+
file,
|
|
188
|
+
line: position ? position.line + 1 : 1,
|
|
189
|
+
column: position?.col ?? null,
|
|
190
|
+
message: "En-tête illisible : vérifie les deux-points et les guillemets (YAML).",
|
|
191
|
+
})
|
|
192
|
+
return undefined
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Vérifie une page : en-tête YAML avec un `title` (Starlight l'exige), compilation MDX
|
|
198
|
+
* comme au build, composants connus. Les numéros de ligne sont ceux du fichier entier.
|
|
199
|
+
*/
|
|
200
|
+
export async function checkPage(file: string, source: string): Promise<Array<Problem>> {
|
|
201
|
+
const problems: Array<Problem> = []
|
|
202
|
+
const front = splitFrontmatter(source)
|
|
203
|
+
// Un extrait ou le README n'est pas une page : seule la syntaxe compte, pas l'en-tête.
|
|
204
|
+
if (!isPageFile(file)) {
|
|
205
|
+
if (front.raw !== null) checkYaml(problems, file, front.raw)
|
|
206
|
+
} else if (front.raw === null) {
|
|
207
|
+
problems.push({
|
|
208
|
+
file,
|
|
209
|
+
line: 1,
|
|
210
|
+
column: 1,
|
|
211
|
+
message: "Il manque l'en-tête de la page : commence par ---, title: Le titre, puis ---.",
|
|
212
|
+
})
|
|
213
|
+
} else {
|
|
214
|
+
const data = checkYaml(problems, file, front.raw)
|
|
215
|
+
const title = data && typeof data === "object" ? (data as Record<string, unknown>).title : undefined
|
|
216
|
+
if (data !== undefined && (typeof title !== "string" || !title.trim()))
|
|
217
|
+
problems.push({
|
|
218
|
+
file,
|
|
219
|
+
line: 2,
|
|
220
|
+
column: 1,
|
|
221
|
+
message: "L'en-tête doit donner un titre : title: Le titre de la page.",
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Les lignes de l'en-tête restent, vides : les positions de MDX tombent sur la bonne ligne.
|
|
226
|
+
const body = "\n".repeat(front.lines) + front.body
|
|
227
|
+
try {
|
|
228
|
+
await compile(body, {
|
|
229
|
+
format: file.toLowerCase().endsWith(".md") ? "md" : "mdx",
|
|
230
|
+
remarkPlugins: [remarkGfm, unknownComponents(problems, file)],
|
|
231
|
+
})
|
|
232
|
+
} catch (error) {
|
|
233
|
+
const failure = error as VFileMessageLike
|
|
234
|
+
const reason = String(failure.reason ?? failure.message ?? error)
|
|
235
|
+
problems.push({ file, ...positionOf(failure, reason), message: translate(reason) })
|
|
236
|
+
}
|
|
237
|
+
return problems.sort((a, b) => (a.line ?? 0) - (b.line ?? 0))
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Vérifie `docs.json` et sa navigation contre les fichiers de la doc : schéma, une seule
|
|
242
|
+
* forme de navigation, et chaque page citée présente dans le dossier.
|
|
243
|
+
*/
|
|
244
|
+
export function checkSite(docsJson: string, files: Iterable<string>): Array<Problem> {
|
|
245
|
+
const parsed = parseDocsConfig(docsJson)
|
|
246
|
+
if (!parsed.ok) return parsed.errors.map((message) => ({ file: "docs.json", line: null, column: null, message }))
|
|
247
|
+
const existing = new Set<string>()
|
|
248
|
+
for (const file of files) {
|
|
249
|
+
const page = pageOfFile(file)
|
|
250
|
+
if (page) existing.add(pageToSlug(page))
|
|
251
|
+
}
|
|
252
|
+
const problems: Array<Problem> = missingPages(normalizeNavigation(parsed.config), existing).map((page) => ({
|
|
253
|
+
file: "docs.json",
|
|
254
|
+
line: null,
|
|
255
|
+
column: null,
|
|
256
|
+
message: `La navigation cite la page ${page}, mais ${page}.mdx n'existe pas.`,
|
|
257
|
+
}))
|
|
258
|
+
const slug = (path: string) =>
|
|
259
|
+
path
|
|
260
|
+
.split(/[?#]/)[0]!
|
|
261
|
+
.replace(/^\/+|\/+$/g, "")
|
|
262
|
+
.toLowerCase()
|
|
263
|
+
const sources = new Set<string>()
|
|
264
|
+
for (const redirect of parsed.config.redirects ?? []) {
|
|
265
|
+
const source = slug(redirect.source)
|
|
266
|
+
const say = (message: string) => problems.push({ file: "docs.json", line: null, column: null, message })
|
|
267
|
+
if (sources.has(source)) say(`Deux redirections partent de ${redirect.source}.`)
|
|
268
|
+
sources.add(source)
|
|
269
|
+
// Une redirection depuis une page qui existe la cacherait : le build écrirait les deux au même endroit.
|
|
270
|
+
if (existing.has(source))
|
|
271
|
+
say(`La redirection ${redirect.source} masque une page qui existe : retire-la ou supprime la page.`)
|
|
272
|
+
if (redirect.destination.startsWith("/") && !existing.has(slug(redirect.destination)))
|
|
273
|
+
say(`La redirection ${redirect.source} mène à ${redirect.destination}, une page qui n'existe pas.`)
|
|
274
|
+
}
|
|
275
|
+
return problems
|
|
276
|
+
}
|
package/src/integration.ts
CHANGED
|
@@ -8,9 +8,10 @@ import type { AstroIntegration, AstroUserConfig } from "astro"
|
|
|
8
8
|
|
|
9
9
|
import { remarkAutoImport } from "./build/auto-import.ts"
|
|
10
10
|
import { remarkBaseLinks } from "./build/base-links.ts"
|
|
11
|
+
import { rehypeDocsContent } from "./build/content.ts"
|
|
11
12
|
import { publicFiles } from "./build/public-files.ts"
|
|
12
13
|
import { writeMachineReadable } from "./build/outputs.ts"
|
|
13
|
-
import { parseDocsConfig, withHostProject, type DocsConfig } from "./core/config.ts"
|
|
14
|
+
import { parseDocsConfig, socialNetwork, withHostProject, type DocsConfig } from "./core/config.ts"
|
|
14
15
|
import {
|
|
15
16
|
missingPages,
|
|
16
17
|
normalizeNavigation,
|
|
@@ -95,9 +96,12 @@ function collectPublic(contentDir: string, declared: ReadonlyArray<string>): str
|
|
|
95
96
|
return target
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
/**
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
/** Ce que le frontmatter d'une page change dans la barre : `sidebarTitle` et `tag` (champs Mintlify). */
|
|
100
|
+
type PageMeta = { label: string | null; tag: string | null }
|
|
101
|
+
|
|
102
|
+
/** Pages du dépôt (`guides/publier`) et leurs réglages de barre latérale. */
|
|
103
|
+
function scanPages(contentDir: string): Map<string, PageMeta> {
|
|
104
|
+
const pages = new Map<string, PageMeta>()
|
|
101
105
|
const walk = (dir: string) => {
|
|
102
106
|
for (const name of readdirSync(dir)) {
|
|
103
107
|
if (name.startsWith(".") || IGNORED_DIRS.has(name)) continue
|
|
@@ -108,8 +112,9 @@ function scanPages(contentDir: string): Map<string, string | null> {
|
|
|
108
112
|
.replaceAll("\\", "/")
|
|
109
113
|
.replace(/\.mdx?$/, "")
|
|
110
114
|
const frontmatter = /^---\r?\n([\s\S]*?)\r?\n---/.exec(readFileSync(path, "utf8"))?.[1] ?? ""
|
|
111
|
-
const
|
|
112
|
-
|
|
115
|
+
const field = (name: string) =>
|
|
116
|
+
new RegExp(`^${name}:\\s*["']?(.+?)["']?\\s*$`, "m").exec(frontmatter)?.[1] ?? null
|
|
117
|
+
pages.set(pageToSlug(page), { label: field("sidebarTitle"), tag: field("tag") })
|
|
113
118
|
}
|
|
114
119
|
}
|
|
115
120
|
}
|
|
@@ -117,15 +122,21 @@ function scanPages(contentDir: string): Map<string, string | null> {
|
|
|
117
122
|
return pages
|
|
118
123
|
}
|
|
119
124
|
|
|
120
|
-
type SidebarItem =
|
|
125
|
+
type SidebarItem =
|
|
126
|
+
| { slug: string; label?: string; badge?: { text: string; variant: "note" } }
|
|
127
|
+
| { label: string; collapsed: boolean; items: Array<SidebarItem> }
|
|
121
128
|
|
|
122
|
-
function sidebarItems(items: Array<NavItem>, labels: ReadonlyMap<string,
|
|
129
|
+
function sidebarItems(items: Array<NavItem>, labels: ReadonlyMap<string, PageMeta>): Array<SidebarItem> {
|
|
123
130
|
return items.map((item) => {
|
|
124
131
|
if (item.type === "group")
|
|
125
132
|
return { label: item.label, collapsed: !item.expanded, items: sidebarItems(item.items, labels) }
|
|
126
133
|
const slug = pageToSlug(item.page)
|
|
127
|
-
const
|
|
128
|
-
return
|
|
134
|
+
const meta = labels.get(slug)
|
|
135
|
+
return {
|
|
136
|
+
slug,
|
|
137
|
+
...(meta?.label ? { label: meta.label } : {}),
|
|
138
|
+
...(meta?.tag ? { badge: { text: meta.tag.slice(0, 16), variant: "note" as const } } : {}),
|
|
139
|
+
}
|
|
129
140
|
})
|
|
130
141
|
}
|
|
131
142
|
|
|
@@ -133,10 +144,7 @@ function sidebarItems(items: Array<NavItem>, labels: ReadonlyMap<string, string
|
|
|
133
144
|
* Une entrée de premier niveau par couple (version, onglet), dans l'ordre de l'arbre ;
|
|
134
145
|
* `route-data.ts` ne garde ensuite que celle de la page affichée.
|
|
135
146
|
*/
|
|
136
|
-
export function starlightSidebar(
|
|
137
|
-
tree: NavTree,
|
|
138
|
-
labels: ReadonlyMap<string, string | null> = new Map(),
|
|
139
|
-
): Array<SidebarItem> {
|
|
147
|
+
export function starlightSidebar(tree: NavTree, labels: ReadonlyMap<string, PageMeta> = new Map()): Array<SidebarItem> {
|
|
140
148
|
const sections = tree.versions.flatMap((version) => version.tabs)
|
|
141
149
|
if (sections.length === 1) return sidebarItems(sections[0]!.items, labels)
|
|
142
150
|
return tree.versions.flatMap((version) =>
|
|
@@ -148,17 +156,27 @@ export function starlightSidebar(
|
|
|
148
156
|
)
|
|
149
157
|
}
|
|
150
158
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
"
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
/**
|
|
160
|
+
* `redirects` de docs.json en redirections d'Astro : une page qui renvoie à la nouvelle
|
|
161
|
+
* adresse (le site est statique). Chemins écrits comme les liens de la doc, `base` ajouté.
|
|
162
|
+
*/
|
|
163
|
+
export function astroRedirects(
|
|
164
|
+
redirects: ReadonlyArray<{ source: string; destination: string; permanent?: boolean | undefined }>,
|
|
165
|
+
base: string,
|
|
166
|
+
): Record<string, { status: 301 | 302; destination: string }> {
|
|
167
|
+
const slash = (path: string) => (path.endsWith("/") ? path : `${path}/`)
|
|
168
|
+
return Object.fromEntries(
|
|
169
|
+
redirects.map((item) => [
|
|
170
|
+
slash(item.source),
|
|
171
|
+
{
|
|
172
|
+
status: item.permanent === false ? 302 : 301,
|
|
173
|
+
destination: item.destination.startsWith("/")
|
|
174
|
+
? `${base}${slash(item.destination.split("#")[0]!)}${item.destination.includes("#") ? `#${item.destination.split("#")[1]}` : ""}`
|
|
175
|
+
: item.destination,
|
|
176
|
+
},
|
|
177
|
+
]),
|
|
178
|
+
)
|
|
179
|
+
}
|
|
162
180
|
|
|
163
181
|
function virtualConfigPlugin(data: VirtualConfig) {
|
|
164
182
|
const id = "virtual:hgdc-docs/config"
|
|
@@ -215,9 +233,10 @@ export function createAstroConfig(options: SiteOptions = readSiteOptions()): Ast
|
|
|
215
233
|
const theme = themeFor(config.colors?.primary, config.colors?.dark)
|
|
216
234
|
const logo = typeof config.logo === "string" ? { light: config.logo } : config.logo
|
|
217
235
|
const asset = (path: string) => join(options.contentDir, path.replace(/^\//, ""))
|
|
218
|
-
const social = Object.entries(config.footer?.socials ?? {})
|
|
219
|
-
|
|
220
|
-
|
|
236
|
+
const social = Object.entries(config.footer?.socials ?? {}).flatMap(([key, href]) => {
|
|
237
|
+
const network = socialNetwork(key)
|
|
238
|
+
return network ? [{ icon: network.icon as "github", label: network.label, href }] : []
|
|
239
|
+
})
|
|
221
240
|
|
|
222
241
|
return {
|
|
223
242
|
root: file("../template"),
|
|
@@ -231,7 +250,14 @@ export function createAstroConfig(options: SiteOptions = readSiteOptions()): Ast
|
|
|
231
250
|
site: options.site ?? undefined,
|
|
232
251
|
...(base ? { base } : {}),
|
|
233
252
|
trailingSlash: "always",
|
|
234
|
-
|
|
253
|
+
devToolbar: { enabled: false },
|
|
254
|
+
redirects: astroRedirects(config.redirects ?? [], base),
|
|
255
|
+
markdown: {
|
|
256
|
+
processor: unified({
|
|
257
|
+
remarkPlugins: [remarkAutoImport, [remarkBaseLinks, { base }]],
|
|
258
|
+
rehypePlugins: [rehypeDocsContent],
|
|
259
|
+
}),
|
|
260
|
+
},
|
|
235
261
|
vite: {
|
|
236
262
|
plugins: [virtualConfigPlugin(data)],
|
|
237
263
|
server: { fs: { allow: [options.contentDir, file("..")] } },
|
|
@@ -252,11 +278,57 @@ export function createAstroConfig(options: SiteOptions = readSiteOptions()): Ast
|
|
|
252
278
|
routeMiddleware: file("./overrides/route-data.ts"),
|
|
253
279
|
components: {
|
|
254
280
|
Head: file("./overrides/Head.astro"),
|
|
281
|
+
Header: file("./overrides/Header.astro"),
|
|
282
|
+
ThemeProvider: file("./overrides/ThemeProvider.astro"),
|
|
283
|
+
Search: file("./overrides/Search.astro"),
|
|
255
284
|
Sidebar: file("./overrides/Sidebar.astro"),
|
|
256
285
|
PageTitle: file("./overrides/PageTitle.astro"),
|
|
257
286
|
PageFrame: file("./overrides/PageFrame.astro"),
|
|
287
|
+
PageSidebar: file("./overrides/PageSidebar.astro"),
|
|
288
|
+
TwoColumnContent: file("./overrides/TwoColumnContent.astro"),
|
|
289
|
+
Footer: file("./overrides/Footer.astro"),
|
|
290
|
+
},
|
|
291
|
+
expressiveCode: {
|
|
292
|
+
// Clair d'abord (thème par défaut du site) ; le sombre suit `data-hd-theme` (ThemeProvider).
|
|
293
|
+
themes: ["github-light-default", "github-dark-default"],
|
|
294
|
+
useDarkModeMediaQuery: false,
|
|
295
|
+
themeCssSelector: (theme) => (theme.type === "dark" ? '[data-hd-theme="dark"]' : false),
|
|
296
|
+
// Blocs dessinés par theme.css (filet, en-tête, actions) : un cadre unique pour le
|
|
297
|
+
// shell comme pour le reste. Le bouton Copier d'Expressive Code reste dans le HTML,
|
|
298
|
+
// caché : son `data-code` porte le texte exact (build/markdown.ts, widget/code.ts).
|
|
299
|
+
defaultProps: { frame: "code" },
|
|
300
|
+
styleOverrides: {
|
|
301
|
+
borderRadius: "1rem",
|
|
302
|
+
borderColor: "var(--hd-border)",
|
|
303
|
+
borderWidth: "1px",
|
|
304
|
+
codeBackground: "var(--hd-code-bg)",
|
|
305
|
+
codeFontFamily: "var(--hd-font-mono)",
|
|
306
|
+
codeFontSize: "0.8125rem",
|
|
307
|
+
codeLineHeight: "1.7",
|
|
308
|
+
codePaddingBlock: "0.875rem",
|
|
309
|
+
codePaddingInline: "1rem",
|
|
310
|
+
uiFontFamily: "var(--hd-font-sans)",
|
|
311
|
+
uiFontSize: "0.8125rem",
|
|
312
|
+
frames: {
|
|
313
|
+
frameBoxShadowCssValue: "none",
|
|
314
|
+
editorTabBarBackground: "var(--hd-code-header)",
|
|
315
|
+
editorTabBarBorderBottomColor: "var(--hd-border)",
|
|
316
|
+
editorActiveTabBackground: "transparent",
|
|
317
|
+
editorActiveTabForeground: "var(--hd-fg)",
|
|
318
|
+
editorActiveTabBorderColor: "transparent",
|
|
319
|
+
editorActiveTabIndicatorTopColor: "transparent",
|
|
320
|
+
editorActiveTabIndicatorBottomColor: "var(--hd-accent)",
|
|
321
|
+
editorActiveTabIndicatorHeight: "2px",
|
|
322
|
+
editorTabBorderRadius: "0",
|
|
323
|
+
editorBackground: "var(--hd-code-bg)",
|
|
324
|
+
terminalBackground: "var(--hd-code-bg)",
|
|
325
|
+
terminalTitlebarBackground: "var(--hd-code-header)",
|
|
326
|
+
terminalTitlebarBorderBottomColor: "var(--hd-border)",
|
|
327
|
+
terminalTitlebarForeground: "var(--hd-muted-fg)",
|
|
328
|
+
terminalTitlebarDotsOpacity: "0",
|
|
329
|
+
},
|
|
330
|
+
},
|
|
258
331
|
},
|
|
259
|
-
expressiveCode: { themes: ["github-dark-default", "github-light-default"] },
|
|
260
332
|
pagination: true,
|
|
261
333
|
}),
|
|
262
334
|
machineReadableOutputs(data, options),
|
|
@@ -1,39 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
import data from "virtual:hgdc-docs/config"
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import Icon from "./Icon.astro"
|
|
5
|
+
|
|
6
|
+
// Assistant. Fermé : une barre « Pose une question… » au bas du contenu. Ouvert : un
|
|
7
|
+
// panneau à droite qui pousse la page (une feuille qui monte du bas sur téléphone).
|
|
8
|
+
// Logique dans `../widget/client.ts`.
|
|
6
9
|
const endpoint = new URL("/api/v1/ask", data.config.assistant?.endpoint ?? data.apiEndpoint).toString()
|
|
7
10
|
---
|
|
8
11
|
|
|
9
12
|
<hgdc-assistant data-endpoint={endpoint} data-project={data.config.project} data-name={data.config.name}>
|
|
10
|
-
<
|
|
11
|
-
<
|
|
12
|
-
<path d="M12 3l1.9 4.6L18.5 9.5l-4.6 1.9L12 16l-1.9-4.6L5.5 9.5l4.6-1.9z" fill="currentColor"></path>
|
|
13
|
-
<path d="M18.5 15l.8 1.9 1.9.8-1.9.8-.8 1.9-.8-1.9-1.9-.8 1.9-.8z" fill="currentColor"></path>
|
|
14
|
-
</svg>
|
|
15
|
-
<span>Demander à l'IA</span>
|
|
16
|
-
<kbd class="hgdc-kbd" data-shortcut aria-hidden="true">Ctrl I</kbd>
|
|
17
|
-
</button>
|
|
18
|
-
|
|
19
|
-
<section class="hgdc-panel" role="dialog" aria-modal="false" aria-labelledby="hgdc-assistant-title" hidden>
|
|
13
|
+
<section class="hgdc-panel" role="dialog" aria-modal="false" aria-labelledby="hgdc-assistant-title" data-panel inert>
|
|
14
|
+
<div class="hgdc-panel__grip" aria-hidden="true"></div>
|
|
20
15
|
<header class="hgdc-panel__header">
|
|
21
|
-
<
|
|
22
|
-
<h2 id="hgdc-assistant-title">Assistant</h2>
|
|
23
|
-
<p>Répond à partir de cette documentation, avec ses sources.</p>
|
|
24
|
-
</div>
|
|
16
|
+
<h2 id="hgdc-assistant-title"><Icon name="sparkles" />Assistant</h2>
|
|
25
17
|
<div class="hgdc-panel__tools">
|
|
26
|
-
<button type="button" class="
|
|
27
|
-
<
|
|
28
|
-
><path d="M4 12a8 8 0 1 0 2.3-5.7M4 4v4h4" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"
|
|
29
|
-
></path></svg
|
|
30
|
-
>
|
|
18
|
+
<button type="button" class="hd-icon-button" data-reset aria-label="Nouvelle conversation" title="Nouvelle conversation" hidden>
|
|
19
|
+
<Icon name="rotate" />
|
|
31
20
|
</button>
|
|
32
|
-
<button type="button" class="
|
|
33
|
-
<
|
|
34
|
-
><path d="M6 6l12 12M18 6 6 18" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"
|
|
35
|
-
></path></svg
|
|
36
|
-
>
|
|
21
|
+
<button type="button" class="hd-icon-button" data-close aria-label="Fermer l'assistant" title="Fermer (Échap)">
|
|
22
|
+
<Icon name="x" />
|
|
37
23
|
</button>
|
|
38
24
|
</div>
|
|
39
25
|
</header>
|
|
@@ -41,26 +27,18 @@ const endpoint = new URL("/api/v1/ask", data.config.assistant?.endpoint ?? data.
|
|
|
41
27
|
<div class="hgdc-panel__body" data-log aria-live="polite">
|
|
42
28
|
<div class="hgdc-empty" data-empty>
|
|
43
29
|
<p class="hgdc-empty__title">Pose ta question sur {data.config.name}.</p>
|
|
44
|
-
<p>
|
|
45
|
-
Je cherche dans les pages de cette documentation et je cite mes sources. Si la réponse n'y est pas, je te le
|
|
46
|
-
dis.
|
|
47
|
-
</p>
|
|
30
|
+
<p>Je cherche dans les pages de cette documentation et je cite mes sources. Si la réponse n'y est pas, je te le dis.</p>
|
|
48
31
|
</div>
|
|
49
32
|
</div>
|
|
50
33
|
|
|
51
34
|
<form class="hgdc-panel__form" data-form>
|
|
52
35
|
<label class="sr-only" for="hgdc-question">Ta question</label>
|
|
53
|
-
<textarea id="hgdc-question" data-input rows="1" maxlength="1000" placeholder="
|
|
54
|
-
|
|
55
|
-
<button type="submit" class="hgdc-send" data-send aria-label="Envoyer la question">
|
|
56
|
-
<svg aria-hidden="true" viewBox="0 0 24 24" width="18" height="18"
|
|
57
|
-
><path d="M12 19V5M5 12l7-7 7 7" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
58
|
-
></path></svg
|
|
59
|
-
>
|
|
60
|
-
</button>
|
|
36
|
+
<textarea id="hgdc-question" data-input rows="1" maxlength="1000" placeholder="Pose une question…" required></textarea>
|
|
37
|
+
<button type="submit" class="hd-send" data-send aria-label="Envoyer la question"><Icon name="arrow-up" size={16} /></button>
|
|
61
38
|
</form>
|
|
62
39
|
<p class="hgdc-panel__note">
|
|
63
|
-
Réponses générées par IA (Claude, d'Anthropic), à vérifier. Les questions sont conservées 90 jours pour améliorer
|
|
40
|
+
Réponses générées par IA (Claude, d'Anthropic), à vérifier. Les questions sont conservées 90 jours pour améliorer
|
|
41
|
+
cette documentation.
|
|
64
42
|
</p>
|
|
65
43
|
</section>
|
|
66
44
|
</hgdc-assistant>
|