From 65e549a5afc3e7a3531f2015cb918b04be97db8d Mon Sep 17 00:00:00 2001 From: muerwre Date: Fri, 7 Dec 2018 17:38:49 +0700 Subject: [PATCH] changelog: dialog for changelog --- src/components/dialogs/AppInfoDialog.jsx | 74 ++++++++++++++++++++++++ src/components/panels/UserPanel.jsx | 15 ++++- src/components/user/UserMenu.jsx | 10 +++- src/constants/app_info.js | 40 ++++++------- src/constants/dialogs.js | 1 + src/containers/LeftDialog.jsx | 8 ++- src/redux/user/actions.js | 5 +- src/redux/user/constants.js | 1 + src/redux/user/reducer.js | 13 ++++- src/styles/dialogs.less | 73 +++++++++++++++++++++++ src/styles/main.less | 9 +++ src/styles/panel.less | 3 +- 12 files changed, 218 insertions(+), 34 deletions(-) create mode 100644 src/components/dialogs/AppInfoDialog.jsx diff --git a/src/components/dialogs/AppInfoDialog.jsx b/src/components/dialogs/AppInfoDialog.jsx new file mode 100644 index 0000000..92c30dd --- /dev/null +++ b/src/components/dialogs/AppInfoDialog.jsx @@ -0,0 +1,74 @@ +// @flow +import React from 'react'; +import { Scroll } from '$components/Scroll'; +import { APP_INFO } from '$constants/app_info'; + +export const AppInfoDialog = () => ( +
+
+
+ Orchid Map +
+
+ версия{' '} + {(APP_INFO.VERSION || 1)}. + {(APP_INFO.CHANGELOG[APP_INFO.VERSION].length || 0)} +
+
+
+ Исходный код:{' '} + github.com/muerwre/orchidMap +
+
+
+
+ Frontend:{' '} + ReactJS,{' '} + Leaflet,{' '} + Leaflet Routing Machine{' '} +
+
+ Backend:{' '} + OSRM,{' '} + NodeJS,{' '} + ExpressJS,{' '} + MongoDB +
+
+
+ +
+
+

История изменений

+ { + [...Object.keys(APP_INFO.CHANGELOG)].reverse().map((version, i) => ( +
+
{version}.
+
+ { + APP_INFO.CHANGELOG[version].map((release, y) => ( +
+
{APP_INFO.CHANGELOG[version].length - y}.
+
+ { + APP_INFO.CHANGELOG[version][y].map((build, z) => ( +
+
{(z)}.
+ {APP_INFO.CHANGELOG[version][y][z]} +
+ )) + } +
+
+ )) + } +
+
+ )) + } +
+
+
+
+); + diff --git a/src/components/panels/UserPanel.jsx b/src/components/panels/UserPanel.jsx index 0286069..b2778ed 100644 --- a/src/components/panels/UserPanel.jsx +++ b/src/components/panels/UserPanel.jsx @@ -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, setDialog, gotVkUser } from '$redux/user/actions'; +import { setUser, userLogout, takeAShot, setDialog, gotVkUser, setDialogActive } from '$redux/user/actions'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import type { UserType } from '$constants/types'; @@ -21,6 +21,7 @@ type Props = { userLogout: Function, setDialog: Function, + setDialogActive: Function, gotVkUser: Function, }; @@ -59,7 +60,14 @@ export class Component extends React.PureComponent { setMenuOpened = () => this.setState({ menuOpened: !this.state.menuOpened }); openMapsDialog = () => { - this.props.setDialog({ dialog: DIALOGS.MAP_LIST }); + this.props.setDialog(DIALOGS.MAP_LIST); + this.props.setDialogActive(this.props.dialog !== DIALOGS.MAP_LIST); + }; + + openAppInfoDialog = () => { + this.setMenuOpened(); + this.props.setDialog(DIALOGS.APP_INFO); + this.props.setDialogActive(this.props.dialog !== DIALOGS.APP_INFO); }; openOauthFrame = () => { @@ -94,7 +102,7 @@ export class Component extends React.PureComponent { } { (user && user.role && user.role !== 'guest' && menuOpened) && - + } @@ -125,6 +133,7 @@ const mapDispatchToProps = dispatch => bindActionCreators({ takeAShot, setDialog, gotVkUser, + setDialogActive, }, dispatch); export const UserPanel = connect(mapStateToProps, mapDispatchToProps)(Component); diff --git a/src/components/user/UserMenu.jsx b/src/components/user/UserMenu.jsx index 11557a0..5945ec5 100644 --- a/src/components/user/UserMenu.jsx +++ b/src/components/user/UserMenu.jsx @@ -1,20 +1,24 @@ import React from 'react'; -import { CLIENT } from '$config/frontend'; +import { APP_INFO } from '$constants/app_info'; type Props = { userLogout: Function, + openAppInfoDialog: Function, } -export const UserMenu = ({ userLogout }: Props) => ( +export const UserMenu = ({ userLogout, openAppInfoDialog }: Props) => (
ORCHID
MAP - - { CLIENT.VER } + - {(APP_INFO.VERSION || 1)}.{(APP_INFO.RELEASE.length || 0)}
+
+ О редакторе карт +
Проект на github diff --git a/src/constants/app_info.js b/src/constants/app_info.js index 6c28981..5f98810 100644 --- a/src/constants/app_info.js +++ b/src/constants/app_info.js @@ -3,28 +3,28 @@ export const APP_INFO = { RELEASE: 1, CHANGELOG: { - 2: { - 0: [ - '15.08.18 Первый коммит', - '15.08.18 ReactJS для управления интерфейсом', - '16.08.18 Карта, роутер, стикеры, панели редактора', - '27.08.18 Выбор логотипа и стиля карты', - '29.08.18 Переключение режимов, сохранение', - '04.09.18 Загрузка карт, перерисовка данных, маршруты', + 2: [ + [ + 'Redux, redux-saga', // [26.11.18] + 'Рисование карт на стороне клиента', // [28.11.18] + 'Backend на expressjs + mongoose', // [30.11.18] + 'Импорт данных из старых версий карт', // [06.12.18] + 'Диалог со списком карт пользователя', // [07.12.18] + 'Мобильный интерфейс', // [07.12.18] ], - 1: [ - '26.11.18 Redux, redux-saga', - '28.11.18 Рисование карт на стороне клиента', - '30.11.18 Backend на expressjs + mongoose', - '04.12.18 Backend на expressjs + mongoose', - '06.12.18 Импорт данных из старых версий карт', - '07.12.18 Диалог со списком карт пользователя', - ] - }, - 1: { - 0: [ + [ + 'Первый коммит', // [15.08.18] + 'ReactJS для управления интерфейсом', // [15.08.18] + 'Карта, роутер, стикеры, панели редактора', // [16.08.18] + 'Выбор логотипа и стиля карты', // [27.08.18] + 'Переключение режимов, сохранение', // [29.08.18] + 'Загрузка карт, перерисовка данных, маршруты', // [04.09.18] + ], + ], + 1: [ + [ 'Первый работающий редактор карт' ] - } + ] } }; diff --git a/src/constants/dialogs.js b/src/constants/dialogs.js index 65d9fa6..65ff3ee 100644 --- a/src/constants/dialogs.js +++ b/src/constants/dialogs.js @@ -2,4 +2,5 @@ export const DIALOGS = ({ NONE: 'NONE', MAP_LIST: 'MAP_LIST', + APP_INFO: 'APP_INFO', }: { [key: String]: String }); diff --git a/src/containers/LeftDialog.jsx b/src/containers/LeftDialog.jsx index 3d1e54a..61336df 100644 --- a/src/containers/LeftDialog.jsx +++ b/src/containers/LeftDialog.jsx @@ -3,14 +3,20 @@ import React from 'react'; import { DIALOGS } from '$constants/dialogs'; import { MapListDialog } from '$components/dialogs/MapListDialog'; import classnames from 'classnames'; +import { AppInfoDialog } from '$components/dialogs/AppInfoDialog'; type Props = { dialog: String, dialog_active: Boolean, } +const LEFT_DIALOGS = { + [DIALOGS.MAP_LIST]: MapListDialog, + [DIALOGS.APP_INFO]: AppInfoDialog, +}; + export const LeftDialog = ({ dialog, dialog_active }: Props) => (
- { dialog === DIALOGS.MAP_LIST && } + { dialog && LEFT_DIALOGS[dialog] && React.createElement(LEFT_DIALOGS[dialog]) }
); diff --git a/src/redux/user/actions.js b/src/redux/user/actions.js index bfe6f02..7daaa57 100644 --- a/src/redux/user/actions.js +++ b/src/redux/user/actions.js @@ -40,9 +40,10 @@ 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 setDialog = dialog => ({ type: ACTIONS.SET_DIALOG, dialog }); +export const setDialogActive = dialog_active => ({ type: ACTIONS.SET_DIALOG_ACTIVE, dialog_active }); + export const locationChanged = location => ({ type: ACTIONS.LOCATION_CHANGED, location }); export const setReady = ready => ({ type: ACTIONS.SET_READY, ready }); - export const gotVkUser = user => ({ type: ACTIONS.GOT_VK_USER, user }); diff --git a/src/redux/user/constants.js b/src/redux/user/constants.js index 0616175..fe75bb8 100644 --- a/src/redux/user/constants.js +++ b/src/redux/user/constants.js @@ -42,6 +42,7 @@ export const ACTIONS = ({ SET_PROVIDER: 'SET_PROVIDER', SET_DIALOG: 'SET_DIALOG', + SET_DIALOG_ACTIVE: 'SET_DIALOG_ACTIVE', LOCATION_CHANGED: 'LOCATION_CHANGED', SET_READY: 'SET_READY', diff --git a/src/redux/user/reducer.js b/src/redux/user/reducer.js index 6e85774..8767696 100644 --- a/src/redux/user/reducer.js +++ b/src/redux/user/reducer.js @@ -78,10 +78,16 @@ const setRenderer = (state, { payload }) => ({ const setProvider = (state, { provider }) => ({ ...state, provider }); -const setDialog = (state, { dialog, dialog_active }) => ({ +const setDialog = (state, { dialog }) => ({ ...state, - dialog: dialog || state.dialog, - dialog_active: typeof dialog_active !== 'undefined' ? dialog_active : !state.dialog_active, + dialog, + // dialog_active: typeof dialog_active !== 'undefined' ? dialog_active : !state.dialog_active, + // dialog_active, +}); + +const setDialogActive = (state, { dialog_active }) => ({ + ...state, + dialog_active: dialog_active || !state.dialog_active, }); const setReady = (state, { ready = true }) => ({ @@ -114,6 +120,7 @@ const HANDLERS = ({ [ACTIONS.SET_PROVIDER]: setProvider, [ACTIONS.SET_DIALOG]: setDialog, + [ACTIONS.SET_DIALOG_ACTIVE]: setDialogActive, [ACTIONS.SET_READY]: setReady, }: { [key: String]: Function }); diff --git a/src/styles/dialogs.less b/src/styles/dialogs.less index c5cd105..bfe5045 100644 --- a/src/styles/dialogs.less +++ b/src/styles/dialogs.less @@ -38,6 +38,11 @@ display: flex; flex-direction: column; + + a { + color: white; + opacity: 0.8; + } } .dialog-shader { @@ -125,3 +130,71 @@ font-size: 20px; text-transform: uppercase; } + +.app-info-changelog { + color: white; + padding: 10px; + font-size: 0.8em; + + div { + opacity: 0.8; + } +} + +.app-info-number { + width: 16px; +} + +.app-info-changelog-item { + text-transform: uppercase; + display: flex; + flex: 1; + + .app-info-current { + font-size: 0.9em; + opacity: 0.3; + display: inline; + padding-left: 10px; + } +} + +.app-info-version { + padding-bottom: 5px; + flex: 1; + flex-direction: column-reverse; +} + +.app-info-release { + padding-bottom: 5px; + display: flex; + flex: 1; +} + +.app-info-build { + padding-bottom: 5px; + display: flex; + flex-direction: column-reverse; + flex: 1; +} + +.app-info-change { + display: flex; + flex-direction: row; + padding-bottom: 5px; + + .app-info-number { + width: 20px; + } + + span { + flex: 1; + } +} + +.app-info-list { + padding: 10px 0; + + div { + padding: 2.5px 0; + } +} diff --git a/src/styles/main.less b/src/styles/main.less index cba184a..185856a 100644 --- a/src/styles/main.less +++ b/src/styles/main.less @@ -117,3 +117,12 @@ body { @media (max-width: @mobile_breakpoint) { .desktop-only { display: none; } } + + +h2 { + font: inherit; + font-size: 18px; + font-weight: 400; + text-transform: uppercase; + margin: 10px 0; +} diff --git a/src/styles/panel.less b/src/styles/panel.less index c46923f..f19bc83 100644 --- a/src/styles/panel.less +++ b/src/styles/panel.less @@ -164,9 +164,8 @@ } .panel-user { - z-index: 1; - @media (max-width: @mobile_breakpoint) { + z-index: 1; flex-direction: column-reverse; .control-sep {