@rspress/plugin-preview 1.0.0-beta.2 → 1.0.0-beta.3

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": "@rspress/plugin-preview",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.3",
4
4
  "description": "A plugin for rspress to preview the code block in markdown/mdx file.",
5
5
  "bugs": "https://github.com/web-infra-dev/rspress/issues",
6
6
  "repository": {
@@ -24,7 +24,9 @@
24
24
  "@modern-js/utils": "2.35.1",
25
25
  "qrcode.react": "^3.1.0",
26
26
  "remark-gfm": "3.0.1",
27
- "@rspress/shared": "1.0.0-beta.2"
27
+ "rspack-plugin-virtual-module": "0.1.12",
28
+ "codesandbox": "2.2.3",
29
+ "@rspress/shared": "1.0.0-beta.3"
28
30
  },
29
31
  "devDependencies": {
30
32
  "@types/mdast": "^3.0.10",
@@ -36,7 +38,6 @@
36
38
  "react": "^18",
37
39
  "react-dom": "^18",
38
40
  "react-router-dom": "^6.8.1",
39
- "rspack-plugin-virtual-module": "0.1.11",
40
41
  "typescript": "^5",
41
42
  "unified": "^10.1.2",
42
43
  "unist-util-visit": "^4.1.1"
@@ -44,7 +45,7 @@
44
45
  "peerDependencies": {
45
46
  "react": ">=17",
46
47
  "react-router-dom": "^6.8.1",
47
- "@rspress/core": "1.0.0-beta.2"
48
+ "@rspress/core": "1.0.0-beta.3"
48
49
  },
49
50
  "files": [
50
51
  "dist",
@@ -42,9 +42,8 @@
42
42
  &.web {
43
43
  display: flex;
44
44
  justify-content: center;
45
- position: absolute;
46
- top: calc(50% - 14px);
47
- right: 16px;
45
+ align-items: center;
46
+ flex: none;
48
47
  }
49
48
  }
50
49
 
@@ -58,6 +57,7 @@
58
57
  position: relative;
59
58
  border: 1px solid #e6e6e6;
60
59
  border-radius: 8px;
60
+ display: flex;
61
61
  }
62
62
 
63
63
  &-qrcode {
@@ -1,17 +1,23 @@
1
1
  import { useCallback, useState } from 'react';
2
2
  import { withBase, useLang, NoSSR } from '@rspress/core/runtime';
3
+ import { getParameters } from 'codesandbox/lib/api/define';
3
4
  import MobileOperation from './common/mobile-operation';
4
5
  import IconCode from './icons/Code';
6
+ import IconCodesandbox from './icons/Codesandbox';
5
7
  import './Container.scss';
6
8
 
7
9
  type ContainerProps = {
8
10
  children: React.ReactNode[];
9
11
  isMobile: 'true' | 'false';
12
+ enableCodesandbox: 'true' | 'false';
10
13
  url: string;
14
+ content: string;
15
+ packageName: string;
11
16
  };
12
17
 
13
18
  const Container: React.FC<ContainerProps> = props => {
14
- const { children, isMobile, url } = props;
19
+ const { children, isMobile, url, content, packageName, enableCodesandbox } =
20
+ props;
15
21
  const [showCode, setShowCode] = useState(false);
16
22
  const lang = useLang();
17
23
 
@@ -34,6 +40,54 @@ const Container: React.FC<ContainerProps> = props => {
34
40
  setIframeKey(Math.random());
35
41
  }, []);
36
42
 
43
+ const gotoCodeSandBox = () => {
44
+ const sandBoxConfig = {
45
+ files: {
46
+ 'package.json': {
47
+ isBinary: false,
48
+ content: JSON.stringify({
49
+ dependencies: {
50
+ react: '18',
51
+ 'react-dom': '18',
52
+ [packageName]: 'latest',
53
+ },
54
+ }),
55
+ },
56
+ [`demo.tsx`]: {
57
+ isBinary: false,
58
+ content,
59
+ },
60
+ [`index.tsx`]: {
61
+ isBinary: false,
62
+ content: [
63
+ `import React from 'react'`,
64
+ `import ReactDOM from 'react-dom'`,
65
+ `import Demo from './demo'`,
66
+ `ReactDOM.render(<Demo />, document.getElementById('root'))`,
67
+ ].join('\n'),
68
+ },
69
+ },
70
+ };
71
+
72
+ // to specific demo file
73
+ const query = `file=/demo.tsx`;
74
+ const form = document.createElement('form');
75
+ form.action = `https://codesandbox.io/api/v1/sandboxes/define?query=${encodeURIComponent(
76
+ query,
77
+ )}`;
78
+ form.target = '_blank';
79
+ form.method = 'POST';
80
+ form.style.display = 'none';
81
+ const field = document.createElement('input');
82
+ field.name = 'parameters';
83
+ field.type = 'hidden';
84
+ field.setAttribute('value', getParameters(sandBoxConfig));
85
+ form.appendChild(field);
86
+ document.body.appendChild(form);
87
+ form.submit();
88
+ document.body.removeChild(form);
89
+ };
90
+
37
91
  return (
38
92
  <NoSSR>
39
93
  <div className="rspress-preview">
@@ -42,7 +96,13 @@ const Container: React.FC<ContainerProps> = props => {
42
96
  <div className="rspress-preview-code">{children?.[0]}</div>
43
97
  <div className="rspress-preview-device">
44
98
  <iframe src={getPageUrl()} key={iframeKey}></iframe>
45
- <MobileOperation url={url} refresh={refresh} />
99
+ <MobileOperation
100
+ url={url}
101
+ refresh={refresh}
102
+ gotoCodeSandBox={
103
+ enableCodesandbox === 'true' ? gotoCodeSandBox : undefined
104
+ }
105
+ />
46
106
  </div>
47
107
  </div>
48
108
  ) : (
@@ -51,16 +111,28 @@ const Container: React.FC<ContainerProps> = props => {
51
111
  <div
52
112
  style={{
53
113
  overflow: 'auto',
54
- marginRight: '44px',
114
+ flex: 'auto',
55
115
  }}
56
116
  >
57
117
  {children?.[1]}
58
118
  </div>
59
119
  <div className="rspress-preview-operations web">
120
+ {enableCodesandbox === 'true' && (
121
+ <button
122
+ onClick={gotoCodeSandBox}
123
+ aria-label={
124
+ lang === 'zh'
125
+ ? '在 Codesandbox 打开'
126
+ : 'Open in Codesandbox'
127
+ }
128
+ >
129
+ <IconCodesandbox />
130
+ </button>
131
+ )}
60
132
  <button
61
133
  onClick={toggleCode}
62
- aria-label={lang === 'zh' ? '收起代码' : ''}
63
- className={showCode ? 'button-expanded' : 'Collapse Code'}
134
+ aria-label={lang === 'zh' ? '收起代码' : 'Collapse Code'}
135
+ className={showCode ? 'button-expanded' : ''}
64
136
  >
65
137
  <IconCode />
66
138
  </button>
@@ -4,15 +4,18 @@ import { withBase, useLang } from '@rspress/core/runtime';
4
4
  import IconLaunch from '../icons/Launch';
5
5
  import IconQrcode from '../icons/Qrcode';
6
6
  import IconRefresh from '../icons/Refresh';
7
+ import IconCodesandbox from '../icons/Codesandbox';
7
8
 
8
9
  const locales = {
9
10
  zh: {
10
11
  refresh: '刷新页面',
11
12
  open: '在新页面打开',
13
+ codesandbox: '在 Codesandbox 打开',
12
14
  },
13
15
  en: {
14
- refresh: 'refresh',
16
+ refresh: 'Refresh',
15
17
  open: 'Open in new page',
18
+ codesandbox: 'Open in Codesandbox',
16
19
  },
17
20
  };
18
21
 
@@ -20,9 +23,10 @@ export default (props: {
20
23
  url: string;
21
24
  className?: string;
22
25
  refresh: () => void;
26
+ gotoCodeSandBox?: () => void;
23
27
  }) => {
24
28
  const [showQRCode, setShowQRCode] = useState(false);
25
- const { url, className = '', refresh } = props;
29
+ const { url, className = '', refresh, gotoCodeSandBox } = props;
26
30
  const lang = useLang();
27
31
  const triggerRef = useRef(null);
28
32
  const t = lang === 'zh' ? locales.zh : locales.en;
@@ -85,6 +89,11 @@ export default (props: {
85
89
 
86
90
  return (
87
91
  <div className={`rspress-preview-operations mobile ${className}`}>
92
+ {gotoCodeSandBox && (
93
+ <button onClick={gotoCodeSandBox} aria-label={t.codesandbox}>
94
+ <IconCodesandbox />
95
+ </button>
96
+ )}
88
97
  <button onClick={refresh} aria-label={t.refresh}>
89
98
  <IconRefresh />
90
99
  </button>
@@ -0,0 +1,22 @@
1
+ const Codesandbox = ({ color = 'currentColor', ...props }) => (
2
+ <svg
3
+ width="1em"
4
+ height="1em"
5
+ viewBox="0 0 48 48"
6
+ fill="none"
7
+ stroke={color}
8
+ strokeWidth="4"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ {...props}
11
+ >
12
+ <path
13
+ d="M25.0016 1.5998L42.9016 11.8998C43.5016 12.2998 43.9016 12.8998 43.9016 13.5998V34.2998C43.9016 34.9998 43.5016 35.6998 42.9016 35.9998L25.0016 46.3998C24.4016 46.7998 23.6016 46.7998 23.0016 46.3998L5.10156 36.0998C4.50156 35.6998 4.10156 35.0998 4.10156 34.3998V13.6998C4.10156 12.9998 4.50156 12.2998 5.10156 11.9998L23.0016 1.5998C23.6016 1.1998 24.4016 1.1998 25.0016 1.5998ZM38.5016 13.9998L30.6016 9.49981L24.0016 13.9998L17.5016 9.9998L10.2016 14.2998L24.0016 22.9998L38.5016 13.9998ZM22.0016 40.3998V26.2998L8.00156 17.3998V25.2998L16.0016 30.7998V36.9998L22.0016 40.3998ZM26.0016 40.3998L32.0016 36.8998V31.6998L40.0016 26.1998V17.2998L26.0016 26.1998V40.3998Z"
14
+ fill="currentColor"
15
+ stroke="none"
16
+ stroke-width="none"
17
+ stroke-linecap="butt"
18
+ ></path>
19
+ </svg>
20
+ );
21
+
22
+ export default Codesandbox;