@apify/docs-theme 1.0.211 → 1.0.213

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": "@apify/docs-theme",
3
- "version": "1.0.211",
3
+ "version": "1.0.213",
4
4
  "description": "",
5
5
  "main": "./src/index.js",
6
6
  "files": [
@@ -7,6 +7,8 @@ import MDXContent from '@theme/MDXContent';
7
7
  import clsx from 'clsx';
8
8
  import React from 'react';
9
9
 
10
+ import styles from './styles.module.css';
11
+
10
12
  function useSyntheticTitle() {
11
13
  const { metadata, frontMatter, contentTitle } = useDoc();
12
14
  const shouldRender = !frontMatter.hide_title && typeof contentTitle === 'undefined';
@@ -62,11 +64,15 @@ export default function DocItemContent({ children }) {
62
64
  const shouldShowLLMButtons = allowedPaths.some((path) => location.pathname.startsWith(path))
63
65
  && !disallowedPaths.some((path) => location.pathname.includes(path));
64
66
 
65
- return (
66
- <div className={clsx(ThemeClassNames.docs.docMarkdown, 'markdown')}>
67
- {syntheticTitle && <Heading as="h1">{syntheticTitle}</Heading>}
68
- {shouldShowLLMButtons && <LLMButtons />}
69
- <MDXContent>{children}</MDXContent>
70
- </div>
71
- );
67
+ return (
68
+ <div className={clsx(ThemeClassNames.docs.docMarkdown, 'markdown')}>
69
+ {(syntheticTitle || shouldShowLLMButtons) && (
70
+ <div className={styles.docItemContent}>
71
+ {syntheticTitle && <Heading as="h1">{syntheticTitle}</Heading>}
72
+ {shouldShowLLMButtons && <LLMButtons />}
73
+ </div>
74
+ )}
75
+ <MDXContent>{children}</MDXContent>
76
+ </div>
77
+ );
72
78
  }
@@ -0,0 +1,17 @@
1
+ .docItemContent {
2
+ display: flex;
3
+ align-items: center;
4
+ flex-wrap: wrap;
5
+ /* move the h1 margin to padding */
6
+ h1 {
7
+ margin-bottom: 0 !important;
8
+ }
9
+ padding-bottom: calc(
10
+ var(--ifm-h1-vertical-rhythm-bottom) * var(--ifm-leading)
11
+ );
12
+
13
+ @media (max-width: 767px) {
14
+ flex-direction: column;
15
+ align-items: flex-start;
16
+ }
17
+ }
@@ -1,15 +1,295 @@
1
- import React from 'react';
1
+ import clsx from 'clsx';
2
+ import React, { useCallback, useState } from 'react';
3
+
4
+ import {
5
+ AnthropicIcon,
6
+ ChatGptIcon,
7
+ CheckIcon,
8
+ ChevronDownIcon,
9
+ CopyIcon,
10
+ ExternalLinkIcon,
11
+ LoaderIcon,
12
+ MarkdownIcon,
13
+ PerplexityIcon,
14
+ } from '@apify/ui-icons';
15
+ import { Menu, Text, theme } from '@apify/ui-library';
2
16
 
3
- import CopyForLLM from './CopyForLLM';
4
17
  import styles from './styles.module.css';
5
- import ViewAsMarkdown from './ViewAsMarkdown';
6
18
 
7
- export default function LLMButtons() {
8
- return (
9
- <div className={styles.llmButtonsContainer}>
10
- <ViewAsMarkdown />
11
- <div className={styles.llmButtonsSeparator}></div>
12
- <CopyForLLM />
19
+ const DROPDOWN_OPTIONS = [
20
+ {
21
+ label: 'Copy for LLM',
22
+ description: 'Copy page as Markdown for LLMs',
23
+ showExternalIcon: false,
24
+ Icon: CopyIcon,
25
+ value: 'copyForLLM',
26
+ },
27
+ {
28
+ label: 'View as Markdown',
29
+ description: 'View this page as plain text',
30
+ showExternalIcon: true,
31
+ Icon: MarkdownIcon,
32
+ value: 'viewAsMarkdown',
33
+ },
34
+ {
35
+ label: 'Open in ChatGPT',
36
+ description: 'Ask questions about this page',
37
+ showExternalIcon: true,
38
+ Icon: ChatGptIcon,
39
+ value: 'openInChatGPT',
40
+ },
41
+ {
42
+ label: 'Open in Claude',
43
+ description: 'Ask questions about this page',
44
+ showExternalIcon: true,
45
+ Icon: AnthropicIcon,
46
+ value: 'openInClaude',
47
+ },
48
+ {
49
+ label: 'Open in Perplexity',
50
+ description: 'Ask questions about this page',
51
+ showExternalIcon: true,
52
+ Icon: PerplexityIcon,
53
+ value: 'openInPerplexity',
54
+ },
55
+ ];
56
+
57
+ const getPrompt = (currentUrl) => `Read from ${currentUrl} so I can ask questions about it.`;
58
+ const getMarkdownUrl = (currentUrl) => `${currentUrl}.md`;
59
+
60
+ const onOpenInChatGPTClick = () => {
61
+ if (window.analytics) {
62
+ window.analytics.track('Clicked', {
63
+ app: 'docs',
64
+ button_text: 'Open in ChatGPT',
65
+ element: 'llm-buttons.openInChatGPT',
66
+ });
67
+ }
68
+
69
+ const prompt = getPrompt(window.location.href);
70
+
71
+ try {
72
+ window.open(
73
+ `https://chatgpt.com/?hints=search&q=${encodeURIComponent(prompt)}`,
74
+ '_blank',
75
+ );
76
+ } catch (error) {
77
+ console.error('Error opening ChatGPT:', error);
78
+ }
79
+ };
80
+
81
+ const onOpenInClaudeClick = () => {
82
+ if (window.analytics) {
83
+ window.analytics.track('Clicked', {
84
+ app: 'docs',
85
+ button_text: 'Open in Claude',
86
+ element: 'llm-buttons.openInClaude',
87
+ });
88
+ }
89
+
90
+ const prompt = getPrompt(window.location.href);
91
+
92
+ try {
93
+ window.open(
94
+ `https://claude.ai/new?q=${encodeURIComponent(prompt)}`,
95
+ '_blank',
96
+ );
97
+ } catch (error) {
98
+ console.error('Error opening Claude:', error);
99
+ }
100
+ };
101
+
102
+ const onOpenInPerplexityClick = () => {
103
+ if (window.analytics) {
104
+ window.analytics.track('Clicked', {
105
+ app: 'docs',
106
+ button_text: 'Open in Perplexity',
107
+ element: 'llm-buttons.openInPerplexity',
108
+ });
109
+ }
110
+
111
+ const prompt = getPrompt(window.location.href);
112
+
113
+ try {
114
+ window.open(
115
+ `https://www.perplexity.ai/search/new?q=${encodeURIComponent(
116
+ prompt,
117
+ )}`,
118
+ '_blank',
119
+ );
120
+ } catch (error) {
121
+ console.error('Error opening Perplexity:', error);
122
+ }
123
+ };
124
+
125
+ const onCopyAsMarkdownClick = async ({ setCopyingStatus }) => {
126
+ if (window.analytics) {
127
+ window.analytics.track('Clicked', {
128
+ app: 'docs',
129
+ button_text: 'Copy for LLM',
130
+ element: 'llm-buttons.copyForLLM',
131
+ });
132
+ }
133
+
134
+ const markdownUrl = getMarkdownUrl(window.location.href);
135
+
136
+ try {
137
+ setCopyingStatus('loading');
138
+
139
+ // Fetch the markdown content
140
+ const response = await fetch(markdownUrl);
141
+
142
+ if (!response.ok) {
143
+ throw new Error(`Failed to fetch markdown: ${response.status}`);
144
+ }
145
+
146
+ const markdownContent = await response.text();
147
+
148
+ // Copy to clipboard
149
+ await navigator.clipboard.writeText(markdownContent);
150
+
151
+ // Show success feedback
152
+ setCopyingStatus('copied');
153
+ } catch (error) {
154
+ console.error('Failed to copy markdown content:', error);
155
+ } finally {
156
+ setTimeout(() => setCopyingStatus('idle'), 2000);
157
+ }
158
+ };
159
+
160
+ const onViewAsMarkdownClick = () => {
161
+ if (window.analytics) {
162
+ window.analytics.track('Clicked', {
163
+ app: 'docs',
164
+ button_text: 'View as Markdown',
165
+ element: 'llm-buttons.viewAsMarkdown',
166
+ });
167
+ }
168
+
169
+ const markdownUrl = getMarkdownUrl(window.location.href);
170
+
171
+ try {
172
+ window.open(markdownUrl, '_blank');
173
+ } catch (error) {
174
+ console.error('Error opening markdown file:', error);
175
+ }
176
+ };
177
+
178
+ function getButtonText({ status }) {
179
+ switch (status) {
180
+ case 'loading':
181
+ return 'Copying...';
182
+ case 'copied':
183
+ return 'Copied';
184
+ default:
185
+ return 'Copy for LLM';
186
+ }
187
+ }
188
+
189
+ const MenuBase = ({
190
+ children,
191
+ ref,
192
+ copyingStatus,
193
+ setCopyingStatus,
194
+ chevronIconRef,
195
+ ...props
196
+ }) => (
197
+ <div ref={ref} className={styles.llmButtonWrapper}>
198
+ <div className={styles.llmButton}>
199
+ <div
200
+ className={styles.copyUpIconWrapper}
201
+ onClick={() => onCopyAsMarkdownClick({ setCopyingStatus })}
202
+ >
203
+ {copyingStatus === 'loading' && <LoaderIcon size={16} />}
204
+ {copyingStatus === 'copied' && <CheckIcon size={16} />}
205
+ {copyingStatus === 'idle' && <CopyIcon size={16} />}
206
+ </div>
207
+ <Text
208
+ size="regular"
209
+ onClick={() => onCopyAsMarkdownClick({ setCopyingStatus })}
210
+ className={styles.llmButtonText}
211
+ >
212
+ {getButtonText({ status: copyingStatus })}
213
+ </Text>
214
+ <div {...props} className={styles.chevronIconWrapper}>
215
+ <ChevronDownIcon
216
+ size="16"
217
+ color={theme.color.neutral.icon}
218
+ className={styles.chevronIcon}
219
+ ref={chevronIconRef}
220
+ />
221
+ </div>
222
+ </div>
223
+ </div>
224
+ );
225
+
226
+ const Option = ({ Icon, label, description, showExternalIcon }) => (
227
+ <div className={styles.menuOption}>
228
+ <Icon size={16} className={styles.menuOptionIcon} />
229
+ <div className={styles.menuOptionText}>
230
+ <Text size="regular">{label}</Text>
231
+ <Text size="small" color={theme.color.neutral.textSubtle}>
232
+ {description}
233
+ </Text>
13
234
  </div>
235
+ {showExternalIcon && (
236
+ <ExternalLinkIcon
237
+ size={16}
238
+ className={styles.menuOptionExternalIcon}
239
+ />
240
+ )}
241
+ </div>
242
+ );
243
+
244
+ export default function LLMButtons({ isApiReferencePage = false }) {
245
+ const [copyingStatus, setCopyingStatus] = useState('idle');
246
+ const chevronIconRef = React.useRef(null);
247
+
248
+ const onMenuOptionClick = useCallback((value) => {
249
+ switch (value) {
250
+ case 'copyForLLM':
251
+ onCopyAsMarkdownClick({ setCopyingStatus });
252
+ break;
253
+ case 'viewAsMarkdown':
254
+ onViewAsMarkdownClick();
255
+ break;
256
+ case 'openInChatGPT':
257
+ onOpenInChatGPTClick();
258
+ break;
259
+ case 'openInClaude':
260
+ onOpenInClaudeClick();
261
+ break;
262
+ case 'openInPerplexity':
263
+ onOpenInPerplexityClick();
264
+ break;
265
+ default:
266
+ break;
267
+ }
268
+ }, []);
269
+
270
+ return (
271
+ <Menu
272
+ className={clsx(styles.llmMenu, {
273
+ [styles.llmMenuApiReferencePage]: isApiReferencePage,
274
+ })}
275
+ onMenuOpen={(isOpen) => chevronIconRef.current?.classList.toggle(
276
+ styles.chevronIconOpen,
277
+ isOpen,
278
+ )
279
+ }
280
+ components={{
281
+ MenuBase: (props) => (
282
+ <MenuBase
283
+ copyingStatus={copyingStatus}
284
+ setCopyingStatus={setCopyingStatus}
285
+ chevronIconRef={chevronIconRef}
286
+ {...props}
287
+ />
288
+ ),
289
+ }}
290
+ onSelect={onMenuOptionClick}
291
+ options={DROPDOWN_OPTIONS}
292
+ renderOption={Option}
293
+ />
14
294
  );
15
295
  }
@@ -1,57 +1,115 @@
1
- .llmButtonsContainer {
1
+ :global .menu-list[data-floating-ui-focusable] {
2
+ gap: 0.4rem;
3
+ padding: 0.6rem;
4
+ }
5
+
6
+ .llmMenu {
7
+ margin-top: 1.2rem;
8
+ width: fit-content;
9
+
10
+ @media (min-width: 768px) {
11
+ margin-left: auto;
12
+ }
13
+ }
14
+
15
+ .llmButtonWrapper {
2
16
  display: flex;
3
- align-items: center;
4
- gap: 12px;
5
- margin-top: -8px;
6
- margin-bottom: calc(var(--ifm-h1-vertical-rhythm-bottom) * var(--ifm-leading));
17
+ justify-content: flex-end;
18
+
19
+ @media (min-width: 768px) {
20
+ /* hack to make the dropdown menu align to the right */
21
+ width: 23.3rem;
22
+ }
7
23
  }
8
24
 
9
- .llmButtonsSeparator {
10
- width: 1px;
11
- height: 16px;
12
- background-color: var(--ifm-hr-background-color);
25
+ .llmMenuApiReferencePage {
26
+ margin-top: -0.8rem;
27
+ margin-bottom: calc(var(--ifm-h1-vertical-rhythm-bottom) * var(--ifm-leading));
28
+ margin-left: 0 !important;
29
+ .llmButtonWrapper {
30
+ width: fit-content !important;
31
+ }
13
32
  }
14
33
 
15
34
  .llmButton {
35
+ width: fit-content;
36
+ display: inline-flex;
37
+ align-items: center;
38
+ height: 3rem;
39
+
16
40
  display: flex;
17
41
  align-items: center;
18
- background-color: transparent;
19
- border: none;
20
- height: 16px;
42
+ border-radius: 8px;
43
+ border: 1px solid var(--color-Neutral_SeparatorSubtle);
44
+ background-color: var(--color-Neutral_BackgroundMuted);
45
+
21
46
  cursor: pointer;
22
- padding: 0;
23
- gap: 4px;
47
+ transition: background-color 0.2s ease-in-out;
48
+
49
+ &:hover {
50
+ background-color: var(--color-Neutral_BackgroundMuted);
51
+ }
24
52
  }
25
53
 
26
- .llmButtonIcon {
27
- width: 16px;
28
- height: 16px;
29
- margin: 0 !important;
30
- cursor: pointer;
31
- background-size: contain;
32
- background-repeat: no-repeat;
33
- background-position: center;
34
- display: inline-block;
54
+ .copyUpIconWrapper {
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ padding-left: 0.8rem;
59
+ padding-right: 0.4rem;
60
+ height: 100%;
61
+ }
62
+
63
+ .llmButtonText {
64
+ height: 100%;
65
+ display: flex;
66
+ align-items: center;
67
+ padding-right: 0.8rem;
68
+ min-width: 9.3rem;
69
+
70
+ /* prevents font size glitch when loading the page */
71
+ margin: 0px;
72
+ font-size: 1.4rem;
73
+ font-weight: 400;
74
+ font-family: Inter, sans-serif;
35
75
  }
36
76
 
37
- .llmButtonIconBackgroundMarkdown {
38
- background-image: url('https://docs.apify.com/img/markdown.svg');
77
+ .chevronIconWrapper {
78
+ border-left: 1px solid var(--color-Neutral_SeparatorSubtle);
79
+ display: flex;
80
+ align-items: center;
81
+ justify-content: center;
82
+ padding-inline: 0.8rem;
83
+ height: 100%;
84
+ }
39
85
 
86
+ .chevronIcon {
87
+ transition: transform 0.2s ease-in-out;
40
88
  }
41
89
 
42
- .llmButtonIconBackgroundCopy {
43
- background-image: url('https://docs.apify.com/img/copy.svg');
90
+ .chevronIconOpen {
91
+ transform: rotate(180deg);
44
92
  }
45
93
 
46
- /* Dark theme adjustments */
47
- [data-theme='dark'] .llmButtonIcon {
48
- color: #e0e0e0;
94
+ .menuOption {
95
+ padding-block: 0.4rem;
96
+ display: flex;
97
+ gap: 0.4rem;
49
98
  }
50
99
 
51
- [data-theme='dark'] .llmButtonIconBackgroundMarkdown {
52
- background-image: url('https://docs.apify.com/img/markdown-dark-theme.svg');
100
+ .menuOptionIcon {
101
+ flex-shrink: 0;
102
+ margin-top: 0.4rem;
103
+ }
104
+
105
+ .menuOptionText {
106
+ flex: 1;
107
+ display: flex;
108
+ flex-direction: column;
109
+ gap: 0.2rem;
53
110
  }
54
111
 
55
- [data-theme='dark'] .llmButtonIconBackgroundCopy {
56
- background-image: url('https://docs.apify.com/img/copy-dark-theme.svg');
112
+ .menuOptionExternalIcon {
113
+ flex-shrink: 0;
114
+ margin-top: 0.2rem;
57
115
  }
@@ -1740,18 +1740,6 @@ html[data-theme='dark'] .runnable-code-block svg .apify-logo {
1740
1740
 
1741
1741
  }
1742
1742
 
1743
- .redocusaurus table code {
1744
- word-break: normal;
1745
- }
1746
-
1747
- .redocusaurus .menu-content div:nth-child(2) ul {
1748
- padding-bottom: 0;
1749
- }
1750
-
1751
- .redocusaurus .menu-content div:nth-child(2) div {
1752
- display: none;
1753
- }
1754
-
1755
1743
  .apiPage .tsd-panel-header .tsd-anchor-id {
1756
1744
  top: -13rem;
1757
1745
  }
@@ -1763,44 +1751,40 @@ iframe[src*="youtube"] {
1763
1751
  margin-bottom: 1.6rem;
1764
1752
  }
1765
1753
 
1766
- .redocusaurus div[data-section-id] span[id] {
1767
- margin-top: -130px;
1768
- position: absolute;
1769
- }
1770
-
1771
- .redocusaurus .openapi-clients-box {
1754
+ .theme-api-markdown .openapi-clients-box {
1772
1755
  display: block;
1773
1756
  float: right;
1774
- padding-left: 6px;
1757
+ padding-left: 12px;
1758
+ padding-right: 6px;
1775
1759
  }
1776
1760
 
1777
- .redocusaurus .openapi-clients-box-heading {
1778
- display: inline-block;
1779
- font-family: 'San Francisco', Helvetica, Arial, sans-serif;
1780
- color: #6C7590;
1781
- font-style: normal;
1782
- font-weight: 700;
1783
- font-size: 14px;
1784
- line-height: 20px;
1785
- text-transform: uppercase;
1786
- padding-bottom: 6px;
1761
+ .client-docs-link img {
1762
+ border: 1px solid var(--color-neutral-action-secondary);
1763
+ border-radius: 8px;
1787
1764
  }
1788
1765
 
1789
- .redocusaurus .openapi-clients-box-icon {
1790
- display: block;
1791
- padding-bottom: 6px;
1766
+ .client-docs-link {
1767
+ display: flex;
1768
+ flex-direction: row;
1769
+ align-items: center;
1770
+ justify-content: left;
1771
+ gap: 8px;
1772
+ padding: 4px 8px 8px 0px;
1792
1773
  }
1793
1774
 
1794
- .theme-api-markdown .openapi-clients-box {
1795
- display: block;
1796
- float: right;
1797
- padding-left: 6px;
1775
+ a.client-docs-link {
1776
+ font-weight: 500;
1777
+ color: var(--color-neutral-text-muted);
1778
+ }
1779
+
1780
+ .theme-admonition {
1781
+ clear: right;
1798
1782
  }
1799
1783
 
1800
1784
  .theme-api-markdown .openapi-clients-box-heading {
1801
1785
  display: inline-block;
1802
1786
  font-family: 'San Francisco', Helvetica, Arial, sans-serif;
1803
- color: #6C7590;
1787
+ color: var(--color-neutral-text-muted);
1804
1788
  font-style: normal;
1805
1789
  font-weight: 700;
1806
1790
  font-size: 14px;
@@ -1811,7 +1795,7 @@ iframe[src*="youtube"] {
1811
1795
 
1812
1796
  .theme-api-markdown .openapi-clients-box-icon {
1813
1797
  display: block;
1814
- padding-bottom: 6px;
1798
+ padding: 2px;
1815
1799
  margin: 0 !important;
1816
1800
  }
1817
1801
 
@@ -1,71 +0,0 @@
1
- import React, { useState } from 'react';
2
-
3
- import styles from '../styles.module.css';
4
-
5
- // Custom component for button text
6
- function ButtonText({ isLoading, isCopied }) {
7
- if (isLoading) {
8
- return 'Copying...';
9
- }
10
- if (isCopied) {
11
- return 'Copied!';
12
- }
13
- return 'Copy for LLM';
14
- }
15
-
16
- export default function CopyForLLM() {
17
- const [isLoading, setIsLoading] = useState(false);
18
- const [isCopied, setIsCopied] = useState(false);
19
-
20
- const handleCopy = async () => {
21
- if (window.analytics) {
22
- window.analytics.track('Clicked', {
23
- app: 'docs',
24
- button_text: 'Copy for LLM',
25
- element: 'llm-buttons.copyForLLM',
26
- });
27
- }
28
-
29
- try {
30
- setIsLoading(true);
31
-
32
- const currentUrl = window.location.href;
33
- const markdownUrl = `${currentUrl}.md`;
34
-
35
- // Fetch the markdown content
36
- const response = await fetch(markdownUrl);
37
-
38
- if (!response.ok) {
39
- throw new Error(`Failed to fetch markdown: ${response.status}`);
40
- }
41
-
42
- const markdownContent = await response.text();
43
-
44
- // Copy to clipboard
45
- await navigator.clipboard.writeText(markdownContent);
46
-
47
- // Show success feedback
48
- setIsCopied(true);
49
- setTimeout(() => setIsCopied(false), 2000);
50
- } catch (error) {
51
- console.error('Failed to copy markdown content:', error);
52
- } finally {
53
- setIsLoading(false);
54
- }
55
- };
56
-
57
- return (
58
- <button
59
- className={styles.llmButton}
60
- title="Copy for LLM"
61
- onClick={handleCopy}
62
- disabled={isLoading}
63
- >
64
- <span
65
- className={`${styles.llmButtonIcon} ${styles.llmButtonIconBackgroundCopy}`}
66
- aria-label="Copy for LLM"
67
- />
68
- <ButtonText isLoading={isLoading} isCopied={isCopied} />
69
- </button>
70
- );
71
- }
@@ -1,37 +0,0 @@
1
- import React from 'react';
2
-
3
- import styles from '../styles.module.css';
4
-
5
- export default function ViewAsMarkdown() {
6
- const handleClick = () => {
7
- if (window.analytics) {
8
- window.analytics.track('Clicked', {
9
- app: 'docs',
10
- button_text: 'View as Markdown',
11
- element: 'llm-buttons.viewAsMarkdown',
12
- });
13
- }
14
-
15
- try {
16
- const currentUrl = window.location.href;
17
- const markdownUrl = `${currentUrl}.md`;
18
- window.open(markdownUrl, '_blank');
19
- } catch (error) {
20
- console.error('Error opening markdown file:', error);
21
- }
22
- };
23
-
24
- return (
25
- <button
26
- className={styles.llmButton}
27
- title="View as Markdown"
28
- onClick={handleClick}
29
- >
30
- <span
31
- className={`${styles.llmButtonIcon} ${styles.llmButtonIconBackgroundMarkdown}`}
32
- aria-label="View as Markdown"
33
- />
34
- View as Markdown
35
- </button>
36
- );
37
- }