feat: connection check and welcome pop-up

This commit is contained in:
arielherself 2023-11-24 20:06:22 +08:00
parent 18be7e13ee
commit 890c3b77c3
11 changed files with 170 additions and 60 deletions

12
.idea/frontend.iml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/frontend.iml" filepath="$PROJECT_DIR$/.idea/frontend.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -1,27 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="3c7078e7-6f30-4d92-9696-11496f9e6dff" name="Changes" comment=""> <list default="true" id="3c7078e7-6f30-4d92-9696-11496f9e6dff" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/nanomap/.idea/.gitignore" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/.idea/jsLibraryMappings.xml" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/public/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/public/index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/.idea/modules.xml" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/src/App.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/App.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/.idea/nanomap.iml" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/src/Networking.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/Networking.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/.idea/vcs.xml" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/src/SimulateClick.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/SimulateClick.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/.gitignore" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/src/UMap.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/UMap.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/README.md" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/package-lock.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/package.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/public/favicon.ico" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/public/index.html" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/src/App.css" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/src/App.js" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/src/App.test.js" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/src/Networking.js" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/src/SimulateClick.js" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/src/UMap.js" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/src/index.css" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/src/index.js" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/nanomap/nanomap/src/logo.svg" beforeDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -34,29 +23,29 @@
<component name="MarkdownSettingsMigration"> <component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" /> <option name="stateVersion" value="1" />
</component> </component>
<component name="ProjectColorInfo"><![CDATA[{ <component name="ProjectColorInfo">{
"associatedIndex": 3 &quot;associatedIndex&quot;: 3
}]]></component> }</component>
<component name="ProjectId" id="2Yc9rUDmr9wvYpz7Xdq1eJVJoJy" /> <component name="ProjectId" id="2Yc9rUDmr9wvYpz7Xdq1eJVJoJy" />
<component name="ProjectViewState"> <component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent"><![CDATA[{ <component name="PropertiesComponent">{
"keyToString": { &quot;keyToString&quot;: {
"RunOnceActivity.OpenProjectViewOnStart": "true", &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
"RunOnceActivity.ShowReadmeOnStart": "true", &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
"WebServerToolWindowFactoryState": "false", &quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
"git-widget-placeholder": "dev", &quot;git-widget-placeholder&quot;: &quot;dev&quot;,
"last_opened_file_path": "/home/user/Documents/fd_data-structures/pj/nanomap-frontend", &quot;last_opened_file_path&quot;: &quot;/home/user/Documents/fd_data-structures/pj/frontend&quot;,
"node.js.detected.package.eslint": "true", &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
"node.js.detected.package.tslint": "true", &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
"node.js.selected.package.eslint": "(autodetect)", &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
"node.js.selected.package.tslint": "(autodetect)", &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
"nodejs_package_manager_path": "npm", &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
"vue.rearranger.settings.migration": "true" &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
} }
}]]></component> }</component>
<component name="RunManager"> <component name="RunManager">
<configuration name="start" type="js.build_tools.npm" temporary="true" nameIsGenerated="true"> <configuration name="start" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
<package-json value="$PROJECT_DIR$/package.json" /> <package-json value="$PROJECT_DIR$/package.json" />
@ -83,6 +72,8 @@
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1700814200305</updated> <updated>1700814200305</updated>
<workItem from="1700814201341" duration="315000" /> <workItem from="1700814201341" duration="315000" />
<workItem from="1700814808669" duration="47000" />
<workItem from="1700822693197" duration="4588000" />
</task> </task>
<servers /> <servers />
</component> </component>

BIN
misc/icon.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
public/icon.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -6,7 +6,7 @@
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/> crossorigin=""/>
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <link rel="shortcut icon" href="%PUBLIC_URL%/icon.jpeg">
<!-- <!--
Notice the use of %PUBLIC_URL% in the tag above. Notice the use of %PUBLIC_URL% in the tag above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
@ -16,7 +16,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>nanoMap</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@ -1,18 +1,110 @@
import React, { Component } from 'react'; import React, {Component, useState} from 'react';
import logo from './logo.svg'; import {Transition} from 'react-transition-group';
import './App.css'; import './App.css';
import UMap from "./UMap"; import UMap from "./UMap";
import {
Alert,
Box,
CircularProgress,
DialogContent,
DialogTitle,
Modal,
ModalDialog,
Sheet,
Typography
} from "@mui/joy";
import {WebhookOutlined} from "@mui/icons-material";
import {post} from "./Networking";
class App extends Component { export default function App() {
render() { const [featureOpen, setFeatureOpen] = useState(true);
const [version, setVersion] = useState('');
const [intro, setIntro] = useState('');
const hs=setInterval(()=>{
post('handshake', []).then((response)=>{
const [version,intro]=response.split('@@');
setVersion(version);
setIntro(intro);
clearInterval(hs);
}).catch((e)=> {
console.error(e);
setVersion('');
});
}, 1000);
return ( return (
<div className="App"> <div className="App" style={{pointerEvents: version !== '' ? 'all' : 'none'}}>
<div style={{display: 'flex', justifyContent: 'center', alignItems: 'center'}}> <div style={{display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<UMap/> <UMap/>
<Transition in={featureOpen} timeout={400}>
{(state) => (
<Modal style={{pointerEvents: version !== '' ? 'all' : 'none'}}
keepMounted
open={!['exited', 'exiting'].includes(state)}
onClose={() => setFeatureOpen(false)}
slotProps={{
backdrop: {
sx: {
opacity: 0,
backdropFilter: 'none',
transition: `opacity 400ms, backdrop-filter 400ms`,
...{
entering: {opacity: 1, backdropFilter: 'blur(8px)'},
entered: {opacity: 1, backdropFilter: 'blur(8px)'},
}[state],
},
},
}}
sx={{
visibility: state === 'exited' ? 'hidden' : 'visible',
zIndex: 'tooltip'
}}
>
<ModalDialog
sx={{
opacity: 0,
transition: `opacity 300ms`,
...{
entering: {opacity: 1},
entered: {opacity: 1},
}[state],
}}
>
<Alert style={{display: version!==''?'none':'flex'}}
variant="soft"
color="warning"
invertedColors
startDecorator={
<CircularProgress size="lg" color="warning">
<WebhookOutlined/>
</CircularProgress>
}
sx={{alignItems: 'flex-start', gap: '1rem'}}
>
<Box sx={{flex: 1}}>
<Typography level="title-lg">Still connecting...</Typography>
<Typography level="body-md">
nanoMap requires a valid backend to work. If it takes too long, please check
your connection or see our status page.
</Typography>
</Box>
</Alert>
<Sheet style={{display: version !== '' ? 'flex' : 'none'}}>
<img src={'icon.jpeg'}
style={{height: '150px', display: 'flex', margin: 'auto', borderRadius: '50%'}}
alt={'nanoMap'}/>
</Sheet>
<DialogTitle style={{display: version !== '' ? 'flex' : 'none'}}
sx={{margin: 'auto', fontSize: '200%'}}>What's new in
nanoMap {version}</DialogTitle>
<DialogContent style={{display: version !== '' ? 'flex' : 'none'}}
sx={{margin: 'auto'}}>
<div dangerouslySetInnerHTML={{ __html: intro }} />
</DialogContent>
</ModalDialog>
</Modal>
)}
</Transition>
</div> </div>
</div> </div>
); );
}
} }
export default App;

View File

@ -13,4 +13,4 @@ export function post(method,args) {
return response_data; return response_data;
}; };
return ft(); return ft();
}; }

View File

@ -1,12 +1,12 @@
import {Button, IconButton, ButtonGroup, Menu, MenuItem, Stack} from "@mui/joy"; import {Button, IconButton, ButtonGroup, Menu, MenuItem, Stack} from "@mui/joy";
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
import React from "react"; import React from "react";
import {Add} from "@mui/icons-material";
export default function SimulateClick() { export default function SimulateClick() {
return ( return (
<ButtonGroup buttonFlex={1} aria-label="flex button group" sx={{zIndex: 'modal'}}> <ButtonGroup buttonFlex={1} aria-label="flex button group" sx={{zIndex: 'modal'}}>
<Button variant={'solid'} color={'success'}>Starting</Button> <Button variant={'solid'} color={'primary'} startDecorator={<Add />}>Add</Button>
<Button variant={'solid'} color={'primary'}>Destination</Button>
</ButtonGroup> </ButtonGroup>
); );
} }

View File

@ -1,4 +1,5 @@
import React, {Component, useEffect, useRef, useState} from 'react'; import React, {Component, useEffect, useRef, useState} from 'react';
import * as L from 'leaflet';
import SearchIcon from '@mui/icons-material/Search'; import SearchIcon from '@mui/icons-material/Search';
import {MapContainer, TileLayer, Marker, Popup, useMap} from 'react-leaflet'; import {MapContainer, TileLayer, Marker, Popup, useMap} from 'react-leaflet';
import {useMapEvents} from 'react-leaflet/hooks'; import {useMapEvents} from 'react-leaflet/hooks';
@ -7,7 +8,6 @@ import {Autocomplete, CircularProgress, Sheet} from "@mui/joy";
import SimulateClick from "./SimulateClick"; import SimulateClick from "./SimulateClick";
const AppleParkLoc=[37.334835049999995,-122.01139165956805]; const AppleParkLoc=[37.334835049999995,-122.01139165956805];
class Markers extends Component { class Markers extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -16,12 +16,10 @@ class Markers extends Component {
render() { render() {
const mks=this.state.markers.map((p, i) => ( const mks=this.state.markers.map((p, i) => (
<Marker position={[p[0], p[1]]} opacity={1.0}><Popup>Generated <Marker interactive={false} position={[p[0], p[1]]} opacity={1.0} />
by <code>Markers()</code></Popup></Marker>
)); ));
const cmks=this.state.candMarkers.map((p, i) => ( const cmks=this.state.candMarkers.map((p, i) => (
<Marker interactive={false} position={[p[0], p[1]]} opacity={0.5}><Popup>Generated <Marker interactive={false} position={[p[0], p[1]]} opacity={0.5} />
by <code>Markers()</code></Popup></Marker>
)); ));
return mks.concat(cmks); return mks.concat(cmks);
} }
@ -71,7 +69,10 @@ function MapClickHandler({mks}) {
const lat = e.latlng.lat, lng = e.latlng.lng; const lat = e.latlng.lat, lng = e.latlng.lng;
console.info(`Clicking on ${lat} ${lng}`); console.info(`Clicking on ${lat} ${lng}`);
mks.current.addMarker(lat, lng); mks.current.addMarker(lat, lng);
post('click', [lat, lng]); post('click', [lat, lng]).catch((e)=>{
console.error(e);
location.reload();
});
}, },
// TODO // TODO
locationfound: (location) => { locationfound: (location) => {