mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 19:16:41 +07:00
changelog: dialog for changelog
This commit is contained in:
parent
b719b3f1a2
commit
65e549a5af
12 changed files with 218 additions and 34 deletions
74
src/components/dialogs/AppInfoDialog.jsx
Normal file
74
src/components/dialogs/AppInfoDialog.jsx
Normal file
|
@ -0,0 +1,74 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { Scroll } from '$components/Scroll';
|
||||
import { APP_INFO } from '$constants/app_info';
|
||||
|
||||
export const AppInfoDialog = () => (
|
||||
<div className="dialog-content">
|
||||
<div className="dialog-head">
|
||||
<div className="dialog-head-title">
|
||||
Orchid Map
|
||||
</div>
|
||||
<div className="small gray">
|
||||
версия{' '}
|
||||
{(APP_INFO.VERSION || 1)}.
|
||||
{(APP_INFO.CHANGELOG[APP_INFO.VERSION].length || 0)}
|
||||
</div>
|
||||
<div className="small app-info-list">
|
||||
<div>
|
||||
Исходный код:{' '}
|
||||
<a href="//github.com/muerwre/orchidMap" target="_blank">github.com/muerwre/orchidMap</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="small app-info-list">
|
||||
<div>
|
||||
Frontend:{' '}
|
||||
<a href="//reactjs.org/" target="_blank">ReactJS</a>,{' '}
|
||||
<a href="//leafletjs.com" target="_blank">Leaflet</a>,{' '}
|
||||
<a href="//www.liedman.net/leaflet-routing-machine/" target="_blank">Leaflet Routing Machine</a>{' '}
|
||||
</div>
|
||||
<div>
|
||||
Backend:{' '}
|
||||
<a href="//project-osrm.org/" target="_blank">OSRM</a>,{' '}
|
||||
<a href="//nodejs.org/" target="_blank">NodeJS</a>,{' '}
|
||||
<a href="//expressjs.com/" target="_blank">ExpressJS</a>,{' '}
|
||||
<a href="//mongodb.com/" target="_blank">MongoDB</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Scroll className="dialog-shader">
|
||||
<div>
|
||||
<div className="app-info-changelog">
|
||||
<h2>История изменений</h2>
|
||||
{
|
||||
[...Object.keys(APP_INFO.CHANGELOG)].reverse().map((version, i) => (
|
||||
<div className="app-info-changelog-item" key={version}>
|
||||
<div className="app-info-number">{version}.</div>
|
||||
<div className="app-info-version">
|
||||
{
|
||||
APP_INFO.CHANGELOG[version].map((release, y) => (
|
||||
<div className="app-info-release" key={release}>
|
||||
<div className="app-info-number">{APP_INFO.CHANGELOG[version].length - y}.</div>
|
||||
<div className="app-info-build">
|
||||
{
|
||||
APP_INFO.CHANGELOG[version][y].map((build, z) => (
|
||||
<div className="app-info-change" key={build}>
|
||||
<div className="app-info-number">{(z)}.</div>
|
||||
<span>{APP_INFO.CHANGELOG[version][y][z]}</span>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Scroll>
|
||||
</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, 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<Props, void> {
|
|||
|
||||
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<Props, void> {
|
|||
}
|
||||
{
|
||||
(user && user.role && user.role !== 'guest' && menuOpened) &&
|
||||
<UserMenu user={user} userLogout={this.props.userLogout} />
|
||||
<UserMenu user={user} userLogout={this.props.userLogout} openAppInfoDialog={this.openAppInfoDialog} />
|
||||
}
|
||||
</div>
|
||||
|
||||
|
@ -125,6 +133,7 @@ const mapDispatchToProps = dispatch => bindActionCreators({
|
|||
takeAShot,
|
||||
setDialog,
|
||||
gotVkUser,
|
||||
setDialogActive,
|
||||
}, dispatch);
|
||||
|
||||
export const UserPanel = connect(mapStateToProps, mapDispatchToProps)(Component);
|
||||
|
|
|
@ -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) => (
|
||||
<div className="user-panel-menu">
|
||||
<div className="user-panel-title">
|
||||
ORCHID
|
||||
<br />
|
||||
MAP
|
||||
<span className="user-panel-ver">
|
||||
- { CLIENT.VER }
|
||||
- {(APP_INFO.VERSION || 1)}.{(APP_INFO.RELEASE.length || 0)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="user-panel-item" onClick={openAppInfoDialog}>
|
||||
О редакторе карт
|
||||
</div>
|
||||
<a className="user-panel-item" href="https://github.com/muerwre/orchidMap" target="_blank" rel="noopener noreferrer">
|
||||
Проект на github
|
||||
</a>
|
||||
|
|
|
@ -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: [
|
||||
[
|
||||
'Первый работающий редактор карт'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
export const DIALOGS = ({
|
||||
NONE: 'NONE',
|
||||
MAP_LIST: 'MAP_LIST',
|
||||
APP_INFO: 'APP_INFO',
|
||||
}: { [key: String]: String });
|
||||
|
|
|
@ -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) => (
|
||||
<div className={classnames('dialog', { active: dialog_active })}>
|
||||
{ dialog === DIALOGS.MAP_LIST && <MapListDialog /> }
|
||||
{ dialog && LEFT_DIALOGS[dialog] && React.createElement(LEFT_DIALOGS[dialog]) }
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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',
|
||||
|
||||
|
|
|
@ -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 });
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -164,9 +164,8 @@
|
|||
}
|
||||
|
||||
.panel-user {
|
||||
z-index: 1;
|
||||
|
||||
@media (max-width: @mobile_breakpoint) {
|
||||
z-index: 1;
|
||||
flex-direction: column-reverse;
|
||||
|
||||
.control-sep {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue