@hgdc/docs 0.2.0 → 0.3.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/core/components.ts +166 -0
- package/src/core/config.ts +42 -0
- package/src/core/feedback-api.ts +17 -0
- package/src/core/validate.ts +276 -0
- package/src/integration.ts +29 -15
- package/src/overrides/Footer.astro +154 -0
- package/src/overrides/Head.astro +14 -14
- package/src/overrides/PageTitle.astro +95 -95
- package/src/overrides/Sidebar.astro +60 -60
- package/src/overrides/SocialIcons.astro +59 -0
- package/template/.astro/content-assets.mjs +4 -1
- package/template/.astro/content-modules.mjs +15 -15
- package/template/.build/.well-known/llms.txt +15 -15
- package/template/.build/404.html +5 -5
- package/template/.build/_astro/Search.astro_astro_type_script_index_0_lang.g9hoxVJg.js +1 -0
- package/template/.build/_astro/common.CQYUsl_5.css +3 -0
- package/template/.build/_astro/{ui-core.CrG20ya_.js → ui-core.Clh5jUUO.js} +1 -1
- package/template/.build/_hgdc/corpus.json +1 -1
- package/template/.build/demarrer/premiere-doc/index.html +15 -15
- package/template/.build/demarrer/premiere-doc.md +3 -3
- package/template/.build/explications/donnees/index.html +10 -10
- package/template/.build/explications/fonctionnement/index.html +10 -11
- package/template/.build/guides/agents/index.html +11 -11
- package/template/.build/guides/agents.md +1 -1
- package/template/.build/guides/assistant/index.html +11 -11
- package/template/.build/guides/composants/index.html +19 -19
- package/template/.build/guides/composants.md +10 -8
- package/template/.build/guides/ecrire/index.html +12 -13
- package/template/.build/guides/elements/index.html +1 -0
- package/template/.build/guides/navigation/index.html +12 -13
- package/template/.build/guides/publier/index.html +14 -23
- package/template/.build/guides/publier.md +1 -1
- package/template/.build/guides/theme/index.html +12 -13
- package/template/.build/index.html +11 -12
- package/template/.build/index.md +9 -9
- package/template/.build/llms-full.txt +59 -63
- package/template/.build/llms.txt +15 -15
- package/template/.build/pagefind/fragment/fr-ch_148313b.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_35f556a.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_48ca71e.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_c589c2a.pf_fragment +0 -0
- package/template/.build/pagefind/index/fr-ch_c5ced52.pf_index +0 -0
- package/template/.build/pagefind/pagefind-entry.json +1 -1
- package/template/.build/pagefind/pagefind.fr-ch_8a246aa922758.pf_meta +0 -0
- package/template/.build/reference/api-assistant/index.html +12 -12
- package/template/.build/reference/api-assistant.md +2 -12
- package/template/.build/reference/cli/index.html +10 -10
- package/template/.build/reference/docs-json/index.html +35 -11
- package/template/.build/reference/docs-json.md +18 -14
- package/template/.build/reference/mcp/index.html +11 -11
- package/template/node_modules/.vite/deps/_metadata.json +8 -8
- package/template/.build/_astro/Search.astro_astro_type_script_index_0_lang.Cn3-p701.js +0 -1
- package/template/.build/_astro/common.C-MpX45O.css +0 -3
- package/template/.build/pagefind/fragment/fr-ch_68e734b.pf_fragment +0 -0
- package/template/.build/pagefind/fragment/fr-ch_cfa4336.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/index/fr-ch_a71411b.pf_index +0 -0
- package/template/.build/pagefind/pagefind.fr-ch_2f3ea8fccf961.pf_meta +0 -0
package/src/integration.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { remarkAutoImport } from "./build/auto-import.ts"
|
|
|
10
10
|
import { remarkBaseLinks } from "./build/base-links.ts"
|
|
11
11
|
import { publicFiles } from "./build/public-files.ts"
|
|
12
12
|
import { writeMachineReadable } from "./build/outputs.ts"
|
|
13
|
-
import { parseDocsConfig, withHostProject, type DocsConfig } from "./core/config.ts"
|
|
13
|
+
import { parseDocsConfig, socialNetwork, withHostProject, type DocsConfig } from "./core/config.ts"
|
|
14
14
|
import {
|
|
15
15
|
missingPages,
|
|
16
16
|
normalizeNavigation,
|
|
@@ -148,17 +148,27 @@ export function starlightSidebar(
|
|
|
148
148
|
)
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
"
|
|
160
|
-
|
|
161
|
-
|
|
151
|
+
/**
|
|
152
|
+
* `redirects` de docs.json en redirections d'Astro : une page qui renvoie à la nouvelle
|
|
153
|
+
* adresse (le site est statique). Chemins écrits comme les liens de la doc, `base` ajouté.
|
|
154
|
+
*/
|
|
155
|
+
export function astroRedirects(
|
|
156
|
+
redirects: ReadonlyArray<{ source: string; destination: string; permanent?: boolean | undefined }>,
|
|
157
|
+
base: string,
|
|
158
|
+
): Record<string, { status: 301 | 302; destination: string }> {
|
|
159
|
+
const slash = (path: string) => (path.endsWith("/") ? path : `${path}/`)
|
|
160
|
+
return Object.fromEntries(
|
|
161
|
+
redirects.map((item) => [
|
|
162
|
+
slash(item.source),
|
|
163
|
+
{
|
|
164
|
+
status: item.permanent === false ? 302 : 301,
|
|
165
|
+
destination: item.destination.startsWith("/")
|
|
166
|
+
? `${base}${slash(item.destination.split("#")[0]!)}${item.destination.includes("#") ? `#${item.destination.split("#")[1]}` : ""}`
|
|
167
|
+
: item.destination,
|
|
168
|
+
},
|
|
169
|
+
]),
|
|
170
|
+
)
|
|
171
|
+
}
|
|
162
172
|
|
|
163
173
|
function virtualConfigPlugin(data: VirtualConfig) {
|
|
164
174
|
const id = "virtual:hgdc-docs/config"
|
|
@@ -215,9 +225,10 @@ export function createAstroConfig(options: SiteOptions = readSiteOptions()): Ast
|
|
|
215
225
|
const theme = themeFor(config.colors?.primary, config.colors?.dark)
|
|
216
226
|
const logo = typeof config.logo === "string" ? { light: config.logo } : config.logo
|
|
217
227
|
const asset = (path: string) => join(options.contentDir, path.replace(/^\//, ""))
|
|
218
|
-
const social = Object.entries(config.footer?.socials ?? {})
|
|
219
|
-
|
|
220
|
-
|
|
228
|
+
const social = Object.entries(config.footer?.socials ?? {}).flatMap(([key, href]) => {
|
|
229
|
+
const network = socialNetwork(key)
|
|
230
|
+
return network ? [{ icon: network.icon as "github", label: network.label, href }] : []
|
|
231
|
+
})
|
|
221
232
|
|
|
222
233
|
return {
|
|
223
234
|
root: file("../template"),
|
|
@@ -231,6 +242,7 @@ export function createAstroConfig(options: SiteOptions = readSiteOptions()): Ast
|
|
|
231
242
|
site: options.site ?? undefined,
|
|
232
243
|
...(base ? { base } : {}),
|
|
233
244
|
trailingSlash: "always",
|
|
245
|
+
redirects: astroRedirects(config.redirects ?? [], base),
|
|
234
246
|
markdown: { processor: unified({ remarkPlugins: [remarkAutoImport, [remarkBaseLinks, { base }]] }) },
|
|
235
247
|
vite: {
|
|
236
248
|
plugins: [virtualConfigPlugin(data)],
|
|
@@ -255,6 +267,8 @@ export function createAstroConfig(options: SiteOptions = readSiteOptions()): Ast
|
|
|
255
267
|
Sidebar: file("./overrides/Sidebar.astro"),
|
|
256
268
|
PageTitle: file("./overrides/PageTitle.astro"),
|
|
257
269
|
PageFrame: file("./overrides/PageFrame.astro"),
|
|
270
|
+
SocialIcons: file("./overrides/SocialIcons.astro"),
|
|
271
|
+
Footer: file("./overrides/Footer.astro"),
|
|
258
272
|
},
|
|
259
273
|
expressiveCode: { themes: ["github-dark-default", "github-light-default"] },
|
|
260
274
|
pagination: true,
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Default from "@astrojs/starlight/components/Footer.astro"
|
|
3
|
+
import data from "virtual:hgdc-docs/config"
|
|
4
|
+
|
|
5
|
+
// « Cette page t'a aidé ? » au bas de chaque page, envoyé à la console (`/api/v1/feedback`).
|
|
6
|
+
// Sans projet relié, rien n'est affiché : il n'y a personne pour lire les réponses.
|
|
7
|
+
const endpoint = new URL("/api/v1/feedback", data.config.assistant?.endpoint ?? data.apiEndpoint).toString()
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
data.config.project && (
|
|
12
|
+
<hgdc-feedback class="hgdc-feedback not-content" data-endpoint={endpoint} data-project={data.config.project} data-pagefind-ignore>
|
|
13
|
+
<div data-step="ask">
|
|
14
|
+
<p class="hgdc-feedback__question">Cette page t'a aidé ?</p>
|
|
15
|
+
<div class="hgdc-feedback__choices">
|
|
16
|
+
<button type="button" data-helpful="true">Oui</button>
|
|
17
|
+
<button type="button" data-helpful="false">Non</button>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<form data-step="comment" hidden>
|
|
21
|
+
<label for="hgdc-feedback-comment">Qu'est-ce qui manquait ou pourrait être plus clair ? (facultatif)</label>
|
|
22
|
+
<textarea id="hgdc-feedback-comment" name="comment" rows="3" maxlength="1000"></textarea>
|
|
23
|
+
<div class="hgdc-feedback__choices">
|
|
24
|
+
<button type="submit">Envoyer</button>
|
|
25
|
+
<button type="button" data-skip>Passer</button>
|
|
26
|
+
</div>
|
|
27
|
+
</form>
|
|
28
|
+
<p data-step="done" class="hgdc-feedback__done" role="status" hidden>Merci, c'est noté.</p>
|
|
29
|
+
</hgdc-feedback>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
<Default />
|
|
33
|
+
|
|
34
|
+
<script>
|
|
35
|
+
class HgdcFeedback extends HTMLElement {
|
|
36
|
+
#helpful: boolean | null = null
|
|
37
|
+
|
|
38
|
+
connectedCallback() {
|
|
39
|
+
for (const button of this.querySelectorAll<HTMLButtonElement>("[data-helpful]"))
|
|
40
|
+
button.addEventListener("click", () => this.#choose(button.dataset.helpful === "true"))
|
|
41
|
+
const form = this.querySelector("form")!
|
|
42
|
+
form.addEventListener("submit", (event) => {
|
|
43
|
+
event.preventDefault()
|
|
44
|
+
const comment = new FormData(form).get("comment")
|
|
45
|
+
void this.#send(typeof comment === "string" ? comment.trim() : "")
|
|
46
|
+
})
|
|
47
|
+
this.querySelector("[data-skip]")?.addEventListener("click", () => void this.#send(""))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#show(step: "ask" | "comment" | "done") {
|
|
51
|
+
for (const element of this.querySelectorAll<HTMLElement>("[data-step]")) element.hidden = element.dataset.step !== step
|
|
52
|
+
if (step === "comment") this.querySelector("textarea")?.focus()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#choose(helpful: boolean) {
|
|
56
|
+
this.#helpful = helpful
|
|
57
|
+
// Un oui part tout de suite ; un non attend le commentaire (ou « Passer ») : un seul envoi par avis.
|
|
58
|
+
if (helpful) void this.#send("")
|
|
59
|
+
else this.#show("comment")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async #send(comment: string) {
|
|
63
|
+
if (this.#helpful === null) return
|
|
64
|
+
try {
|
|
65
|
+
await fetch(this.dataset.endpoint!, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: { "content-type": "application/json" },
|
|
68
|
+
body: JSON.stringify({
|
|
69
|
+
project: this.dataset.project,
|
|
70
|
+
page: location.pathname,
|
|
71
|
+
helpful: this.#helpful,
|
|
72
|
+
...(comment ? { comment } : {}),
|
|
73
|
+
}),
|
|
74
|
+
keepalive: true,
|
|
75
|
+
})
|
|
76
|
+
} catch {
|
|
77
|
+
// Un retour perdu ne gêne pas la lecture : rien à afficher.
|
|
78
|
+
}
|
|
79
|
+
this.#show("done")
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
customElements.define("hgdc-feedback", HgdcFeedback)
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<style>
|
|
86
|
+
.hgdc-feedback {
|
|
87
|
+
display: block;
|
|
88
|
+
margin-block: 2.5rem 1.5rem;
|
|
89
|
+
padding: 1rem 1.25rem;
|
|
90
|
+
border-radius: 1rem;
|
|
91
|
+
background: var(--sl-color-gray-6);
|
|
92
|
+
}
|
|
93
|
+
.hgdc-feedback__question,
|
|
94
|
+
.hgdc-feedback label {
|
|
95
|
+
margin: 0 0 0.6rem;
|
|
96
|
+
font-size: var(--sl-text-sm);
|
|
97
|
+
font-weight: 500;
|
|
98
|
+
color: var(--sl-color-white);
|
|
99
|
+
}
|
|
100
|
+
.hgdc-feedback [data-step="ask"] {
|
|
101
|
+
display: flex;
|
|
102
|
+
flex-wrap: wrap;
|
|
103
|
+
align-items: center;
|
|
104
|
+
justify-content: space-between;
|
|
105
|
+
gap: 0.75rem;
|
|
106
|
+
}
|
|
107
|
+
.hgdc-feedback [data-step="ask"] .hgdc-feedback__question {
|
|
108
|
+
margin: 0;
|
|
109
|
+
}
|
|
110
|
+
.hgdc-feedback [hidden] {
|
|
111
|
+
display: none !important;
|
|
112
|
+
}
|
|
113
|
+
.hgdc-feedback__choices {
|
|
114
|
+
display: flex;
|
|
115
|
+
gap: 0.5rem;
|
|
116
|
+
}
|
|
117
|
+
.hgdc-feedback button {
|
|
118
|
+
border: 1px solid var(--sl-color-gray-5);
|
|
119
|
+
background: var(--sl-color-black);
|
|
120
|
+
color: var(--sl-color-white);
|
|
121
|
+
border-radius: 999px;
|
|
122
|
+
padding: 0.35rem 1rem;
|
|
123
|
+
font: inherit;
|
|
124
|
+
font-size: var(--sl-text-sm);
|
|
125
|
+
cursor: pointer;
|
|
126
|
+
}
|
|
127
|
+
.hgdc-feedback button:hover {
|
|
128
|
+
border-color: var(--sl-color-accent);
|
|
129
|
+
}
|
|
130
|
+
.hgdc-feedback button[type="submit"] {
|
|
131
|
+
background: var(--sl-color-accent);
|
|
132
|
+
border-color: var(--sl-color-accent);
|
|
133
|
+
color: var(--hgdc-on-accent, #fff);
|
|
134
|
+
}
|
|
135
|
+
.hgdc-feedback form {
|
|
136
|
+
display: grid;
|
|
137
|
+
gap: 0.6rem;
|
|
138
|
+
}
|
|
139
|
+
.hgdc-feedback textarea {
|
|
140
|
+
width: 100%;
|
|
141
|
+
border-radius: 0.75rem;
|
|
142
|
+
border: 1px solid var(--sl-color-gray-5);
|
|
143
|
+
background: var(--sl-color-black);
|
|
144
|
+
color: var(--sl-color-white);
|
|
145
|
+
padding: 0.5rem 0.75rem;
|
|
146
|
+
font: inherit;
|
|
147
|
+
font-size: var(--sl-text-sm);
|
|
148
|
+
}
|
|
149
|
+
.hgdc-feedback__done {
|
|
150
|
+
margin: 0;
|
|
151
|
+
font-size: var(--sl-text-sm);
|
|
152
|
+
color: var(--sl-color-gray-2);
|
|
153
|
+
}
|
|
154
|
+
</style>
|
package/src/overrides/Head.astro
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
---
|
|
2
|
-
import Default from "@astrojs/starlight/components/Head.astro"
|
|
3
|
-
import data from "virtual:hgdc-docs/config"
|
|
4
|
-
|
|
5
|
-
import { markdownPath } from "../core/llms.ts"
|
|
6
|
-
import { withBase, withoutBase } from "../core/navigation.ts"
|
|
7
|
-
|
|
8
|
-
// llmstxt.org : chaque page annonce sa version Markdown et l'index qui la décrit.
|
|
9
|
-
const markdown = withBase(data.base, markdownPath(withoutBase(data.base, Astro.url.pathname)))
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<Default><slot /></Default>
|
|
13
|
-
<link rel="alternate" type="text/markdown" href={markdown} />
|
|
14
|
-
<link rel="describedby" type="text/markdown" href={withBase(data.base, "/llms.txt")} />
|
|
1
|
+
---
|
|
2
|
+
import Default from "@astrojs/starlight/components/Head.astro"
|
|
3
|
+
import data from "virtual:hgdc-docs/config"
|
|
4
|
+
|
|
5
|
+
import { markdownPath } from "../core/llms.ts"
|
|
6
|
+
import { withBase, withoutBase } from "../core/navigation.ts"
|
|
7
|
+
|
|
8
|
+
// llmstxt.org : chaque page annonce sa version Markdown et l'index qui la décrit.
|
|
9
|
+
const markdown = withBase(data.base, markdownPath(withoutBase(data.base, Astro.url.pathname)))
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<Default><slot /></Default>
|
|
13
|
+
<link rel="alternate" type="text/markdown" href={markdown} />
|
|
14
|
+
<link rel="describedby" type="text/markdown" href={withBase(data.base, "/llms.txt")} />
|
|
@@ -1,95 +1,95 @@
|
|
|
1
|
-
---
|
|
2
|
-
import Default from "@astrojs/starlight/components/PageTitle.astro"
|
|
3
|
-
import data from "virtual:hgdc-docs/config"
|
|
4
|
-
|
|
5
|
-
import { markdownPath } from "../core/llms.ts"
|
|
6
|
-
import { withBase, withoutBase } from "../core/navigation.ts"
|
|
7
|
-
|
|
8
|
-
const markdown = withBase(data.base, markdownPath(withoutBase(data.base, Astro.url.pathname)))
|
|
9
|
-
const assistant = Boolean(data.config.project) && data.config.assistant?.enabled !== false
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<div class="hgdc-title">
|
|
13
|
-
<Default><slot /></Default>
|
|
14
|
-
<div class="hgdc-page-actions not-content" data-hgdc-skip data-pagefind-ignore>
|
|
15
|
-
<button type="button" class="hgdc-action" data-hgdc-copy={markdown}>
|
|
16
|
-
<svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16"
|
|
17
|
-
><rect x="8" y="8" width="12" height="12" rx="3" fill="none" stroke="currentColor" stroke-width="1.8"
|
|
18
|
-
></rect><path d="M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2" fill="none" stroke="currentColor" stroke-width="1.8"
|
|
19
|
-
></path></svg
|
|
20
|
-
>
|
|
21
|
-
<span data-label>Copier pour un LLM</span>
|
|
22
|
-
</button>
|
|
23
|
-
<details class="hgdc-menu">
|
|
24
|
-
<summary class="hgdc-action hgdc-action--icon" aria-label="Autres formats de la page">
|
|
25
|
-
<svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16"
|
|
26
|
-
><path d="m6 9 6 6 6-6" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"></path></svg
|
|
27
|
-
>
|
|
28
|
-
</summary>
|
|
29
|
-
<ul class="hgdc-menu__list">
|
|
30
|
-
<li><a href={markdown}>Voir en Markdown</a></li>
|
|
31
|
-
<li><a data-hgdc-open="claude" href="https://claude.ai/new" target="_blank" rel="noopener">Ouvrir dans Claude</a></li>
|
|
32
|
-
<li><a data-hgdc-open="chatgpt" href="https://chatgpt.com/" target="_blank" rel="noopener">Ouvrir dans ChatGPT</a></li>
|
|
33
|
-
<li><a href={withBase(data.base, "/llms.txt")}>Index pour les agents (llms.txt)</a></li>
|
|
34
|
-
</ul>
|
|
35
|
-
</details>
|
|
36
|
-
{
|
|
37
|
-
assistant && (
|
|
38
|
-
<button type="button" class="hgdc-action" data-hgdc-ask>
|
|
39
|
-
<svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16">
|
|
40
|
-
<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" />
|
|
41
|
-
</svg>
|
|
42
|
-
<span>Demander à l'assistant</span>
|
|
43
|
-
</button>
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
<span class="sr-only" role="status" aria-live="polite" data-hgdc-copy-status></span>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
<script>
|
|
51
|
-
const status = document.querySelector<HTMLElement>("[data-hgdc-copy-status]")
|
|
52
|
-
|
|
53
|
-
for (const button of document.querySelectorAll<HTMLButtonElement>("[data-hgdc-copy]")) {
|
|
54
|
-
const label = button.querySelector<HTMLElement>("[data-label]")!
|
|
55
|
-
button.addEventListener("click", async () => {
|
|
56
|
-
const done = (text: string) => {
|
|
57
|
-
label.textContent = text
|
|
58
|
-
if (status) status.textContent = text
|
|
59
|
-
setTimeout(() => (label.textContent = "Copier pour un LLM"), 2000)
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
const response = await fetch(button.dataset.hgdcCopy!)
|
|
63
|
-
if (!response.ok) throw new Error(String(response.status))
|
|
64
|
-
await navigator.clipboard.writeText(await response.text())
|
|
65
|
-
done("Page copiée")
|
|
66
|
-
} catch {
|
|
67
|
-
done("Copie impossible")
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// « Ouvrir dans… » : l'assistant externe lit la version Markdown de cette page.
|
|
73
|
-
const markdownUrl = new URL(document.querySelector<HTMLElement>("[data-hgdc-copy]")!.dataset.hgdcCopy!, location.href)
|
|
74
|
-
const prompt = `Lis ${markdownUrl.href} et réponds à mes questions sur cette page.`
|
|
75
|
-
for (const link of document.querySelectorAll<HTMLAnchorElement>("[data-hgdc-open]")) {
|
|
76
|
-
const base = link.dataset.hgdcOpen === "claude" ? "https://claude.ai/new" : "https://chatgpt.com/"
|
|
77
|
-
link.href = `${base}?q=${encodeURIComponent(prompt)}`
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Le menu se ferme au clic extérieur et à Échap, comme un menu natif.
|
|
81
|
-
for (const menu of document.querySelectorAll<HTMLDetailsElement>(".hgdc-menu")) {
|
|
82
|
-
document.addEventListener("click", (event) => {
|
|
83
|
-
if (menu.open && !menu.contains(event.target as Node)) menu.open = false
|
|
84
|
-
})
|
|
85
|
-
menu.addEventListener("keydown", (event) => {
|
|
86
|
-
if (event.key === "Escape" && menu.open) {
|
|
87
|
-
menu.open = false
|
|
88
|
-
menu.querySelector("summary")?.focus()
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
for (const button of document.querySelectorAll("[data-hgdc-ask]"))
|
|
94
|
-
button.addEventListener("click", () => document.dispatchEvent(new CustomEvent("hgdc:assistant-open")))
|
|
95
|
-
</script>
|
|
1
|
+
---
|
|
2
|
+
import Default from "@astrojs/starlight/components/PageTitle.astro"
|
|
3
|
+
import data from "virtual:hgdc-docs/config"
|
|
4
|
+
|
|
5
|
+
import { markdownPath } from "../core/llms.ts"
|
|
6
|
+
import { withBase, withoutBase } from "../core/navigation.ts"
|
|
7
|
+
|
|
8
|
+
const markdown = withBase(data.base, markdownPath(withoutBase(data.base, Astro.url.pathname)))
|
|
9
|
+
const assistant = Boolean(data.config.project) && data.config.assistant?.enabled !== false
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<div class="hgdc-title">
|
|
13
|
+
<Default><slot /></Default>
|
|
14
|
+
<div class="hgdc-page-actions not-content" data-hgdc-skip data-pagefind-ignore>
|
|
15
|
+
<button type="button" class="hgdc-action" data-hgdc-copy={markdown}>
|
|
16
|
+
<svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16"
|
|
17
|
+
><rect x="8" y="8" width="12" height="12" rx="3" fill="none" stroke="currentColor" stroke-width="1.8"
|
|
18
|
+
></rect><path d="M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2" fill="none" stroke="currentColor" stroke-width="1.8"
|
|
19
|
+
></path></svg
|
|
20
|
+
>
|
|
21
|
+
<span data-label>Copier pour un LLM</span>
|
|
22
|
+
</button>
|
|
23
|
+
<details class="hgdc-menu">
|
|
24
|
+
<summary class="hgdc-action hgdc-action--icon" aria-label="Autres formats de la page">
|
|
25
|
+
<svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16"
|
|
26
|
+
><path d="m6 9 6 6 6-6" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"></path></svg
|
|
27
|
+
>
|
|
28
|
+
</summary>
|
|
29
|
+
<ul class="hgdc-menu__list">
|
|
30
|
+
<li><a href={markdown}>Voir en Markdown</a></li>
|
|
31
|
+
<li><a data-hgdc-open="claude" href="https://claude.ai/new" target="_blank" rel="noopener">Ouvrir dans Claude</a></li>
|
|
32
|
+
<li><a data-hgdc-open="chatgpt" href="https://chatgpt.com/" target="_blank" rel="noopener">Ouvrir dans ChatGPT</a></li>
|
|
33
|
+
<li><a href={withBase(data.base, "/llms.txt")}>Index pour les agents (llms.txt)</a></li>
|
|
34
|
+
</ul>
|
|
35
|
+
</details>
|
|
36
|
+
{
|
|
37
|
+
assistant && (
|
|
38
|
+
<button type="button" class="hgdc-action" data-hgdc-ask>
|
|
39
|
+
<svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16">
|
|
40
|
+
<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" />
|
|
41
|
+
</svg>
|
|
42
|
+
<span>Demander à l'assistant</span>
|
|
43
|
+
</button>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
<span class="sr-only" role="status" aria-live="polite" data-hgdc-copy-status></span>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<script>
|
|
51
|
+
const status = document.querySelector<HTMLElement>("[data-hgdc-copy-status]")
|
|
52
|
+
|
|
53
|
+
for (const button of document.querySelectorAll<HTMLButtonElement>("[data-hgdc-copy]")) {
|
|
54
|
+
const label = button.querySelector<HTMLElement>("[data-label]")!
|
|
55
|
+
button.addEventListener("click", async () => {
|
|
56
|
+
const done = (text: string) => {
|
|
57
|
+
label.textContent = text
|
|
58
|
+
if (status) status.textContent = text
|
|
59
|
+
setTimeout(() => (label.textContent = "Copier pour un LLM"), 2000)
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const response = await fetch(button.dataset.hgdcCopy!)
|
|
63
|
+
if (!response.ok) throw new Error(String(response.status))
|
|
64
|
+
await navigator.clipboard.writeText(await response.text())
|
|
65
|
+
done("Page copiée")
|
|
66
|
+
} catch {
|
|
67
|
+
done("Copie impossible")
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// « Ouvrir dans… » : l'assistant externe lit la version Markdown de cette page.
|
|
73
|
+
const markdownUrl = new URL(document.querySelector<HTMLElement>("[data-hgdc-copy]")!.dataset.hgdcCopy!, location.href)
|
|
74
|
+
const prompt = `Lis ${markdownUrl.href} et réponds à mes questions sur cette page.`
|
|
75
|
+
for (const link of document.querySelectorAll<HTMLAnchorElement>("[data-hgdc-open]")) {
|
|
76
|
+
const base = link.dataset.hgdcOpen === "claude" ? "https://claude.ai/new" : "https://chatgpt.com/"
|
|
77
|
+
link.href = `${base}?q=${encodeURIComponent(prompt)}`
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Le menu se ferme au clic extérieur et à Échap, comme un menu natif.
|
|
81
|
+
for (const menu of document.querySelectorAll<HTMLDetailsElement>(".hgdc-menu")) {
|
|
82
|
+
document.addEventListener("click", (event) => {
|
|
83
|
+
if (menu.open && !menu.contains(event.target as Node)) menu.open = false
|
|
84
|
+
})
|
|
85
|
+
menu.addEventListener("keydown", (event) => {
|
|
86
|
+
if (event.key === "Escape" && menu.open) {
|
|
87
|
+
menu.open = false
|
|
88
|
+
menu.querySelector("summary")?.focus()
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
for (const button of document.querySelectorAll("[data-hgdc-ask]"))
|
|
94
|
+
button.addEventListener("click", () => document.dispatchEvent(new CustomEvent("hgdc:assistant-open")))
|
|
95
|
+
</script>
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
---
|
|
2
|
-
import Default from "@astrojs/starlight/components/Sidebar.astro"
|
|
3
|
-
import data from "virtual:hgdc-docs/config"
|
|
4
|
-
|
|
5
|
-
import { pagesOf, pageToPath, withBase } from "../core/navigation.ts"
|
|
6
|
-
|
|
7
|
-
// Onglets et versions de docs.json, en tête de la sidebar : visibles sur ordinateur et dans
|
|
8
|
-
// le menu mobile, sans toucher à la hauteur de l'en-tête de Starlight.
|
|
9
|
-
const sections = data.tree.versions.flatMap((version) => version.tabs.map((tab) => ({ version, tab })))
|
|
10
|
-
const index = Astro.locals.hgdcSection ?? 0
|
|
11
|
-
const current = sections[index] ?? sections[0]!
|
|
12
|
-
const firstPath = (items: Parameters<typeof pagesOf>[0]) => {
|
|
13
|
-
const first = pagesOf(items)[0]
|
|
14
|
-
return withBase(data.base, first ? pageToPath(first) : "/")
|
|
15
|
-
}
|
|
16
|
-
const tabs = current.version.tabs.filter((tab) => tab.label)
|
|
17
|
-
const versions = data.tree.versions.filter((version) => version.label)
|
|
18
|
-
const tabPosition = current.version.tabs.indexOf(current.tab)
|
|
19
|
-
const versionHref = (version: (typeof versions)[number]) =>
|
|
20
|
-
firstPath((version.tabs[tabPosition] ?? version.tabs[0]!).items)
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
{
|
|
24
|
-
(tabs.length > 1 || versions.length > 1) && (
|
|
25
|
-
<div class="hgdc-sections">
|
|
26
|
-
{versions.length > 1 && (
|
|
27
|
-
<label class="hgdc-version">
|
|
28
|
-
<span class="sr-only">Version de la documentation</span>
|
|
29
|
-
<select data-hgdc-version>
|
|
30
|
-
{versions.map((version) => (
|
|
31
|
-
<option value={versionHref(version)} selected={version === current.version}>
|
|
32
|
-
{version.label}
|
|
33
|
-
{version.isDefault ? " (actuelle)" : ""}
|
|
34
|
-
</option>
|
|
35
|
-
))}
|
|
36
|
-
</select>
|
|
37
|
-
</label>
|
|
38
|
-
)}
|
|
39
|
-
{tabs.length > 1 && (
|
|
40
|
-
<nav aria-label="Sections de la documentation">
|
|
41
|
-
<ul class="hgdc-tabs">
|
|
42
|
-
{tabs.map((tab) => (
|
|
43
|
-
<li>
|
|
44
|
-
<a href={firstPath(tab.items)} aria-current={tab === current.tab ? "page" : undefined}>
|
|
45
|
-
{tab.label}
|
|
46
|
-
</a>
|
|
47
|
-
</li>
|
|
48
|
-
))}
|
|
49
|
-
</ul>
|
|
50
|
-
</nav>
|
|
51
|
-
)}
|
|
52
|
-
</div>
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
<Default><slot /></Default>
|
|
56
|
-
|
|
57
|
-
<script>
|
|
58
|
-
for (const select of document.querySelectorAll<HTMLSelectElement>("[data-hgdc-version]"))
|
|
59
|
-
select.addEventListener("change", () => window.location.assign(select.value))
|
|
60
|
-
</script>
|
|
1
|
+
---
|
|
2
|
+
import Default from "@astrojs/starlight/components/Sidebar.astro"
|
|
3
|
+
import data from "virtual:hgdc-docs/config"
|
|
4
|
+
|
|
5
|
+
import { pagesOf, pageToPath, withBase } from "../core/navigation.ts"
|
|
6
|
+
|
|
7
|
+
// Onglets et versions de docs.json, en tête de la sidebar : visibles sur ordinateur et dans
|
|
8
|
+
// le menu mobile, sans toucher à la hauteur de l'en-tête de Starlight.
|
|
9
|
+
const sections = data.tree.versions.flatMap((version) => version.tabs.map((tab) => ({ version, tab })))
|
|
10
|
+
const index = Astro.locals.hgdcSection ?? 0
|
|
11
|
+
const current = sections[index] ?? sections[0]!
|
|
12
|
+
const firstPath = (items: Parameters<typeof pagesOf>[0]) => {
|
|
13
|
+
const first = pagesOf(items)[0]
|
|
14
|
+
return withBase(data.base, first ? pageToPath(first) : "/")
|
|
15
|
+
}
|
|
16
|
+
const tabs = current.version.tabs.filter((tab) => tab.label)
|
|
17
|
+
const versions = data.tree.versions.filter((version) => version.label)
|
|
18
|
+
const tabPosition = current.version.tabs.indexOf(current.tab)
|
|
19
|
+
const versionHref = (version: (typeof versions)[number]) =>
|
|
20
|
+
firstPath((version.tabs[tabPosition] ?? version.tabs[0]!).items)
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
{
|
|
24
|
+
(tabs.length > 1 || versions.length > 1) && (
|
|
25
|
+
<div class="hgdc-sections">
|
|
26
|
+
{versions.length > 1 && (
|
|
27
|
+
<label class="hgdc-version">
|
|
28
|
+
<span class="sr-only">Version de la documentation</span>
|
|
29
|
+
<select data-hgdc-version>
|
|
30
|
+
{versions.map((version) => (
|
|
31
|
+
<option value={versionHref(version)} selected={version === current.version}>
|
|
32
|
+
{version.label}
|
|
33
|
+
{version.isDefault ? " (actuelle)" : ""}
|
|
34
|
+
</option>
|
|
35
|
+
))}
|
|
36
|
+
</select>
|
|
37
|
+
</label>
|
|
38
|
+
)}
|
|
39
|
+
{tabs.length > 1 && (
|
|
40
|
+
<nav aria-label="Sections de la documentation">
|
|
41
|
+
<ul class="hgdc-tabs">
|
|
42
|
+
{tabs.map((tab) => (
|
|
43
|
+
<li>
|
|
44
|
+
<a href={firstPath(tab.items)} aria-current={tab === current.tab ? "page" : undefined}>
|
|
45
|
+
{tab.label}
|
|
46
|
+
</a>
|
|
47
|
+
</li>
|
|
48
|
+
))}
|
|
49
|
+
</ul>
|
|
50
|
+
</nav>
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
<Default><slot /></Default>
|
|
56
|
+
|
|
57
|
+
<script>
|
|
58
|
+
for (const select of document.querySelectorAll<HTMLSelectElement>("[data-hgdc-version]"))
|
|
59
|
+
select.addEventListener("change", () => window.location.assign(select.value))
|
|
60
|
+
</script>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Default from "@astrojs/starlight/components/SocialIcons.astro"
|
|
3
|
+
import data from "virtual:hgdc-docs/config"
|
|
4
|
+
|
|
5
|
+
/** Barre du haut : liens de `navbar.links`, bouton `navbar.primary`, puis les réseaux. */
|
|
6
|
+
const links = data.config.navbar?.links ?? []
|
|
7
|
+
const primary = data.config.navbar?.primary
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
(links.length > 0 || primary) && (
|
|
12
|
+
<nav class="hgdc-navbar" aria-label="Liens">
|
|
13
|
+
{links.map((link) => (
|
|
14
|
+
<a class="hgdc-navbar__link" href={link.href}>
|
|
15
|
+
{link.label}
|
|
16
|
+
</a>
|
|
17
|
+
))}
|
|
18
|
+
{primary && (
|
|
19
|
+
<a class="hgdc-navbar__primary" href={primary.href}>
|
|
20
|
+
{primary.label}
|
|
21
|
+
</a>
|
|
22
|
+
)}
|
|
23
|
+
</nav>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
<Default />
|
|
27
|
+
|
|
28
|
+
<style>
|
|
29
|
+
.hgdc-navbar {
|
|
30
|
+
display: none;
|
|
31
|
+
align-items: center;
|
|
32
|
+
gap: 1rem;
|
|
33
|
+
margin-inline-end: 0.5rem;
|
|
34
|
+
}
|
|
35
|
+
@media (min-width: 72rem) {
|
|
36
|
+
.hgdc-navbar {
|
|
37
|
+
display: flex;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
.hgdc-navbar__link {
|
|
41
|
+
color: var(--sl-color-gray-2);
|
|
42
|
+
font-size: var(--sl-text-sm);
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
white-space: nowrap;
|
|
45
|
+
}
|
|
46
|
+
.hgdc-navbar__link:hover {
|
|
47
|
+
color: var(--sl-color-white);
|
|
48
|
+
}
|
|
49
|
+
.hgdc-navbar__primary {
|
|
50
|
+
background: var(--sl-color-accent);
|
|
51
|
+
color: var(--hgdc-on-accent, #fff);
|
|
52
|
+
border-radius: 999px;
|
|
53
|
+
padding: 0.35rem 0.9rem;
|
|
54
|
+
font-size: var(--sl-text-sm);
|
|
55
|
+
font-weight: 500;
|
|
56
|
+
text-decoration: none;
|
|
57
|
+
white-space: nowrap;
|
|
58
|
+
}
|
|
59
|
+
</style>
|