mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 02:56:41 +07:00
styled panels
This commit is contained in:
parent
7229a48297
commit
d17a7b6aef
24 changed files with 470 additions and 421 deletions
10
package-lock.json
generated
10
package-lock.json
generated
|
@ -11923,6 +11923,11 @@
|
|||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
||||
"dev": true
|
||||
},
|
||||
"typeface-montserrat": {
|
||||
"version": "0.0.54",
|
||||
"resolved": "https://registry.npmjs.org/typeface-montserrat/-/typeface-montserrat-0.0.54.tgz",
|
||||
"integrity": "sha512-Typhap0PWT299+Va0G/8ZtycHMXrH4gBWKfiW977KEBx5rXUUCa70gvqLx1fdA0WAo6bhSAQmo8uc+QFAmjPww=="
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.18",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz",
|
||||
|
@ -12993,6 +12998,11 @@
|
|||
"integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==",
|
||||
"dev": true
|
||||
},
|
||||
"wfk-montserrat": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wfk-montserrat/-/wfk-montserrat-1.0.0.tgz",
|
||||
"integrity": "sha512-XgRPn20Qp20BHs1UXyvMVQgblHSwl3bMhrNeXF921fqxIOT0ZPMynqWa60q5wU5RkRTxQfZsgv0Rt6prMSpvhQ=="
|
||||
},
|
||||
"whatwg-fetch": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
|
||||
|
|
|
@ -63,7 +63,9 @@
|
|||
"scrypt": "^6.0.3",
|
||||
"styled-components": "^3.2.6",
|
||||
"styled-theming": "^2.2.0",
|
||||
"webpack-git-hash": "^1.0.2"
|
||||
"typeface-montserrat": "0.0.54",
|
||||
"webpack-git-hash": "^1.0.2",
|
||||
"wfk-montserrat": "^1.0.0"
|
||||
},
|
||||
"flow-coverage-report": {
|
||||
"includeGlob": [
|
||||
|
|
|
@ -11,7 +11,7 @@ export const Fills = () => (
|
|||
|
||||
<defs>
|
||||
<linearGradient id="activePathGradient" x1="-20%" x2="50%" y1="0%" y2="140%">
|
||||
<stop offset="0%" stopColor="#ff9900" />
|
||||
<stop offset="0%" stopColor="#ff7700" />
|
||||
<stop offset="100%" stopColor="#ff3344" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
|
14
src/components/panels/EditorDialog.jsx
Normal file
14
src/components/panels/EditorDialog.jsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
import { MODES } from '$constants/modes';
|
||||
|
||||
import { RouterHelper } from '$components/router/RouterHelper';
|
||||
|
||||
export const EditorDialog = ({ mode, routerPoints }) => {
|
||||
const showDialog = (mode === MODES.ROUTER);
|
||||
return (
|
||||
showDialog &&
|
||||
<div id="control-dialog">
|
||||
{ mode === MODES.ROUTER && <RouterHelper routerPoints={routerPoints} /> }
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -2,7 +2,8 @@ import React from 'react';
|
|||
import { MODES } from '$constants/modes';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { Icon } from '$components/Icon';
|
||||
import { Icon } from '$components/panels/Icon';
|
||||
import { EditorDialog } from '$components/panels/EditorDialog';
|
||||
|
||||
export class EditorPanel extends React.PureComponent {
|
||||
startPolyMode = () => this.props.editor.changeMode(MODES.POLY);
|
||||
|
@ -14,35 +15,69 @@ export class EditorPanel extends React.PureComponent {
|
|||
startShotterMode = () => this.props.editor.changeMode(MODES.SHOTTER);
|
||||
|
||||
render() {
|
||||
const { mode } = this.props;
|
||||
const { mode, routerPoints } = this.props;
|
||||
|
||||
return (
|
||||
<div id="control-screen">
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.ROUTER })}
|
||||
onClick={this.startRouterMode}
|
||||
>
|
||||
<Icon icon="icon-router" />
|
||||
</button>
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.POLY })}
|
||||
onClick={this.startPolyMode}
|
||||
>
|
||||
<Icon icon="icon-poly" />
|
||||
</button>
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.STICKERS })}
|
||||
onClick={this.startStickerMode}
|
||||
>
|
||||
<Icon icon="icon-sticker" />
|
||||
</button>
|
||||
<div>
|
||||
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.SHOTTER })}
|
||||
onClick={this.startShotterMode}
|
||||
>
|
||||
<Icon icon="icon-shooter" />
|
||||
</button>
|
||||
<EditorDialog
|
||||
mode={mode}
|
||||
routerPoints={routerPoints}
|
||||
/>
|
||||
|
||||
<div className="panel">
|
||||
<div className="control-bar">
|
||||
<button
|
||||
onClick={this.startShotterMode}
|
||||
>
|
||||
<span>РЕДАКТОР</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="panel right">
|
||||
<div className="control-bar">
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.ROUTER })}
|
||||
onClick={this.startRouterMode}
|
||||
>
|
||||
<Icon icon="icon-router" />
|
||||
</button>
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.POLY })}
|
||||
onClick={this.startPolyMode}
|
||||
>
|
||||
<Icon icon="icon-poly" />
|
||||
</button>
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.STICKERS })}
|
||||
onClick={this.startStickerMode}
|
||||
>
|
||||
<Icon icon="icon-sticker" />
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="control-sep" />
|
||||
|
||||
<div className="control-bar">
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.SHOTTER })}
|
||||
onClick={this.startShotterMode}
|
||||
>
|
||||
<Icon icon="icon-shooter" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={classnames('highlighted', { active: mode === MODES.SHOTTER })}
|
||||
onClick={this.startShotterMode}
|
||||
>
|
||||
<span>СХОРОНИТЬ</span>
|
||||
<Icon icon="icon-shooter" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import sprite from '$sprites/icon.svg';
|
||||
|
||||
export const Icon = ({ icon, size = 32 }) => (
|
||||
<svg width={size} height={size} viewBox="0 0 32 32" preserveAspectRatio="midXmidY meet">
|
||||
<svg width={size} height={size} viewBox="0 0 32 32">
|
||||
<use xlinkHref={`${sprite}#${icon}`} x={0} y={0} />
|
||||
</svg>
|
||||
);
|
54
src/components/router/RouterHelper.jsx
Normal file
54
src/components/router/RouterHelper.jsx
Normal file
|
@ -0,0 +1,54 @@
|
|||
import React from 'react';
|
||||
|
||||
const noPoints = () => (
|
||||
<div className="router-helper">
|
||||
<div className="router-helper__text">
|
||||
<div className="big white">Укажите на карте первую точку маршрута</div>
|
||||
<div className="small gray">Путь прокладывается по улицам, тротуарам и тропинкам</div>
|
||||
</div>
|
||||
<div className="router-helper__buttons">
|
||||
<div className="button router-helper__button">
|
||||
Отмена
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const firstPoint = () => (
|
||||
<div className="router-helper">
|
||||
<div className="router-helper__text">
|
||||
<div className="big white">Укажите на карте конечную точку маршрута</div>
|
||||
<div className="small gray"> Вы сможете добавить уточняющие точки</div>
|
||||
</div>
|
||||
<div className="router-helper__buttons">
|
||||
<div className="button router-helper__button">
|
||||
Отмена
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const draggablePoints = () => (
|
||||
<div className="router-helper">
|
||||
<div className="router-helper__text">
|
||||
<div className="big white">Продолжите маршрут, щелкая по карте</div>
|
||||
<div className="small gray">Потяните линию, чтобы указать промежуточные точки</div>
|
||||
</div>
|
||||
<div className="router-helper__buttons button-group">
|
||||
<div className="button button_red router-helper__button">
|
||||
Отмена
|
||||
</div>
|
||||
<div className="button primary router-helper__button">
|
||||
Применить
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const RouterHelper = ({ routerPoints }) => (
|
||||
<div>
|
||||
{ !routerPoints && noPoints() }
|
||||
{ routerPoints === 1 && firstPoint() }
|
||||
{ routerPoints >= 2 && draggablePoints() }
|
||||
</div>
|
||||
);
|
|
@ -7,37 +7,38 @@ import { Fills } from '$components/Fills';
|
|||
export class App extends React.Component {
|
||||
state = {
|
||||
mode: 'none',
|
||||
editor: null,
|
||||
routerPoints: 0,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const container = 'map';
|
||||
const { mode } = this.state;
|
||||
|
||||
const editor = new Editor({
|
||||
container,
|
||||
mode,
|
||||
setMode: this.setMode,
|
||||
});
|
||||
|
||||
this.setState({ editor })
|
||||
}
|
||||
|
||||
setMode = mode => {
|
||||
this.setState({ mode });
|
||||
};
|
||||
setRouterPoints = routerPoints => {
|
||||
this.setState({ routerPoints });
|
||||
};
|
||||
|
||||
editor = new Editor({
|
||||
container: 'map',
|
||||
mode: this.state.mode,
|
||||
setMode: this.setMode,
|
||||
setRouterPoints: this.setRouterPoints,
|
||||
});
|
||||
|
||||
render() {
|
||||
const {
|
||||
state: { mode, editor },
|
||||
editor,
|
||||
state: { mode, routerPoints },
|
||||
} = this;
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Fills />
|
||||
<div id="map" />
|
||||
<EditorPanel editor={editor} mode={mode} />
|
||||
<EditorPanel
|
||||
editor={editor}
|
||||
mode={mode}
|
||||
routerPoints={routerPoints}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,5 +11,7 @@
|
|||
<meta content="/misc/vk_preview.png">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<section id="index"></section>
|
||||
<div id="map" />
|
||||
</body>
|
||||
|
|
|
@ -3,8 +3,7 @@ import ReactDOM from 'react-dom';
|
|||
|
||||
import { App } from '$containers/App';
|
||||
|
||||
import '$styles/map.less';
|
||||
import '$styles/controls.less';
|
||||
import '$styles/main.less';
|
||||
|
||||
export const Index = () => (
|
||||
<App />
|
||||
|
|
|
@ -9,7 +9,8 @@ export class Editor {
|
|||
constructor({
|
||||
container,
|
||||
mode,
|
||||
setMode
|
||||
setMode,
|
||||
setRouterPoints,
|
||||
}) {
|
||||
this.map = new Map({ container });
|
||||
|
||||
|
@ -17,7 +18,7 @@ export class Editor {
|
|||
|
||||
this.poly = new Poly({ map, routerMoveStart, lockMapClicks });
|
||||
this.stickers = new Stickers({ map, lockMapClicks });
|
||||
this.router = new Router({ map, lockMapClicks });
|
||||
this.router = new Router({ map, lockMapClicks, setRouterPoints });
|
||||
this.shotter = new Shotter({ map });
|
||||
|
||||
this.setMode = setMode;
|
||||
|
@ -91,7 +92,7 @@ export class Editor {
|
|||
|
||||
if (!latlngs || !latlngs.length) return;
|
||||
|
||||
this.router.startFrom(latlngs.pop());
|
||||
this.router.startFrom(latlngs[latlngs.length - 1]);
|
||||
};
|
||||
|
||||
routerMoveStart = () => {
|
||||
|
|
|
@ -8,7 +8,7 @@ export class Map {
|
|||
constructor({ container }) {
|
||||
this.map = map(container, { editable: true }).setView([55.0153275, 82.9071235], 13);
|
||||
|
||||
this.tileLayer = tileLayer(providers.default, {
|
||||
this.tileLayer = tileLayer(providers.dgis, {
|
||||
attribution: 'Независимое Велосообщество',
|
||||
maxNativeZoom: 18,
|
||||
maxZoom: 18,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { polyline } from "leaflet";
|
||||
|
||||
const polyStyle = { color: 'url(#activePathGradient)', weight: '5' };
|
||||
const polyStyle = { color: 'url(#activePathGradient)', weight: '6' };
|
||||
// const polyStyle = { color: '#ff3344', weight: '5' };
|
||||
|
||||
export class Poly {
|
||||
constructor({ map, routerMoveStart, lockMapClicks }) {
|
||||
|
|
|
@ -4,11 +4,13 @@ import { CONFIG } from '$config';
|
|||
import { DomMarker } from '$utils/DomMarker';
|
||||
|
||||
export class Router {
|
||||
constructor({ map, lockMapClicks }) {
|
||||
constructor({ map, lockMapClicks, setRouterPoints }) {
|
||||
const routeLine = r => Routing.line(r, {
|
||||
styles: [
|
||||
{ color: 'white', opacity: 0.8, weight: 6 },
|
||||
{ color: '#4597d0', opacity: 1, weight: 4, dashArray: '15,10' }
|
||||
{
|
||||
color: '#4597d0', opacity: 1, weight: 4, dashArray: '15,10'
|
||||
}
|
||||
],
|
||||
addWaypoints: true,
|
||||
}).on('linetouched', this.lockPropagations);
|
||||
|
@ -30,14 +32,13 @@ export class Router {
|
|||
routeWhileDragging: true,
|
||||
}),
|
||||
routeWhileDragging: true
|
||||
});
|
||||
// .on('waypointschanged', this.updateWaypointsByEvent);
|
||||
}).on('waypointschanged', this.updateWaypointsCount);
|
||||
|
||||
this.router.addTo(map);
|
||||
|
||||
this.waypoints = [];
|
||||
this.lockMapClicks = lockMapClicks;
|
||||
|
||||
this.setRouterPoints = setRouterPoints;
|
||||
// this.router._line.on('mousedown', console.log);
|
||||
}
|
||||
//
|
||||
|
@ -46,22 +47,7 @@ export class Router {
|
|||
console.log('push', waypoints);
|
||||
this.router.setWaypoints([...waypoints, { lat, lng }]);
|
||||
};
|
||||
//
|
||||
// pushWaypoint = latlng => {
|
||||
// this.waypoints.push(latlng);
|
||||
// this.updateWaypoints();
|
||||
// };
|
||||
//
|
||||
// updateWaypointsByEvent = (e) => {
|
||||
// console.log('upd', e);
|
||||
// // this.waypoints = waypoints.map(({ latlng }) => latlng);
|
||||
//
|
||||
// };
|
||||
//
|
||||
// updateWaypoints = () => {
|
||||
// this.router.setWaypoints(this.waypoints);
|
||||
// };
|
||||
//
|
||||
|
||||
createWaypointMarker = () => {
|
||||
const element = document.createElement('div');
|
||||
|
||||
|
@ -119,4 +105,9 @@ export class Router {
|
|||
|
||||
this.router.setWaypoints(waypoints);
|
||||
};
|
||||
|
||||
updateWaypointsCount = () => {
|
||||
const waypoints = this.router.getWaypoints().filter(({ latLng }) => !!latLng);
|
||||
this.setRouterPoints(waypoints.length);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,5 +34,6 @@
|
|||
<g transform="translate(18 6)">
|
||||
<path d="m0 0l-4.391.054c-1.418.531-2.34 1.756-3.176 3.102h-5.178c-.68.317-1.351.655-1.455 2.584v11.49c.17 1.001.58 1.765 1.455 2.06h22.537c.746-.044 1.288-.426 1.68-1.06v-13.517c-.185-1.643-.916-1.65-1.68-1.557h-6.62c-.326-1.26-1.91-2.247-3.172-3.156zm-2.122 5.289c3.227 0 5.87 2.626 5.87 5.846s-2.643 5.845-5.87 5.845c-3.227 0-5.869-2.626-5.869-5.845 0-3.22 2.642-5.846 5.87-5.846zm0 1.998a3.844 3.844 0 0 0-3.869 3.848 3.842 3.842 0 0 0 3.87 3.845 3.84 3.84 0 0 0 3.866-3.845 3.842 3.842 0 0 0-3.867-3.848z" />
|
||||
</g>
|
||||
</g>
|
||||
</defs>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
35
src/styles/button.less
Normal file
35
src/styles/button.less
Normal file
|
@ -0,0 +1,35 @@
|
|||
.button {
|
||||
background: #444444;
|
||||
padding: 4px 16px;
|
||||
height: 18px;
|
||||
line-height: 1em;
|
||||
border-radius: 2px;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&.primary {
|
||||
background: #3c78db;
|
||||
}
|
||||
|
||||
&.danger {
|
||||
background: #ed2f3b;
|
||||
}
|
||||
}
|
||||
|
||||
.button-group {
|
||||
.button {
|
||||
border-radius: 0;
|
||||
|
||||
&:first-child {
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
|
||||
#control-screen {
|
||||
position: fixed;
|
||||
right: 10px;
|
||||
bottom: 0px;
|
||||
height: 48px;
|
||||
min-width: 120px;
|
||||
background: #333333;
|
||||
z-index: 2;
|
||||
color: white;
|
||||
border-radius: 4px 4px 0 0;
|
||||
padding: 0 4px 0 4px;
|
||||
|
||||
button {
|
||||
border: none;
|
||||
background: transparent;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
padding: 8px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
svg {
|
||||
fill: url(#activeButtonGradient);
|
||||
stroke: url(#activeButtonGradient);
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: white;
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
import styled from 'styled-components';
|
||||
|
||||
export const ControlsScreen = styled.div`
|
||||
position: fixed;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
height: 48px;
|
||||
min-width: 120px;
|
||||
background: #333333;
|
||||
border-radius: 2px;
|
||||
z-index: 2;
|
||||
color: white;
|
||||
`;
|
26
src/styles/main.less
Normal file
26
src/styles/main.less
Normal file
|
@ -0,0 +1,26 @@
|
|||
@import 'map.less';
|
||||
@import 'panel.less';
|
||||
@import 'router.less';
|
||||
@import 'stickers.less';
|
||||
@import 'button.less';
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.gray {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.big {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.small {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.white {
|
||||
color: white;
|
||||
}
|
|
@ -38,139 +38,3 @@
|
|||
.leaflet-control-container .leaflet-routing-container-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.router-waypoint {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-left: -20px;
|
||||
margin-top: -20px;
|
||||
outline: none;
|
||||
z-index: 10001;
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 0 2px #4597d0;
|
||||
margin-left: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.sticker-container {
|
||||
outline: none;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: ' ';
|
||||
box-shadow: 0 0 10px 1px #ff3344;
|
||||
background: #ff334422;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
left: -24px;
|
||||
top: -24px;
|
||||
position: absolute;
|
||||
border-radius: 40px;
|
||||
opacity: 0;
|
||||
transition: opacity 250ms, transform 500ms;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
&:hover, &:active {
|
||||
.sticker-delete {
|
||||
transform: scale(1);
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
&:before {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sticker-label {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
position: absolute;
|
||||
background: white;
|
||||
border-radius: 32px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
outline: none;
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
box-shadow: 0 0 0 1px #ff3344;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
left: -16px;
|
||||
top: -16px;
|
||||
position: absolute;
|
||||
border-radius: 40px;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sticker-arrow {
|
||||
position: absolute;
|
||||
background: red;
|
||||
transform-origin: 0 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
background: #ff3344;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transform-origin: 0 0;
|
||||
transform: rotate(-45deg);
|
||||
left: 0;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.sticker-delete {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: red;
|
||||
border-radius: 24px;
|
||||
transition: transform 500ms;
|
||||
transform: scale(0);
|
||||
opacity: 1;
|
||||
pointer-events: none;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-control-container .leaflet-routing-container-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.router-waypoint {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-left: -20px;
|
||||
margin-top: -20px;
|
||||
outline: none;
|
||||
z-index: 10001;
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 0 2px #4597d0;
|
||||
margin-left: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,162 +0,0 @@
|
|||
import styled, { css } from 'styled-components';
|
||||
|
||||
const vertexMixin = css`
|
||||
.leaflet-vertex-icon, .leaflet-middle-icon {
|
||||
border-radius: 10px;
|
||||
opacity :1;
|
||||
border: none;
|
||||
width: 16px !important;
|
||||
height: 16px !important;margin-left:-8px !important;margin-top:-8px !important;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.leaflet-vertex-icon::after, .leaflet-middle-icon::after {
|
||||
content: ' ';
|
||||
position:absolute;top:4px;left:4px;width:8px;height:8px;
|
||||
background:white;border-radius: 8px;transform:scale(1);
|
||||
transition:transform 150ms;
|
||||
}
|
||||
|
||||
.leaflet-vertex-icon:hover, .leaflet-middle-icon:hover {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.leaflet-vertex-icon:hover::after, .leaflet-middle-icon:hover::after,
|
||||
.leaflet-vertex-icon:active::after, .leaflet-middle-icon:active::after {
|
||||
transform: scale(2);
|
||||
box-shadow: #999 0 0 5px 2px;
|
||||
}
|
||||
`;
|
||||
|
||||
const routerMixin = css`
|
||||
.leaflet-control-container .leaflet-routing-container-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.router-waypoint {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-left: -20px;
|
||||
margin-top: -20px;
|
||||
outline: none;
|
||||
z-index: 10001;
|
||||
|
||||
::after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 0 2px #4597d0;
|
||||
margin-left: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const stickers = css`
|
||||
.sticker-container {
|
||||
outline: none;
|
||||
position: relative;
|
||||
|
||||
::before {
|
||||
content: ' ';
|
||||
box-shadow: 0 0 10px 1px #ff3344;
|
||||
background: #ff334422;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
left: -24px;
|
||||
top: -24px;
|
||||
position: absolute;
|
||||
border-radius: 40px;
|
||||
opacity: 0;
|
||||
transition: opacity 250ms;
|
||||
}
|
||||
|
||||
:hover {
|
||||
.sticker-delete {
|
||||
transform: scale(1);
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
::before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.sticker-label {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
position: absolute;
|
||||
background: white;
|
||||
border-radius: 32px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
outline: none;
|
||||
|
||||
::after {
|
||||
content: ' ';
|
||||
box-shadow: 0 0 0 1px #ff3344;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
left: ${24 - 40}px;
|
||||
top: ${24 - 40}px;
|
||||
position: absolute;
|
||||
border-radius: 40px;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sticker-arrow {
|
||||
position: absolute;
|
||||
background: red;
|
||||
transform-origin: 0 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
::after {
|
||||
content: ' ';
|
||||
background: #ff3344;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transform-origin: 0 0;
|
||||
transform: rotate(-45deg);
|
||||
left: 0;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.sticker-delete {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: red;
|
||||
border-radius: 24px;
|
||||
transition: transform 500ms;
|
||||
transform: scale(0);
|
||||
opacity: 1;
|
||||
pointer-events: none;
|
||||
|
||||
:hover {
|
||||
transform: scale(1.2) !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const MapScreen = styled.div.attrs({ id: 'map' })`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
${vertexMixin}
|
||||
${stickers}
|
||||
${routerMixin}
|
||||
`;
|
92
src/styles/panel.less
Normal file
92
src/styles/panel.less
Normal file
|
@ -0,0 +1,92 @@
|
|||
.control-bar {
|
||||
background: #333333;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
box-shadow: rgba(0,0,0,0.3) 0 2px 0, inset rgba(255, 255, 255, 0.05) 1px 1px;
|
||||
}
|
||||
|
||||
.control-sep {
|
||||
height: 44px;
|
||||
background: #222222;
|
||||
width: 3px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
position: fixed;
|
||||
left: 10px;
|
||||
bottom: 10px;
|
||||
z-index: 3;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.right {
|
||||
left: auto;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 8px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
color: white;
|
||||
align-items: center;
|
||||
transition: background-color 500ms;
|
||||
height: 48px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:hover {
|
||||
background: rgba(100, 100, 100, 0.2);
|
||||
}
|
||||
|
||||
span {
|
||||
margin-right: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 200;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
svg {
|
||||
fill: url(#activeButtonGradient);
|
||||
stroke: url(#activeButtonGradient);
|
||||
}
|
||||
}
|
||||
|
||||
&.highlighted {
|
||||
background: linear-gradient(150deg, #05a4ff, #7137c8);
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: white;
|
||||
stroke: white;
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.panel-separator {
|
||||
height: 48px;
|
||||
width: 4px;
|
||||
background: #222222;
|
||||
}
|
||||
|
||||
#control-dialog {
|
||||
background: #222222;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
border-radius: 3px;
|
||||
z-index: 2;
|
||||
color: white;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 48px;
|
||||
box-shadow: rgba(0,0,0,0.3) 0 2px 0, inset rgba(255, 255, 255, 0.05) 1px 1px;
|
||||
}
|
36
src/styles/router.less
Normal file
36
src/styles/router.less
Normal file
|
@ -0,0 +1,36 @@
|
|||
.router-waypoint {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-left: -20px;
|
||||
margin-top: -20px;
|
||||
outline: none;
|
||||
z-index: 10001;
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 0 2px #4597d0;
|
||||
margin-left: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.router-helper {
|
||||
width: 500px;
|
||||
padding: 10px;
|
||||
font-weight: 200;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.router-helper__text {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.router-helper__buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
95
src/styles/stickers.less
Normal file
95
src/styles/stickers.less
Normal file
|
@ -0,0 +1,95 @@
|
|||
.sticker-container {
|
||||
outline: none;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: ' ';
|
||||
box-shadow: 0 0 10px 1px #ff3344;
|
||||
background: #ff334422;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
left: -24px;
|
||||
top: -24px;
|
||||
position: absolute;
|
||||
border-radius: 40px;
|
||||
opacity: 0;
|
||||
transition: opacity 250ms, transform 500ms;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
&:hover, &:active {
|
||||
.sticker-delete {
|
||||
transform: scale(1);
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
&:before {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sticker-label {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
position: absolute;
|
||||
background: white;
|
||||
border-radius: 32px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
outline: none;
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
box-shadow: 0 0 0 1px #ff3344;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
left: -16px;
|
||||
top: -16px;
|
||||
position: absolute;
|
||||
border-radius: 40px;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sticker-arrow {
|
||||
position: absolute;
|
||||
background: red;
|
||||
transform-origin: 0 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
background: #ff3344;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transform-origin: 0 0;
|
||||
transform: rotate(-45deg);
|
||||
left: 0;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.sticker-delete {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: red;
|
||||
border-radius: 24px;
|
||||
transition: transform 500ms;
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
pointer-events: none;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-control-container .leaflet-routing-container-hide {
|
||||
display: none;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue