@stainless-api/docs 0.1.0-beta.30 → 0.1.0-beta.32

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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @stainless-api/docs
2
2
 
3
+ ## 0.1.0-beta.32
4
+
5
+ ### Patch Changes
6
+
7
+ - 58040d8: feat: ui primitives updates, cursor support
8
+ - Updated dependencies [58040d8]
9
+ - @stainless-api/docs-ui@0.1.0-beta.26
10
+ - @stainless-api/ui-primitives@0.1.0-beta.19
11
+
12
+ ## 0.1.0-beta.31
13
+
14
+ ### Patch Changes
15
+
16
+ - Updated dependencies [afd1f8e]
17
+ - Updated dependencies [279fa0e]
18
+ - @stainless-api/docs-ui@0.1.0-beta.25
19
+
3
20
  ## 0.1.0-beta.30
4
21
 
5
22
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stainless-api/docs",
3
- "version": "0.1.0-beta.30",
3
+ "version": "0.1.0-beta.32",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -50,8 +50,8 @@
50
50
  "remark-gfm": "^4.0.1",
51
51
  "remark-stringify": "^11.0.0",
52
52
  "unified": "^11.0.5",
53
- "@stainless-api/docs-ui": "0.1.0-beta.24",
54
- "@stainless-api/ui-primitives": "0.1.0-beta.18"
53
+ "@stainless-api/docs-ui": "0.1.0-beta.26",
54
+ "@stainless-api/ui-primitives": "0.1.0-beta.19"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@astrojs/check": "^0.9.5",
@@ -1,15 +1,29 @@
1
1
  import { initDropdownButton } from '@stainless-api/ui-primitives/scripts';
2
2
  import { getPageLoadEvent } from '../helpers/getPageLoadEvent';
3
3
 
4
- export type DropdownIcon = 'markdown' | 'copy' | 'claude' | 'chatgpt';
4
+ export type DropdownIcon = 'markdown' | 'copy' | 'claude' | 'chatgpt' | 'gemini' | 'cursor';
5
5
 
6
6
  interface DropdownOptionInputProps {
7
7
  onClick: () => void;
8
8
  icon: DropdownIcon;
9
9
  primaryAction?: boolean;
10
- label: string[] | string;
10
+ clientHidden?: boolean;
11
+ external: boolean;
11
12
  }
12
13
 
14
+ function option(label: string[] | string, props: DropdownOptionInputProps) {
15
+ const labelArr = typeof label === 'string' ? [label] : label;
16
+ return {
17
+ ...props,
18
+ label: labelArr,
19
+ primaryAction: props.primaryAction ?? false,
20
+ clientHidden: props.clientHidden ?? false,
21
+ id: labelArr.join('').toLowerCase().replace(/ /g, '-'),
22
+ };
23
+ }
24
+
25
+ type DropdownOption = ReturnType<typeof option>;
26
+
13
27
  function getMarkdownUrl(type: 'relative' | 'absolute') {
14
28
  const currentUrl = new URL(window.location.href);
15
29
  const hasTrailingSlash = currentUrl.pathname.endsWith('/');
@@ -24,28 +38,94 @@ function getMarkdownUrl(type: 'relative' | 'absolute') {
24
38
  return markdownUrl;
25
39
  }
26
40
 
27
- function openInLLM(serviceUrl: string) {
41
+ function getURLEncodedPrompt() {
28
42
  const mdUrl = getMarkdownUrl('absolute');
29
- const prompt = encodeURIComponent(
43
+ const aiPrompt = encodeURIComponent(
30
44
  `Load the contents of ${mdUrl} into this chat's context so we can discuss it.`,
31
45
  );
32
- window.open(`${serviceUrl}${prompt}`, '_blank');
46
+ return aiPrompt;
33
47
  }
34
48
 
49
+ function openDeepLink({ deepLinkUrl, fallbackUrl }: { deepLinkUrl: string; fallbackUrl: string }) {
50
+ if (navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrom')) {
51
+ // safari doesn't let us detect if the deep link worked
52
+ window.open(fallbackUrl, '_blank');
53
+ return;
54
+ }
55
+
56
+ const controller = new AbortController();
57
+ let frame: HTMLIFrameElement | null;
58
+
59
+ // We are using a native deep link with a fallback web url.
60
+ if (navigator.userAgent.includes('Chrom')) {
61
+ // In Chrome, load it in a hidden frame, this shows the "Do you want to open ...?" prompt, but unlike
62
+ // top level navigation this preserves our userActivation, so we can open the fallback if it fails.
63
+ frame = Object.assign(document.createElement('iframe'), { src: deepLinkUrl });
64
+ document.head.append(frame);
65
+ } else {
66
+ // In Firefox do the opposite.
67
+ location.href = deepLinkUrl;
68
+ }
69
+
70
+ // The popup (in non-Safari browsers) fires a `blur` event.
71
+ window.addEventListener(
72
+ 'blur',
73
+ () => {
74
+ controller.abort();
75
+ },
76
+ controller,
77
+ );
78
+
79
+ // If it's been 300ms with no popup, open the fallback web url.
80
+ const timeout = setTimeout(() => {
81
+ window.open(fallbackUrl, '_blank');
82
+ }, 300);
83
+
84
+ controller.signal.addEventListener('abort', () => {
85
+ clearTimeout(timeout);
86
+ frame?.remove();
87
+ });
88
+ }
89
+
90
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent#mobile_tablet_or_desktop
91
+ const hasMobileUserAgent = navigator.userAgent.includes('Mobi');
92
+
35
93
  // 2d array of dropdown options
36
94
  // each sub-array is a group, separated by a horizontal rule in the UI
37
- const aiDropdownOptions: DropdownOptionInputProps[][] = [
95
+ const aiDropdownOptions: DropdownOption[][] = [
38
96
  [
39
- {
40
- label: 'View as Markdown',
97
+ option(['Open in ', 'Claude'], {
41
98
  onClick: () => {
42
- window.open(getMarkdownUrl('absolute'), '_blank');
99
+ window.open(`https://claude.ai/new?q=${getURLEncodedPrompt()}`, '_blank');
43
100
  },
44
- icon: 'markdown',
45
- primaryAction: true,
46
- },
47
- {
48
- label: 'Copy Markdown',
101
+ icon: 'claude',
102
+ primaryAction: false,
103
+ external: true,
104
+ }),
105
+ option(['Open in ', 'ChatGPT'], {
106
+ onClick: () => {
107
+ window.open(`https://chatgpt.com/?hints=search&prompt=${getURLEncodedPrompt()}`, '_blank');
108
+ },
109
+ icon: 'chatgpt',
110
+ primaryAction: false,
111
+ external: true,
112
+ }),
113
+ option(['Open in ', 'Cursor'], {
114
+ onClick: () => {
115
+ const aiPrompt = getURLEncodedPrompt();
116
+ openDeepLink({
117
+ deepLinkUrl: `cursor://anysphere.cursor-deeplink/prompt?text=${aiPrompt}`,
118
+ fallbackUrl: `https://cursor.com/link/prompt?text=${aiPrompt}`,
119
+ });
120
+ },
121
+ clientHidden: hasMobileUserAgent,
122
+ icon: 'cursor',
123
+ primaryAction: false,
124
+ external: true,
125
+ }),
126
+ ],
127
+ [
128
+ option('Copy Markdown', {
49
129
  onClick: () => {
50
130
  // Source: https://wolfgangrittner.dev/how-to-use-clipboard-api-in-firefox/
51
131
  const markdownUrl = getMarkdownUrl('relative');
@@ -74,54 +154,34 @@ const aiDropdownOptions: DropdownOptionInputProps[][] = [
74
154
  }
75
155
  },
76
156
  icon: 'copy',
77
- primaryAction: false,
78
- },
79
- ],
80
- [
81
- {
82
- label: ['Open in ', 'Claude'],
83
- onClick: () => {
84
- openInLLM('https://claude.ai/new?q=');
85
- },
86
- icon: 'claude',
87
- primaryAction: false,
88
- },
89
- {
90
- label: ['Open in ', 'ChatGPT'],
157
+ primaryAction: true,
158
+ external: false,
159
+ }),
160
+ option('View as Markdown', {
91
161
  onClick: () => {
92
- openInLLM('https://chatgpt.com/?hints=search&prompt=');
162
+ window.open(getMarkdownUrl('absolute'), '_blank');
93
163
  },
94
- icon: 'chatgpt',
164
+ icon: 'markdown',
95
165
  primaryAction: false,
96
- },
97
- // TODO: Add Cursor support
98
- // {
99
- // label: ['Open in ', 'Cursor'],
100
- // onClick: () => {
101
- // openInLLM('https://www.cursor.so/?prompt=');
102
- // },
103
- // icon: 'cursor',
104
- // primaryAction: false,
105
- // }
166
+ external: true,
167
+ }),
106
168
  ],
107
169
  ];
108
170
 
109
- function renderGroup(group: DropdownOptionInputProps[]) {
110
- return group.map((option) => {
111
- const label = typeof option.label === 'string' ? [option.label] : option.label;
112
- return {
113
- ...option,
114
- label: label,
115
- primaryAction: option.primaryAction ?? false,
116
- id: label.join('').toLowerCase().replace(/ /g, '-'),
117
- };
118
- });
119
- }
171
+ // TODO: Add support for more LLMs
172
+ // {
173
+ // label: ['Open in ', 'Gemini'],
174
+ // onClick: () => {
175
+ // openInLLM('https://gemini.google.com?prompt_action=prefill&prompt_text=');
176
+ // },
177
+ // icon: 'gemini',
178
+ // primaryAction: false,
179
+ // },
120
180
 
121
181
  export function getAIDropdownOptions() {
122
182
  const renderedOptions = aiDropdownOptions.map((group, index) => {
123
183
  return {
124
- options: renderGroup(group),
184
+ options: group,
125
185
  isLast: index === aiDropdownOptions.length - 1,
126
186
  reactKey: index,
127
187
  };
@@ -138,14 +198,26 @@ export function getAIDropdownOptions() {
138
198
 
139
199
  export function wireAIDropdown() {
140
200
  const { primaryAction, groups } = getAIDropdownOptions();
201
+ const flatOptions = groups.flatMap((group) => group.options);
141
202
  function triggerOption(id: string) {
142
- const option = groups.flatMap((group) => group.options).find((option) => option.id === id);
203
+ const option = flatOptions.find((option) => option.id === id);
143
204
  if (!option) return;
144
205
  option.onClick();
145
206
  }
146
207
 
147
208
  document.addEventListener(getPageLoadEvent(), () => {
209
+ // we hide the Cursor option on non-desktop devices
210
+ for (const option of flatOptions) {
211
+ if (option.clientHidden === true) {
212
+ const el = document.querySelector(`[data-value="${option.id}"]`);
213
+ if (el) {
214
+ el.remove();
215
+ }
216
+ }
217
+ }
218
+
148
219
  const dropdowns = document.querySelectorAll('[data-dropdown-id]');
220
+
149
221
  dropdowns.forEach((dropdown) => {
150
222
  initDropdownButton({
151
223
  dropdown: dropdown,
@@ -26,7 +26,7 @@ export const GET: APIRoute<RouteProps> = async ({ props }) => {
26
26
  if (props.kind === 'readme') {
27
27
  const readmeContent = await getReadmeContent(spec, props.language);
28
28
  return new Response(readmeContent, {
29
- headers: { 'Content-Type': 'text/markdown' },
29
+ headers: { 'Content-Type': 'text/plain' },
30
30
  });
31
31
  }
32
32
 
@@ -51,7 +51,7 @@ export const GET: APIRoute<RouteProps> = async ({ props }) => {
51
51
  const output = renderMarkdown(env, target);
52
52
 
53
53
  return new Response(output, {
54
- headers: { 'Content-Type': 'text/markdown' },
54
+ headers: { 'Content-Type': 'text/plain' },
55
55
  });
56
56
  };
57
57
 
@@ -2,7 +2,9 @@ import { DropdownButton } from '@stainless-api/ui-primitives';
2
2
  import { CopyIcon } from 'lucide-react';
3
3
  import { ChatGPTIcon } from './icons/chat-gpt';
4
4
  import { ClaudeIcon } from './icons/claude';
5
+ import { GeminiIcon } from './icons/gemini';
5
6
  import { MarkdownIcon } from './icons/markdown';
7
+ import { CursorIcon } from './icons/cursor';
6
8
  import React from 'react';
7
9
 
8
10
  import { getAIDropdownOptions, type DropdownIcon } from '../../plugin/globalJs/ai-dropdown-options';
@@ -12,16 +14,25 @@ const iconMap: { [key in DropdownIcon]: React.ReactNode } = {
12
14
  copy: <CopyIcon size={16} />,
13
15
  claude: <ClaudeIcon />,
14
16
  chatgpt: <ChatGPTIcon />,
17
+ gemini: <GeminiIcon />,
18
+ cursor: <CursorIcon />,
15
19
  };
16
20
 
17
21
  const { primaryAction, groups } = getAIDropdownOptions();
18
22
 
19
23
  function ItemLabel({ label }: { label: string[] }) {
20
- const isExternal = label.length > 1;
24
+ if (label.length > 1) {
25
+ return (
26
+ <DropdownButton.MenuItemText subtle>
27
+ {label[0]}
28
+ <strong>{label[1]}</strong>
29
+ </DropdownButton.MenuItemText>
30
+ );
31
+ }
32
+
21
33
  return (
22
- <DropdownButton.MenuItemText subtle={isExternal}>
23
- {label[0]}
24
- {isExternal && <strong>{label[1]}</strong>}
34
+ <DropdownButton.MenuItemText>
35
+ <strong>{label[0]}</strong>
25
36
  </DropdownButton.MenuItemText>
26
37
  );
27
38
  }
@@ -38,7 +49,7 @@ export function AIDropdown() {
38
49
  {groups.map((group) => (
39
50
  <React.Fragment key={group.reactKey}>
40
51
  {group.options.map((option) => (
41
- <DropdownButton.MenuItem value={option.id} isExternalLink key={option.id}>
52
+ <DropdownButton.MenuItem value={option.id} isExternalLink={option.external} key={option.id}>
42
53
  <DropdownButton.MenuItemIcon>{iconMap[option.icon]}</DropdownButton.MenuItemIcon>
43
54
  <ItemLabel label={option.label} />
44
55
  </DropdownButton.MenuItem>
@@ -0,0 +1,10 @@
1
+ export function CursorIcon() {
2
+ return (
3
+ <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 466.73 532.09">
4
+ <path
5
+ fill="var(--stl-ui-foreground)"
6
+ d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z"
7
+ />
8
+ </svg>
9
+ );
10
+ }
@@ -0,0 +1,19 @@
1
+ export const GeminiIcon = () => (
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 192" width="16" height="16">
3
+ <defs>
4
+ <clipPath id="clippath">
5
+ <path
6
+ d="M164.93 86.68c-13.56-5.84-25.42-13.84-35.6-24.01-10.17-10.17-18.18-22.04-24.01-35.6-2.23-5.19-4.04-10.54-5.42-16.02C99.45 9.26 97.85 8 96 8s-3.45 1.26-3.9 3.05c-1.38 5.48-3.18 10.81-5.42 16.02-5.84 13.56-13.84 25.43-24.01 35.6-10.17 10.16-22.04 18.17-35.6 24.01-5.19 2.23-10.54 4.04-16.02 5.42C9.26 92.55 8 94.15 8 96s1.26 3.45 3.05 3.9c5.48 1.38 10.81 3.18 16.02 5.42 13.56 5.84 25.42 13.84 35.6 24.01 10.17 10.17 18.18 22.04 24.01 35.6 2.24 5.2 4.04 10.54 5.42 16.02A4.03 4.03 0 0 0 96 184c1.85 0 3.45-1.26 3.9-3.05 1.38-5.48 3.18-10.81 5.42-16.02 5.84-13.56 13.84-25.42 24.01-35.6 10.17-10.17 22.04-18.18 35.6-24.01 5.2-2.24 10.54-4.04 16.02-5.42A4.03 4.03 0 0 0 184 96c0-1.85-1.26-3.45-3.05-3.9-5.48-1.38-10.81-3.18-16.02-5.42"
7
+ className="st0"
8
+ />
9
+ </clipPath>
10
+ </defs>
11
+ <g style={{ clipPath: 'url(#clippath)' }}>
12
+ <image
13
+ xlinkHref="data:image/webp;base64,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"
14
+ width={192}
15
+ height={192}
16
+ />
17
+ </g>
18
+ </svg>
19
+ );