fix: add mobile fit

topwar
guofei 2024-11-18 11:56:35 +08:00
parent d4959a2260
commit 9473427bd6
9 changed files with 280 additions and 169 deletions

View File

@ -15,6 +15,34 @@
} }
} }
@media only screen and (orientation: landscape) {
#abc {
width: 200px;
height: 200px;
background-color: red;
}
}
/* 竖屏 */
@media only screen and (orientation: portrait) {
#abc {
width: 200px;
height: 200px;
background-color: blue;
}
}
.pane_mobile {
position: fixed;
left: 0;
top: 0;
bottom: 0;
width: 200px;
height: 100vh;
background-color: #535353;
z-index: 1000;
}
.App-header { .App-header {
background-color: #282c34; background-color: #282c34;
min-height: 100vh; min-height: 100vh;
@ -62,7 +90,7 @@
} }
.pane-btn.checked { .pane-btn.checked {
border: 3px solid #00DE7A; border: 3px solid #00de7a;
} }
.pane-btn + .pane-btn { .pane-btn + .pane-btn {
@ -94,8 +122,8 @@
.language-select-container .language-select { .language-select-container .language-select {
width: 156px; width: 156px;
height: 42px; height: 42px;
background-color: #36383A; background-color: #36383a;
color: #EEEEEE; color: #eeeeee;
font-size: 14px; font-size: 14px;
display: flex; display: flex;
align-items: center; align-items: center;
@ -104,8 +132,8 @@
.language-select-warpper { .language-select-warpper {
position: relative; position: relative;
border-radius: 5px; border-radius: 5px;
background: #36383A; background: #36383a;
border: 1px solid #5B5B5B; border: 1px solid #5b5b5b;
box-shadow: 0px 3px 0px 0px rgba(0, 0, 0, 0.3); box-shadow: 0px 3px 0px 0px rgba(0, 0, 0, 0.3);
} }

View File

@ -29,6 +29,8 @@ import { withTranslation } from "react-i18next";
import i18n from "i18next"; import i18n from "i18next";
import languageImg from "./images/language.png"; import languageImg from "./images/language.png";
import Arrow from './images/arrow.svg' import Arrow from './images/arrow.svg'
import logoPanePng from "./images/logo-pane.png";
import SvgIcon from '@mui/material/SvgIcon'; import SvgIcon from '@mui/material/SvgIcon';
@ -40,11 +42,14 @@ function CustomIcon(props) {
); );
} }
const isMobile = () => {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)
}
class App extends React.Component { class App extends React.Component {
constructor(props) { constructor(props) {
super(); super();
this.state = { this.state = {
mode: "normal",
projects: [], projects: [],
selectedProject: {}, selectedProject: {},
selectedProjectName: "", selectedProjectName: "",
@ -61,10 +66,16 @@ class App extends React.Component {
keepLogin: false, keepLogin: false,
}, },
language: localStorage.getItem("lang") ?? "zh", language: localStorage.getItem("lang") ?? "zh",
isMobile: isMobile(),
}; };
this.t = props.t; this.t = props.t;
} }
componentDidMount() { componentDidMount() {
window.addEventListener('resize', () => {
this.setState({ isMobile: isMobile() });
})
const loginInfo = getLoginInfo(); const loginInfo = getLoginInfo();
var tenant = utils.getTenant(); var tenant = utils.getTenant();
const hideLogo = queryString.parseUrl(window.location.href)?.query const hideLogo = queryString.parseUrl(window.location.href)?.query
@ -161,12 +172,6 @@ class App extends React.Component {
}); });
} }
setMode(mode) {
this.setState({
mode: mode,
});
}
setLoginForm(form) { setLoginForm(form) {
this.setState({ this.setState({
loginForm: { loginForm: {
@ -208,18 +213,7 @@ class App extends React.Component {
} }
render() { render() {
var { const { device, projects, dataUrl, loading, loginOpen, loginForm, hideLogo, language, isMobile } = this.state;
mode,
device,
projects,
selectedProject,
dataUrl,
loading,
loginOpen,
loginForm,
hideLogo,
language,
} = this.state;
const { t } = this.props; const { t } = this.props;
return ( return (
@ -277,9 +271,10 @@ class App extends React.Component {
<Button onClick={() => this.login()}>{t("submit")}</Button> <Button onClick={() => this.login()}>{t("submit")}</Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
{
<Pane <Pane
mode={mode} isMobile={isMobile}
onModeChange={(_mode) => this.setMode(_mode)}
projects={projects} projects={projects}
device={device} device={device}
loading={loading} loading={loading}
@ -289,6 +284,10 @@ class App extends React.Component {
}} }}
onDeviceChange={(_device) => this.setDevice(_device)} onDeviceChange={(_device) => this.setDevice(_device)}
/> />
}
{
!isMobile &&
<div className="language-select-container"> <div className="language-select-container">
<div className="language-select-warpper"> <div className="language-select-warpper">
<img className="language-icon" src={languageImg} style={{ width: "18px" }} alt="" /> <img className="language-icon" src={languageImg} style={{ width: "18px" }} alt="" />
@ -315,6 +314,9 @@ class App extends React.Component {
</Select> </Select>
</div> </div>
</div> </div>
}
<div <div
style={{ style={{
display: "flex", display: "flex",
@ -326,20 +328,13 @@ class App extends React.Component {
backgroundRepeat: "no-repeat", backgroundRepeat: "no-repeat",
}} }}
> >
{mode === "normal" ? (
<DeviceFrame <DeviceFrame
isMobile={isMobile}
htmlUrl={this.selectedProjectUrl} htmlUrl={this.selectedProjectUrl}
device={device} device={device}
qrDataUrl={dataUrl} qrDataUrl={dataUrl}
refreshQrCode={() => this.refreshQrCode()} refreshQrCode={() => this.refreshQrCode()}
/> />
) : (
<SettingFrame
setting={selectedProject?.TextObjStr}
settingValue={this.projectSettingValue}
generate={(value) => this.UpdateSetting(value)}
/>
)}
</div> </div>
</div> </div>
); );

View File

@ -15,6 +15,7 @@
right: 24px; right: 24px;
bottom: 24px; bottom: 24px;
cursor: pointer; cursor: pointer;
z-index: 1000;
} }
.qrCode { .qrCode {

View File

@ -85,6 +85,7 @@ function DeviceFrame(props) {
var [cacheKey, setCacheKey] = useState(new Date().getTime()); var [cacheKey, setCacheKey] = useState(new Date().getTime());
var [openPopup, setOpenPopup] = useState(false); var [openPopup, setOpenPopup] = useState(false);
var [absoluteUrl, setAbsoluteUrl] = useState(""); var [absoluteUrl, setAbsoluteUrl] = useState("");
var [isMobile, setIsMobile] = useState(props.isMobile);
const { t } = useTranslation(); const { t } = useTranslation();
useEffect(() => { useEffect(() => {
@ -134,8 +135,9 @@ function DeviceFrame(props) {
return ( return (
<div className="deviceFrameContainer"> <div className="deviceFrameContainer">
<img src={refreshButtonPng} alt="refresh" onClick={() => refresh()} className="refreshButton" /> <img src={refreshButtonPng} alt="refresh" onClick={() => refresh()} className="refreshButton" />
{props.qrDataUrl && ( {props.qrDataUrl && !isMobile && (
<div className="qrCode"> <div className="qrCode">
<img src={props.qrDataUrl} alt="qr code" /> <img src={props.qrDataUrl} alt="qr code" />
<p style={{ margin: "0", }}> <p style={{ margin: "0", }}>
@ -147,6 +149,8 @@ function DeviceFrame(props) {
</div> </div>
)} )}
<Snackbar <Snackbar
open={openPopup} open={openPopup}
onClose={() => setOpenPopup(false)} onClose={() => setOpenPopup(false)}
@ -159,6 +163,10 @@ function DeviceFrame(props) {
{t("copySuccess")} {t("copySuccess")}
</Alert> </Alert>
</Snackbar> </Snackbar>
{
!isMobile ?
<div> <div>
<img src={config.bkg} alt="background" style={{ <img src={config.bkg} alt="background" style={{
position: "absolute", position: "absolute",
@ -188,7 +196,24 @@ function DeviceFrame(props) {
frameBorder={"0"} frameBorder={"0"}
/> />
)} )}
</div> : <div>
{
props.htmlUrl && <iframe
id="deviceFrame_mobile"
allow="clipboard-read; clipboard-write *"
title="preview"
src={absoluteUrl + "&cacheKey=" + cacheKey}
style={{
position: 'fixed',
inset: 0,
width: '100vw',
height: window.innerHeight,
}}
frameBorder={"0"}
/>
}
</div> </div>
}
</div> </div>
); );
} }

View File

@ -9,6 +9,56 @@
position: relative; position: relative;
} }
.selectPager {
left: 25px !important;
/* width: 319px !important; */
}
.Pane.mobile {
position: relative;
left: 0;
top: 0;
bottom: 0;
width: 60vw;
height: 100vh;
background-color: #535353;
z-index: 1000;
overflow: hidden;
transition: width 0.2s linear;
}
.flod-menu-btn-warpper {
position: fixed;
right: 12px;
top: 10px;
padding: 6px;
border-radius: 6px;
z-index: 1000;
display: flex;
background-color: #535353;
}
.flod-menu-btn-warpper .flod-menu-btn {
width: 28px;
height: 28px;
transition: all 0.2s linear;
}
.Pane.mobile.fold {
padding: 0;
width: 0;
}
.logo_mobile {
position: absolute;
width: 90%;
bottom: 20px;
left: 0;
right: 0;
margin: auto;
display: block;
}
.modeSelect { .modeSelect {
width: 100%; width: 100%;
border: none; border: none;
@ -38,11 +88,6 @@
cursor: pointer; cursor: pointer;
} }
.selectPager {
left: 25px !important;
width: 319px !important;
}
.bottomLogo { .bottomLogo {
position: absolute; position: absolute;
width: 322px; width: 322px;

View File

@ -15,6 +15,7 @@ import horizentalButton from "../../images/horizental-button.png";
import verticalChecked from "../../images/vertical-button-checked.png"; import verticalChecked from "../../images/vertical-button-checked.png";
import verticalButton from "../../images/vertical-button.png"; import verticalButton from "../../images/vertical-button.png";
import modeSelectPng from "../../images/mode-select.png"; import modeSelectPng from "../../images/mode-select.png";
import menuIcon from "../../images/menu.png";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import SvgIcon from '@mui/material/SvgIcon'; import SvgIcon from '@mui/material/SvgIcon';
@ -26,7 +27,7 @@ function CustomIcon(props) {
); );
} }
var deviceConfigs = [ const deviceConfigs = [
{ {
name: "iPhone", name: "iPhone",
icon: iphonePng, icon: iphonePng,
@ -51,16 +52,12 @@ var deviceConfigs = [
]; ];
function Pane(props) { function Pane(props) {
var [mode, setMode] = useState(props.mode); var [isMobile] = useState(props.isMobile);
var [device, setDevice] = useState(props.device); var [device, setDevice] = useState(props.device);
var [project, setProject] = useState(props.project); var [project, setProject] = useState(props.project);
const { t } = useTranslation();
var modeChange = (e) => { const [foldPanel, setFoldPanel] = useState(props.isMobile ? true : false);
var _mode = e.target.value; const { t } = useTranslation();
setMode(_mode);
props.onModeChange(e.target.value);
};
var deviceChange = (_device) => { var deviceChange = (_device) => {
setDevice(_device); setDevice(_device);
@ -70,6 +67,7 @@ function Pane(props) {
var projectSelect = (e) => { var projectSelect = (e) => {
var projectName = e.target.value; var projectName = e.target.value;
setProject(projectName); setProject(projectName);
setFoldPanel(true)
props.onProjectSelect(projectName); props.onProjectSelect(projectName);
}; };
@ -77,8 +75,26 @@ function Pane(props) {
props.projects.length && !project && setProject(props.projects[0]); props.projects.length && !project && setProject(props.projects[0]);
}, [props.projects]); }, [props.projects]);
return ( return (
<div className="Pane"> <div className={`Pane ${isMobile ? 'mobile' : ''} ${foldPanel ? 'fold' : ''}`} style={{ height: window.innerHeight }}>
{
isMobile &&
<div className="flod-menu-btn-warpper">
<img
onClick={() => {
setFoldPanel(!foldPanel)
}}
src={menuIcon}
alt="menu"
className="flod-menu-btn"
style={{
transform: !foldPanel ? 'rotate(-90deg)' : '',
}}
/>
</div>
}
<div> <div>
{props.loading ? ( {props.loading ? (
<CircularProgress color="inherit" /> <CircularProgress color="inherit" />
@ -98,9 +114,6 @@ function Pane(props) {
borderRadius: '5px', borderRadius: '5px',
color: "white", color: "white",
boxShadow: '0px 3px 0px 0px rgba(0, 0, 0, 0.3)', boxShadow: '0px 3px 0px 0px rgba(0, 0, 0, 0.3)',
// '&.MuiOutlinedInput-notchedOutline': {
// borderColor: '#757575', // 设置焦点时的边框颜色为红色
// },
'&.Mui-focused': { '&.Mui-focused': {
borderColor: '#757575', borderColor: '#757575',
'&.MuiOutlinedInput-notchedOutline': { '&.MuiOutlinedInput-notchedOutline': {
@ -124,7 +137,9 @@ function Pane(props) {
)} )}
</div> </div>
<List
{
!isMobile && <List
sx={{ sx={{
paddingTop: '20px' paddingTop: '20px'
}} }}
@ -164,8 +179,10 @@ function Pane(props) {
</ListItem> </ListItem>
))} ))}
</List> </List>
}
{!props.hideLogo && <div className="bottomLogo"><img src={logoPanePng} alt="logo" width={"100%"} /></div>} {(!props.hideLogo && !isMobile) && <div className="bottomLogo"><img src={logoPanePng} alt="logo" width={"100%"} /></div>}
{(!props.hideLogo && isMobile) && <img src={logoPanePng} className="logo_mobile" alt="logo" width={"100%"} />}
</div> </div>
); );
} }

View File

@ -1,6 +1,6 @@
var BaseUrl = "https://api.soyootech.com/"; // var BaseUrl = "https://api.soyootech.com/";
// var BaseUrl = "api/"; var BaseUrl = "api/";
export async function UserLogin(loginForm) { export async function UserLogin(loginForm) {
try { try {
var response = await fetch(BaseUrl + "SoyooUser/previewlogin", { var response = await fetch(BaseUrl + "SoyooUser/previewlogin", {

BIN
src/images/menu.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,12 +1,12 @@
const { createProxyMiddleware } = require("http-proxy-middleware"); const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) { module.exports = function (app) {
// app.use( app.use(
// "/api", "/api",
// createProxyMiddleware({ createProxyMiddleware({
// target: "https://api.soyootech.com/", target: "https://api.soyootech.com/",
// changeOrigin: true, changeOrigin: true,
// pathRewrite: { "^/api": "" }, pathRewrite: { "^/api": "" },
// }) })
// ); );
}; };