Skip to content

Commit

Permalink
Feat/mobile preview (#332)
Browse files Browse the repository at this point in the history
* feat: mobile preview
  • Loading branch information
maoxiaoke authored Apr 25, 2022
1 parent 9c54707 commit c965e9f
Show file tree
Hide file tree
Showing 18 changed files with 712 additions and 442 deletions.
4 changes: 3 additions & 1 deletion examples/package/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { defineConfig } from '@ice/pkg';

export default defineConfig({
plugins: [
// '@ice/pkg-plugin-docusaurus',
['@ice/pkg-plugin-docusaurus', {
mobilePreview: true,
}],
// './plugin.js',
],
sourceMaps: 'inline',
Expand Down
24 changes: 23 additions & 1 deletion examples/package/docs/02-Foo/01-Basic.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
hide_table_of_contents: true
---

## 今天、明天

import Button from './Button.tsx';
Expand All @@ -9,8 +13,9 @@ import React, { useState } from 'react';
import Button from './Button';

export default function App () {
const str = 'abc';
const [state, setState] = useState(0);

const [testStr] = useState(`${str}-0`);
const add = () => {
setState(c => c + 1)
}
Expand All @@ -20,6 +25,23 @@ export default function App () {
{state}
<button onClick={add}>Add</button>
// 我这里加点东西,再加地阿内容个,这是真的真的可以随便
<p>在这里多加一点内容吧 { testStr}</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p><p>在这里多加一点内容吧</p>
<p>在这里多加一点内容吧</p>
<a href="/">跳转</a>
<Button />
</div>
)
Expand Down
5 changes: 3 additions & 2 deletions examples/package/docs/02-Foo/02-Complex.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
## 后天

import Button from './Button.tsx';
<!-- import Button from './Button.tsx'; -->

### 这里是第一个 demo

```jsx preview title="/src/components/HelloCodeTitle.js"
```jsx preview
import React, { useState } from 'react';

export default function App () {
Expand All @@ -17,6 +17,7 @@ export default function App () {
return (
<div>
{state}
<a href="/">跳转</a>
<button onClick={add}>Add</button>
</div>
)
Expand Down
3 changes: 3 additions & 0 deletions examples/package/docs/02-Foo/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* {
color: red;
}
1 change: 1 addition & 0 deletions examples/package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"license": "ISC",
"dependencies": {
"@docusaurus/preset-classic": "2.0.0-beta.17",
"@swc/helpers": "^0.3.8",
"core-js": "^3.21.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-docusaurus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"fs-extra": "^10.0.0",
"handlebars": "^4.7.7",
"hast-util-find-and-replace": "3",
"prism-react-renderer": "^1.3.1",
"react-tooltip": "^4.2.21",
"unist-util-remove": "2.1.0",
"unist-util-visit": "2.0.3"
Expand Down
64 changes: 64 additions & 0 deletions packages/plugin-docusaurus/src/Previewer/Mobile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { useRef } from 'react';
import CodeBlock from '@theme-original/CodeBlock';
import styles from './styles.module.css';
import './styles.css';

function ReloadSvg(props) {
return (
<svg width="20px" height="20px" viewBox="0 0 16 16" {...props}><g fill="currentColor"><path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"></path><path fillRule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182a.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"></path></g></svg>
);
}

function FullScreenSvg(props) {
return (
<svg width="15px" height="15px" viewBox="0 0 16 16" {...props}><path fill="currentColor" fillRule="evenodd" d="M5.828 10.172a.5.5 0 0 0-.707 0l-4.096 4.096V11.5a.5.5 0 0 0-1 0v3.975a.5.5 0 0 0 .5.5H4.5a.5.5 0 0 0 0-1H1.732l4.096-4.096a.5.5 0 0 0 0-.707zm4.344 0a.5.5 0 0 1 .707 0l4.096 4.096V11.5a.5.5 0 1 1 1 0v3.975a.5.5 0 0 1-.5.5H11.5a.5.5 0 0 1 0-1h2.768l-4.096-4.096a.5.5 0 0 1 0-.707zm0-4.344a.5.5 0 0 0 .707 0l4.096-4.096V4.5a.5.5 0 1 0 1 0V.525a.5.5 0 0 0-.5-.5H11.5a.5.5 0 0 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 0 .707zm-4.344 0a.5.5 0 0 1-.707 0L1.025 1.732V4.5a.5.5 0 0 1-1 0V.525a.5.5 0 0 1 .5-.5H4.5a.5.5 0 0 1 0 1H1.732l4.096 4.096a.5.5 0 0 1 0 .707z"></path></svg>
);
}

function MobilePreview({ code, url }) {
const iframe = useRef(null);
const redirctFullScreen = () => {
window.open(url);
};
const reloadIframe = () => {
iframe?.current?.contentWindow.location.reload();
};

return (
<div className={`${styles.mobileWrapper} mobile-previewer`}>
<div className={styles.mobileCodeWrapper}>
<CodeBlock
children={code}
className="language-jsx"
mdxType= "code"
originalType="code"
parentName="pre" />
</div>

<div className={styles.mobilePreviewArea}>
<div className={styles.mobileOperations}>
<div
className={styles.operationItem}
onClick={reloadIframe}
><ReloadSvg /> &nbsp;刷新</div>
<div
className={styles.operationItem}
onClick={redirctFullScreen}
><FullScreenSvg /> &nbsp;全屏模式</div>
</div>
<div className={styles.iframeWrapper}>
<iframe
ref={iframe}
style={{ width: '325px', height: '600px', backgroundColor: '#FFF' }}
scrolling="yes"
frameBorder="0"
src={url}
/>
</div>

</div>
</div>
);
}

export default MobilePreview;
98 changes: 98 additions & 0 deletions packages/plugin-docusaurus/src/Previewer/Pc.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { useState } from 'react';
import CodeBlock from '@theme-original/CodeBlock';
import ReactTooltip from 'react-tooltip';
import copy from 'copy-text-to-clipboard';
import styles from './styles.module.css';

function UnfoldSvg() {
return (
<svg
width="20px"
height="20px"
viewBox="0 0 20 20"
fill="currentColor"
>
<path d="M14.4307124,13.5667899 L15.1349452,14.276759 L10.7473676,18.6288871 L6.42783259,14.2738791 L7.13782502,13.5696698 L10.7530744,17.2147744 L14.4307124,13.5667899 Z M4.79130753,8.067524 L16.3824174,11.1733525 L16.1235984,12.1392784 L4.53248848,9.03344983 L4.79130753,8.067524 Z M10.8154102,1.57503552 L15.1349452,5.93004351 L14.4249528,6.63425282 L10.809949,2.98914817 L7.13206544,6.6371327 L6.42783259,5.92716363 L10.8154102,1.57503552 Z" transform="translate(10.457453, 10.101961) rotate(90.000000) translate(-10.457453, -10.101961) "></path>
</svg>
);
}

function CopySvg() {
return (
<svg viewBox="0 0 20 20" focusable="false" data-icon="snippets" width="20px" height="20px" fill="currentColor" aria-hidden="true">
<path d="M15,5 L15,18 L2,18 L2,5 L15,5 Z M14,6 L3,6 L3,17 L14,17 L14,6 Z M18,2 L18,15 L16,15 L16,13.999 L17,14 L17,3 L6,3 L6,4 L5,4 L5,2 L18,2 Z M9,8 L9,11 L12,11 L12,12 L9,12 L9,15 L8,15 L8,12 L5,12 L5,11 L8,11 L8,8 L9,8 Z"></path>
</svg>
);
}

function FullScreenSvg(props) {
return (
<svg width="15px" height="15px" viewBox="0 0 16 16" {...props}><path fill="currentColor" fillRule="evenodd" d="M5.828 10.172a.5.5 0 0 0-.707 0l-4.096 4.096V11.5a.5.5 0 0 0-1 0v3.975a.5.5 0 0 0 .5.5H4.5a.5.5 0 0 0 0-1H1.732l4.096-4.096a.5.5 0 0 0 0-.707zm4.344 0a.5.5 0 0 1 .707 0l4.096 4.096V11.5a.5.5 0 1 1 1 0v3.975a.5.5 0 0 1-.5.5H11.5a.5.5 0 0 1 0-1h2.768l-4.096-4.096a.5.5 0 0 1 0-.707zm0-4.344a.5.5 0 0 0 .707 0l4.096-4.096V4.5a.5.5 0 1 0 1 0V.525a.5.5 0 0 0-.5-.5H11.5a.5.5 0 0 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 0 .707zm-4.344 0a.5.5 0 0 1-.707 0L1.025 1.732V4.5a.5.5 0 0 1-1 0V.525a.5.5 0 0 1 .5-.5H4.5a.5.5 0 0 1 0 1H1.732l4.096 4.096a.5.5 0 0 1 0 .707z"></path></svg>
);
}


function PcPreview({ children, code, url }) {
const [unfold, triggerFold] = useState(false);

const doCopy = () => {
copy(code);
};

const redirctFullScreen = () => {
window.open(url);
};

return (
<div>
<div className={[styles.container, !unfold && styles.unfoldContainer].filter(Boolean).join(' ')}>
{/* Preview Demo Content */}
<div className={styles.preview}>
{children}
</div>

<ReactTooltip
effect="solid"
/>

<div className={styles.operations}>
<div
className={styles.item}
onClick={redirctFullScreen}
data-tip="全屏模式"
><FullScreenSvg /></div>

<div
className={styles.item}
onClick={() => doCopy()}
data-tip="复制"
><CopySvg /></div>

<div
className={styles.item}
onClick={() => triggerFold((fold) => !fold)}
data-tip={ unfold ? '收起' : '展开'}
><UnfoldSvg /></div>
</div>

</div>

<div className={styles.codeWrapper}>
{ unfold && (
<CodeBlock
children={code}
className="language-jsx"
mdxType= "code"
originalType="code"
parentName="pre"
/>
) }
</div>


</div>

);
}

export default PcPreview;
72 changes: 16 additions & 56 deletions packages/plugin-docusaurus/src/Previewer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,20 @@
import React, { useState } from 'react';
import CodeBlock from '@theme-original/CodeBlock';
import ReactTooltip from 'react-tooltip';
import copy from 'copy-text-to-clipboard';
import { UnfoldSvg, CopySvg } from './svgs';
import styles from './styles.module.css';

function Previewer({ children, code }) {
const [unfold, triggerFold] = useState(false);

const doCopy = () => {
copy(code);
import React from 'react';
import PcPreview from './Pc';
import MobilePreview from './Mobile';

function Previewer({ mobilePreview, children, code, ...props }) {
const deserializedCode = (code || '')
.replace(/&#x60;/g, '`')
.replace(/&#36;/g, '$');

if (mobilePreview) {
return <MobilePreview code={deserializedCode} {...props} />;
} else {
return <PcPreview
code={deserializedCode}
{ ...props }
>{ children }</PcPreview>;
}

return (
<div>
<div className={[styles.container, !unfold && styles.unfoldContainer].filter(Boolean).join(' ')}>
{/* Preview Demo Content */}
<div className={styles.preview}>
{children}
</div>

<ReactTooltip
effect="solid"
/>

<div className={styles.operations}>
<div
className={styles.item}
onClick={() => doCopy()}
><CopySvg /></div>

<div
className={styles.item}
onClick={() => triggerFold((fold) => !fold)}
data-tip={ unfold ? '收起' : '展开'}
><UnfoldSvg /></div>
</div>

</div>

<div className={styles.codeWrapper}>
{ unfold && (
<CodeBlock
children={code}
className="language-jsx"
mdxType= "code"
originalType="code"
parentName="pre"
/>
) }
</div>


</div>

);
}

export default Previewer;
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions packages/plugin-docusaurus/src/Previewer/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.mobile-previewer pre {
height: 720px;
}

iframe body::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
50 changes: 50 additions & 0 deletions packages/plugin-docusaurus/src/Previewer/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,53 @@
border-color: #eee;
border-style: solid;
}

.mobileWrapper {
display: flex;
justify-content: space-between;
}

.iframeWrapper {
padding-top: 75px;
width: 375px;
height: 730px;
overflow: hidden;
display: flex;
justify-content: center;
background: url(./iphoneX.png) no-repeat;
background-size: 100%;
}

.mobilePreviewWrapper {
display: flex;
}

.mobilePreviewArea {
margin-left: 20px;
position: relative;
}

.mobileOperations {
transform: translateX(-50%);
left: 50%;
display: flex;
justify-content: space-around;
align-items: center;
position: absolute;
height: 40px;
width: 325px;
bottom: 20px;
border-top: 2px solid #eee;
}

.mobileCodeWrapper {
flex: 1;
}

.operationItem {
display: flex;
align-items: center;
font-size: 14px;
color: #666;
cursor: pointer;
}
Loading

0 comments on commit c965e9f

Please sign in to comment.