diff --git a/src/components/dialogs/MapListDialog.tsx b/src/components/dialogs/MapListDialog.tsx index 5280bd2..13795cd 100644 --- a/src/components/dialogs/MapListDialog.tsx +++ b/src/components/dialogs/MapListDialog.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { RouteRow } from '$components/maps/RouteRow'; +import { RouteRowWrapper } from '$components/maps/RouteRowWrapper'; import { Scroll } from '$components/Scroll'; import { searchSetDistance, @@ -21,6 +21,8 @@ import { IRootState, IRouteListItem } from '$redux/user/reducer'; export interface IMapListDialogProps extends IRootState { marks: { [x: number]: string }, routes_sorted: Array, + routes: IRootState['routes'], + ready: IRootState['ready'], mapsLoadMore: typeof mapsLoadMore, searchSetDistance: typeof searchSetDistance, @@ -30,32 +32,44 @@ export interface IMapListDialogProps extends IRootState { } export interface IMapListDialogState { - selected_item: IRouteListItem['_id'], - selected_item_mode: 'menu' | 'edit' | 'drop' | null, + menu_target: IRouteListItem['_id'], + editor_target: IRouteListItem['_id'], + + is_editing: boolean, + is_dropping: boolean, } class Component extends React.Component { state = { - selected_item: null, - selected_item_mode: null, + menu_target: null, + editor_target: null, + + is_editing: false, + is_dropping: false, }; - startEditing = (selected_item: IRouteListItem['_id']): void => this.setState({ - selected_item: ((this.state.selected_item !== selected_item && selected_item) || null), - selected_item_mode: 'edit', + startEditing = (editor_target: IRouteListItem['_id']): void => this.setState({ + editor_target, + menu_target: null, + is_editing: true, + is_dropping: false, }); - showMenu = (selected_item: IRouteListItem['_id']): void => this.setState({ - selected_item: ((this.state.selected_item !== selected_item && selected_item) || null), - selected_item_mode: 'menu', + showMenu = (menu_target: IRouteListItem['_id']): void => this.setState({ + menu_target, }); - showDropCard = (selected_item: IRouteListItem['_id']): void => this.setState({ - selected_item: ((this.state.selected_item !== selected_item && selected_item) || null), - selected_item_mode: 'drop', + showDropCard = (editor_target: IRouteListItem['_id']): void => this.setState({ + editor_target, + menu_target: null, + is_editing: false, + is_dropping: true, }); - stopEditing = (): void => this.setState({ selected_item: null }); + stopEditing = (): void => { + console.log('stop it!'); + this.setState({ editor_target: null }); + }; setTitle = ({ target: { value } }: { target: { value: string }}): void => { this.props.searchSetTitle(value); @@ -64,6 +78,8 @@ class Component extends React.Component { if (isMobile()) this.props.setDialogActive(false); + this.stopEditing(); + pushPath(`/${_id}/${this.props.editing ? 'edit' : ''}`); }; @@ -80,6 +96,8 @@ class Component extends React.Component null; + render() { const { ready, @@ -97,7 +115,7 @@ class Component extends React.Component @@ -166,19 +184,21 @@ class Component extends React.Component { list.map(route => ( - )) diff --git a/src/components/maps/RouteRow.tsx b/src/components/maps/RouteRow.tsx deleted file mode 100644 index a5f07cd..0000000 --- a/src/components/maps/RouteRow.tsx +++ /dev/null @@ -1,69 +0,0 @@ -// @flow -import * as React from 'react'; -import { Icon } from '$components/panels/Icon'; -import classnames from 'classnames'; -import { IMapListDialogState, MapListDialog } from "$components/dialogs/MapListDialog"; -import { Tooltip } from "$components/panels/Tooltip"; - -interface Props { - _id: string, - tab: string, - selected: boolean, - title: string, - distance: number, - is_public: boolean, - mode: IMapListDialogState['selected_item_mode'], - - openRoute: typeof MapListDialog.openRoute, - startEditing: typeof MapListDialog.startEditing, - stopEditing: typeof MapListDialog.stopEditing, - showMenu: typeof MapListDialog.showMenu, - showDropCard: typeof MapListDialog.showDropCard, - key: string, -} - -export const RouteRow = ({ - title, distance, _id, openRoute, tab, selected, startEditing, showMenu, showDropCard, mode -}: Props) => ( -
-
-
openRoute(_id)}> -
- {(title || _id)} -
-
- - - {_id} - - - - {(distance && `${distance} km`) || '0 km'} - -
-
-
-
showMenu(_id)}> - -
-
showDropCard(_id)}> - Удалить - -
-
startEditing(_id)}> - Редактировать - -
-
-
-
-); diff --git a/src/components/maps/RouteRowDrop.tsx b/src/components/maps/RouteRowDrop.tsx new file mode 100644 index 0000000..41fe59e --- /dev/null +++ b/src/components/maps/RouteRowDrop.tsx @@ -0,0 +1,29 @@ +// @flow +import * as React from 'react'; +import { Icon } from '$components/panels/Icon'; +import { MapListDialog } from "$components/dialogs/MapListDialog"; +import { Tooltip } from "$components/panels/Tooltip"; +import { ReactElement } from "react"; + +interface Props { + _id: string, + stopEditing: typeof MapListDialog.stopEditing, + dropRoute: typeof MapListDialog.dropRoute, +} + +export const RouteRowDrop = ({ + _id, stopEditing, dropRoute, +}: Props): ReactElement => ( +
+
+
+
dropRoute(_id)}>Удалить
+
Отмена
+
+
+
+); diff --git a/src/components/maps/RouteRowEditor.tsx b/src/components/maps/RouteRowEditor.tsx index 501cb56..9eea74e 100644 --- a/src/components/maps/RouteRowEditor.tsx +++ b/src/components/maps/RouteRowEditor.tsx @@ -5,9 +5,8 @@ import { Switch } from '$components/Switch'; interface Props { title: string; - is_editing: boolean; - distance: number; _id: string; + is_public: boolean, } interface State { @@ -32,46 +31,34 @@ export class RouteRowEditor extends React.Component { render() { const { state: { title, is_public }, - props: { distance, _id } + props: { _id } } = this; return ( -
-
- -
-
- - - {_id} - - - - {(distance && `${distance} km`) || '0 km'} - -
-
-
-
- - { - is_public - ? ' В каталоге карт' - : ' Только по ссылке' - } -
-
- OK +
+
+
+ +
+
+
+
+ + { + is_public + ? ' В каталоге карт' + : ' Только по ссылке' + } +
+
+ OK +
diff --git a/src/components/maps/RouteRowView.tsx b/src/components/maps/RouteRowView.tsx new file mode 100644 index 0000000..814a3d9 --- /dev/null +++ b/src/components/maps/RouteRowView.tsx @@ -0,0 +1,61 @@ +// @flow +import * as React from 'react'; +import { Icon } from '$components/panels/Icon'; +import { MapListDialog } from "$components/dialogs/MapListDialog"; +import { Tooltip } from "$components/panels/Tooltip"; +import { ReactElement } from "react"; + +interface Props { + _id: string, + tab: string, + title: string, + distance: number, + is_public: boolean, + + openRoute: typeof MapListDialog.openRoute, + startEditing: typeof MapListDialog.startEditing, + stopEditing: typeof MapListDialog.stopEditing, + showMenu: typeof MapListDialog.showMenu, + showDropCard: typeof MapListDialog.showDropCard, +} + +export const RouteRowView = ({ + title, distance, _id, openRoute, tab, startEditing, showMenu, showDropCard +}: Props): ReactElement => ( +
+
openRoute(_id)} + > +
+ {(title || _id)} +
+ +
+ + + {_id} + + + + {(distance && `${distance} km`) || '0 km'} + +
+
+
showMenu(_id)}> + +
+
+
showDropCard(_id)}> + Удалить + +
+
startEditing(_id)}> + Редактировать + +
+
+
+); diff --git a/src/components/maps/RouteRowWrapper.tsx b/src/components/maps/RouteRowWrapper.tsx new file mode 100644 index 0000000..e8ab8ad --- /dev/null +++ b/src/components/maps/RouteRowWrapper.tsx @@ -0,0 +1,72 @@ +import * as React from 'react'; +import classnames from 'classnames'; +import { MapListDialog } from "$components/dialogs/MapListDialog"; +import { RouteRowView } from "$components/maps/RouteRowView"; +import { RouteRowEditor } from "$components/maps/RouteRowEditor"; +import { RouteRowDrop } from "$components/maps/RouteRowDrop"; +import { ReactElement } from "react"; + +interface Props { + _id: string, + tab: string, + title: string, + distance: number, + is_public: boolean, + + is_editing_target: boolean, + is_menu_target: boolean, + + openRoute: typeof MapListDialog.openRoute, + startEditing: typeof MapListDialog.startEditing, + stopEditing: typeof MapListDialog.stopEditing, + showMenu: typeof MapListDialog.showMenu, + showDropCard: typeof MapListDialog.showDropCard, + dropRoute: typeof MapListDialog.dropRoute, + + is_editing_mode: 'edit' | 'drop', +} + +export const RouteRowWrapper = ({ + title, distance, _id, openRoute, tab, startEditing, showMenu, + showDropCard, is_public, is_editing_target, is_menu_target, is_editing_mode, + dropRoute, stopEditing, +}: Props): ReactElement => ( +
+ { + is_editing_target && is_editing_mode === 'edit' && + + } + { + is_editing_target && is_editing_mode === 'drop' && + + } + { + !is_editing_target && + + } +
+); diff --git a/src/modules/Poly.ts b/src/modules/Poly.ts index e1a3fe0..7dea05b 100644 --- a/src/modules/Poly.ts +++ b/src/modules/Poly.ts @@ -1,11 +1,10 @@ -import { Map, LayerGroup, LatLng, LatLngLiteral, LeafletEventHandlerFn, marker, divIcon, Marker } from 'leaflet'; +import { Map, LatLng } from 'leaflet'; import { EditablePolyline } from '$utils/EditablePolyline'; import { simplify } from '$utils/simplify'; import { CLIENT } from '$config/frontend'; import { editor, Editor } from "$modules/Editor"; import { ILatLng } from "$modules/Stickers"; import { InteractivePoly } from "$modules/InteractivePoly"; -import { clusterIcon } from "$utils/clusterIcon"; import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js'; import { angleBetweenPoints, dist2, distToSegment, middleCoord } from "$utils/geom"; import { arrowClusterIcon, createArrow } from "$utils/arrow"; @@ -23,17 +22,17 @@ export class Poly { constructor({ map, routerMoveStart, lockMapClicks, setDistance, triggerOnChange, editor, }: Props) { - this.poly = new InteractivePoly([], { + this.poly = new InteractivePoly([ ], { color: 'url(#activePathGradient)', weight: 6, maxMarkers: 100, smoothFactor: 3, - // bubblingMouseEvents: false, }) .on('distancechange', this.onDistanceUpdate) .on('allvertexhide', this.onVertexHide) .on('allvertexshow', this.onVertexShow) - .on('latlngschange', this.updateArrows); + .on('latlngschange', this.updateArrows) + .on('latlngschange', triggerOnChange); this.poly.addTo(map); this.editor = editor; @@ -162,7 +161,7 @@ export class Poly { return (!this.latlngs || Object.values(this.latlngs).length <= 0); } - poly: EditablePolyline; + poly; arrowLayer: MarkerClusterGroup = new MarkerClusterGroup({ spiderfyOnMaxZoom: false, showCoverageOnHover: false, diff --git a/src/styles/button.less b/src/styles/button.less index 0e326f2..058cf9a 100644 --- a/src/styles/button.less +++ b/src/styles/button.less @@ -13,6 +13,7 @@ box-shadow: inset rgba(100,100,100, 0.3) 1px 0, inset rgba(0,0,0, 0.1) -1px 0; color: white; font-weight: 400; + border: none; &.primary { background: #3c78db; diff --git a/src/styles/dialogs.less b/src/styles/dialogs.less index 7c60194..c585555 100644 --- a/src/styles/dialogs.less +++ b/src/styles/dialogs.less @@ -188,13 +188,14 @@ margin-bottom: 10px; transition: all 500ms; display: flex; + flex-direction: column; &.has_edit { //transform: translateY(-2px); - .route-row { background: rgba(255, 100, 100, 0.2); } + .route-row { background: fade(@green_secondary, 30%); } } - &.has_menu { + &.is_menu_target { .route-row { transform: translateX(-100px); } @@ -204,18 +205,37 @@ } } } -// -//.route-row-editor { -// color: white; -// padding: 20px 0 5px; -//} -// -//.route-row-buttons { -// flex: 1; -// flex-direction: row; -// display: flex; -// align-items: center; -//} + +.route-row-editor { + color: white; + padding: 5px 0 5px; +} + +.route-row-buttons { + flex: 1; + flex-direction: row; + display: flex; + align-items: center; +} + +.route-row-view { + overflow: hidden; + transition: height 500ms; + padding-right: 32px; + position: relative; +} + +.route-row-edit { + background: fade(@green_secondary, 30%); +} + +.route-row-drop { + background: fade(@red_secondary, 20%); + + .route-row { + align-items: center; + } +} .route-row { background: rgba(255, 255, 255, 0.05); @@ -226,6 +246,12 @@ transition: background 250ms, transform 500ms; position: relative; flex: 1; + min-height: 64px; + box-sizing: border-box; + display: flex; + flex-direction: column; + justify-content: center; + align-items: stretch; &:hover { background: rgba(255, 255, 255, 0.1); @@ -246,7 +272,10 @@ justify-content: center; align-items: center; transition: all 250ms; - position: relative; + position: absolute; + top: 0; + right: 0; + height: 100%; &:hover { background: rgba(255, 255, 255, 0.1); @@ -256,13 +285,14 @@ .route-row-edit-menu { width: 0; height: 100%; - right: 100%; + right: 32px; bottom: 0; position: absolute; background: rgba(0, 0, 0, 0.1); overflow: hidden; transition: all 500ms; display: flex; + fill: fade(white, 30%); div { width: 50px; diff --git a/webpack.config.js b/webpack.config.js index 4f3d145..8e63ec4 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -41,7 +41,6 @@ const resolve = { $utils: join(__dirname, 'src/utils'), $modules: join(__dirname, 'src/modules'), }, - extensions: ['*', '.ts', '.tsx', '.js', '.jsx', '.json'] };