Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 818031a

Browse filesBrowse files
committed
docs: improve ExampleSnippet component
1 parent 842f2e2 commit 818031a
Copy full SHA for 818031a

File tree

5 files changed

+196
-87
lines changed
Filter options

5 files changed

+196
-87
lines changed

‎packages/docs/gatsby-node.mjs

Copy file name to clipboardExpand all lines: packages/docs/gatsby-node.mjs
+22-1Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
1-
import { resolve } from 'node:path'
1+
import { dirname, resolve } from 'node:path'
2+
import { fileURLToPath } from 'node:url'
23
import { createFilePath } from 'gatsby-source-filesystem'
4+
import { glob } from 'glob'
5+
6+
const __dirname = dirname(fileURLToPath(import.meta.url))
7+
8+
export const onCreateWebpackConfig = ({ actions }) => {
9+
const { setWebpackConfig } = actions
10+
11+
// Find all 'examples' directories
12+
const examplePaths = glob.sync(resolve(__dirname, 'content/**/**/examples'))
13+
14+
// Create Webpack alias
15+
setWebpackConfig({
16+
resolve: {
17+
alias: {
18+
'@assets': resolve(__dirname, 'content/assets'),
19+
'@example': examplePaths, // Adds all paths to a single alias
20+
},
21+
},
22+
})
23+
}
324

425
export const onCreateNode = async ({
526
node,

‎packages/docs/src/components/ExampleSnippet.tsx

Copy file name to clipboardExpand all lines: packages/docs/src/components/ExampleSnippet.tsx
+98-42Lines changed: 98 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import React, { FC, ReactNode, useState } from 'react'
1+
import React, { FC, lazy, ReactNode, Suspense, useEffect, useMemo, useState } from 'react'
22
import { Highlight, Language } from 'prism-react-renderer'
3-
43
import CIcon from '@coreui/icons-react'
54
import { cibCodesandbox, cilCheckAlt, cilCopy } from '@coreui/icons'
65
import { CNav, CNavLink, CTooltip, useClipboard } from '@coreui/react'
7-
86
import { openStackBlitzProject } from '../utils/stackblitz'
97
import { openCodeSandboxProject } from '../utils/codesandbox'
108

@@ -16,8 +14,9 @@ interface CodeSnippets {
1614
export interface ExampleSnippetProps {
1715
children: ReactNode
1816
className?: string
19-
code: string | CodeSnippets
17+
code?: string | CodeSnippets
2018
codeSandbox?: boolean
19+
component?: string
2120
componentName?: string
2221
pro?: boolean
2322
stackBlitz?: boolean
@@ -28,22 +27,62 @@ const ExampleSnippet: FC<ExampleSnippetProps> = ({
2827
className = '',
2928
code,
3029
codeSandbox = true,
30+
component,
3131
componentName,
3232
pro = false,
3333
stackBlitz = true,
3434
}) => {
35+
const [codeJS, setCodeJS] = useState<string>()
36+
const [codeTS, setCodeTS] = useState<string>()
3537
const [language, setLanguage] = useState<'js' | 'ts'>('js')
3638
const { copy, isCopied } = useClipboard()
3739

38-
// Type Guards to determine the shape of 'code' prop
39-
const isCodeString = typeof code === 'string'
40-
const codeJS = isCodeString ? code : code.js || code.ts
41-
const codeTS = isCodeString ? code : code.ts
42-
const hasJS = Boolean(codeJS)
43-
const hasTS = Boolean(codeTS)
40+
const Preview = useMemo(() => {
41+
if (!component) return null
42+
return lazy(() =>
43+
import(`@example/${component}.tsx`)
44+
.then((module) => ({ default: module[component] }))
45+
.catch((error) => {
46+
console.error(`Failed to load Preview component for ${component}:`, error)
47+
return { default: () => <div>Preview not available.</div> }
48+
}),
49+
)
50+
}, [component])
51+
52+
useEffect(() => {
53+
const loadCode = async () => {
54+
if (code) {
55+
if (typeof code === 'string') {
56+
setCodeJS(code)
57+
} else {
58+
setCodeJS(code.js)
59+
setCodeTS(code.ts)
60+
}
61+
} else if (component) {
62+
try {
63+
const tsModule = await import(`!!raw-loader!@example/${component}.tsx`)
64+
setCodeTS(tsModule.default)
65+
setCodeJS(tsModule.default)
66+
} catch (error) {
67+
console.error(`Failed to load TypeScript code for component ${component}:`, error)
68+
}
69+
70+
try {
71+
const jsModule = await import(`!!raw-loader!@example/${component}.jsx`)
72+
setCodeJS(jsModule.default)
73+
} catch {
74+
// JSX version may not exist
75+
}
76+
}
77+
}
78+
79+
loadCode()
80+
}, [code, component])
4481

45-
// Set initial language based on available code snippets
46-
React.useEffect(() => {
82+
const hasJS = codeJS !== undefined && codeJS !== ''
83+
const hasTS = codeTS !== undefined && codeTS !== ''
84+
85+
useEffect(() => {
4786
if (!hasJS && hasTS) {
4887
setLanguage('ts')
4988
} else {
@@ -53,20 +92,35 @@ const ExampleSnippet: FC<ExampleSnippetProps> = ({
5392

5493
const handleCopy = () => {
5594
const codeToCopy = language === 'js' ? codeJS : codeTS
56-
if (codeToCopy) {
57-
copy(codeToCopy)
58-
}
95+
if (codeToCopy) copy(codeToCopy)
5996
}
6097

6198
const prismLanguage: Language = language === 'js' ? 'jsx' : 'tsx'
62-
63-
// Determine if both languages are available
64-
const showJSTab = hasJS && (isCodeString || code.js !== code.ts)
99+
const showJSTab = hasJS && !(typeof code === 'object' && code?.js === code?.ts)
65100
const showTSTab = hasTS
66101

102+
const getProjectName = (): string => {
103+
if (React.isValidElement(children)) {
104+
const childType = (children as React.ReactElement).type
105+
if (typeof childType === 'string') return childType
106+
if (typeof childType === 'function' && childType.name) return childType.name
107+
}
108+
return 'ExampleProject'
109+
}
110+
67111
return (
68112
<div className="docs-example-snippet">
69-
{children && <div className={`docs-example ${className}`}>{children}</div>}
113+
<div className={`docs-example ${className}`}>
114+
{children ? (
115+
children
116+
) : Preview ? (
117+
<Suspense fallback={<div>Loading preview...</div>}>
118+
<Preview />
119+
</Suspense>
120+
) : (
121+
<div>No component specified.</div>
122+
)}
123+
</div>
70124
<div className="highlight-toolbar border-top">
71125
<CNav className="px-3" variant="underline-border">
72126
{showJSTab && (
@@ -88,9 +142,9 @@ const ExampleSnippet: FC<ExampleSnippetProps> = ({
88142
aria-label="Try it on CodeSandbox"
89143
onClick={() =>
90144
openCodeSandboxProject({
91-
name: React.isValidElement(children) && (children as any).type?.name,
145+
name: component || getProjectName(),
92146
language,
93-
code: language === 'js' ? codeJS : codeTS || '',
147+
code: language === 'js' ? codeJS || '' : codeTS || '',
94148
componentName,
95149
pro,
96150
})
@@ -109,9 +163,9 @@ const ExampleSnippet: FC<ExampleSnippetProps> = ({
109163
aria-label="Try it on StackBlitz"
110164
onClick={() =>
111165
openStackBlitzProject({
112-
name: React.isValidElement(children) && (children as any).type?.name,
166+
name: component || getProjectName(),
113167
language,
114-
code: language === 'js' ? codeJS : codeTS || '',
168+
code: language === 'js' ? codeJS || '' : codeTS || '',
115169
componentName,
116170
pro,
117171
})
@@ -148,25 +202,27 @@ const ExampleSnippet: FC<ExampleSnippetProps> = ({
148202
</CNav>
149203
</div>
150204

151-
<div className="highlight">
152-
<Highlight
153-
code={language === 'js' ? codeJS : codeTS || ''}
154-
language={prismLanguage}
155-
theme={{ plain: {}, styles: [] }}
156-
>
157-
{({ className, style, tokens, getLineProps, getTokenProps }) => (
158-
<pre className={className} style={style}>
159-
{tokens.map((line, i) => (
160-
<div {...getLineProps({ line, key: i })} key={i}>
161-
{line.map((token, key) => (
162-
<span {...getTokenProps({ token, key })} key={key} />
163-
))}
164-
</div>
165-
))}
166-
</pre>
167-
)}
168-
</Highlight>
169-
</div>
205+
{(hasJS || hasTS) && (
206+
<div className="highlight">
207+
<Highlight
208+
code={language === 'js' ? codeJS || '' : codeTS || ''}
209+
language={prismLanguage}
210+
theme={{ plain: {}, styles: [] }}
211+
>
212+
{({ className: highlightClass, style, tokens, getLineProps, getTokenProps }) => (
213+
<pre className={highlightClass} style={style}>
214+
{tokens.map((line, i) => (
215+
<div {...getLineProps({ line, key: i })} key={i}>
216+
{line.map((token, key) => (
217+
<span {...getTokenProps({ token, key })} key={key} />
218+
))}
219+
</div>
220+
))}
221+
</pre>
222+
)}
223+
</Highlight>
224+
</div>
225+
)}
170226
</div>
171227
)
172228
}

‎packages/docs/src/utils/codesandbox.ts

Copy file name to clipboardExpand all lines: packages/docs/src/utils/codesandbox.ts
+2-4Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// openCodeSandboxProject.ts
2-
31
import {
42
ProjectOptions,
53
generateTitle,
@@ -25,15 +23,15 @@ export const openCodeSandboxProject = async (options: CodeSandboxOptions) => {
2523
const indexHTML = generateIndexHTML(title)
2624
const indexExtension = language === 'ts' ? 'tsx' : 'js'
2725
const indexJS = generateIndexJS(name, language, pro, 'codesandbox')
28-
const packageJSON = generatePackageJSON(title, description, language, pro, 'codesandbox')
26+
const packageJSON = generatePackageJSON(title, description, language, pro, code, 'codesandbox')
2927

3028
// Define the files structure
3129
const files: Record<string, { content: string }> = {
3230
'public/index.html': {
3331
content: indexHTML,
3432
},
3533
[`src/${name}.${language}x`]: {
36-
content: code,
34+
content: code.replaceAll('@assets/images/', '@coreui/projects-assets/images/'),
3735
},
3836
[`src/index.${indexExtension}`]: {
3937
content: indexJS,

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.