Skip to content

Commit 58a7a2b

Browse files
committed
feat: style tweaks, add quick copy button
1 parent ac045c8 commit 58a7a2b

12 files changed

+116
-12
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
"react-loadable": "5.5.0",
8787
"react-masonry-css": "1.0.16",
8888
"react-multivalue-text-input": "1.0.0",
89+
"react-tooltip": "4.2.21",
8990
"readable-stream": "3.6.0",
9091
"redoc": "2.0.0-rc.55",
9192
"stream-browserify": "3.0.0",

src/components/HeaderLink.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ const HeaderLink = ({
1919
<Icon icon='docsRing' size='2xs' className={classNames(colorClass, 'mr-2')}/>
2020
</div>
2121
)}
22-
<Link colorClassName={'text-black'} to={link}>{text}</Link>
22+
<div className='text-left'>
23+
<Link colorClassName={'text-black'} to={link}>{text}</Link>
24+
</div>
2325
</li>
2426
)
2527
}

src/components/Icon.js

+4
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import Automate from './icon/Automate'
44
import Bars from './icon/Bars'
55
import Behance from './icon/Behance'
66
import CaretRight from './icon/CaretRight'
7+
import Check from './icon/Check'
78
import Clock from './icon/Clock'
89
import Close from './icon/Close'
10+
import Copy from './icon/Copy'
911
import Discord from './icon/Discord'
1012
import DocsRing from './icon/DocsRing'
1113
import Github from './icon/Github'
@@ -22,8 +24,10 @@ const Icon = (props) => {
2224
bars: <Bars {...props} />,
2325
behance: <Behance {...props} />,
2426
caretRight: <CaretRight {...props} />,
27+
check: <Check {...props} />,
2528
clock: <Clock {...props} />,
2629
close: <Close {...props} />,
30+
copy: <Copy {...props} />,
2731
discord: <Discord {...props} />,
2832
docsRing: <DocsRing {...props} />,
2933
github: <Github {...props} />,

src/components/icon/Check.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from 'react'
2+
import CustomIcon from '../CustomIcon'
3+
4+
const Check = (props) => (
5+
<CustomIcon {...props}>
6+
<path d="M20 6.61938L9 17.6194L4 12.6194" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
7+
</CustomIcon>
8+
)
9+
10+
export default Check

src/components/icon/Copy.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react'
2+
import CustomIcon from '../CustomIcon'
3+
4+
const Copy = (props) => (
5+
<CustomIcon {...props}>
6+
<path d="M20 10H11C9.89543 10 9 10.8954 9 12V21C9 22.1046 9.89543 23 11 23H20C21.1046 23 22 22.1046 22 21V12C22 10.8954 21.1046 10 20 10Z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
7+
<path d="M5 16H4C3.46957 16 2.96086 15.7893 2.58579 15.4142C2.21071 15.0391 2 14.5304 2 14V5C2 4.46957 2.21071 3.96086 2.58579 3.58579C2.96086 3.21071 3.46957 3 4 3H13C13.5304 3 14.0391 3.21071 14.4142 3.58579C14.7893 3.96086 15 4.46957 15 5V6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
8+
</CustomIcon>
9+
)
10+
11+
export default Copy

src/components/mdxComponents/codeBlock.js

+53-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
import * as React from 'react'
1+
import React, { useState, useRef } from 'react'
22
import classNames from 'classnames'
33
import Highlight, { defaultProps } from 'prism-react-renderer'
44
import prismTheme from 'prism-react-renderer/themes/github'
55
import Loadable from 'react-loadable'
6+
import ReactTooltip from 'react-tooltip'
7+
68
import LoadingProvider from './loading'
9+
import Icon from '../Icon'
710

811
// override background and default text color
912
prismTheme.plain = {
@@ -30,10 +33,30 @@ const LoadableComponent = Loadable({
3033
})
3134

3235
/* eslint-disable react/jsx-key */
33-
const CodeBlock = ({ children: exampleCode, className, containerClassName, ...props }) => {
36+
const CodeBlock = ({
37+
children: exampleCode,
38+
className,
39+
containerClassName,
40+
id = '',
41+
copyable = false,
42+
...props
43+
}) => {
3444
const match = className.match(/language-(\w*)/)
3545
const language = match ? match[1] : 'text'
3646

47+
const tooltipEl = useRef(null)
48+
const [copySuccess, setCopySuccess] = useState(false)
49+
50+
const copyToClipboard = (text) => {
51+
navigator.clipboard.writeText(text)
52+
setCopySuccess(true)
53+
ReactTooltip.show(tooltipEl.current)
54+
setTimeout(() => {
55+
setCopySuccess(false)
56+
ReactTooltip.hide(tooltipEl.current)
57+
}, 2000)
58+
}
59+
3760
let title = ''
3861
if (className?.includes('title=')) {
3962
title = className.split('title=')[1]
@@ -45,7 +68,7 @@ const CodeBlock = ({ children: exampleCode, className, containerClassName, ...pr
4568
)
4669
} else {
4770
return (
48-
<div className={classNames(containerClassName, 'bg-qrigray-100')}>
71+
<div className={classNames(containerClassName, 'bg-qrigray-100 group relative')}>
4972
{title && (
5073
<div className='border-b px-4 py-2 text-sm'>
5174
{title}
@@ -110,6 +133,33 @@ const CodeBlock = ({ children: exampleCode, className, containerClassName, ...pr
110133
)}
111134
</Highlight>
112135
</div>
136+
{
137+
copyable && (
138+
<>
139+
<div
140+
className={classNames('group-hover:visible absolute bottom-4 right-4 rounded bg-white p-1.5 text-center text-black hover:cursor-pointer', {
141+
invisible: !copySuccess
142+
})}
143+
style={{ height: 34, width: 34 }}
144+
onClick={() => { copyToClipboard(exampleCode) }}
145+
data-tip='Copied!'
146+
data-for={id}
147+
data-event='noevent'
148+
ref={tooltipEl}
149+
>
150+
{!copySuccess && <Icon icon='copy' size='sm' />}
151+
{copySuccess && <Icon icon='check' size='sm' className='text-green-600' />}
152+
</div>
153+
<ReactTooltip
154+
id={id}
155+
effect='solid'
156+
place='bottom'
157+
padding='2px'
158+
className='codeblock-tooltip'
159+
/>
160+
</>
161+
)
162+
}
113163
</div>
114164
)
115165
}

src/components/snippets/Snippet.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const Snippet = ({ snippet }) => (
1515
<TagChips tags={snippet.tags} />
1616
</div>
1717
<div className='rounded-lg mb-10 overflow-hidden'>
18-
<CodeBlock containerClassName='p-5' className='language-python text-sm'>{snippet.code}</CodeBlock>
18+
<CodeBlock id={snippet.id} containerClassName='p-5' className='language-python text-sm' copyable>{snippet.code}</CodeBlock>
1919
</div>
2020
</>
2121

src/components/snippets/SnippetCard.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import CodeBlock from '../mdxComponents/CodeBlock'
55
import AnchorTag from '../mdxComponents/AnchorTag'
66
import Link from '../Link'
77
import TagChips from '../TagChips'
8+
import Icon from '../Icon'
89
import markdownComponents from '../mdxComponents'
910

1011
export const markdownOptions = {
@@ -23,14 +24,19 @@ const TransformSnippetCard = ({ snippet }) => {
2324
>
2425
<div className='px-5 py-5'>
2526
<Link to={`/docs/transform-snippets/${id}`}>
26-
<div className='font-bold text-lg mb-2.5'>{title}</div>
27+
<div className='flex items-start'>
28+
<div className='flex-shrink-0'>
29+
<Icon icon='docsRing' size='3xs' className='mr-2 text-qrinavy-700 -mt-0.5'/>
30+
</div>
31+
<div className='font-bold text-black mb-2 tracking-wide'>{title}</div>
32+
</div>
2733
</Link>
2834
<div className='text-xs mb-2.5 text-qrigray-400'>
2935
<Markdown options={markdownOptions}>{description}</Markdown>
3036
</div>
3137
<div>{tags && <TagChips tags={tags}/>}</div>
3238
</div>
33-
<CodeBlock containerClassName='p-5' className='language-python text-sm'>{code}</CodeBlock>
39+
<CodeBlock id={id} containerClassName='p-5' className='language-python text-sm' copyable>{code}</CodeBlock>
3440
</div>
3541
)
3642
}

src/components/snippets/SnippetEditor.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const SnippetEditor = ({ snippet }) => {
3333
navigate(`/docs/transform-snippets/${id}`)
3434
}
3535
} else {
36-
const res = createSnippet(body, token)
36+
const res = await createSnippet(body, token)
3737

3838
if (res.meta?.code === 200) {
3939
navigate(`/docs/transform-snippets/${id}`)

src/scss/style.scss

+6
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,9 @@ body {
218218
-ms-overflow-style: none; /* IE and Edge */
219219
scrollbar-width: none; /* Firefox */
220220
}
221+
222+
/* custom styles for codeblock tooltip, used in code snippets */
223+
.codeblock-tooltip {
224+
padding: 2px 4px !important;
225+
font-size: 12px !important;
226+
}

tailwind.config.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ module.exports = {
193193
cursor: ['hover'],
194194
borderWidth: ['last'],
195195
margin: ['last'],
196-
padding: ['first', 'last']
196+
padding: ['first', 'last'],
197+
visibility: ['group-hover']
197198
}
198199
},
199200
plugins: [

yarn.lock

+16-3
Original file line numberDiff line numberDiff line change
@@ -10556,7 +10556,7 @@ gatsby-plugin-typescript@^3.9.0:
1055610556
"@babel/runtime" "^7.14.0"
1055710557
babel-plugin-remove-graphql-queries "^3.9.0"
1055810558

10559-
gatsby-plugin-use-query-params@^1.0.1:
10559+
1056010560
version "1.0.1"
1056110561
resolved "https://registry.yarnpkg.com/gatsby-plugin-use-query-params/-/gatsby-plugin-use-query-params-1.0.1.tgz#5e4982580d2e9bad15d243186cff379afef8a207"
1056210562
integrity sha512-k3xaKuf8VhLq6/arocYRZqiQMTQ84ZRY0JklsO4tuKsRqi64b94zGf6B8SZn6yo0fvtJ/zw684DpH77y/iKdbA==
@@ -17293,7 +17293,7 @@ [email protected]:
1729317293
resolved "https://registry.yarnpkg.com/react-masonry-css/-/react-masonry-css-1.0.16.tgz#72b28b4ae3484e250534700860597553a10f1a2c"
1729417294
integrity sha512-KSW0hR2VQmltt/qAa3eXOctQDyOu7+ZBevtKgpNDSzT7k5LA/0XntNa9z9HKCdz3QlxmJHglTZ18e4sX4V8zZQ==
1729517295

17296-
react-multivalue-text-input@^1.0.0:
17296+
1729717297
version "1.0.0"
1729817298
resolved "https://registry.yarnpkg.com/react-multivalue-text-input/-/react-multivalue-text-input-1.0.0.tgz#d4ecda3e4a3d2415bfd4df4f6cef5bd389e7c43e"
1729917299
integrity sha512-h/QWdyktrLG7hwMq2YtHShApPRyuNNtjFr4LZ4EJOkmSfrnAYOFwrBUcN6Shca7zOcOKuQhe+ZEgXGvcOkjXxA==
@@ -17349,6 +17349,14 @@ react-tabs@^3.2.2:
1734917349
clsx "^1.1.0"
1735017350
prop-types "^15.5.0"
1735117351

17352+
react-tooltip@^4.2.21:
17353+
version "4.2.21"
17354+
resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-4.2.21.tgz#840123ed86cf33d50ddde8ec8813b2960bfded7f"
17355+
integrity sha512-zSLprMymBDowknr0KVDiJ05IjZn9mQhhg4PRsqln0OZtURAJ1snt1xi5daZfagsh6vfsziZrc9pErPTDY1ACig==
17356+
dependencies:
17357+
prop-types "^15.7.2"
17358+
uuid "^7.0.3"
17359+
1735217360
react-transition-group@^4.0.0:
1735317361
version "4.3.0"
1735417362
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.3.0.tgz#fea832e386cf8796c58b61874a3319704f5ce683"
@@ -20717,7 +20725,7 @@ use-debounce@^7.0.0:
2071720725
resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-7.0.0.tgz#00a67d23d4fe09905e11145a99278da06c01c880"
2071820726
integrity sha512-4fvxEEs7ztdNMh+c497HAgysdq2+Ascem6EaDANGlCIap1JzqfL03Xw8xkYc2lShfXm4uO6PA6V5zcXN7gJdFA==
2071920727

20720-
use-query-params@^1.2.3:
20728+
2072120729
version "1.2.3"
2072220730
resolved "https://registry.yarnpkg.com/use-query-params/-/use-query-params-1.2.3.tgz#306c31a0cbc714e8a3b4bd7e91a6a9aaccaa5e22"
2072320731
integrity sha512-cdG0tgbzK+FzsV6DAt2CN8Saa3WpRnze7uC4Rdh7l15epSFq7egmcB/zuREvPNwO5Yk80nUpDZpiyHsoq50d8w==
@@ -20799,6 +20807,11 @@ [email protected], uuid@^3.4.0:
2079920807
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
2080020808
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
2080120809

20810+
uuid@^7.0.3:
20811+
version "7.0.3"
20812+
resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
20813+
integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
20814+
2080220815
v8-compile-cache@^2.0.3:
2080320816
version "2.1.0"
2080420817
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"

0 commit comments

Comments
 (0)