starlight-cannoli-plugins 2.17.1 → 2.17.2

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/README.md CHANGED
@@ -364,11 +364,15 @@ export default defineConfig({
364
364
 
365
365
  - `preserveDirs` (required): Names of child directories inside `public/` to preserve during sync. These will not be deleted when re-syncing.
366
366
  - `ignorePatterns` (optional): Glob patterns for files to exclude from syncing. Patterns are matched against paths relative to `src/content/docs/`.
367
+ - `exposePageSrcButton` (optional, default: `false`): Injects a client-side script on every page that adds a `⋮` dropdown next to the page's `<h1>` with "Copy Page", "Copy raw URL", and "View raw" actions for the page's raw markdown source.
368
+ - `enableAskAiOption` (optional, default: `false`): Adds "Ask ChatGPT", "Ask Claude", and "Ask Gemini" entries to the same `⋮` dropdown, each opening the respective chat app in a new tab with a prompt pre-filled to read the page's raw markdown URL. Independent of `exposePageSrcButton` — enabling this on its own still injects the dropdown button, containing only the "Ask" entries.
367
369
 
368
370
  ```ts
369
371
  syncDocsToPublic({
370
372
  preserveDirs: ["static"],
371
373
  ignorePatterns: ["**/*.txt", "**/drafts/**"],
374
+ exposePageSrcButton: true,
375
+ enableAskAiOption: true,
372
376
  });
373
377
  ```
374
378
 
@@ -138,17 +138,18 @@ var DEFAULT_SRC_DIR = "src/content/docs";
138
138
  var DEFAULT_PUBLIC_DIR = "public";
139
139
  function validateOptions(options) {
140
140
  const mdProbePaths = ["test.md", "test.mdx", "foo/test.md", "foo/test.mdx"];
141
- if (!options.exposePageSrcButton) return;
141
+ const needsRawMd = options.exposePageSrcButton || options.enableAskAiOption;
142
+ if (!needsRawMd) return;
142
143
  const offendingMdPatterns = (options.ignorePatterns ?? []).filter(
143
144
  (pattern) => mdProbePaths.some((probe) => minimatch(probe, pattern, { dot: true }))
144
145
  );
145
146
  const offendingMtPatternsStr = offendingMdPatterns.map((p) => ` - "${p}"`).join("\n");
146
147
  if (offendingMdPatterns.length > 0) {
147
148
  throw new Error(
148
- `The 'exposePageSrcButton' option is enabled but the following 'ignorePatterns' values conflict with it:
149
+ `The 'exposePageSrcButton'/'enableAskAiOption' option is enabled but the following 'ignorePatterns' values conflict with it:
149
150
  ${offendingMtPatternsStr}
150
151
 
151
- Since these ignore patterns match md/mdx files, the page source button would break. Either disable 'exposePageSrcButton' or remove these patterns.`
152
+ Since these ignore patterns match md/mdx files, the page action button would break. Either disable these options or remove these patterns.`
152
153
  );
153
154
  }
154
155
  }
@@ -256,7 +257,8 @@ function syncDocsToPublic(options) {
256
257
  const {
257
258
  preserveDirs: rawPreserveDirs,
258
259
  ignorePatterns = [],
259
- exposePageSrcButton = false
260
+ exposePageSrcButton = false,
261
+ enableAskAiOption = false
260
262
  } = options;
261
263
  const preserveDirs = rawPreserveDirs.map((d) => d.replace(/\/+$/, ""));
262
264
  return {
@@ -264,7 +266,7 @@ function syncDocsToPublic(options) {
264
266
  hooks: {
265
267
  "astro:config:setup": ({ injectScript }) => {
266
268
  validateOptions(options);
267
- if (exposePageSrcButton) {
269
+ if (exposePageSrcButton || enableAskAiOption) {
268
270
  injectScript(
269
271
  "page",
270
272
  `
@@ -288,8 +290,16 @@ function syncDocsToPublic(options) {
288
290
  import.meta.url
289
291
  );
290
292
  }
291
- const scriptPath = fileURLToPath(pageScriptUrl);
292
- injectScript("page", `import ${JSON.stringify(scriptPath)};`);
293
+ const scriptPath = JSON.stringify(fileURLToPath(pageScriptUrl));
294
+ const actionBarOptions = JSON.stringify({
295
+ exposePageSrcButton,
296
+ enableAskAiOption
297
+ });
298
+ injectScript(
299
+ "page",
300
+ `import { initPageActionBar } from ${scriptPath};
301
+ initPageActionBar(${actionBarOptions});`
302
+ );
293
303
  }
294
304
  },
295
305
  "astro:build:start": async () => {
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  import "./chunk-LJWSZSPB.js";
17
17
  import {
18
18
  syncDocsToPublic
19
- } from "./chunk-4ZJKEEDA.js";
19
+ } from "./chunk-BM7LMGAH.js";
20
20
  import {
21
21
  parseFrontmatter
22
22
  } from "./chunk-EEPQVOZC.js";
@@ -1,2 +1,7 @@
1
+ interface ActionBarOptions {
2
+ exposePageSrcButton: boolean;
3
+ enableAskAiOption: boolean;
4
+ }
5
+ declare function initPageActionBar(options: ActionBarOptions): void;
1
6
 
2
- export { }
7
+ export { initPageActionBar };
@@ -1,3 +1,5 @@
1
+ import "../../chunk-4VNS5WPM.js";
2
+
1
3
  // src/plugins/astro-sync-docs-to-public/page-script.ts
2
4
  function showBanner(message, variant) {
3
5
  const banner = document.createElement("div");
@@ -28,7 +30,21 @@ async function getRawMdUrl() {
28
30
  }
29
31
  return new URL("index.md", base).toString();
30
32
  }
31
- function createActionBar() {
33
+ var LLM_ASK_TARGETS = [
34
+ {
35
+ label: "Ask ChatGPT",
36
+ buildUrl: (prompt) => `https://chatgpt.com/?${new URLSearchParams({ q: prompt })}`
37
+ },
38
+ {
39
+ label: "Ask Claude",
40
+ buildUrl: (prompt) => `https://claude.ai/new?${new URLSearchParams({ q: prompt })}`
41
+ },
42
+ {
43
+ label: "Ask Gemini",
44
+ buildUrl: (prompt) => `https://gemini.google.com/app?${new URLSearchParams({ q: prompt })}`
45
+ }
46
+ ];
47
+ function createActionBar(options) {
32
48
  const bar = document.createElement("div");
33
49
  bar.className = "page-src-action-bar";
34
50
  const menuBtn = document.createElement("button");
@@ -39,29 +55,48 @@ function createActionBar() {
39
55
  }
40
56
  const menu = document.createElement("div");
41
57
  menu.className = "page-src-action-bar__menu";
42
- const menuItems = [
43
- {
44
- label: "Copy Page",
45
- action: () => {
46
- setLoading(true);
47
- getRawMdUrl().then((url) => fetch(url)).then((resp) => resp.text()).then((text) => navigator.clipboard.writeText(text)).then(() => showBanner("Page source copied to clipboard!", "success")).catch(() => showBanner("Failed to copy page source.", "error")).finally(() => setLoading(false));
48
- }
49
- },
50
- {
51
- label: "Copy raw URL",
52
- action: () => {
53
- setLoading(true);
54
- getRawMdUrl().then((url) => navigator.clipboard.writeText(url)).then(() => showBanner("Raw URL copied to clipboard!", "success")).catch(() => showBanner("Failed to copy raw URL.", "error")).finally(() => setLoading(false));
55
- }
56
- },
57
- {
58
- label: "View raw",
59
- action: () => {
60
- setLoading(true);
61
- getRawMdUrl().then((url) => window.open(url, "_blank")).catch(() => showBanner("Failed to open raw source.", "error")).finally(() => setLoading(false));
58
+ const menuItems = [];
59
+ if (options.exposePageSrcButton) {
60
+ menuItems.push(
61
+ {
62
+ label: "Copy Page",
63
+ action: () => {
64
+ setLoading(true);
65
+ getRawMdUrl().then((url) => fetch(url)).then((resp) => resp.text()).then((text) => navigator.clipboard.writeText(text)).then(
66
+ () => showBanner("Page source copied to clipboard!", "success")
67
+ ).catch(() => showBanner("Failed to copy page source.", "error")).finally(() => setLoading(false));
68
+ }
69
+ },
70
+ {
71
+ label: "Copy raw URL",
72
+ action: () => {
73
+ setLoading(true);
74
+ getRawMdUrl().then((url) => navigator.clipboard.writeText(url)).then(() => showBanner("Raw URL copied to clipboard!", "success")).catch(() => showBanner("Failed to copy raw URL.", "error")).finally(() => setLoading(false));
75
+ }
76
+ },
77
+ {
78
+ label: "View raw",
79
+ action: () => {
80
+ setLoading(true);
81
+ getRawMdUrl().then((url) => window.open(url, "_blank")).catch(() => showBanner("Failed to open raw source.", "error")).finally(() => setLoading(false));
82
+ }
62
83
  }
84
+ );
85
+ }
86
+ if (options.enableAskAiOption) {
87
+ for (const { label, buildUrl } of LLM_ASK_TARGETS) {
88
+ menuItems.push({
89
+ label,
90
+ action: () => {
91
+ setLoading(true);
92
+ getRawMdUrl().then((url) => {
93
+ const prompt = `Read from ${url} so I can ask questions about it.`;
94
+ window.open(buildUrl(prompt), "_blank");
95
+ }).catch(() => showBanner(`Failed to open ${label}.`, "error")).finally(() => setLoading(false));
96
+ }
97
+ });
63
98
  }
64
- ];
99
+ }
65
100
  for (const item of menuItems) {
66
101
  const btn = document.createElement("button");
67
102
  btn.className = "page-src-action-bar__menu-item";
@@ -93,13 +128,15 @@ function createActionBar() {
93
128
  bar.appendChild(menu);
94
129
  return bar;
95
130
  }
96
- function main() {
131
+ function initPageActionBar(options) {
97
132
  const h1 = document.querySelector(".sl-container > h1");
98
133
  if (h1 === null) return;
99
134
  const wrapper = document.createElement("div");
100
135
  wrapper.className = "page-src-h1-wrapper";
101
136
  h1.replaceWith(wrapper);
102
137
  wrapper.appendChild(h1);
103
- wrapper.appendChild(createActionBar());
138
+ wrapper.appendChild(createActionBar(options));
104
139
  }
105
- main();
140
+ export {
141
+ initPageActionBar
142
+ };
@@ -17,6 +17,15 @@ interface SyncDocsToPublicOptions {
17
17
  * dev and build modes.
18
18
  */
19
19
  exposePageSrcButton?: boolean;
20
+ /**
21
+ * When true, adds "Ask ChatGPT", "Ask Claude", and "Ask Gemini" entries to
22
+ * the page action dropdown menu, each opening the respective chat app with
23
+ * a prompt pre-filled to read the current page's raw markdown URL.
24
+ *
25
+ * Independent of `exposePageSrcButton` — enabling this on its own still
26
+ * injects the dropdown button, containing only the "Ask" entries.
27
+ */
28
+ enableAskAiOption?: boolean;
20
29
  }
21
30
  declare function syncDocsToPublic(options: SyncDocsToPublicOptions): AstroIntegration;
22
31
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  syncDocsToPublic
3
- } from "../chunk-4ZJKEEDA.js";
3
+ } from "../chunk-BM7LMGAH.js";
4
4
  import "../chunk-EEPQVOZC.js";
5
5
  import "../chunk-7D2KLZGE.js";
6
6
  import "../chunk-4VNS5WPM.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "starlight-cannoli-plugins",
3
3
  "type": "module",
4
- "version": "2.17.1",
4
+ "version": "2.17.2",
5
5
  "description": "Starlight plugins for automatic sidebar generation and link validation",
6
6
  "license": "ISC",
7
7
  "main": "./dist/index.js",