@farming-labs/nuxt-theme 0.1.113 → 0.1.114

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/nuxt-theme",
3
- "version": "0.1.113",
3
+ "version": "0.1.114",
4
4
  "description": "Nuxt/Vue UI components for @farming-labs/docs — layout, sidebar, TOC, search, and theme toggle",
5
5
  "keywords": [
6
6
  "docs",
@@ -88,7 +88,7 @@
88
88
  },
89
89
  "dependencies": {
90
90
  "sugar-high": "^0.9.5",
91
- "@farming-labs/docs": "0.1.113"
91
+ "@farming-labs/docs": "0.1.114"
92
92
  },
93
93
  "peerDependencies": {
94
94
  "nuxt": ">=3.0.0",
@@ -6,10 +6,21 @@ import { toDocsMarkdownUrl } from "@farming-labs/docs";
6
6
  import DocsPage from "./DocsPage.vue";
7
7
 
8
8
  const DEFAULT_OPEN_PROVIDERS = [
9
- { name: "ChatGPT", urlTemplate: "https://chatgpt.com/?hints=search&q=Read+{url}.md,+I+want+to+ask+questions+about+it." },
10
- { name: "Claude", urlTemplate: "https://claude.ai/new?q=Read+{url}.md,+I+want+to+ask+questions+about+it." },
9
+ { name: "ChatGPT", urlTemplate: "https://chatgpt.com/?q={prompt}" },
10
+ { name: "Claude", urlTemplate: "https://claude.ai/new?q={prompt}" },
11
11
  ];
12
12
 
13
+ const DEFAULT_OPEN_PROMPT = "Read this documentation: {url}";
14
+ const DEFAULT_OPEN_TARGET = "markdown";
15
+ const OPEN_PROVIDER_PRESETS: Record<string, { name: string; urlTemplate: string; target?: string }> = {
16
+ chatgpt: { name: "ChatGPT", urlTemplate: "https://chatgpt.com/?q={prompt}" },
17
+ claude: { name: "Claude", urlTemplate: "https://claude.ai/new?q={prompt}" },
18
+ cursor: { name: "Cursor", urlTemplate: "https://cursor.com/link/prompt?text={prompt}" },
19
+ gemini: { name: "Gemini", urlTemplate: "https://gemini.google.com/app?q={prompt}" },
20
+ copilot: { name: "Copilot", urlTemplate: "https://github.com/copilot?prompt={prompt}" },
21
+ github: { name: "GitHub", urlTemplate: "{githubUrl}", target: "github" },
22
+ };
23
+
13
24
  const props = defineProps<{
14
25
  data: {
15
26
  title: string;
@@ -100,6 +111,30 @@ const markdownAlternateHref = computed(() =>
100
111
  props.config?.staticExport ? null : toDocsMarkdownUrl(pageUrl.value, { locale: props.data.locale }),
101
112
  );
102
113
 
114
+ function resolveMarkdownUrl(url: string) {
115
+ try {
116
+ const parsed = new URL(url);
117
+ const pathname = parsed.pathname.replace(/\/+$/, "") || parsed.pathname;
118
+ parsed.pathname = pathname.endsWith(".md") ? pathname : `${pathname}.md`;
119
+ parsed.search = "";
120
+ parsed.hash = "";
121
+ return parsed.toString();
122
+ } catch {
123
+ const clean = url.replace(/[?#].*$/, "").replace(/\/+$/, "") || url;
124
+ return clean.endsWith(".md") ? clean : `${clean}.md`;
125
+ }
126
+ }
127
+
128
+ function fillOpenPrompt(template: string, values: Record<string, string>) {
129
+ return template
130
+ .replace(/\{pageUrl\}/g, values.pageUrl)
131
+ .replace(/\{markdownUrl\}/g, values.markdownUrl)
132
+ .replace(/\{sourceUrl\}/g, values.sourceUrl)
133
+ .replace(/\{mdxUrl\}/g, values.sourceUrl)
134
+ .replace(/\{githubUrl\}/g, values.githubUrl)
135
+ .replace(/\{url\}/g, values.url);
136
+ }
137
+
103
138
  const copyMarkdownEnabled = computed(() => {
104
139
  const pa = props.config?.pageActions as Record<string, unknown> | undefined;
105
140
  if (!pa) return false;
@@ -121,19 +156,38 @@ const openDocsEnabled = computed(() => {
121
156
  const openDocsProviders = computed(() => {
122
157
  const pa = props.config?.pageActions as Record<string, unknown> | undefined;
123
158
  const od = pa && typeof pa === "object" && pa.openDocs != null ? pa.openDocs : null;
159
+ const target = od && typeof od === "object" ? (od as { target?: string }).target : undefined;
160
+ const prompt = od && typeof od === "object" ? (od as { prompt?: string }).prompt : undefined;
124
161
  const list = od && typeof od === "object" && "providers" in od
125
- ? (od as { providers?: Array<{ name?: string; urlTemplate?: string }> }).providers
162
+ ? (od as { providers?: Array<string | { id?: string; name?: string; label?: string; urlTemplate?: string; prompt?: string; target?: string; mode?: string }> }).providers
126
163
  : undefined;
127
164
  if (Array.isArray(list) && list.length > 0) {
128
165
  const mapped = list
129
- .map((p) => ({
130
- name: typeof p?.name === "string" ? p.name : "Open",
131
- urlTemplate: typeof p?.urlTemplate === "string" ? p.urlTemplate : "",
132
- }))
166
+ .map((p) => {
167
+ const id =
168
+ typeof p === "string" ? p.toLowerCase() : (p.id ?? p.name ?? p.label)?.toLowerCase();
169
+ const preset = id ? OPEN_PROVIDER_PRESETS[id] : undefined;
170
+ const cursorApp = id === "cursor" && typeof p === "object" && p.mode === "app";
171
+ const hasCustomUrlTemplate = typeof p === "object" && typeof p.urlTemplate === "string";
172
+ return {
173
+ name: typeof p === "object" ? (p.name ?? p.label ?? preset?.name ?? "Open") : (preset?.name ?? p),
174
+ urlTemplate:
175
+ hasCustomUrlTemplate
176
+ ? p.urlTemplate
177
+ : cursorApp
178
+ ? "cursor://anysphere.cursor-deeplink/prompt?text={prompt}"
179
+ : (preset?.urlTemplate ?? ""),
180
+ target:
181
+ typeof p === "object"
182
+ ? (p.target ?? preset?.target ?? target ?? (hasCustomUrlTemplate ? "page" : undefined))
183
+ : (preset?.target ?? target),
184
+ prompt: typeof p === "object" ? (p.prompt ?? prompt) : prompt,
185
+ };
186
+ })
133
187
  .filter((p) => p.urlTemplate.length > 0);
134
188
  if (mapped.length > 0) return mapped;
135
189
  }
136
- return DEFAULT_OPEN_PROVIDERS;
190
+ return DEFAULT_OPEN_PROVIDERS.map((provider) => ({ ...provider, target, prompt }));
137
191
  });
138
192
 
139
193
  const pageActionsPosition = computed(() => {
@@ -282,16 +336,41 @@ function closeDropdown() {
282
336
  openDropdownMenu.value = false;
283
337
  }
284
338
 
285
- function openInProvider(provider: { name: string; urlTemplate: string }) {
339
+ function openInProvider(provider: { name: string; urlTemplate: string; target?: string; prompt?: string }) {
286
340
  const pathname = route.path;
287
341
  const pageUrl = typeof window !== "undefined" ? window.location.href : "";
288
- const mdxUrl = typeof window !== "undefined"
342
+ const sourceUrl = typeof window !== "undefined"
289
343
  ? window.location.origin + pathname + (pathname.endsWith("/") ? "page.mdx" : ".mdx")
290
344
  : "";
345
+ const markdownUrl = resolveMarkdownUrl(pageUrl);
291
346
  const githubUrl = props.data.editOnGithub || "";
347
+ if (/\{githubUrl\}/.test(provider.urlTemplate) && !githubUrl) {
348
+ closeDropdown();
349
+ return;
350
+ }
351
+ const target = provider.target ?? DEFAULT_OPEN_TARGET;
352
+ const targetUrl =
353
+ target === "markdown"
354
+ ? markdownUrl
355
+ : target === "source"
356
+ ? sourceUrl
357
+ : target === "github"
358
+ ? (githubUrl || pageUrl)
359
+ : pageUrl;
360
+ const prompt = fillOpenPrompt(provider.prompt ?? DEFAULT_OPEN_PROMPT, {
361
+ url: targetUrl,
362
+ pageUrl,
363
+ markdownUrl,
364
+ sourceUrl,
365
+ githubUrl,
366
+ });
292
367
  const url = provider.urlTemplate
293
- .replace(/\{url\}/g, encodeURIComponent(pageUrl))
294
- .replace(/\{mdxUrl\}/g, encodeURIComponent(mdxUrl))
368
+ .replace(/\{prompt\}/g, encodeURIComponent(prompt))
369
+ .replace(/\{url\}/g, encodeURIComponent(targetUrl))
370
+ .replace(/\{pageUrl\}/g, encodeURIComponent(pageUrl))
371
+ .replace(/\{markdownUrl\}/g, encodeURIComponent(markdownUrl))
372
+ .replace(/\{sourceUrl\}/g, encodeURIComponent(sourceUrl))
373
+ .replace(/\{mdxUrl\}/g, encodeURIComponent(sourceUrl))
295
374
  .replace(/\{githubUrl\}/g, githubUrl);
296
375
  if (typeof window !== "undefined") window.open(url, "_blank", "noopener,noreferrer");
297
376
  closeDropdown();