Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Enable device based preview (mobile/tablet/desktop) with orientations (landscape/portrait)#1513

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
FalkWolsky merged 2 commits intodevfromfeat/mobile-preview
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletionsclient/packages/lowcoder/package.json
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -52,6 +52,7 @@
"file-saver":"^2.0.5",
"github-markdown-css":"^5.1.0",
"hotkeys-js":"^3.8.7",
"html5-device-mockups":"^3.2.1",
"immer":"^9.0.7",
"less":"^4.1.3",
"lodash":"^4.17.21",
Expand All@@ -67,6 +68,7 @@
"react":"^18.2.0",
"react-best-gradient-color-picker":"^3.0.10",
"react-colorful":"^5.5.1",
"react-device-mockups":"^0.1.12",
"react-documents":"^1.2.1",
"react-dom":"^18.2.0",
"react-draggable":"^4.4.4",
Expand Down
13 changes: 13 additions & 0 deletionsclient/packages/lowcoder/src/comps/editorState.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,9 @@ export type CompInfo = {

typeSelectSourceType="editor"|"leftPanel"|"addComp"|"rightPanel";

exporttypeDeviceType="desktop"|"tablet"|"mobile";
exporttypeDeviceOrientation="landscape"|"portrait";

/**
* All editor states are placed here and are still immutable.
*
Expand All@@ -56,6 +59,8 @@ export class EditorState {
readonlyselectedBottomResType?:BottomResTypeEnum;
readonlyshowResultCompName:string="";
readonlyselectSource?:SelectSourceType;// the source of select type
readonlydeviceType:DeviceType="desktop";
readonlydeviceOrientation:DeviceOrientation="portrait";

privatereadonlysetEditorState:(
fn:(editorState:EditorState)=>EditorState
Expand DownExpand Up@@ -357,6 +362,14 @@ export class EditorState {
this.changeState({editorModeStatus:newEditorModeStatus});
}

setDeviceType(type:DeviceType){
this.changeState({deviceType:type});
}

setDeviceOrientation(orientation:DeviceOrientation){
this.changeState({deviceOrientation:orientation});
}

setDragging(dragging:boolean){
if(this.isDragging===dragging){
return;
Expand Down
22 changes: 16 additions & 6 deletionsclient/packages/lowcoder/src/comps/hooks/screenInfoComp.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect,useMemo,useState } from "react";
import { hookToStateComp } from "../generators/hookToComp";
import { CanvasContainerID } from "@lowcoder-ee/index.sdk";

enum ScreenTypes {
Mobile = 'mobile',
Expand All@@ -19,9 +20,13 @@ type ScreenInfo = {
}

function useScreenInfo() {
const getDeviceType = () => {
if (window.innerWidth < 768) return ScreenTypes.Mobile;
if (window.innerWidth < 889) return ScreenTypes.Tablet;
const canvasContainer = document.getElementById(CanvasContainerID);
const canvas = document.getElementsByClassName('lowcoder-app-canvas')?.[0];
const canvasWidth = canvasContainer?.clientWidth || canvas?.clientWidth;

const getDeviceType = (width: number) => {
if (width < 768) return ScreenTypes.Mobile;
if (width < 889) return ScreenTypes.Tablet;
return ScreenTypes.Desktop;
}
const getFlagsByDeviceType = (deviceType: ScreenType) => {
Expand All@@ -41,16 +46,17 @@ function useScreenInfo() {

const getScreenInfo = useCallback(() => {
const { innerWidth, innerHeight } = window;
const deviceType = getDeviceType();
const deviceType = getDeviceType(canvasWidth || window.innerWidth);
const flags = getFlagsByDeviceType(deviceType);

return {
width: innerWidth,
height: innerHeight,
canvasWidth,
deviceType,
...flags
};
}, [])
}, [canvasWidth])

const [screenInfo, setScreenInfo] = useState<ScreenInfo>({});

Expand All@@ -64,6 +70,10 @@ function useScreenInfo() {
return () => window.removeEventListener('resize', updateScreenInfo);
}, [ updateScreenInfo ])

useEffect(() => {
updateScreenInfo();
}, [canvasWidth]);

return screenInfo;
}

Expand Down
41 changes: 40 additions & 1 deletionclient/packages/lowcoder/src/pages/common/previewHeader.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,12 +15,17 @@ import ProfileDropdown from "./profileDropdown";
import{trans}from"i18n";
import{Logo}from"@lowcoder-ee/assets/images";
import{AppPermissionDialog}from"../../components/PermissionDialog/AppPermissionDialog";
import{useMemo,useState}from"react";
import{useContext,useMemo,useState}from"react";
import{getBrandingConfig}from"../../redux/selectors/configSelectors";
import{HeaderStartDropdown}from"./headerStartDropdown";
import{useParams}from"react-router";
import{AppPathParams}from"constants/applicationConstants";
importReactfrom"react";
importSegmentedfrom"antd/es/segmented";
importMobileOutlinedfrom"@ant-design/icons/MobileOutlined";
importTabletOutlinedfrom"@ant-design/icons/TabletOutlined";
importDesktopOutlinedfrom"@ant-design/icons/DesktopOutlined";
import{DeviceOrientation,DeviceType,EditorContext}from"@lowcoder-ee/comps/editorState";

constHeaderFont=styled.div<{$bgColor:string}>`
font-weight: 500;
Expand DownExpand Up@@ -130,6 +135,7 @@ export function HeaderProfile(props: { user: User }) {

constPreviewHeaderComp=()=>{
constparams=useParams<AppPathParams>();
consteditorState=useContext(EditorContext);
constuser=useSelector(getUser);
constapplication=useSelector(currentApplication);
constisPublicApp=useSelector(isPublicApplication);
Expand DownExpand Up@@ -197,9 +203,42 @@ const PreviewHeaderComp = () => {
<HeaderProfileuser={user}/>
</Wrapper>
);

constheaderMiddle=(
<>
{/* Devices */}
<Segmented<DeviceType>
options={[
{value:'mobile',icon:<MobileOutlined/>},
{value:'tablet',icon:<TabletOutlined/>},
{value:'desktop',icon:<DesktopOutlined/>},
]}
value={editorState.deviceType}
onChange={(value)=>{
editorState.setDeviceType(value);
}}
/>

{/* Orientation */}
{editorState.deviceType!=='desktop'&&(
<Segmented<DeviceOrientation>
options={[
{value:'portrait',label:"Portrait"},
{value:'landscape',label:"Landscape"},
]}
value={editorState.deviceOrientation}
onChange={(value)=>{
editorState.setDeviceOrientation(value);
}}
/>
)}
</>
);

return(
<Header
headerStart={headerStart}
headerMiddle={headerMiddle}
headerEnd={headerEnd}
style={{backgroundColor:brandingConfig?.headerColor}}
/>
Expand Down
88 changes: 87 additions & 1 deletionclient/packages/lowcoder/src/pages/editor/editorView.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,10 +30,12 @@ import {
UserGuideLocationState,
}from"pages/tutorials/tutorialsConstant";
importReact,{
ReactNode,
Suspense,
lazy,
useCallback,
useContext,
useEffect,
useLayoutEffect,
useMemo,
useState,
Expand All@@ -58,6 +60,7 @@ import EditorSkeletonView from "./editorSkeletonView";
import{getCommonSettings}from"@lowcoder-ee/redux/selectors/commonSettingSelectors";
import{isEqual,noop}from"lodash";
import{AppSettingContext,AppSettingType}from"@lowcoder-ee/comps/utils/appSettingContext";
importFlexfrom"antd/es/flex";
// import { BottomSkeleton } from "./bottom/BottomContent";

constHeader=lazy(
Expand DownExpand Up@@ -251,6 +254,13 @@ export const EditorWrapper = styled.div`
flex: 1 1 0;
`;

constDeviceWrapperInner=styled(Flex)`
margin: 20px 0 0;
.screen {
overflow: auto;
}
`;

interfaceEditorViewProps{
uiComp:InstanceType<typeofUIComp>;
preloadComp:InstanceType<typeofPreloadComp>;
Expand DownExpand Up@@ -298,6 +308,64 @@ const aggregationSiderItems = [
}
];

constDeviceWrapper=({
deviceType,
deviceOrientation,
children,
}:{
deviceType:string,
deviceOrientation:string,
children:ReactNode,
})=>{
const[Wrapper,setWrapper]=useState<React.ElementType|null>(null);

useEffect(()=>{
constloadWrapper=async()=>{
if(deviceType==="tablet"){
awaitimport('html5-device-mockups/dist/device-mockups.min.css');
const{ IPad}=awaitimport("react-device-mockups");
setWrapper(()=>IPad);
}elseif(deviceType==="mobile"){
awaitimport('html5-device-mockups/dist/device-mockups.min.css');
const{ IPhone7}=awaitimport("react-device-mockups");
setWrapper(()=>IPhone7);
}else{
setWrapper(()=>null);
}
};

loadWrapper();
},[deviceType]);

constdeviceWidth=useMemo(()=>{
if(deviceType==='tablet'&&deviceOrientation==='portrait'){
return700;
}
if(deviceType==='tablet'&&deviceOrientation==='landscape'){
return1000;
}
if(deviceType==='mobile'&&deviceOrientation==='portrait'){
return400;
}
if(deviceType==='mobile'&&deviceOrientation==='landscape'){
return800;
}
},[deviceType,deviceOrientation]);

if(!Wrapper)return<>{children}</>;

return(
<DeviceWrapperInnerjustify="center">
<Wrapper
orientation={deviceOrientation}
width={deviceWidth}
>
{children}
</Wrapper>
</DeviceWrapperInner>
);
}

functionEditorView(props:EditorViewProps){
const{ uiComp}=props;
constparams=useParams<AppPathParams>();
Expand DownExpand Up@@ -416,6 +484,24 @@ function EditorView(props: EditorViewProps) {
uiComp,
]);

constuiCompViewWrapper=useMemo(()=>{
if(isViewMode)returnuiComp.getView();

return(
<DeviceWrapper
deviceType={editorState.deviceType}
deviceOrientation={editorState.deviceOrientation}
>
{uiComp.getView()}
</DeviceWrapper>
)
},[
uiComp,
isViewMode,
editorState.deviceType,
editorState.deviceOrientation,
]);

// we check if we are on the public cloud
constisLowCoderDomain=window.location.hostname==='app.lowcoder.cloud';
constisLocalhost=window.location.hostname==='localhost';
Expand DownExpand Up@@ -455,7 +541,7 @@ function EditorView(props: EditorViewProps) {
{!hideBodyHeader&&<PreviewHeader/>}
<EditorContainerWithViewMode>
<ViewBody$hideBodyHeader={hideBodyHeader}$height={height}>
{uiComp.getView()}
{uiCompViewWrapper}
</ViewBody>
<divstyle={{zIndex:Layers.hooksCompContainer}}>
{hookCompViews}
Expand Down
21 changes: 21 additions & 0 deletionsclient/yarn.lock
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -11455,6 +11455,13 @@ coolshapes-react@lowcoder-org/coolshapes-react:
languageName: node
linkType: hard

"html5-device-mockups@npm:^3.2.1":
version: 3.2.1
resolution: "html5-device-mockups@npm:3.2.1"
checksum: abba0bccc6398313102a9365203092a7c0844879d1b0492168279c516c9462d2a7e016045be565bc183e3405a1ae4929402eaceb1952abdbf16f1580afa68df3
languageName: node
linkType: hard

"http-cache-semantics@npm:^4.1.1":
version: 4.1.1
resolution: "http-cache-semantics@npm:4.1.1"
Expand DownExpand Up@@ -14159,6 +14166,7 @@ coolshapes-react@lowcoder-org/coolshapes-react:
file-saver: ^2.0.5
github-markdown-css: ^5.1.0
hotkeys-js: ^3.8.7
html5-device-mockups: ^3.2.1
http-proxy-middleware: ^2.0.6
immer: ^9.0.7
less: ^4.1.3
Expand All@@ -14175,6 +14183,7 @@ coolshapes-react@lowcoder-org/coolshapes-react:
react: ^18.2.0
react-best-gradient-color-picker: ^3.0.10
react-colorful: ^5.5.1
react-device-mockups: ^0.1.12
react-documents: ^1.2.1
react-dom: ^18.2.0
react-draggable: ^4.4.4
Expand DownExpand Up@@ -17672,6 +17681,18 @@ coolshapes-react@lowcoder-org/coolshapes-react:
languageName: node
linkType: hard

"react-device-mockups@npm:^0.1.12":
version: 0.1.12
resolution: "react-device-mockups@npm:0.1.12"
peerDependencies:
html5-device-mockups: ^3.2.1
prop-types: ^15.5.4
react: ^15.0.0 || ^16.0.0 || ^17.0.0
react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0
checksum: 738e969802c32810c2ca3ca3bd6c9bacf9b3d7adda0569c4f5c7fb1d68bab860ac7bb5a50aa2677d852143cb30ab8520e556c4dc7f53be154fd16ca08a9ba32c
languageName: node
linkType: hard

"react-documents@npm:^1.2.1":
version: 1.2.1
resolution: "react-documents@npm:1.2.1"
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp