@hgdc/docs 0.3.0 → 0.4.1

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.
Files changed (230) hide show
  1. package/package.json +1 -1
  2. package/src/build/content.ts +82 -0
  3. package/src/build/markdown.ts +10 -5
  4. package/src/components/Accordion.astro +3 -1
  5. package/src/components/Callout.astro +31 -0
  6. package/src/components/Card.astro +3 -1
  7. package/src/components/Check.astro +2 -3
  8. package/src/components/CodeGroup.astro +9 -1
  9. package/src/components/Danger.astro +2 -3
  10. package/src/components/Info.astro +2 -3
  11. package/src/components/Note.astro +2 -3
  12. package/src/components/Tip.astro +2 -3
  13. package/src/components/Warning.astro +2 -3
  14. package/src/core/feedback-api.ts +17 -7
  15. package/src/core/theme.ts +6 -3
  16. package/src/integration.ts +74 -16
  17. package/src/overrides/Assistant.astro +17 -39
  18. package/src/overrides/Footer.astro +27 -74
  19. package/src/overrides/Header.astro +92 -0
  20. package/src/overrides/Icon.astro +65 -0
  21. package/src/overrides/PageFrame.astro +55 -8
  22. package/src/overrides/PageSidebar.astro +7 -0
  23. package/src/overrides/PageTitle.astro +93 -62
  24. package/src/overrides/Search.astro +54 -0
  25. package/src/overrides/Sidebar.astro +89 -44
  26. package/src/overrides/SidebarList.astro +52 -0
  27. package/src/overrides/SiteFooter.astro +51 -0
  28. package/src/overrides/ThemeProvider.astro +23 -0
  29. package/src/overrides/ThemeToggle.astro +90 -0
  30. package/src/overrides/TwoColumnContent.astro +45 -0
  31. package/src/overrides/sections.ts +29 -0
  32. package/src/styles/theme.css +2137 -511
  33. package/src/widget/client.ts +51 -19
  34. package/src/widget/code.ts +218 -0
  35. package/src/widget/excerpt.ts +5 -0
  36. package/src/widget/search.ts +226 -0
  37. package/template/.astro/collections/docs.schema.json +3 -0
  38. package/template/.astro/content-assets.mjs +1 -4
  39. package/template/.astro/content-modules.mjs +35 -15
  40. package/template/.astro/data-store.json +1 -0
  41. package/template/.astro/settings.json +5 -0
  42. package/template/.build/.well-known/llms.txt +51 -34
  43. package/template/.build/404.html +16 -42
  44. package/template/.build/_astro/Assistant.astro_astro_type_script_index_0_lang.C1pz7yK1.js +4 -0
  45. package/template/.build/_astro/CodeGroup.astro_astro_type_script_index_0_lang.-eM8maAX.js +1 -0
  46. package/template/.build/_astro/Footer.astro_astro_type_script_index_0_lang.DzCnn3OT.js +1 -0
  47. package/template/.build/_astro/Search.astro_astro_type_script_index_0_lang.D7EcezBU.js +1 -0
  48. package/template/.build/_astro/code.smqv0zhe.js +9 -0
  49. package/template/.build/_astro/common.Dx3aBIS0.css +3 -0
  50. package/template/.build/_astro/{ec.8nqtp.css → ec.t9qpe.css} +1 -1
  51. package/template/.build/_astro/logo.BPu921Tp.svg +1 -0
  52. package/template/.build/_hgdc/corpus.json +1 -1
  53. package/template/.build/concepts/confidentialite/index.html +50 -0
  54. package/template/.build/concepts/confidentialite.md +38 -0
  55. package/template/.build/concepts/deploiements/index.html +106 -0
  56. package/template/.build/concepts/deploiements.md +70 -0
  57. package/template/.build/concepts/organisations-et-roles/index.html +83 -0
  58. package/template/.build/concepts/organisations-et-roles.md +39 -0
  59. package/template/.build/concepts/preversion/index.html +49 -0
  60. package/template/.build/concepts/preversion.md +52 -0
  61. package/template/.build/concepts/secrets-et-coffre/index.html +70 -0
  62. package/template/.build/concepts/secrets-et-coffre.md +54 -0
  63. package/template/.build/demarrer/depuis-github/index.html +34 -0
  64. package/template/.build/demarrer/depuis-github.md +68 -0
  65. package/template/.build/demarrer/premier-site/index.html +28 -0
  66. package/template/.build/demarrer/premier-site.md +94 -0
  67. package/template/.build/guides/brancher-un-domaine/index.html +91 -0
  68. package/template/.build/guides/brancher-un-domaine.md +81 -0
  69. package/template/.build/guides/cle-d-api/index.html +62 -0
  70. package/template/.build/guides/cle-d-api.md +78 -0
  71. package/template/.build/guides/depannage/index.html +64 -0
  72. package/template/.build/guides/depannage.md +69 -0
  73. package/template/.build/guides/deployer-depuis-github/index.html +45 -0
  74. package/template/.build/guides/deployer-depuis-github.md +70 -0
  75. package/template/.build/guides/deployer-un-framework/index.html +81 -0
  76. package/template/.build/guides/deployer-un-framework.md +74 -0
  77. package/template/.build/guides/github-actions-sans-application/index.html +53 -0
  78. package/template/.build/guides/github-actions-sans-application.md +95 -0
  79. package/template/.build/guides/inviter-une-personne/index.html +28 -0
  80. package/template/.build/guides/inviter-une-personne.md +38 -0
  81. package/template/.build/guides/lire-les-logs/index.html +37 -0
  82. package/template/.build/guides/lire-les-logs.md +48 -0
  83. package/template/.build/guides/migrer-depuis-vercel/index.html +25 -0
  84. package/template/.build/guides/migrer-depuis-vercel.md +51 -0
  85. package/template/.build/guides/monorepo/index.html +40 -0
  86. package/template/.build/guides/monorepo.md +42 -0
  87. package/template/.build/guides/revenir-en-arriere/index.html +39 -0
  88. package/template/.build/guides/revenir-en-arriere.md +50 -0
  89. package/template/.build/guides/site-statique/index.html +41 -0
  90. package/template/.build/guides/site-statique.md +59 -0
  91. package/template/.build/guides/synchroniser-doppler/index.html +46 -0
  92. package/template/.build/guides/synchroniser-doppler.md +63 -0
  93. package/template/.build/guides/variables-d-environnement/index.html +73 -0
  94. package/template/.build/guides/variables-d-environnement.md +92 -0
  95. package/template/.build/images/famille/account.svg +1 -0
  96. package/template/.build/images/famille/analytics.svg +1 -0
  97. package/template/.build/images/famille/docs.svg +1 -0
  98. package/template/.build/images/famille/host.svg +1 -0
  99. package/template/.build/images/famille/mail.svg +1 -0
  100. package/template/.build/images/famille/portal.svg +1 -0
  101. package/template/.build/images/famille/status.svg +1 -0
  102. package/template/.build/images/logo.svg +1 -0
  103. package/template/.build/index.html +30 -85
  104. package/template/.build/index.md +59 -21
  105. package/template/.build/llms-full.txt +2330 -514
  106. package/template/.build/llms.txt +51 -34
  107. package/template/.build/pagefind/fragment/fr-ch_16987e2.pf_fragment +0 -0
  108. package/template/.build/pagefind/fragment/fr-ch_2b4c97b.pf_fragment +0 -0
  109. package/template/.build/pagefind/fragment/fr-ch_3294a5c.pf_fragment +0 -0
  110. package/template/.build/pagefind/fragment/fr-ch_34858c9.pf_fragment +0 -0
  111. package/template/.build/pagefind/fragment/fr-ch_39ddba1.pf_fragment +0 -0
  112. package/template/.build/pagefind/fragment/fr-ch_4ab1899.pf_fragment +0 -0
  113. package/template/.build/pagefind/fragment/fr-ch_4d3a52a.pf_fragment +0 -0
  114. package/template/.build/pagefind/fragment/fr-ch_506c187.pf_fragment +0 -0
  115. package/template/.build/pagefind/fragment/fr-ch_5aa255a.pf_fragment +0 -0
  116. package/template/.build/pagefind/fragment/fr-ch_6841c7d.pf_fragment +0 -0
  117. package/template/.build/pagefind/fragment/fr-ch_6dc7a2d.pf_fragment +0 -0
  118. package/template/.build/pagefind/fragment/fr-ch_847edff.pf_fragment +0 -0
  119. package/template/.build/pagefind/fragment/fr-ch_8745af7.pf_fragment +0 -0
  120. package/template/.build/pagefind/fragment/fr-ch_8aac5e6.pf_fragment +0 -0
  121. package/template/.build/pagefind/fragment/fr-ch_916b233.pf_fragment +0 -0
  122. package/template/.build/pagefind/fragment/fr-ch_9fd014a.pf_fragment +0 -0
  123. package/template/.build/pagefind/fragment/fr-ch_a0808f8.pf_fragment +0 -0
  124. package/template/.build/pagefind/fragment/fr-ch_a4e1f69.pf_fragment +0 -0
  125. package/template/.build/pagefind/fragment/fr-ch_a80a53d.pf_fragment +0 -0
  126. package/template/.build/pagefind/fragment/fr-ch_a9e725b.pf_fragment +0 -0
  127. package/template/.build/pagefind/fragment/fr-ch_ac3f64c.pf_fragment +0 -0
  128. package/template/.build/pagefind/fragment/fr-ch_af292f1.pf_fragment +0 -0
  129. package/template/.build/pagefind/fragment/fr-ch_af3e716.pf_fragment +0 -0
  130. package/template/.build/pagefind/fragment/fr-ch_b0689a4.pf_fragment +0 -0
  131. package/template/.build/pagefind/fragment/fr-ch_baed996.pf_fragment +0 -0
  132. package/template/.build/pagefind/fragment/fr-ch_c89e27a.pf_fragment +0 -0
  133. package/template/.build/pagefind/fragment/fr-ch_cd6ca13.pf_fragment +0 -0
  134. package/template/.build/pagefind/fragment/fr-ch_d09af09.pf_fragment +0 -0
  135. package/template/.build/pagefind/fragment/fr-ch_d4bcea8.pf_fragment +0 -0
  136. package/template/.build/pagefind/fragment/fr-ch_dc2a134.pf_fragment +0 -0
  137. package/template/.build/pagefind/fragment/fr-ch_ded7ddc.pf_fragment +0 -0
  138. package/template/.build/pagefind/fragment/fr-ch_e2528cb.pf_fragment +0 -0
  139. package/template/.build/pagefind/fragment/fr-ch_e3cbb4e.pf_fragment +0 -0
  140. package/template/.build/pagefind/fragment/fr-ch_e7902d9.pf_fragment +0 -0
  141. package/template/.build/pagefind/fragment/fr-ch_f48ca47.pf_fragment +0 -0
  142. package/template/.build/pagefind/index/fr-ch_8a5f905.pf_index +0 -0
  143. package/template/.build/pagefind/index/fr-ch_fbd9c96.pf_index +0 -0
  144. package/template/.build/pagefind/pagefind-entry.json +1 -1
  145. package/template/.build/pagefind/pagefind.fr-ch_211aacbfa7f0e.pf_meta +0 -0
  146. package/template/.build/reference/api/deploiements/index.html +326 -0
  147. package/template/.build/reference/api/deploiements.md +170 -0
  148. package/template/.build/reference/api/erreurs/index.html +102 -0
  149. package/template/.build/reference/api/erreurs.md +50 -0
  150. package/template/.build/reference/api/fichiers/index.html +82 -0
  151. package/template/.build/reference/api/fichiers.md +62 -0
  152. package/template/.build/reference/api/introduction/index.html +126 -0
  153. package/template/.build/reference/api/introduction.md +84 -0
  154. package/template/.build/reference/api/projets/index.html +184 -0
  155. package/template/.build/reference/api/projets.md +102 -0
  156. package/template/.build/reference/api/utilisateur/index.html +96 -0
  157. package/template/.build/reference/api/utilisateur.md +89 -0
  158. package/template/.build/reference/api/variables/index.html +75 -0
  159. package/template/.build/reference/api/variables.md +58 -0
  160. package/template/.build/reference/cli/index.html +165 -82
  161. package/template/.build/reference/cli.md +159 -23
  162. package/template/.build/reference/compatibilite/index.html +196 -0
  163. package/template/.build/reference/compatibilite.md +64 -0
  164. package/template/.build/reference/domaines/index.html +171 -0
  165. package/template/.build/reference/domaines.md +76 -0
  166. package/template/.build/reference/limites/index.html +159 -0
  167. package/template/.build/reference/limites.md +56 -0
  168. package/template/.build/reference/variables/index.html +164 -0
  169. package/template/.build/reference/variables.md +63 -0
  170. package/template/.build/reference/vercel-json/index.html +65 -0
  171. package/template/.build/reference/vercel-json.md +51 -0
  172. package/template/node_modules/.vite/deps/_metadata.json +8 -8
  173. package/template/src/content.config.ts +8 -2
  174. package/src/overrides/SocialIcons.astro +0 -59
  175. package/template/.build/_astro/Assistant.astro_astro_type_script_index_0_lang.DWgmlr85.js +0 -4
  176. package/template/.build/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.C3fM4Kra.js +0 -1
  177. package/template/.build/_astro/Search.astro_astro_type_script_index_0_lang.g9hoxVJg.js +0 -1
  178. package/template/.build/_astro/TableOfContents.astro_astro_type_script_index_0_lang.BpJaGz7G.js +0 -1
  179. package/template/.build/_astro/common.CQYUsl_5.css +0 -3
  180. package/template/.build/_astro/logo-clair.BqNh6JNi.svg +0 -1
  181. package/template/.build/_astro/logo-sombre.BkgsFXxh.svg +0 -1
  182. package/template/.build/_astro/starlight-toc.D4UDIxQL.js +0 -1
  183. package/template/.build/_astro/ui-core.Clh5jUUO.js +0 -2
  184. package/template/.build/demarrer/premiere-doc/index.html +0 -84
  185. package/template/.build/demarrer/premiere-doc.md +0 -65
  186. package/template/.build/explications/donnees/index.html +0 -114
  187. package/template/.build/explications/donnees.md +0 -28
  188. package/template/.build/explications/fonctionnement/index.html +0 -92
  189. package/template/.build/explications/fonctionnement.md +0 -32
  190. package/template/.build/guides/agents/index.html +0 -118
  191. package/template/.build/guides/agents.md +0 -54
  192. package/template/.build/guides/assistant/index.html +0 -119
  193. package/template/.build/guides/assistant.md +0 -46
  194. package/template/.build/guides/composants/index.html +0 -97
  195. package/template/.build/guides/composants.md +0 -103
  196. package/template/.build/guides/ecrire/index.html +0 -115
  197. package/template/.build/guides/ecrire.md +0 -63
  198. package/template/.build/guides/elements/index.html +0 -1
  199. package/template/.build/guides/navigation/index.html +0 -89
  200. package/template/.build/guides/navigation.md +0 -63
  201. package/template/.build/guides/publier/index.html +0 -86
  202. package/template/.build/guides/publier.md +0 -65
  203. package/template/.build/guides/theme/index.html +0 -86
  204. package/template/.build/guides/theme.md +0 -33
  205. package/template/.build/images/favicon.svg +0 -1
  206. package/template/.build/images/logo-clair.svg +0 -1
  207. package/template/.build/images/logo-sombre.svg +0 -1
  208. package/template/.build/pagefind/fragment/fr-ch_148313b.pf_fragment +0 -0
  209. package/template/.build/pagefind/fragment/fr-ch_2a431a9.pf_fragment +0 -0
  210. package/template/.build/pagefind/fragment/fr-ch_35f556a.pf_fragment +0 -0
  211. package/template/.build/pagefind/fragment/fr-ch_456586a.pf_fragment +0 -0
  212. package/template/.build/pagefind/fragment/fr-ch_48ca71e.pf_fragment +0 -0
  213. package/template/.build/pagefind/fragment/fr-ch_4f8575c.pf_fragment +0 -0
  214. package/template/.build/pagefind/fragment/fr-ch_72b91f4.pf_fragment +0 -0
  215. package/template/.build/pagefind/fragment/fr-ch_8f256dd.pf_fragment +0 -0
  216. package/template/.build/pagefind/fragment/fr-ch_95a15cc.pf_fragment +0 -0
  217. package/template/.build/pagefind/fragment/fr-ch_aa80c55.pf_fragment +0 -0
  218. package/template/.build/pagefind/fragment/fr-ch_ab79738.pf_fragment +0 -0
  219. package/template/.build/pagefind/fragment/fr-ch_c589c2a.pf_fragment +0 -0
  220. package/template/.build/pagefind/fragment/fr-ch_dab8f5e.pf_fragment +0 -0
  221. package/template/.build/pagefind/fragment/fr-ch_de60b43.pf_fragment +0 -0
  222. package/template/.build/pagefind/fragment/fr-ch_e2c46e3.pf_fragment +0 -0
  223. package/template/.build/pagefind/index/fr-ch_c5ced52.pf_index +0 -0
  224. package/template/.build/pagefind/pagefind.fr-ch_8a246aa922758.pf_meta +0 -0
  225. package/template/.build/reference/api-assistant/index.html +0 -161
  226. package/template/.build/reference/api-assistant.md +0 -60
  227. package/template/.build/reference/docs-json/index.html +0 -216
  228. package/template/.build/reference/docs-json.md +0 -47
  229. package/template/.build/reference/mcp/index.html +0 -151
  230. package/template/.build/reference/mcp.md +0 -49
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hgdc/docs",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Modèle de site de HGDC Docs : documentation MDX (docs.json) construite avec Astro Starlight, recherche, versions, llms.txt et assistant.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -0,0 +1,82 @@
1
+ import type { Element, ElementContent, Root, RootContent } from "hast"
2
+
3
+ /**
4
+ * Mise en forme du contenu, au build.
5
+ *
6
+ * Titre d'endpoint (`## GET /v9/projects`) en barre de méthode : la méthode en pastille
7
+ * colorée, le chemin en police mono, ses paramètres (`:id`, `{id}`) soulignés. Le texte du
8
+ * titre ne change pas : l'ancre, la table des matières et la recherche restent les mêmes.
9
+ * Tableau : enveloppé dans `.hd-table`, qui défile en largeur sans déborder de la colonne.
10
+ */
11
+ const ENDPOINT = /^(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+(\/\S*)$/
12
+ const PARAM = /(:[A-Za-z_][\w]*|\{[^}/]+\})/
13
+
14
+ export function parseEndpoint(text: string): { method: string; path: string } | null {
15
+ const match = ENDPOINT.exec(text.trim())
16
+ return match ? { method: match[1]!, path: match[2]! } : null
17
+ }
18
+
19
+ function textOf(node: Element): string | null {
20
+ let text = ""
21
+ for (const child of node.children) {
22
+ if (child.type === "text") text += child.value
23
+ else if (child.type === "element" && child.tagName === "code") {
24
+ for (const inner of child.children) if (inner.type === "text") text += inner.value
25
+ } else return null
26
+ }
27
+ return text
28
+ }
29
+
30
+ function pathChildren(path: string): Array<ElementContent> {
31
+ return path
32
+ .split(PARAM)
33
+ .filter(Boolean)
34
+ .map((part) =>
35
+ PARAM.test(part)
36
+ ? {
37
+ type: "element",
38
+ tagName: "span",
39
+ properties: { className: ["hd-path__param"] },
40
+ children: [{ type: "text", value: part }],
41
+ }
42
+ : { type: "text", value: part },
43
+ )
44
+ }
45
+
46
+ export function rehypeDocsContent() {
47
+ const walk = (nodes: Array<RootContent | ElementContent>) => {
48
+ for (const [index, node] of nodes.entries()) {
49
+ if (node.type !== "element") continue
50
+ // Tableau : un cadre qui défile seul en largeur, le tableau garde toute la largeur.
51
+ if (node.tagName === "table") {
52
+ nodes[index] = { type: "element", tagName: "div", properties: { className: ["hd-table"] }, children: [node] }
53
+ continue
54
+ }
55
+ if (node.tagName !== "h2" && node.tagName !== "h3") {
56
+ walk(node.children)
57
+ continue
58
+ }
59
+ const text = textOf(node)
60
+ const endpoint = text ? parseEndpoint(text) : null
61
+ if (!endpoint) continue
62
+ node.properties.className = [...((node.properties.className as Array<string>) ?? []), "hd-endpoint"]
63
+ node.children = [
64
+ {
65
+ type: "element",
66
+ tagName: "span",
67
+ properties: { className: ["hd-method"], dataMethod: endpoint.method.toLowerCase() },
68
+ children: [{ type: "text", value: endpoint.method }],
69
+ },
70
+ { type: "text", value: " " },
71
+ {
72
+ type: "element",
73
+ tagName: "code",
74
+ properties: { className: ["hd-path"] },
75
+ children: pathChildren(endpoint.path),
76
+ },
77
+ ]
78
+ }
79
+ }
80
+ // Typé en `unknown` : Astro et ce paquet ne résolvent pas toujours le même @types/hast.
81
+ return (tree: unknown) => walk((tree as Root).children)
82
+ }
@@ -70,12 +70,17 @@ function replaceCodeBlocks(content: Element): void {
70
70
  }
71
71
  }
72
72
 
73
- /** Encadré → citation dont la première ligne porte le titre en gras : `> **Note**`. */
73
+ /**
74
+ * Encadré → citation dont la première ligne porte le titre en gras : `> **Note**`. Le titre
75
+ * est celui de la page, sinon le nom du type (`aria-label` de `.hd-callout`).
76
+ */
74
77
  function replaceAsides(content: Element): void {
75
- for (const aside of selectAll("aside.starlight-aside", content)) {
76
- const title = select(".starlight-aside__title", aside)
77
- const body = select(".starlight-aside__content", aside)
78
- const label = title ? toString(title as Parameters<typeof toString>[0]).trim() : ""
78
+ for (const aside of selectAll("aside.starlight-aside, aside.hd-callout", content)) {
79
+ const title = select(".starlight-aside__title, .hd-callout__title", aside)
80
+ const body = select(".starlight-aside__content, .hd-callout__body", aside)
81
+ if (body && title) body.children = body.children.filter((child) => child !== title)
82
+ const named = typeof aside.properties["ariaLabel"] === "string" ? aside.properties["ariaLabel"] : ""
83
+ const label = title ? toString(title as Parameters<typeof toString>[0]).trim() : named
79
84
  const quote: Element = {
80
85
  type: "element",
81
86
  tagName: "blockquote",
@@ -1,4 +1,6 @@
1
1
  ---
2
+ import Icon from "../overrides/Icon.astro"
3
+
2
4
  interface Props {
3
5
  title: string
4
6
  defaultOpen?: boolean
@@ -7,6 +9,6 @@ const { title, defaultOpen = false } = Astro.props
7
9
  ---
8
10
 
9
11
  <details class="hgdc-accordion" open={defaultOpen}>
10
- <summary>{title}</summary>
12
+ <summary><Icon name="chevron-right" size={16} class="hgdc-accordion__chevron" /><span>{title}</span></summary>
11
13
  <div class="hgdc-accordion__body"><slot /></div>
12
14
  </details>
@@ -0,0 +1,31 @@
1
+ ---
2
+ import Icon from "../overrides/Icon.astro"
3
+
4
+ /**
5
+ * Encadré commun à Note, Info, Tip, Check, Warning et Danger : un lavis de sa couleur, un
6
+ * filet de la même teinte et son icône. Le type est dit au lecteur d'écran.
7
+ */
8
+ export type CalloutTone = "note" | "info" | "tip" | "check" | "warning" | "danger"
9
+ interface Props {
10
+ tone: CalloutTone
11
+ title?: string | undefined
12
+ }
13
+ const LABELS: Record<CalloutTone, string> = {
14
+ note: "Note",
15
+ info: "Info",
16
+ tip: "Astuce",
17
+ check: "Validé",
18
+ warning: "Attention",
19
+ danger: "Danger",
20
+ }
21
+ const ICONS = { note: "note", info: "info", tip: "tip", check: "circle-check", warning: "warning", danger: "danger" } as const
22
+ const { tone, title } = Astro.props
23
+ ---
24
+
25
+ <aside class="hd-callout" data-tone={tone} aria-label={title ?? LABELS[tone]}>
26
+ <Icon name={ICONS[tone]} class="hd-callout__icon" />
27
+ <div class="hd-callout__body">
28
+ {title && <p class="hd-callout__title">{title}</p>}
29
+ <slot />
30
+ </div>
31
+ </aside>
@@ -1,4 +1,6 @@
1
1
  ---
2
+ import Icon from "../overrides/Icon.astro"
3
+
2
4
  interface Props {
3
5
  title: string
4
6
  href?: string
@@ -10,6 +12,6 @@ const Tag = href ? "a" : "div"
10
12
  ---
11
13
 
12
14
  <Tag class:list={["hgdc-card", { "hgdc-card--link": href }]} href={href}>
13
- <span class="hgdc-card__title">{title}</span>
15
+ <span class="hgdc-card__title">{title}{href && <Icon name="arrow-right" size={16} class="hgdc-card__arrow" />}</span>
14
16
  <div class="hgdc-card__body"><slot /></div>
15
17
  </Tag>
@@ -1,10 +1,9 @@
1
1
  ---
2
- import { Aside } from "@astrojs/starlight/components"
2
+ import Callout from "./Callout.astro"
3
3
 
4
4
  interface Props {
5
5
  title?: string
6
6
  }
7
- const { title } = Astro.props
8
7
  ---
9
8
 
10
- <Aside type="tip" title={title}><slot /></Aside>
9
+ <Callout tone="check" title={Astro.props.title}><slot /></Callout>
@@ -1,4 +1,12 @@
1
1
  ---
2
+ // Plusieurs blocs de code en onglets, nommés d'après le titre de chaque bloc (```bash npm).
3
+ // Sans JavaScript, seul le premier bloc s'affiche ; le script ajoute les onglets.
2
4
  ---
3
5
 
4
- <div class="hgdc-code-group"><slot /></div>
6
+ <hd-code-group class="hgdc-code-group not-content"><slot /></hd-code-group>
7
+
8
+ <script>
9
+ import { defineCodeGroup } from "../widget/code.ts"
10
+
11
+ defineCodeGroup()
12
+ </script>
@@ -1,10 +1,9 @@
1
1
  ---
2
- import { Aside } from "@astrojs/starlight/components"
2
+ import Callout from "./Callout.astro"
3
3
 
4
4
  interface Props {
5
5
  title?: string
6
6
  }
7
- const { title } = Astro.props
8
7
  ---
9
8
 
10
- <Aside type="danger" title={title}><slot /></Aside>
9
+ <Callout tone="danger" title={Astro.props.title}><slot /></Callout>
@@ -1,10 +1,9 @@
1
1
  ---
2
- import { Aside } from "@astrojs/starlight/components"
2
+ import Callout from "./Callout.astro"
3
3
 
4
4
  interface Props {
5
5
  title?: string
6
6
  }
7
- const { title = "Info" } = Astro.props
8
7
  ---
9
8
 
10
- <Aside type="note" title={title}><slot /></Aside>
9
+ <Callout tone="info" title={Astro.props.title}><slot /></Callout>
@@ -1,10 +1,9 @@
1
1
  ---
2
- import { Aside } from "@astrojs/starlight/components"
2
+ import Callout from "./Callout.astro"
3
3
 
4
4
  interface Props {
5
5
  title?: string
6
6
  }
7
- const { title } = Astro.props
8
7
  ---
9
8
 
10
- <Aside type="note" title={title}><slot /></Aside>
9
+ <Callout tone="note" title={Astro.props.title}><slot /></Callout>
@@ -1,10 +1,9 @@
1
1
  ---
2
- import { Aside } from "@astrojs/starlight/components"
2
+ import Callout from "./Callout.astro"
3
3
 
4
4
  interface Props {
5
5
  title?: string
6
6
  }
7
- const { title } = Astro.props
8
7
  ---
9
8
 
10
- <Aside type="tip" title={title}><slot /></Aside>
9
+ <Callout tone="tip" title={Astro.props.title}><slot /></Callout>
@@ -1,10 +1,9 @@
1
1
  ---
2
- import { Aside } from "@astrojs/starlight/components"
2
+ import Callout from "./Callout.astro"
3
3
 
4
4
  interface Props {
5
5
  title?: string
6
6
  }
7
- const { title } = Astro.props
8
7
  ---
9
8
 
10
- <Aside type="caution" title={title}><slot /></Aside>
9
+ <Callout tone="warning" title={Astro.props.title}><slot /></Callout>
@@ -5,13 +5,23 @@ import { z } from "zod"
5
5
  * et la console. Aucune donnée personnelle : la page, la réponse, un commentaire facultatif.
6
6
  */
7
7
  export const MAX_FEEDBACK_COMMENT = 1000
8
+ /** Code joint à un signalement « Signaler un code faux », tronqué par le site. */
9
+ export const MAX_FEEDBACK_CODE = 2000
8
10
 
9
- export const feedbackRequestSchema = z.object({
10
- project: z.string().regex(/^[a-z0-9]{8,64}$/),
11
- /** Chemin de la page, `base` compris (`/docs/guides/publier/`). */
12
- page: z.string().startsWith("/").max(512),
13
- helpful: z.boolean(),
14
- comment: z.string().trim().max(MAX_FEEDBACK_COMMENT).optional(),
15
- })
11
+ export const feedbackRequestSchema = z
12
+ .object({
13
+ project: z.string().regex(/^[a-z0-9]{8,64}$/),
14
+ /** Chemin de la page, `base` compris (`/docs/guides/publier/`). */
15
+ page: z.string().startsWith("/").max(512),
16
+ helpful: z.boolean(),
17
+ comment: z.string().trim().max(MAX_FEEDBACK_COMMENT).optional(),
18
+ /** `code` : « Signaler un code faux » sur un bloc de code ; absent, l'avis porte sur la page. */
19
+ kind: z.enum(["page", "code"]).optional(),
20
+ code: z.string().max(MAX_FEEDBACK_CODE).optional(),
21
+ })
22
+ .refine((value) => value.kind !== "code" || Boolean(value.comment), {
23
+ message: "un signalement de code dit ce qui ne va pas",
24
+ path: ["comment"],
25
+ })
16
26
 
17
27
  export type FeedbackRequest = z.infer<typeof feedbackRequestSchema>
package/src/core/theme.ts CHANGED
@@ -12,8 +12,10 @@ export type Theme = { light: AccentPalette; dark: AccentPalette }
12
12
  /** Accent violet de la DA HGDC (`--brand-accent` du kit), si le client n'en donne pas. */
13
13
  export const HGDC_ACCENT = "#7c3aed"
14
14
 
15
- const LIGHT_BG = "#ffffff"
16
- const DARK_BG = "#0f0f10"
15
+ /** Fonds sur lesquels l'accent doit tenir 4,5:1 : la surface la plus proche de lui (élément
16
+ * courant teinté, encart `muted`), un cran plus foncé ou plus clair que la page. */
17
+ const LIGHT_BG = "#f2f2f2"
18
+ const DARK_BG = "#2a2a2a"
17
19
 
18
20
  export function themeFor(primary: string = HGDC_ACCENT, dark?: string): Theme {
19
21
  const base = hexToOklch(primary)
@@ -48,7 +50,8 @@ export function withContrast(color: Oklch, background: string, ratio: number): s
48
50
  export function themeCss(theme: Theme): string {
49
51
  const vars = (p: AccentPalette) =>
50
52
  `--sl-color-accent-low:${p.low};--sl-color-accent:${p.accent};--sl-color-accent-high:${p.high};--hgdc-on-accent:${p.onAccent};`
51
- return `:root{${vars(theme.dark)}}:root[data-theme="light"]{${vars(theme.light)}}`
53
+ // Clair par défaut : le sombre ne vaut que choisi (`data-hd-theme`, overrides/ThemeProvider.astro).
54
+ return `:root{${vars(theme.dark)}}:root:not([data-hd-theme="dark"]){${vars(theme.light)}}`
52
55
  }
53
56
 
54
57
  // --- Conversions sRGB ↔ OKLCH (Björn Ottosson) et contraste WCAG 2 ---
@@ -8,6 +8,7 @@ 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
14
  import { parseDocsConfig, socialNetwork, withHostProject, type DocsConfig } from "./core/config.ts"
@@ -95,9 +96,12 @@ function collectPublic(contentDir: string, declared: ReadonlyArray<string>): str
95
96
  return target
96
97
  }
97
98
 
98
- /** Pages du dépôt (`guides/publier`) et leur `sidebarTitle` éventuel (champ Mintlify). */
99
- function scanPages(contentDir: string): Map<string, string | null> {
100
- const pages = new Map<string, string | null>()
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 label = /^sidebarTitle:\s*["']?(.+?)["']?\s*$/m.exec(frontmatter)?.[1] ?? null
112
- pages.set(pageToSlug(page), label)
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 = { slug: string; label?: string } | { label: string; collapsed: boolean; items: Array<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, string | null>): Array<SidebarItem> {
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 label = labels.get(slug)
128
- return label ? { slug, label } : { slug }
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) =>
@@ -242,8 +250,14 @@ export function createAstroConfig(options: SiteOptions = readSiteOptions()): Ast
242
250
  site: options.site ?? undefined,
243
251
  ...(base ? { base } : {}),
244
252
  trailingSlash: "always",
253
+ devToolbar: { enabled: false },
245
254
  redirects: astroRedirects(config.redirects ?? [], base),
246
- markdown: { processor: unified({ remarkPlugins: [remarkAutoImport, [remarkBaseLinks, { base }]] }) },
255
+ markdown: {
256
+ processor: unified({
257
+ remarkPlugins: [remarkAutoImport, [remarkBaseLinks, { base }]],
258
+ rehypePlugins: [rehypeDocsContent],
259
+ }),
260
+ },
247
261
  vite: {
248
262
  plugins: [virtualConfigPlugin(data)],
249
263
  server: { fs: { allow: [options.contentDir, file("..")] } },
@@ -264,13 +278,57 @@ export function createAstroConfig(options: SiteOptions = readSiteOptions()): Ast
264
278
  routeMiddleware: file("./overrides/route-data.ts"),
265
279
  components: {
266
280
  Head: file("./overrides/Head.astro"),
281
+ Header: file("./overrides/Header.astro"),
282
+ ThemeProvider: file("./overrides/ThemeProvider.astro"),
283
+ Search: file("./overrides/Search.astro"),
267
284
  Sidebar: file("./overrides/Sidebar.astro"),
268
285
  PageTitle: file("./overrides/PageTitle.astro"),
269
286
  PageFrame: file("./overrides/PageFrame.astro"),
270
- SocialIcons: file("./overrides/SocialIcons.astro"),
287
+ PageSidebar: file("./overrides/PageSidebar.astro"),
288
+ TwoColumnContent: file("./overrides/TwoColumnContent.astro"),
271
289
  Footer: file("./overrides/Footer.astro"),
272
290
  },
273
- expressiveCode: { themes: ["github-dark-default", "github-light-default"] },
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
+ },
331
+ },
274
332
  pagination: true,
275
333
  }),
276
334
  machineReadableOutputs(data, options),
@@ -1,39 +1,25 @@
1
1
  ---
2
2
  import data from "virtual:hgdc-docs/config"
3
3
 
4
- // Widget de l'assistant : panneau latéral non modal (la page reste lisible), plein écran
5
- // sur téléphone. Logique dans `../widget/client.ts`.
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
- <button type="button" class="hgdc-launcher" data-open aria-haspopup="dialog" aria-expanded="false">
11
- <svg aria-hidden="true" viewBox="0 0 24 24" width="18" height="18">
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
- <div>
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="hgdc-icon-button" data-reset aria-label="Nouvelle conversation" hidden>
27
- <svg aria-hidden="true" viewBox="0 0 24 24" width="18" height="18"
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="hgdc-icon-button" data-close aria-label="Fermer l'assistant">
33
- <svg aria-hidden="true" viewBox="0 0 24 24" width="18" height="18"
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="Comment publier ma doc ?" required
54
- ></textarea>
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 cette documentation.
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>