Fix:1; Feat:1 #44
@@ -14,8 +14,8 @@
|
||||
-ms-overflow-style: none;
|
||||
|
||||
.hide-scrollbar-content {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
width: fit-content;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
padding: 20px;
|
||||
|
||||
.card-box {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
1
src/assets/svg/arrowDown.svg
Normal file
1
src/assets/svg/arrowDown.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M482.133333 738.133333L136.533333 392.533333c-17.066667-17.066667-17.066667-42.666667 0-59.733333 8.533333-8.533333 19.2-12.8 29.866667-12.8h689.066667c23.466667 0 42.666667 19.2 42.666666 42.666667 0 10.666667-4.266667 21.333333-12.8 29.866666L541.866667 738.133333c-17.066667 17.066667-42.666667 17.066667-59.733334 0z" /></svg>
|
||||
|
After Width: | Height: | Size: 404 B |
1
src/assets/svg/rotateLeft.svg
Normal file
1
src/assets/svg/rotateLeft.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M672 418H144c-17.7 0-32 14.3-32 32v414c0 17.7 14.3 32 32 32h528c17.7 0 32-14.3 32-32V450c0-17.7-14.3-32-32-32z m-44 402H188V494h440v326z" /><path d="M819.3 328.5c-78.8-100.7-196-153.6-314.6-154.2l-0.2-64c0-6.5-7.6-10.1-12.6-6.1l-128 101c-4 3.1-3.9 9.1 0 12.3L492 318.6c5.1 4 12.7 0.4 12.6-6.1v-63.9c12.9 0.1 25.9 0.9 38.8 2.5 42.1 5.2 82.1 18.2 119 38.7 38.1 21.2 71.2 49.7 98.4 84.3 27.1 34.7 46.7 73.7 58.1 115.8 11 40.7 14 82.7 8.9 124.8-0.7 5.4-1.4 10.8-2.4 16.1h74.9c14.8-103.6-11.3-213-81-302.3z" /></svg>
|
||||
|
After Width: | Height: | Size: 585 B |
1
src/assets/svg/rotateRight.svg
Normal file
1
src/assets/svg/rotateRight.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M480.5 251.2c13-1.6 25.9-2.4 38.8-2.5v63.9c0 6.5 7.5 10.1 12.6 6.1L660 217.6c4-3.2 4-9.2 0-12.3l-128-101c-5.1-4-12.6-0.4-12.6 6.1l-0.2 64c-118.6 0.5-235.8 53.4-314.6 154.2-69.6 89.2-95.7 198.6-81.1 302.4h74.9c-0.9-5.3-1.7-10.7-2.4-16.1-5.1-42.1-2.1-84.1 8.9-124.8 11.4-42.2 31-81.1 58.1-115.8 27.2-34.7 60.3-63.2 98.4-84.3 37-20.6 76.9-33.6 119.1-38.8z" /><path d="M880 418H352c-17.7 0-32 14.3-32 32v414c0 17.7 14.3 32 32 32h528c17.7 0 32-14.3 32-32V450c0-17.7-14.3-32-32-32z m-44 402H396V494h440v326z" /></svg>
|
||||
|
After Width: | Height: | Size: 585 B |
1
src/assets/svg/zoom.svg
Normal file
1
src/assets/svg/zoom.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M720 464H560V304a48 48 0 1 0-96 0v160H304a48 48 0 1 0 0 96h160v160a48 48 0 1 0 96 0V560h160a48 48 0 1 0 0-96zM512 0C229.232 0 0 229.232 0 512c0 282.768 229.232 512 512 512h464a48 48 0 0 0 48-48V512.032 512C1024 229.232 794.768 0 512 0z m416 512.016C928 741.744 741.776 927.968 512.064 928H512C282.256 928 96 741.76 96 512 96 282.256 282.256 96 512 96s416 186.256 416 416.016z" /></svg>
|
||||
|
After Width: | Height: | Size: 459 B |
@@ -1,19 +1,30 @@
|
||||
import { ChangeEvent } from 'react'
|
||||
import '@/components/Playground/Output/Preview/render.scss'
|
||||
import { COLOR_FONT_MAIN } from '@/constants/common.constants'
|
||||
import iframeRaw from '@/components/Playground/Output/Preview/iframe.html?raw'
|
||||
import HideScrollbar from '@/components/common/HideScrollbar'
|
||||
|
||||
interface RenderProps {
|
||||
iframeKey: string
|
||||
compiledCode: string
|
||||
mobileMode?: boolean
|
||||
}
|
||||
|
||||
interface IMessage {
|
||||
type: 'LOADED' | 'ERROR' | 'UPDATE' | 'DONE'
|
||||
type: 'LOADED' | 'ERROR' | 'UPDATE' | 'DONE' | 'SCALE'
|
||||
msg: string
|
||||
data: {
|
||||
compiledCode: string
|
||||
compiledCode?: string
|
||||
zoom?: number
|
||||
}
|
||||
}
|
||||
|
||||
interface IDevice {
|
||||
name: string
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
const getIframeUrl = (iframeRaw: string) => {
|
||||
const shimsUrl = '//unpkg.com/es-module-shims/dist/es-module-shims.js'
|
||||
// 判断浏览器是否支持esm ,不支持esm就引入es-module-shims
|
||||
@@ -29,9 +40,112 @@ const getIframeUrl = (iframeRaw: string) => {
|
||||
|
||||
const iframeUrl = getIframeUrl(iframeRaw)
|
||||
|
||||
const Render = ({ iframeKey, compiledCode }: RenderProps) => {
|
||||
const Render = ({ iframeKey, compiledCode, mobileMode = false }: RenderProps) => {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null)
|
||||
const [loaded, setLoaded] = useState(false)
|
||||
const [selectedDevice, setSelectedDevice] = useState('Pixel 7')
|
||||
const [zoom, setZoom] = useState(1)
|
||||
const [isRotate, setIsRotate] = useState(false)
|
||||
|
||||
const devices: IDevice[] = [
|
||||
{
|
||||
name: 'iPhone SE',
|
||||
width: 375,
|
||||
height: 667
|
||||
},
|
||||
{
|
||||
name: 'iPhone XR',
|
||||
width: 414,
|
||||
height: 896
|
||||
},
|
||||
{
|
||||
name: 'iPhone 12 Pro',
|
||||
width: 390,
|
||||
height: 844
|
||||
},
|
||||
{
|
||||
name: 'iPhone 14 Pro Max',
|
||||
width: 430,
|
||||
height: 932
|
||||
},
|
||||
{
|
||||
name: 'Pixel 7',
|
||||
width: 412,
|
||||
height: 915
|
||||
},
|
||||
{
|
||||
name: 'Samsung Galaxy S8+',
|
||||
width: 360,
|
||||
height: 740
|
||||
},
|
||||
{
|
||||
name: 'Samsung Galaxy S20 Ultra',
|
||||
width: 412,
|
||||
height: 915
|
||||
},
|
||||
{
|
||||
name: 'iPad Mini',
|
||||
width: 768,
|
||||
height: 1024
|
||||
},
|
||||
{
|
||||
name: 'iPad Air',
|
||||
width: 820,
|
||||
height: 1180
|
||||
},
|
||||
{
|
||||
name: 'iPad Pro',
|
||||
width: 1024,
|
||||
height: 1366
|
||||
},
|
||||
{
|
||||
name: 'Surface Pro 7',
|
||||
width: 912,
|
||||
height: 1368
|
||||
},
|
||||
{
|
||||
name: 'Surface Duo',
|
||||
width: 540,
|
||||
height: 720
|
||||
},
|
||||
{
|
||||
name: 'Galaxy Fold',
|
||||
width: 280,
|
||||
height: 653
|
||||
},
|
||||
{
|
||||
name: 'Asus Zenbook Fold',
|
||||
width: 853,
|
||||
height: 1280
|
||||
},
|
||||
{
|
||||
name: 'Samsung Galaxy A51/71',
|
||||
width: 412,
|
||||
height: 914
|
||||
},
|
||||
{
|
||||
name: 'Nest Hub',
|
||||
width: 1024,
|
||||
height: 600
|
||||
},
|
||||
{
|
||||
name: 'Nest Hub Max',
|
||||
width: 1280,
|
||||
height: 800
|
||||
}
|
||||
]
|
||||
|
||||
const handleOnChangeDevice = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
setSelectedDevice(e.target.value)
|
||||
}
|
||||
|
||||
const handleOnChangeZoom = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setZoom(Number(e.target.value))
|
||||
}
|
||||
|
||||
const handleOnRotateDevice = () => {
|
||||
setIsRotate(!isRotate)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (loaded) {
|
||||
@@ -43,9 +157,88 @@ const Render = ({ iframeKey, compiledCode }: RenderProps) => {
|
||||
'*'
|
||||
)
|
||||
}
|
||||
}, [compiledCode, loaded])
|
||||
}, [loaded, compiledCode])
|
||||
|
||||
return (
|
||||
useEffect(() => {
|
||||
if (loaded) {
|
||||
iframeRef.current?.contentWindow?.postMessage(
|
||||
{
|
||||
type: 'SCALE',
|
||||
data: { zoom: zoom }
|
||||
} as IMessage,
|
||||
'*'
|
||||
)
|
||||
}
|
||||
}, [loaded, zoom])
|
||||
|
||||
return mobileMode ? (
|
||||
<>
|
||||
<HideScrollbar
|
||||
className={'mobile-mode-background'}
|
||||
isShowVerticalScrollbar
|
||||
isShowHorizontalScrollbar
|
||||
autoHideWaitingTime={1000}
|
||||
>
|
||||
<div className={'mobile-mode-content'} style={{ zoom }}>
|
||||
<div className={`device${isRotate ? ' rotate' : ''}`}>
|
||||
<div className={`device-header${isRotate ? ' rotate' : ''}`} />
|
||||
<div
|
||||
className={`device-content${isRotate ? ' rotate' : ''}`}
|
||||
style={{
|
||||
width: isRotate
|
||||
? devices.find((value) => value.name === selectedDevice)
|
||||
?.height ?? 915
|
||||
: devices.find((value) => value.name === selectedDevice)
|
||||
?.width ?? 412,
|
||||
height: isRotate
|
||||
? devices.find((value) => value.name === selectedDevice)
|
||||
?.width ?? 412
|
||||
: devices.find((value) => value.name === selectedDevice)
|
||||
?.height ?? 915
|
||||
}}
|
||||
>
|
||||
<iframe
|
||||
data-component={'playground-output-preview-render'}
|
||||
key={iframeKey}
|
||||
ref={iframeRef}
|
||||
src={iframeUrl}
|
||||
onLoad={() => setLoaded(true)}
|
||||
sandbox="allow-downloads allow-forms allow-modals allow-scripts"
|
||||
/>
|
||||
</div>
|
||||
<div className={`device-footer${isRotate ? ' rotate' : ''}`} />
|
||||
</div>
|
||||
</div>
|
||||
</HideScrollbar>
|
||||
|
||||
<div className={'switch-device'}>
|
||||
<IconOxygenMobile fill={COLOR_FONT_MAIN} />
|
||||
<select value={selectedDevice} onChange={handleOnChangeDevice}>
|
||||
{devices.map((value) => (
|
||||
<option value={value.name}>{value.name}</option>
|
||||
))}
|
||||
</select>
|
||||
<div className={'rotate-device'} title={'旋转屏幕'} onClick={handleOnRotateDevice}>
|
||||
{isRotate ? (
|
||||
<IconOxygenRotateRight fill={COLOR_FONT_MAIN} />
|
||||
) : (
|
||||
<IconOxygenRotateLeft fill={COLOR_FONT_MAIN} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={'switch-zoom'}>
|
||||
<IconOxygenZoom fill={COLOR_FONT_MAIN} />
|
||||
<input
|
||||
type={'range'}
|
||||
min={0.5}
|
||||
max={2}
|
||||
step={0.1}
|
||||
value={zoom}
|
||||
onChange={handleOnChangeZoom}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<iframe
|
||||
data-component={'playground-output-preview-render'}
|
||||
key={iframeKey}
|
||||
|
||||
@@ -36,6 +36,10 @@
|
||||
document.body.appendChild(script);
|
||||
URL.revokeObjectURL(oldSrc);
|
||||
}
|
||||
|
||||
if (data?.type === "SCALE") {
|
||||
document.getElementById("root").style.zoom = data.data.zoom
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="module" id="appSrc"></script>
|
||||
|
||||
@@ -10,6 +10,7 @@ interface PreviewProps {
|
||||
entryPoint: string
|
||||
preExpansionCode?: string
|
||||
postExpansionCode?: string
|
||||
mobileMode?: boolean
|
||||
}
|
||||
|
||||
const Preview = ({
|
||||
@@ -18,7 +19,8 @@ const Preview = ({
|
||||
importMap,
|
||||
entryPoint,
|
||||
preExpansionCode = '',
|
||||
postExpansionCode = ''
|
||||
postExpansionCode = '',
|
||||
mobileMode = false
|
||||
}: PreviewProps) => {
|
||||
const [errorMsg, setErrorMsg] = useState('')
|
||||
const [compiledCode, setCompiledCode] = useState('')
|
||||
@@ -41,7 +43,7 @@ const Preview = ({
|
||||
|
||||
return (
|
||||
<div data-component={'playground-preview'}>
|
||||
<Render iframeKey={iframeKey} compiledCode={compiledCode} />
|
||||
<Render iframeKey={iframeKey} compiledCode={compiledCode} mobileMode={mobileMode} />
|
||||
{errorMsg && <div className={'playground-error-message'}>{errorMsg}</div>}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
[data-component=playground-preview] {
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: 0;
|
||||
|
||||
.playground-error-message {
|
||||
position: absolute;
|
||||
@@ -13,4 +12,4 @@
|
||||
padding: 5px 10px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,80 @@
|
||||
@use '@/assets/css/constants' as constants;
|
||||
|
||||
[data-component=playground-output-preview-render] {
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-mode-background {
|
||||
background-color: rgba(204, 204, 204, 0.66);
|
||||
|
||||
.mobile-mode-content {
|
||||
padding: 80px;
|
||||
}
|
||||
|
||||
.device {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #EEEFF2;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
border-radius: 40px;
|
||||
|
||||
&.rotate {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.device-header {
|
||||
margin: 20px auto;
|
||||
width: 60px;
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: #C8C9CC;
|
||||
|
||||
&.rotate {
|
||||
margin: auto 20px;
|
||||
width: 10px;
|
||||
height: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.device-content {
|
||||
margin: 0 10px;
|
||||
background-color: white;
|
||||
|
||||
&.rotate {
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.device-footer {
|
||||
margin: 20px auto;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: #C8C9CC;
|
||||
|
||||
&.rotate {
|
||||
margin: auto 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.switch-device, .switch-zoom {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.switch-device {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.switch-zoom {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ interface OutputProps {
|
||||
entryPoint: string
|
||||
preExpansionCode?: string
|
||||
postExpansionCode?: string
|
||||
mobileMode?: boolean
|
||||
}
|
||||
|
||||
const Output = ({
|
||||
@@ -19,7 +20,8 @@ const Output = ({
|
||||
importMap,
|
||||
entryPoint,
|
||||
preExpansionCode,
|
||||
postExpansionCode
|
||||
postExpansionCode,
|
||||
mobileMode = false
|
||||
}: OutputProps) => {
|
||||
const [selectedTab, setSelectedTab] = useState('Preview')
|
||||
|
||||
@@ -42,6 +44,7 @@ const Output = ({
|
||||
entryPoint={entryPoint}
|
||||
preExpansionCode={preExpansionCode}
|
||||
postExpansionCode={postExpansionCode}
|
||||
mobileMode={mobileMode}
|
||||
/>
|
||||
)}
|
||||
{selectedTab === 'Transform' && <Transform file={files[selectedFileName]} />}
|
||||
|
||||
@@ -443,6 +443,7 @@ const Edit = () => {
|
||||
importMap={importMap!}
|
||||
entryPoint={entryPoint}
|
||||
postExpansionCode={baseDist}
|
||||
mobileMode={toolData?.platform === 'ANDROID'}
|
||||
/>
|
||||
</LoadingMask>
|
||||
{showDraggableMask && <div className={'draggable-mask'} />}
|
||||
|
||||
@@ -17,8 +17,10 @@ const View = () => {
|
||||
})
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [compiledCode, setCompiledCode] = useState('')
|
||||
const [isAndroid, setIsAndroid] = useState(false)
|
||||
|
||||
const render = (toolVo: ToolVo) => {
|
||||
setIsAndroid(toolVo.platform === 'ANDROID')
|
||||
if (username === '!') {
|
||||
try {
|
||||
const baseDist = base64ToStr(toolVo.base.dist.data!)
|
||||
@@ -111,6 +113,7 @@ const View = () => {
|
||||
<Playground.Output.Preview.Render
|
||||
iframeKey={`${username}:${toolId}:${ver}`}
|
||||
compiledCode={compiledCode}
|
||||
mobileMode={isAndroid}
|
||||
/>
|
||||
</Card>
|
||||
</FitFullscreen>
|
||||
|
||||
Reference in New Issue
Block a user