Skip to content

Commit ef0aa81

Browse files
authored
feat(ui): inline code block feedback (#8493)
1 parent 640051a commit ef0aa81

File tree

18 files changed

+51
-312
lines changed

18 files changed

+51
-312
lines changed

apps/site/components/Common/CodeBox.tsx

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
'use client';
22

3-
import { CodeBracketIcon } from '@heroicons/react/24/outline';
3+
import {
4+
DocumentDuplicateIcon,
5+
CodeBracketIcon,
6+
} from '@heroicons/react/24/outline';
47
import BaseCodeBox from '@node-core/ui-components/Common/BaseCodeBox';
5-
import styles from '@node-core/ui-components/Common/BaseCodeBox/index.module.css';
6-
import { useNotification } from '@node-core/ui-components/Providers/NotificationProvider';
78
import { useTranslations } from 'next-intl';
89

910
import Link from '#site/components/Link';
@@ -14,34 +15,29 @@ import type { FC, PropsWithChildren } from 'react';
1415
type CodeBoxProps = {
1516
language: string;
1617
className?: string;
17-
showCopyButton?: boolean;
1818
};
1919

2020
const CodeBox: FC<PropsWithChildren<CodeBoxProps>> = props => {
21-
const [, copyToClipboard] = useCopyToClipboard();
22-
const notify = useNotification();
21+
const [copied, copyToClipboard] = useCopyToClipboard();
2322
const t = useTranslations();
2423

25-
const onCopy = (text: string) => {
26-
copyToClipboard(text);
27-
28-
notify({
29-
duration: 800,
30-
message: (
31-
<div className="flex items-center gap-3">
32-
<CodeBracketIcon className={styles.icon} />
33-
{t('components.common.codebox.copied')}
34-
</div>
35-
),
36-
});
37-
};
24+
const ButtonIcon = copied ? DocumentDuplicateIcon : CodeBracketIcon;
3825

3926
return (
4027
<BaseCodeBox
4128
as={Link}
42-
onCopy={onCopy}
29+
onCopy={copyToClipboard}
30+
buttonContent={
31+
<>
32+
<ButtonIcon className="size-4" />
33+
{t(
34+
copied
35+
? 'components.common.codebox.copied'
36+
: 'components.common.codebox.copy'
37+
)}
38+
</>
39+
}
4340
{...props}
44-
buttonText={t('components.common.codebox.copy')}
4541
/>
4642
);
4743
};

apps/site/components/MDX/CodeBox/index.tsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,17 @@ import { getLanguageDisplayName } from '@node-core/rehype-shiki';
22

33
import CodeBox from '#site/components/Common/CodeBox';
44

5-
import type { FC, PropsWithChildren } from 'react';
5+
import type { FC, HTMLAttributes } from 'react';
66

7-
type CodeBoxProps = { className?: string; showCopyButton?: string };
8-
9-
const MDXCodeBox: FC<PropsWithChildren<CodeBoxProps>> = ({
7+
const MDXCodeBox: FC<HTMLAttributes<HTMLElement>> = ({
108
children: code,
119
className,
12-
showCopyButton,
1310
}) => {
1411
const matches = className?.match(/language-(?<language>[a-zA-Z]+)/);
1512
const language = matches?.groups?.language ?? '';
1613

1714
return (
18-
<CodeBox
19-
language={getLanguageDisplayName(language)}
20-
showCopyButton={showCopyButton ? showCopyButton === 'true' : undefined}
21-
className={className}
22-
>
15+
<CodeBox language={getLanguageDisplayName(language)} className={className}>
2316
{code}
2417
</CodeBox>
2518
);

apps/site/layouts/Base.tsx

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
1-
'use client';
2-
3-
import { NotificationProvider } from '@node-core/ui-components/Providers/NotificationProvider';
4-
51
import { NavigationStateProvider } from '#site/providers/navigationStateProvider';
62

73
import type { FC, PropsWithChildren } from 'react';
84

95
import styles from './layouts.module.css';
106

117
const BaseLayout: FC<PropsWithChildren> = ({ children }) => (
12-
<NotificationProvider>
13-
<NavigationStateProvider>
14-
<div className={styles.baseLayout}>{children}</div>
15-
</NavigationStateProvider>
16-
</NotificationProvider>
8+
<NavigationStateProvider>
9+
<div className={styles.baseLayout}>{children}</div>
10+
</NavigationStateProvider>
1711
);
1812

1913
export default BaseLayout;

apps/site/next.config.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ const nextConfig = {
7171
'@radix-ui/react-label',
7272
'@radix-ui/react-select',
7373
'@radix-ui/react-tabs',
74-
'@radix-ui/react-toast',
7574
'@radix-ui/react-tooltip',
7675
'@radix-ui/react-avatar',
7776
'@orama/highlight',

packages/rehype-shiki/src/plugin.mjs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,15 +181,6 @@ export default async function rehypeShikiji(options) {
181181
codeLanguage
182182
);
183183

184-
// Adds a Copy Button to the CodeBox if requested as an additional parameter
185-
// And avoids setting the property (overriding) if undefined or invalid value
186-
if (
187-
meta.showCopyButton &&
188-
['true', 'false'].includes(meta.showCopyButton)
189-
) {
190-
children[0].properties.showCopyButton = meta.showCopyButton;
191-
}
192-
193184
// Replaces the <pre> element with the updated one
194185
parent.children.splice(index, 1, ...children);
195186
});

packages/ui-components/.storybook/preview.tsx

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { withThemeByDataAttribute } from '@storybook/addon-themes';
22

3-
import { NotificationProvider } from '#ui/Providers/NotificationProvider';
4-
53
import type { Preview, ReactRenderer } from '@storybook/react-webpack5';
64

75
import { STORYBOOK_MODES, STORYBOOK_SIZES } from './constants';
@@ -17,11 +15,6 @@ const preview: Preview = {
1715
},
1816

1917
decorators: [
20-
Story => (
21-
<NotificationProvider>
22-
<Story />
23-
</NotificationProvider>
24-
),
2518
withThemeByDataAttribute<ReactRenderer>({
2619
themes: { light: '', dark: 'dark' },
2720
defaultTheme: 'light',

packages/ui-components/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@node-core/ui-components",
3-
"version": "1.4.4",
3+
"version": "1.5.0",
44
"type": "module",
55
"exports": {
66
"./*": [
@@ -44,7 +44,6 @@
4444
"@radix-ui/react-select": "~2.2.6",
4545
"@radix-ui/react-separator": "~1.1.8",
4646
"@radix-ui/react-tabs": "~1.1.13",
47-
"@radix-ui/react-toast": "~1.2.15",
4847
"@radix-ui/react-tooltip": "~1.2.8",
4948
"@tailwindcss/postcss": "~4.1.18",
5049
"@vcarl/remark-headings": "~0.1.0",

packages/ui-components/src/Common/BaseCodeBox/index.module.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,3 @@
7878
}
7979
}
8080
}
81-
82-
.icon {
83-
@apply size-4;
84-
}

packages/ui-components/src/Common/BaseCodeBox/index.stories.tsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,10 @@ server.listen(port, hostname, () => {
2020
console.log(\`Server running at http://\${hostname}:\${port}/\`);
2121
});`;
2222

23-
const args = {
24-
language: 'JavaScript (CJS)',
25-
children: <code>{content}</code>,
26-
};
27-
2823
export const Default: Story = {
29-
args,
30-
};
31-
32-
export const WithCopyButton: Story = {
3324
args: {
34-
...args,
35-
showCopyButton: true,
25+
language: 'JavaScript (CJS)',
26+
children: <code>{content}</code>,
3627
},
3728
};
3829

packages/ui-components/src/Common/BaseCodeBox/index.tsx

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
'use client';
22

3-
import { DocumentDuplicateIcon } from '@heroicons/react/24/outline';
43
import classNames from 'classnames';
54
import { Fragment, isValidElement, useRef } from 'react';
65

76
import BaseButton from '#ui/Common/BaseButton';
87

98
import type { LinkLike } from '#ui/types';
10-
import type { FC, PropsWithChildren, ReactElement } from 'react';
9+
import type { FC, PropsWithChildren, ReactElement, ReactNode } from 'react';
1110

1211
import styles from './index.module.css';
1312

@@ -69,18 +68,16 @@ type CodeBoxProps = {
6968
className?: string;
7069
onCopy: (text: string) => void;
7170
as?: LinkLike;
72-
buttonText: string;
73-
showCopyButton?: boolean;
71+
buttonContent: ReactNode;
7472
};
7573

7674
const BaseCodeBox: FC<PropsWithChildren<CodeBoxProps>> = ({
7775
children,
7876
language,
7977
className,
8078
onCopy,
81-
buttonText,
79+
buttonContent,
8280
as = 'a',
83-
showCopyButton = true,
8481
}: PropsWithChildren<CodeBoxProps>) => {
8582
const containerRef = useRef<HTMLPreElement>(null);
8683

@@ -103,17 +100,14 @@ const BaseCodeBox: FC<PropsWithChildren<CodeBoxProps>> = ({
103100
{language && (
104101
<div className={styles.footer}>
105102
<span className={styles.language}>{language}</span>
106-
{showCopyButton && (
107-
<BaseButton
108-
as={as}
109-
className={styles.action}
110-
kind="neutral"
111-
onClick={handleCopy}
112-
>
113-
<DocumentDuplicateIcon className={styles.icon} />
114-
{buttonText}
115-
</BaseButton>
116-
)}
103+
<BaseButton
104+
as={as}
105+
className={styles.action}
106+
kind="neutral"
107+
onClick={handleCopy}
108+
>
109+
{buttonContent}
110+
</BaseButton>
117111
</div>
118112
)}
119113
</div>

0 commit comments

Comments
 (0)