mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 02:56:41 +07:00
map_list: initial
urls: editing now handled through urls
This commit is contained in:
parent
3771e5d338
commit
0d9bad9095
23 changed files with 386 additions and 68 deletions
16
.flowconfig
16
.flowconfig
|
@ -2,17 +2,17 @@
|
|||
module.system.node.resolve_dirname=node_modules
|
||||
module.system.node.resolve_dirname=src
|
||||
module.name_mapper='^$redux/\([-a-zA-Z0-9$_/]+\)$' -> '<PROJECT_ROOT>/src/redux/\1'
|
||||
module.name_mapper='^components\/\(.*\)$' ->'<PROJECT_ROOT>/src/components/\1'
|
||||
module.name_mapper='^containers\/\(.*\)$' ->'<PROJECT_ROOT>/src/containers/\1'
|
||||
module.name_mapper='^constants\/\(.*\)$' ->'<PROJECT_ROOT>/src/constants/\1'
|
||||
module.name_mapper='^sprites\/\(.*\)$' ->'<PROJECT_ROOT>/src/sprites/\1'
|
||||
module.name_mapper='^config\/\(.*\)$' ->'<PROJECT_ROOT>/src/config/\1'
|
||||
module.name_mapper='^styles\/\(.*\)$' ->'<PROJECT_ROOT>/src/styles/\1'
|
||||
module.name_mapper='^utils\/\(.*\)$' ->'<PROJECT_ROOT>/src/utils/\1'
|
||||
module.name_mapper='^$config/\([-a-zA-Z0-9$_/]+\)$' -> '<PROJECT_ROOT>/config/\1'
|
||||
module.name_mapper='^$components\/\(.*\)$' ->'<PROJECT_ROOT>/src/components/\1'
|
||||
module.name_mapper='^$containers\/\(.*\)$' ->'<PROJECT_ROOT>/src/containers/\1'
|
||||
module.name_mapper='^$constants\/\(.*\)$' ->'<PROJECT_ROOT>/src/constants/\1'
|
||||
module.name_mapper='^$sprites\/\(.*\)$' ->'<PROJECT_ROOT>/src/sprites/\1'
|
||||
module.name_mapper='^$config\/\(.*\)$' ->'<PROJECT_ROOT>/src/config/\1'
|
||||
module.name_mapper='^$styles\/\(.*\)$' ->'<PROJECT_ROOT>/src/styles/\1'
|
||||
module.name_mapper='^$utils\/\(.*\)$' ->'<PROJECT_ROOT>/src/utils/\1'
|
||||
|
||||
[ignore]
|
||||
.*/node_modules
|
||||
.*/node_modules/styled-components/.*
|
||||
|
||||
[include]
|
||||
public
|
||||
|
|
|
@ -13,6 +13,7 @@ const RouteSchema = new Schema(
|
|||
owner: { type: Schema.Types.ObjectId, ref: 'User' },
|
||||
logo: { type: String, default: 'DEFAULT' },
|
||||
distance: { type: Number, default: 0 },
|
||||
public: { type: Boolean, default: true },
|
||||
},
|
||||
{
|
||||
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
const { generateRandomUrl } = require('../auth/guest');
|
||||
const { Route } = require('../../models');
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
|
@ -9,6 +10,7 @@ module.exports = async (req, res) => {
|
|||
|
||||
if (!exists) return res.send({ success: false, mode: 'not_found_2' });
|
||||
const data = exists.toObject();
|
||||
const random_url = await generateRandomUrl();
|
||||
|
||||
return res.send({
|
||||
success: true,
|
||||
|
@ -17,7 +19,8 @@ module.exports = async (req, res) => {
|
|||
owner: {
|
||||
...data.owner,
|
||||
id: data.owner._id,
|
||||
}
|
||||
},
|
||||
random_url,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
35
src/components/dialogs/MapListDialog.jsx
Normal file
35
src/components/dialogs/MapListDialog.jsx
Normal file
|
@ -0,0 +1,35 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { RouteRow } from '$components/maps/RouteRow';
|
||||
import type { Route } from '$constants/types';
|
||||
|
||||
type Props = {
|
||||
routes: { [id: String]: Route },
|
||||
editing: Boolean,
|
||||
};
|
||||
|
||||
const Component = ({ routes, editing }: Props) => (
|
||||
<div className="dialog-maplist">
|
||||
{
|
||||
Object.keys(routes).map(id => (
|
||||
<RouteRow
|
||||
editing={editing}
|
||||
{...routes[id]}
|
||||
key={id}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
const mapStateToProps = ({ user: { editing, user: { routes } } }) => ({
|
||||
routes, editing,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({
|
||||
|
||||
}, dispatch);
|
||||
|
||||
export const MapListDialog = connect(mapStateToProps, mapDispatchToProps)(Component);
|
38
src/components/maps/RouteRow.jsx
Normal file
38
src/components/maps/RouteRow.jsx
Normal file
|
@ -0,0 +1,38 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { Icon } from '$components/panels/Icon';
|
||||
import { pushPath } from '$utils/history';
|
||||
|
||||
type Props = {
|
||||
title: String,
|
||||
distance: Number,
|
||||
created_at: String,
|
||||
_id: String,
|
||||
editing: Boolean,
|
||||
};
|
||||
|
||||
export const RouteRow = ({
|
||||
title, distance, created_at, _id, editing
|
||||
}: Props) => (
|
||||
<div
|
||||
className="route-row"
|
||||
onClick={() => pushPath(`/${_id}/${editing ? 'edit' : ''}`)}
|
||||
>
|
||||
<div className="route-title">
|
||||
{title || _id}
|
||||
</div>
|
||||
<div className="route-description">
|
||||
<span>
|
||||
<Icon icon="icon-link-1" />
|
||||
{_id}
|
||||
</span>
|
||||
</div>
|
||||
<div className="route-description">
|
||||
<span>
|
||||
<Icon icon="icon-cycle-1" />
|
||||
{(distance && `${distance} km`) || 'N/A'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
|
@ -4,7 +4,7 @@ import { GuestButton } from '$components/user/GuestButton';
|
|||
import { DEFAULT_USER, ROLES } from '$constants/auth';
|
||||
import { UserButton } from '$components/user/UserButton';
|
||||
import { UserMenu } from '$components/user/UserMenu';
|
||||
import { setUser, userLogout, takeAShot } from '$redux/user/actions';
|
||||
import { setUser, userLogout, takeAShot, setDialog } from '$redux/user/actions';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import type { UserType } from '$constants/types';
|
||||
|
@ -12,12 +12,14 @@ import { Icon } from '$components/panels/Icon';
|
|||
|
||||
import classnames from 'classnames';
|
||||
import { CLIENT } from '$config/frontend';
|
||||
import { DIALOGS } from '$constants/dialogs';
|
||||
|
||||
type Props = {
|
||||
user: UserType,
|
||||
userLogout: Function,
|
||||
setUser: Function,
|
||||
takeAShot: Function,
|
||||
setDialog: Function,
|
||||
dialog: String,
|
||||
};
|
||||
|
||||
export class Component extends React.PureComponent<Props, void> {
|
||||
|
@ -54,6 +56,9 @@ export class Component extends React.PureComponent<Props, void> {
|
|||
}
|
||||
|
||||
setMenuOpened = () => this.setState({ menuOpened: !this.state.menuOpened });
|
||||
openMapsDialog = () => {
|
||||
this.props.setDialog({ dialog: DIALOGS.MAP_LIST });
|
||||
};
|
||||
|
||||
openOauthFrame = () => {
|
||||
const width = parseInt(window.innerWidth, 10);
|
||||
|
@ -78,7 +83,7 @@ export class Component extends React.PureComponent<Props, void> {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className="panel active">
|
||||
<div className="panel active panel-user">
|
||||
<div className="user-panel">
|
||||
{
|
||||
!user || user.role === ROLES.guest
|
||||
|
@ -96,7 +101,7 @@ export class Component extends React.PureComponent<Props, void> {
|
|||
<div className="control-bar">
|
||||
<button
|
||||
className={classnames({ disabled: route_count <= 0 })}
|
||||
// onClick={this.props.takeAShot}
|
||||
onClick={this.openMapsDialog}
|
||||
>
|
||||
<Icon icon="icon-folder-1" />
|
||||
</button>
|
||||
|
@ -108,7 +113,12 @@ export class Component extends React.PureComponent<Props, void> {
|
|||
}
|
||||
|
||||
|
||||
const mapStateToProps = ({ user: { user } }) => ({ user });
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({ setUser, userLogout, takeAShot }, dispatch);
|
||||
const mapStateToProps = ({ user: { dialog, user } }) => ({ dialog, user });
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({
|
||||
setUser,
|
||||
userLogout,
|
||||
takeAShot,
|
||||
setDialog,
|
||||
}, dispatch);
|
||||
|
||||
export const UserPanel = connect(mapStateToProps, mapDispatchToProps)(Component);
|
||||
|
|
5
src/constants/dialogs.js
Normal file
5
src/constants/dialogs.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
// @flow
|
||||
export const DIALOGS = ({
|
||||
NONE: 'NONE',
|
||||
MAP_LIST: 'MAP_LIST',
|
||||
}: { [key: String]: String });
|
|
@ -1,4 +1,6 @@
|
|||
export const MODES = {
|
||||
// @flow
|
||||
|
||||
export const MODES = ({
|
||||
POLY: 'POLY',
|
||||
STICKERS: 'STICKERS',
|
||||
ROUTER: 'ROUTER',
|
||||
|
@ -9,4 +11,4 @@ export const MODES = {
|
|||
SAVE: 'SAVE',
|
||||
CONFIRM_CANCEL: 'CONFIRM_CANCEL',
|
||||
PROVIDER: 'PROVIDER',
|
||||
};
|
||||
}: { [key: String]: String });
|
||||
|
|
|
@ -14,3 +14,18 @@ export type UserType = {
|
|||
photo: String,
|
||||
}
|
||||
};
|
||||
|
||||
type Path = Array<{ lat: Number, lng: Number }>;
|
||||
type Stickers = Array<Object>;
|
||||
|
||||
export type Route = {
|
||||
_id: String,
|
||||
title: String,
|
||||
version: Number,
|
||||
stickers: Array<Stickers>,
|
||||
route: Array<Path>,
|
||||
logo: String,
|
||||
distance: Number,
|
||||
created_at: String,
|
||||
updated_at: String,
|
||||
}
|
||||
|
|
|
@ -12,11 +12,15 @@ import { hot } from 'react-hot-loader';
|
|||
import { Renderer } from '$components/renderer/Renderer';
|
||||
import { hideRenderer } from '$redux/user/actions';
|
||||
import { Cursor } from '$components/Cursor';
|
||||
import { LeftDialog } from '$containers/LeftDialog';
|
||||
import { DIALOGS } from '$constants/dialogs';
|
||||
|
||||
type Props = {
|
||||
renderer_active: Boolean,
|
||||
hideRenderer: Function,
|
||||
mode: String,
|
||||
dialog: String,
|
||||
dialog_active: Boolean,
|
||||
}
|
||||
|
||||
const Component = (props: Props) => (
|
||||
|
@ -26,15 +30,20 @@ const Component = (props: Props) => (
|
|||
<UserPanel />
|
||||
<EditorPanel />
|
||||
<Cursor mode={props.mode} />
|
||||
<LeftDialog dialog={props.dialog} dialog_active={props.dialog_active} />
|
||||
|
||||
{ props.renderer_active && <Renderer onClick={props.hideRenderer} /> }
|
||||
{ props.renderer_active &&
|
||||
<Renderer onClick={props.hideRenderer} />
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
const mapStateToProps = ({ user }) => ({
|
||||
renderer_active: user.renderer.renderer_active,
|
||||
mode: user.mode,
|
||||
const mapStateToProps = ({ user: { mode, dialog, dialog_active, renderer } }) => ({
|
||||
renderer_active: renderer.renderer_active,
|
||||
mode,
|
||||
dialog,
|
||||
dialog_active,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({ hideRenderer }, dispatch);
|
||||
export const App = connect(mapStateToProps, mapDispatchToProps)(hot(module)(Component));
|
||||
|
|
16
src/containers/LeftDialog.jsx
Normal file
16
src/containers/LeftDialog.jsx
Normal file
|
@ -0,0 +1,16 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { DIALOGS } from '$constants/dialogs';
|
||||
import { MapListDialog } from '$components/dialogs/MapListDialog';
|
||||
import classnames from 'classnames';
|
||||
|
||||
type Props = {
|
||||
dialog: String,
|
||||
dialog_active: Boolean,
|
||||
}
|
||||
|
||||
export const LeftDialog = ({ dialog, dialog_active }: Props) => (
|
||||
<div className={classnames('dialog', { active: dialog_active })}>
|
||||
{ dialog === DIALOGS.MAP_LIST && <MapListDialog /> }
|
||||
</div>
|
||||
);
|
|
@ -218,7 +218,6 @@ export class Editor {
|
|||
this.stickers.clearAll();
|
||||
};
|
||||
|
||||
|
||||
setData = ({
|
||||
route, stickers, version = 1, owner, title, address
|
||||
}) => {
|
||||
|
@ -272,19 +271,21 @@ export class Editor {
|
|||
|
||||
this.setInitialData();
|
||||
|
||||
const url = (this.owner && this.owner.id === id) ? path : random_url;
|
||||
// const url = (this.owner && this.owner.id === id) ? path : random_url;
|
||||
this.owner = { id };
|
||||
|
||||
pushPath(`/${url}/edit`);
|
||||
// console.log('PATH IS', path);
|
||||
// pushPath(`/${url}/edit`);
|
||||
|
||||
if (this.poly.latlngs && this.poly.latlngs.length > 1) this.poly.poly.enableEdit();
|
||||
|
||||
this.stickers.startEditing();
|
||||
};
|
||||
|
||||
stopEditing = () => {
|
||||
const { path } = getUrlData();
|
||||
// const { path } = getUrlData();
|
||||
|
||||
pushPath(`/${(this.initialData && this.initialData.path) || path}`);
|
||||
// console.log('PATH IS', path, this.initialData.path);
|
||||
// pushPath(`/${(this.initialData && this.initialData.path) || path}`);
|
||||
|
||||
this.poly.poly.disableEdit();
|
||||
this.stickers.stopEditing();
|
||||
|
|
|
@ -6,6 +6,8 @@ import createSagaMiddleware from 'redux-saga';
|
|||
|
||||
import { userReducer } from '$redux/user/reducer';
|
||||
import { userSaga } from '$redux/user/sagas';
|
||||
import { createBrowserHistory } from 'history';
|
||||
import { locationChanged } from '$redux/user/actions';
|
||||
|
||||
const userPersistConfig = {
|
||||
key: 'user',
|
||||
|
@ -42,3 +44,8 @@ export function configureStore() {
|
|||
|
||||
return { store, persistor };
|
||||
}
|
||||
|
||||
export const history = createBrowserHistory();
|
||||
export const historyListener = history.listen(location => {
|
||||
store.dispatch(locationChanged(location.pathname));
|
||||
});
|
||||
|
|
|
@ -39,3 +39,7 @@ export const takeAShot = () => ({ type: ACTIONS.TAKE_A_SHOT });
|
|||
export const cropAShot = payload => ({ type: ACTIONS.CROP_A_SHOT, ...payload });
|
||||
|
||||
export const setProvider = provider => ({ type: ACTIONS.SET_PROVIDER, provider });
|
||||
|
||||
export const setDialog = ({ dialog, dialog_active }) => ({ type: ACTIONS.SET_DIALOG, dialog });
|
||||
export const locationChanged = location => ({ type: ACTIONS.LOCATION_CHANGED, location });
|
||||
export const setReady = ready => ({ type: ACTIONS.SET_READY, ready });
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
export const ACTIONS = {
|
||||
// @flow
|
||||
|
||||
export const ACTIONS = ({
|
||||
SET_USER: 'SET_USER',
|
||||
USER_LOGOUT: 'USER_LOGOUT',
|
||||
|
||||
|
@ -38,4 +40,8 @@ export const ACTIONS = {
|
|||
CROP_A_SHOT: 'CROP_A_SHOT',
|
||||
|
||||
SET_PROVIDER: 'SET_PROVIDER',
|
||||
};
|
||||
|
||||
SET_DIALOG: 'SET_DIALOG',
|
||||
LOCATION_CHANGED: 'LOCATION_CHANGED',
|
||||
SET_READY: 'SET_READY',
|
||||
}: { [key: String]: String });
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// @flow
|
||||
import { createReducer } from 'reduxsauce';
|
||||
import { ACTIONS } from '$redux/user/constants';
|
||||
import { DEFAULT_USER } from '$constants/auth';
|
||||
|
@ -5,6 +6,7 @@ import { MODES } from '$constants/modes';
|
|||
import { DEFAULT_LOGO } from '$constants/logos';
|
||||
import { TIPS } from '$constants/tips';
|
||||
import { DEFAULT_PROVIDER } from '$constants/providers';
|
||||
import { DIALOGS } from '$constants/dialogs';
|
||||
|
||||
const getEstimated = distance => {
|
||||
const time = (distance && (distance / 15)) || 0;
|
||||
|
@ -73,7 +75,18 @@ const setRenderer = (state, { payload }) => ({
|
|||
|
||||
const setProvider = (state, { provider }) => ({ ...state, provider });
|
||||
|
||||
const HANDLERS = {
|
||||
const setDialog = (state, { dialog, dialog_active }) => ({
|
||||
...state,
|
||||
dialog: dialog || state.dialog,
|
||||
dialog_active: typeof dialog_active !== 'undefined' ? dialog_active : !state.dialog_active,
|
||||
});
|
||||
|
||||
const setReady = (state, { ready = true }) => ({
|
||||
...state,
|
||||
ready,
|
||||
});
|
||||
|
||||
const HANDLERS = ({
|
||||
[ACTIONS.SET_USER]: setUser,
|
||||
[ACTIONS.SET_EDITING]: setEditing,
|
||||
[ACTIONS.SET_CHANGED]: setChanged,
|
||||
|
@ -96,9 +109,13 @@ const HANDLERS = {
|
|||
[ACTIONS.SET_RENDERER]: setRenderer,
|
||||
|
||||
[ACTIONS.SET_PROVIDER]: setProvider,
|
||||
};
|
||||
|
||||
[ACTIONS.SET_DIALOG]: setDialog,
|
||||
[ACTIONS.SET_READY]: setReady,
|
||||
}: { [key: String]: Function });
|
||||
|
||||
export const INITIAL_STATE = {
|
||||
ready: false,
|
||||
user: { ...DEFAULT_USER },
|
||||
editing: false,
|
||||
mode: MODES.NONE,
|
||||
|
@ -117,6 +134,9 @@ export const INITIAL_STATE = {
|
|||
save_overwriting: false,
|
||||
save_processing: false,
|
||||
|
||||
dialog: DIALOGS.NONE,
|
||||
dialog_active: false,
|
||||
|
||||
renderer: {
|
||||
data: '',
|
||||
width: 0,
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
setActiveSticker, setAddress,
|
||||
setChanged,
|
||||
setEditing,
|
||||
setMode, setRenderer,
|
||||
setMode, setReady, setRenderer,
|
||||
setSaveError,
|
||||
setSaveOverwrite, setSaveSuccess, setTitle,
|
||||
setUser
|
||||
|
@ -62,12 +62,15 @@ function* startEmptyEditorSaga() {
|
|||
}
|
||||
|
||||
function* startEditingSaga() {
|
||||
yield editor.startEditing();
|
||||
yield put(setEditing(true));
|
||||
// yield put(setEditing(true));
|
||||
// yield editor.startEditing();
|
||||
const { path } = getUrlData();
|
||||
yield pushPath(`/${path}/edit`);
|
||||
}
|
||||
|
||||
function* stopEditingSaga() {
|
||||
const { changed, editing, mode } = yield select(getState);
|
||||
const { path } = getUrlData();
|
||||
|
||||
if (!editing) return;
|
||||
if (changed && mode !== MODES.CONFIRM_CANCEL) {
|
||||
|
@ -76,40 +79,59 @@ function* stopEditingSaga() {
|
|||
}
|
||||
|
||||
yield editor.cancelEditing();
|
||||
|
||||
yield put(setMode(MODES.NONE));
|
||||
|
||||
yield put(setChanged(false));
|
||||
|
||||
yield put(setEditing(editor.hasEmptyHistory)); // don't close editor if no previous map
|
||||
|
||||
yield pushPath(`/${path}/`);
|
||||
}
|
||||
|
||||
function* loadMapSaga(path) {
|
||||
const map = yield call(getStoredMap, { name: path });
|
||||
|
||||
if (map) {
|
||||
yield editor.setData(map);
|
||||
yield editor.fitDrawing();
|
||||
yield put(setChanged(false));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
function* mapInitSaga() {
|
||||
const { path, mode } = getUrlData();
|
||||
|
||||
if (path) {
|
||||
const map = yield call(getStoredMap, { name: path });
|
||||
const map = yield call(loadMapSaga, path);
|
||||
// const map = yield call(getStoredMap, { name: path });
|
||||
|
||||
if (map) {
|
||||
yield editor.setData(map);
|
||||
yield editor.fitDrawing();
|
||||
yield put(setChanged(false));
|
||||
// yield editor.setData(map);
|
||||
// yield editor.fitDrawing();
|
||||
// yield put(setChanged(false));
|
||||
|
||||
if (mode && mode === 'edit') {
|
||||
yield call(startEditingSaga);
|
||||
yield put(setEditing(true));
|
||||
editor.startEditing();
|
||||
// yield call(startEditingSaga); // <-- this is working
|
||||
// yield put(setEditing(true));
|
||||
// editor.startEditing();
|
||||
} else {
|
||||
yield put(setEditing(false));
|
||||
// yield put(setEditing(false)); // <-- this is working
|
||||
// yield call(stopEditingSaga);
|
||||
yield put(setEditing(false));
|
||||
editor.stopEditing();
|
||||
}
|
||||
|
||||
return hideLoader();
|
||||
yield put(setReady(true));
|
||||
hideLoader();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return yield call(startEmptyEditorSaga);
|
||||
yield call(startEmptyEditorSaga);
|
||||
yield put(setReady(true));
|
||||
return true;
|
||||
}
|
||||
|
||||
function* authChechSaga() {
|
||||
|
@ -120,7 +142,6 @@ function* authChechSaga() {
|
|||
|
||||
if (user) {
|
||||
yield put(setUser(user));
|
||||
|
||||
return yield call(mapInitSaga);
|
||||
}
|
||||
}
|
||||
|
@ -294,9 +315,37 @@ function setProviderSaga({ provider }) {
|
|||
return put(setMode(MODES.NONE));
|
||||
}
|
||||
|
||||
export function* userSaga() {
|
||||
// ASYNCHRONOUS!!! :-)
|
||||
function* locationChangeSaga({ location }) {
|
||||
const { address, editing, ready, user: { id, random_url } } = yield select(getState);
|
||||
|
||||
if (!ready) return;
|
||||
|
||||
const { path, mode } = getUrlData(location);
|
||||
|
||||
if (address !== path) {
|
||||
const map = yield call(loadMapSaga, path);
|
||||
|
||||
if (map && map.owner && mode === 'edit' && map.owner.id !== id) {
|
||||
pushPath(`/${map.random_url}/edit`);
|
||||
return;
|
||||
}
|
||||
} else if (mode === 'edit' && editor.owner.id !== id) {
|
||||
pushPath(`/${random_url}/edit`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (editing !== (mode === 'edit')) {
|
||||
if (mode === 'edit') {
|
||||
yield put(setEditing(true));
|
||||
editor.startEditing();
|
||||
} else {
|
||||
yield put(setEditing(false));
|
||||
editor.stopEditing();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function* userSaga() {
|
||||
yield takeLatest(REHYDRATE, authChechSaga);
|
||||
yield takeEvery(ACTIONS.SET_MODE, setModeSaga);
|
||||
|
||||
|
@ -322,4 +371,5 @@ export function* userSaga() {
|
|||
yield takeLatest(ACTIONS.CROP_A_SHOT, cropAShotSaga);
|
||||
|
||||
yield takeEvery(ACTIONS.SET_PROVIDER, setProviderSaga);
|
||||
yield takeLatest(ACTIONS.LOCATION_CHANGED, locationChangeSaga);
|
||||
}
|
||||
|
|
|
@ -118,6 +118,22 @@
|
|||
</g>
|
||||
</g>
|
||||
|
||||
<g id="icon-cycle-2">
|
||||
<path fill="black" d="M0 0h32v32H0z"/>
|
||||
<g id="g5604" fill="#fff" transform="matrix(-.36615 0 0 .36615 24.543 7.457)">
|
||||
<g id="g5527">
|
||||
<g id="g5495">
|
||||
<path id="path5483" d="M37.687 24.66c-4.945 0-8.973 4.025-8.973 8.975 0 4.95 4.026 8.974 8.973 8.974 4.95 0 8.977-4.024 8.977-8.974s-4.027-8.975-8.977-8.975zm0 15.384a6.417 6.417 0 0 1-6.409-6.409 6.418 6.418 0 0 1 6.409-6.41 6.417 6.417 0 0 1 6.411 6.41 6.417 6.417 0 0 1-6.411 6.409z"/>
|
||||
<path id="path5485" d="M23.588 15.501v.01h8.047c-2.375-2.4-5.273-5.251-5.99-5.578-1.257-.575-3.966 1.462-4.547 1.748-.532.283-.954.699-1.043 1.236l-2.112 5.927-6.167.069c-1.811.485-.465 2.065-.465 2.065l3.097.041-.295 1.405-1.803 2.989a8.914 8.914 0 0 0-3.333-.648C4.027 24.765 0 28.792 0 33.741c0 4.947 4.026 8.974 8.977 8.974 4.948 0 8.975-4.026 8.975-8.974a8.956 8.956 0 0 0-3.423-7.038l2.005-3.326.487-2.322 2.41.03c.479-.136.833-.538.912-1.029l2.603-4.074zM15.386 33.74a6.417 6.417 0 0 1-6.409 6.409c-3.534 0-6.411-2.876-6.411-6.409a6.419 6.419 0 0 1 6.411-6.411c.694 0 1.36.114 1.986.32l-3.579 5.939 2.197 1.323 3.607-5.989a6.386 6.386 0 0 1 2.198 4.818z"/>
|
||||
<path id="path5487" d="M32.24 23.139s2.468-2.578 2.691-2.968c.225-.392.229-.872.007-1.265 0 0-.725-.76-1.771-1.832v.014h-8.949l4.281 3.716-6.367 9.947a1.264 1.264 0 0 0-.104 1.045l2.563 7.692 3.072-.17-1.741-7.787z"/>
|
||||
<circle id="circle5489" cx="19.703" cy="7.384" r="3.435"/>
|
||||
<path id="path5491" d="M32.845 5.919c-1.06-.744-2.366-.789-3.123-.034l-1.484 1.487c-.756.756-.711 2.062.03 3.124z"/>
|
||||
<path id="path5493" d="M33.007 15.317c1.116 1.116 2.73 1.311 3.607.436l1.485-1.488c.877-.876.685-2.491-.434-3.606l-4.081-4.081-4.659 4.658z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<g id="icon-logo">
|
||||
<path fill="black" stroke="none" d="M0 0h32v32H0z"/>
|
||||
<g transform="matrix(1 0 0 1 2 -1)">
|
||||
|
@ -289,28 +305,34 @@
|
|||
</g>
|
||||
|
||||
<g id="icon-poly-4" stroke="none">
|
||||
<path stroke-opacity=".941" stroke-width=".265" d="M0 0h32v32H0z" fill="black"/>
|
||||
|
||||
<path stroke="none" fill="black"/>
|
||||
<path xmlns="http://www.w3.org/2000/svg" d="M23 8c0 1.1-.9 2-2 2-.18 0-.35-.02-.51-.07l-3.56 3.55c.05.16.07.34.07.52 0 1.1-.9 2-2 2s-2-.9-2-2c0-.18.02-.36.07-.52l-2.55-2.55c-.16.05-.34.07-.52.07s-.36-.02-.52-.07l-4.55 4.56c.05.16.07.33.07.51 0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2c.18 0 .35.02.51.07l4.56-4.55C8.02 9.36 8 9.18 8 9c0-1.1.9-2 2-2s2 .9 2 2c0 .18-.02.36-.07.52l2.55 2.55c.16-.05.34-.07.52-.07s.36.02.52.07l3.55-3.56C19.02 8.35 19 8.18 19 8c0-1.1.9-2 2-2s2 .9 2 2zm0 0c0 1.1-.9 2-2 2-.18 0-.35-.02-.51-.07l-3.56 3.55c.05.16.07.34.07.52 0 1.1-.9 2-2 2s-2-.9-2-2c0-.18.02-.36.07-.52l-2.55-2.55c-.16.05-.34.07-.52.07s-.36-.02-.52-.07l-4.55 4.56c.05.16.07.33.07.51 0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2c.18 0 .35.02.51.07l4.56-4.55C8.02 9.36 8 9.18 8 9c0-1.1.9-2 2-2s2 .9 2 2c0 .18-.02.36-.07.52l2.55 2.55c.16-.05.34-.07.52-.07s.36.02.52.07l3.55-3.56C19.02 8.35 19 8.18 19 8c0-1.1.9-2 2-2s2 .9 2 2z" fill="white" stroke="white" stroke-width="1" transform="translate(4 4)"/>
|
||||
</g>
|
||||
|
||||
<g id="icon-get-1" stroke="none">
|
||||
<path stroke-opacity=".941" stroke-width=".265" d="M0 0h32v32H0z" fill="black"/>
|
||||
|
||||
<path stroke="none" fill="black"/>
|
||||
<path xmlns="http://www.w3.org/2000/svg" d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z" fill="white" stroke="white" stroke-width="1" transform="translate(4 4)"/>
|
||||
</g>
|
||||
|
||||
<g id="icon-folder-1" stroke="none">
|
||||
<path stroke-opacity=".941" stroke-width=".265" d="M0 0h32v32H0z" fill="black"/>
|
||||
|
||||
<path stroke="none" fill="black"/>
|
||||
<path xmlns="http://www.w3.org/2000/svg" d="M9.17 6l2 2H20v10H4V6h5.17M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z" fill="white" stroke="white" stroke-width="0" transform="translate(4 4)"/>
|
||||
</g>
|
||||
|
||||
<g id="icon-folder-1" stroke="none">
|
||||
<path stroke-opacity=".941" stroke-width=".265" d="M0 0h32v32H0z" fill="black"/>
|
||||
|
||||
<path stroke="none" fill="black"/>
|
||||
<path xmlns="http://www.w3.org/2000/svg" d="M9.17 6l2 2H20v10H4V6h5.17M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z" fill="white" stroke="white" stroke-width="0" transform="translate(4 4)"/>
|
||||
</g>
|
||||
|
||||
<g id="icon-cycle-1" stroke="none">
|
||||
<path stroke="none" fill="black"/>
|
||||
<path xmlns="http://www.w3.org/2000/svg" d="M15.5 5.5c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zM5 12c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm0 8.5c-1.9 0-3.5-1.6-3.5-3.5s1.6-3.5 3.5-3.5 3.5 1.6 3.5 3.5-1.6 3.5-3.5 3.5zm5.8-10l2.4-2.4.8.8c1.3 1.3 3 2.1 5.1 2.1V9c-1.5 0-2.7-.6-3.6-1.5l-1.9-1.9c-.5-.4-1-.6-1.6-.6s-1.1.2-1.4.6L7.8 8.4c-.4.4-.6.9-.6 1.4 0 .6.2 1.1.6 1.4L11 14v5h2v-6.2l-2.2-2.3zM19 12c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm0 8.5c-1.9 0-3.5-1.6-3.5-3.5s1.6-3.5 3.5-3.5 3.5 1.6 3.5 3.5-1.6 3.5-3.5 3.5z" fill="white" stroke="white" stroke-width="0" transform="translate(4 4)"/>
|
||||
</g>
|
||||
|
||||
<g id="icon-link-1" stroke="none">
|
||||
<path stroke="none" fill="black"/>
|
||||
<path xmlns="http://www.w3.org/2000/svg" d="M17 7h-4v2h4c1.65 0 3 1.35 3 3s-1.35 3-3 3h-4v2h4c2.76 0 5-2.24 5-5s-2.24-5-5-5zm-6 8H7c-1.65 0-3-1.35-3-3s1.35-3 3-3h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-2zm-3-4h8v2H8z" fill="white" stroke="white" stroke-width="0" transform="translate(4 4)"/>
|
||||
</g>
|
||||
</svg>
|
||||
</defs>
|
||||
|
||||
|
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 30 KiB |
|
@ -3,7 +3,6 @@
|
|||
|
||||
@router_line: #4597d0;
|
||||
|
||||
@bar_shadow: rgba(0,0,0,0.3) 0 2px 0, inset rgba(255, 255, 255, 0.05) 1px 1px;
|
||||
@bar_background: #333333;
|
||||
@dialog_background: #222222;
|
||||
|
||||
|
@ -21,3 +20,6 @@
|
|||
@color_primary: #4597d0;
|
||||
@color_success: #7cd766;
|
||||
@color_danger: #ff3344;
|
||||
|
||||
@bar_shadow: rgba(0,0,0,0.3) 0 2px 0, inset rgba(255, 255, 255, 0.05) 1px 1px;
|
||||
@dialog_shadow: rgba(0,0,0,0.3) 2px 0 0;
|
||||
|
|
73
src/styles/dialogs.less
Normal file
73
src/styles/dialogs.less
Normal file
|
@ -0,0 +1,73 @@
|
|||
.dialog {
|
||||
background: #222222;
|
||||
//background: linear-gradient(130deg, #320523, #020d2b);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 360px;
|
||||
height: 100%;
|
||||
z-index: 3;
|
||||
|
||||
box-shadow: @dialog_shadow;
|
||||
padding: 10px 10px 72px 10px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
pointer-events: none;
|
||||
transition: transform 500ms;
|
||||
|
||||
&.active {
|
||||
transform: translate3d(0, 0, 0);
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: ' ';
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
//background: linear-gradient(0deg, rgba(2, 13, 43, 1) 50%, rgba(2,13,43,0));
|
||||
background: linear-gradient(0deg, rgba(34, 34, 34, 1) 50%, rgba(34, 34, 34, 0));
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
}
|
||||
}
|
||||
|
||||
.route-row {
|
||||
margin-bottom: 10px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
padding: 10px 10px 5px 10px;
|
||||
color: white;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 250ms;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.route-title {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.route-description {
|
||||
font-size: 0.9em;
|
||||
opacity: 0.3;
|
||||
margin-bottom: 5px;
|
||||
|
||||
svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: white;
|
||||
vertical-align: text-bottom;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
span {
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
@import 'user-button.less';
|
||||
@import 'save.less';
|
||||
@import 'renderer.less';
|
||||
@import 'dialogs.less';
|
||||
|
||||
body {
|
||||
font-family: 'Rubik', sans-serif;
|
||||
|
@ -54,8 +55,8 @@ body {
|
|||
|
||||
.cursor-tooltip {
|
||||
position: fixed;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
z-index: 10;
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
position: fixed;
|
||||
left: 10px;
|
||||
bottom: 10px;
|
||||
z-index: 3;
|
||||
z-index: 6;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
export const getPath = () => (window.location && window.location.pathname &&
|
||||
window.location.pathname.replace(/^\//, ''));
|
||||
import { history } from '$redux/store';
|
||||
|
||||
export const pushPath = url => window.history.pushState(url, 'Редактирование маршрута', url);
|
||||
export const getPath = () => (window.location && window.location.pathname);
|
||||
export const pushPath = url => history.push(url);
|
||||
|
||||
export const getUrlData = () => {
|
||||
const url = getPath();
|
||||
|
||||
const [path, mode] = url.split('/');
|
||||
export const getUrlData = (url = getPath()) => {
|
||||
const [, path, mode] = url.split('/');
|
||||
const { host } = window.location;
|
||||
|
||||
return { path, mode, host };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue