forked from ppfun/pixelplanet
add HistorySelection dialog
This commit is contained in:
parent
2ecf670db7
commit
1e1d511d21
|
@ -35,6 +35,12 @@ export function toggleChatBox(): Action {
|
|||
};
|
||||
}
|
||||
|
||||
export function toggleHistoricalView(): Action {
|
||||
return {
|
||||
type: 'TOGGLE_HISTORICAL_VIEW',
|
||||
};
|
||||
}
|
||||
|
||||
export function toggleGrid(): Action {
|
||||
return {
|
||||
type: 'TOGGLE_GRID',
|
||||
|
|
|
@ -24,6 +24,7 @@ export type Action =
|
|||
| { type: 'TOGGLE_POTATO_MODE' }
|
||||
| { type: 'TOGGLE_LIGHT_GRID' }
|
||||
| { type: 'TOGGLE_OPEN_MENU' }
|
||||
| { type: 'TOGGLE_HISTORICAL_VIEW' }
|
||||
| { type: 'SET_NOTIFICATION', notification: string }
|
||||
| { type: 'UNSET_NOTIFICATION' }
|
||||
| { type: 'SET_PLACE_ALLOWED', placeAllowed: boolean }
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { IconContext } from 'react-icons';
|
||||
|
||||
import type { State } from '../reducers';
|
||||
import CoolDownBox from './CoolDownBox';
|
||||
import NotifyBox from './NotifyBox';
|
||||
import CoordinatesBox from './CoordinatesBox';
|
||||
|
@ -20,31 +22,49 @@ import Menu from './Menu';
|
|||
import ReCaptcha from './ReCaptcha';
|
||||
import ExpandMenuButton from './ExpandMenuButton';
|
||||
import ModalRoot from './ModalRoot';
|
||||
import HistorySelect from './HistorySelect';
|
||||
|
||||
import baseCss from './base.tcss';
|
||||
|
||||
const App = () => (
|
||||
const App = ({ isHistoricalView }) => (
|
||||
<div>
|
||||
<style dangerouslySetInnerHTML={{ __html: baseCss }} />
|
||||
<canvas id="gameWindow" />
|
||||
<div id="outstreamContainer" />
|
||||
<ReCaptcha />
|
||||
<IconContext.Provider value={{ style: { verticalAlign: 'middle' } }}>
|
||||
<CoolDownBox />
|
||||
<NotifyBox />
|
||||
<Menu />
|
||||
<GlobeButton />
|
||||
<CanvasSwitchButton />
|
||||
<PalselButton />
|
||||
<Menu />
|
||||
<ChatButton />
|
||||
<Palette />
|
||||
<ChatBox />
|
||||
<OnlineBox />
|
||||
<CoordinatesBox />
|
||||
<ExpandMenuButton />
|
||||
{
|
||||
(isHistoricalView)
|
||||
? <HistorySelect />
|
||||
: (
|
||||
<div>
|
||||
<PalselButton />
|
||||
<Palette />
|
||||
<GlobeButton />
|
||||
<CoolDownBox />
|
||||
<NotifyBox />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<ModalRoot />
|
||||
</IconContext.Provider>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default App;
|
||||
function mapStateToProps(state: State) {
|
||||
const {
|
||||
isHistoricalView,
|
||||
} = state.canvas;
|
||||
return {
|
||||
isHistoricalView,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(App);
|
||||
|
|
128
src/components/HistorySelect.jsx
Normal file
128
src/components/HistorySelect.jsx
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* LogIn Form
|
||||
* @flow
|
||||
*/
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import type { State } from '../reducers';
|
||||
|
||||
function dateToString(date) {
|
||||
const timeString = date.substr(0, 4) + date.substr(5, 2) + date.substr(8, 2);
|
||||
return timeString;
|
||||
}
|
||||
|
||||
async function getTimes(day, canvasId) {
|
||||
try {
|
||||
const response = await fetch(`./api/history?day=${day}&id=${canvasId}`);
|
||||
if (response.status !== 200) {
|
||||
return [];
|
||||
}
|
||||
const times = await response.json();
|
||||
const parsedTimes = times.map((a) => `${a.substr(0, 2)}:${a.substr(-2, 2)}`);
|
||||
return parsedTimes;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
class HistorySelect extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
const date = new Date();
|
||||
let day = date.getDate();
|
||||
let month = date.getMonth() + 1;
|
||||
if (month < 10) month = `0${month}`;
|
||||
if (day < 10) day = `0${day}`;
|
||||
const max = `${date.getFullYear()}-${month}-${day}`;
|
||||
|
||||
this.state = {
|
||||
submitting: false,
|
||||
selectedDate: new Date(),
|
||||
max,
|
||||
};
|
||||
|
||||
this.handleDateChange = this.handleDateChange.bind(this);
|
||||
}
|
||||
|
||||
async handleDateChange(evt) {
|
||||
const {
|
||||
submitting,
|
||||
} = this.state;
|
||||
|
||||
if (submitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
submitting: true,
|
||||
});
|
||||
const {
|
||||
canvasId,
|
||||
} = this.props;
|
||||
const date = dateToString(evt.target.value)
|
||||
const times = await getTimes(date, canvasId);
|
||||
this.setState({
|
||||
submitting: false,
|
||||
selectedDate: date,
|
||||
times,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
setTime,
|
||||
} = this.props;
|
||||
const {
|
||||
submitting,
|
||||
times,
|
||||
selectedDate,
|
||||
max,
|
||||
} = this.state;
|
||||
return (
|
||||
<div id="historyselect">
|
||||
<input
|
||||
type="date"
|
||||
requiredPattern="\d{4}-\d{2}-\d{2}"
|
||||
min="2020-01-08"
|
||||
max={max}
|
||||
onChange={this.handleDateChange}
|
||||
/>
|
||||
<div>
|
||||
{ (times && times.length > 0)
|
||||
? (
|
||||
<select onChange={(evt) => setTime(selectedDate, evt.target.value)}>
|
||||
{times.map((value) => (
|
||||
<option value={value}>{value}</option>
|
||||
))}
|
||||
</select>
|
||||
)
|
||||
: <p>Select Date</p> }
|
||||
{ (submitting) ? <p>Loading...</p> : null }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
setTime(date: string, time: string) {
|
||||
const timeString = time.substr(0, 2) + time.substr(-2, 2);
|
||||
const dateString = dateToString(date);
|
||||
console.log(`${timeString} - ${dateString}`);
|
||||
// dispatch(selectHistoricalTime(dateString, timeString));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function mapStateToProps(state: State) {
|
||||
const {
|
||||
canvasId,
|
||||
} = state.canvas;
|
||||
return { canvasId };
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(HistorySelect);
|
|
@ -17,6 +17,7 @@ import {
|
|||
toggleChatNotify,
|
||||
togglePotatoMode,
|
||||
toggleLightGrid,
|
||||
toggleHistoricalView,
|
||||
} from '../actions';
|
||||
|
||||
import type { State } from '../reducers';
|
||||
|
@ -94,6 +95,7 @@ function SettingsModal({
|
|||
isPixelNotifyShown,
|
||||
isPotato,
|
||||
isLightGrid,
|
||||
isHistoricalView,
|
||||
onMute,
|
||||
autoZoomIn,
|
||||
compactPalette,
|
||||
|
@ -104,6 +106,7 @@ function SettingsModal({
|
|||
onToggleChatNotify,
|
||||
onTogglePotatoMode,
|
||||
onToggleLightGrid,
|
||||
onToggleHistoricalView,
|
||||
chatNotify,
|
||||
}) {
|
||||
return (
|
||||
|
@ -159,6 +162,15 @@ function SettingsModal({
|
|||
value={isLightGrid}
|
||||
onToggle={onToggleLightGrid}
|
||||
/>
|
||||
{ (window.backupurl)
|
||||
? (
|
||||
<SettingsItem
|
||||
title="Historical View"
|
||||
description="Check out past versions of the canvas."
|
||||
value={isHistoricalView}
|
||||
onToggle={onToggleHistoricalView}
|
||||
/>
|
||||
) : null }
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
@ -174,6 +186,9 @@ function mapStateToProps(state: State) {
|
|||
isLightGrid,
|
||||
} = state.gui;
|
||||
const isMuted = mute;
|
||||
const {
|
||||
isHistoricalView,
|
||||
} = state.canvas;
|
||||
const isGridShown = showGrid;
|
||||
const isPixelNotifyShown = showPixelNotify;
|
||||
return {
|
||||
|
@ -185,6 +200,7 @@ function mapStateToProps(state: State) {
|
|||
chatNotify,
|
||||
isPotato,
|
||||
isLightGrid,
|
||||
isHistoricalView,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -214,6 +230,9 @@ function mapDispatchToProps(dispatch) {
|
|||
onToggleLightGrid() {
|
||||
dispatch(toggleLightGrid());
|
||||
},
|
||||
onToggleHistoricalView() {
|
||||
dispatch(toggleHistoricalView());
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -150,11 +150,11 @@ kbd {
|
|||
top: 139px;
|
||||
}
|
||||
:global(#globebutton) {
|
||||
left: 57px;
|
||||
left: 98px;
|
||||
top: 16px;
|
||||
}
|
||||
:global(#canvasbutton) {
|
||||
left: 98px;
|
||||
left: 57px;
|
||||
top: 16px;
|
||||
}
|
||||
:global(#minecrafttpbutton) {
|
||||
|
@ -170,6 +170,27 @@ kbd {
|
|||
right: 57px;
|
||||
}
|
||||
|
||||
:global(#historyselect) {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
height: 70px;
|
||||
width: 140px;
|
||||
background-color: rgba(226, 226, 226, 0.80);
|
||||
color: black;
|
||||
font-size: 14px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border: solid black;
|
||||
border-width: thin;
|
||||
padding: 0 24px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
:global(.Modal) {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
|
|
@ -26,7 +26,6 @@ export type CanvasState = {
|
|||
canvasIdent: string,
|
||||
canvasSize: number,
|
||||
canvasMaxTiledZoom: number,
|
||||
minScale: number,
|
||||
palette: Palette,
|
||||
chunks: Map<string, ChunkRGB>,
|
||||
view: Cell,
|
||||
|
@ -34,6 +33,7 @@ export type CanvasState = {
|
|||
viewscale: number,
|
||||
requested: Set<string>,
|
||||
fetchs: number,
|
||||
isHistoricalView: boolean,
|
||||
// object with all canvas informations from all canvases like colors and size
|
||||
canvases: Object,
|
||||
};
|
||||
|
@ -107,6 +107,7 @@ const initialState: CanvasState = {
|
|||
...getViewFromURL(DEFAULT_CANVASES),
|
||||
requested: new Set(),
|
||||
fetchs: 0,
|
||||
isHistoricalView: false,
|
||||
};
|
||||
|
||||
|
||||
|
@ -141,12 +142,20 @@ export default function gui(
|
|||
}
|
||||
|
||||
case 'SET_SCALE': {
|
||||
let { view, viewscale } = state;
|
||||
const { canvasSize } = state;
|
||||
let {
|
||||
view,
|
||||
viewscale,
|
||||
} = state;
|
||||
const {
|
||||
canvasSize,
|
||||
isHistoricalView,
|
||||
} = state;
|
||||
|
||||
let [hx, hy] = view;
|
||||
let { scale } = action;
|
||||
const { zoompoint } = action;
|
||||
scale = clamp(scale, TILE_SIZE / canvasSize, MAX_SCALE);
|
||||
const minScale = (isHistoricalView) ? 0.7 : TILE_SIZE / canvasSize;
|
||||
scale = clamp(scale, minScale, MAX_SCALE);
|
||||
if (zoompoint) {
|
||||
let scalediff = viewscale;
|
||||
// clamp to 1.0 (just do this when zoompoint is given, or it would mess with phones)
|
||||
|
@ -171,6 +180,15 @@ export default function gui(
|
|||
};
|
||||
}
|
||||
|
||||
case 'TOGGLE_HISTORICAL_VIEW': {
|
||||
return {
|
||||
...state,
|
||||
scale: 1.0,
|
||||
viewscale: 1.0,
|
||||
isHistoricalView: !state.isHistoricalView,
|
||||
};
|
||||
}
|
||||
|
||||
case 'SET_VIEW_COORDINATES': {
|
||||
const { view } = action;
|
||||
const { canvasSize } = state;
|
||||
|
@ -186,7 +204,7 @@ export default function gui(
|
|||
case 'RELOAD_URL': {
|
||||
const { canvasId, chunks, canvases } = state;
|
||||
const nextstate = getViewFromURL(canvases);
|
||||
if (nextstate.canvasId != canvasId) {
|
||||
if (nextstate.canvasId !== canvasId) {
|
||||
chunks.clear();
|
||||
}
|
||||
return {
|
||||
|
@ -205,7 +223,7 @@ export default function gui(
|
|||
y = Math.round(y);
|
||||
const scale = Math.round(Math.log2(viewscale) * 10);
|
||||
const newhash = `#${canvasIdent},${x},${y},${scale}`;
|
||||
history.replaceState(undefined, undefined, newhash);
|
||||
window.history.replaceState(undefined, undefined, newhash);
|
||||
return {
|
||||
...state,
|
||||
};
|
||||
|
@ -316,7 +334,7 @@ export default function gui(
|
|||
const canvasSize = canvases[canvasId].size;
|
||||
const canvasMaxTiledZoom = getMaxTiledZoom(canvasSize);
|
||||
const palette = new Palette(canvas.colors, 0);
|
||||
const view = (canvasId == 0) ? getGivenCoords() : [0, 0];
|
||||
const view = (canvasId === 0) ? getGivenCoords() : [0, 0];
|
||||
chunks.clear();
|
||||
return {
|
||||
...state,
|
||||
|
|
|
@ -28,6 +28,7 @@ export default (store) => (next) => (action) => {
|
|||
break;
|
||||
}
|
||||
|
||||
case 'TOGGLE_HISTORICAL_VIEW':
|
||||
case 'SET_SCALE': {
|
||||
const {
|
||||
viewscale,
|
||||
|
|
Loading…
Reference in New Issue
Block a user