diff --git a/src/components/Apple.js b/src/components/Apple.js
index 049b331..5d4e882 100644
--- a/src/components/Apple.js
+++ b/src/components/Apple.js
@@ -1,10 +1,14 @@
-import styled from "styled-components";
+import styled, { keyframes } from "styled-components";
+
+const fade = keyframes`
+from { transform: scale(.7) }
+to { transform: scale(1) }
+`;
const Apple = styled.div.attrs(({ theme, zoom }) => ({
style: {
height: theme.snake.cell.size * (zoom || 1) + "rem",
width: theme.snake.cell.size * (zoom || 1) + "rem",
- border: theme.snake.cell.border,
fontSize: (zoom || 1) * 1.3 + "rem",
lineHeight: (zoom || 1) * 1.7 + "rem",
paddingLeft: (zoom || 1) * 0.0625 + "rem"
@@ -14,9 +18,10 @@ const Apple = styled.div.attrs(({ theme, zoom }) => ({
vertical-align: top;
&:after {
- // content: "${props => (!props.died ? "🍎" : "🐛")}";
- content: "🍎";
+ content: "${props => (!props.died ? "🍎" : "🐛")}";
+ // content: "🍎";
display: inline-block;
+ animation: ${fade} 1s ease-out alternate infinite;
}
`;
diff --git a/src/components/Button.js b/src/components/Button.js
index 9fc2c46..4d19697 100644
--- a/src/components/Button.js
+++ b/src/components/Button.js
@@ -1,6 +1,6 @@
import React from "react";
import { NavLink } from "react-router-dom";
-import styled from "styled-components";
+import styled, { css } from "styled-components";
const SharedStyle = () => `
border: 1px solid gray;
@@ -21,6 +21,11 @@ const SharedStyle = () => `
}
`;
+const ButtonWrapper = styled.div`
+ position: relative;
+ display: inline-block;
+`;
+
const StyledButton = styled.button`
${SharedStyle}
-webkit-appearance: none;
@@ -39,8 +44,30 @@ const StyledNavLink = styled(NavLink)`
}
`;
+const Tooltip = styled.div`
+ position: absolute;
+ margin-top: 0.5rem;
+ border: 1px solid gray;
+ background-color: palevioletred;
+ color: papayawhip;
+ padding: 5px;
+ box-shadow: 1px 1px 3px #d0bfa3;
+ ${props =>
+ props.hover
+ ? css`
+ transition: opacity 400ms 200ms ease-in;
+ `
+ : css`
+ transition: opacity 100ms ease-out;
+ `}
+ white-space: nowrap;
+ opacity: ${props => (props.hover ? 1 : 0)};
+`;
+
export const Button = (props, refs) => {
+ const [hover, setHover] = React.useState(false);
const updatedProps = { ...props };
+ let tooltip = null;
if (props.onClick) {
updatedProps.onClick = e => e.preventDefault() || props.onClick();
@@ -54,13 +81,20 @@ export const Button = (props, refs) => {
return StyledNavLink.render(updatedProps);
}
+ if (props.tooltip) {
+ tooltip = {props.tooltip};
+ }
+
if (props.icon) {
return (
-
+ setHover(true)} onMouseLeave={() => setHover(false)}>
+
+ {tooltip}
+
);
}
diff --git a/src/components/ControlPanel.js b/src/components/ControlPanel.js
index 2ee6a39..77e5a38 100644
--- a/src/components/ControlPanel.js
+++ b/src/components/ControlPanel.js
@@ -66,10 +66,34 @@ export const ControlPanel = ({
-
-
-
-
+
+
+
+
);
diff --git a/src/components/SnakePart.js b/src/components/SnakePart.js
index 17d7154..3ca3651 100644
--- a/src/components/SnakePart.js
+++ b/src/components/SnakePart.js
@@ -1,13 +1,16 @@
import styled, { css } from "styled-components";
-export const SnakePart = styled.div`
- width: ${({ theme, zoom }) => theme.snake.cell.size * (zoom || 1)}rem;
- height: ${({ theme, zoom }) => theme.snake.cell.size * (zoom || 1)}rem;
+export const SnakePart = styled.div.attrs(({ theme, zoom }) => ({
+ style: {
+ height: theme.snake.cell.size * (zoom || 1) + "rem",
+ width: theme.snake.cell.size * (zoom || 1) + "rem",
+ fontSize: (zoom || 1) * 1.3 + "rem",
+ lineHeight: (zoom || 1) * 1.7 + "rem",
+ paddingLeft: (zoom || 1) * 0.0625 + "rem"
+ }
+}))`
display: inline-block;
- font-size: ${props => (props.zoom || 1) * 1.3}rem;
vertical-align: top;
- line-height: ${props => (props.zoom || 1) * 1.7}rem;
- padding-left: ${props => (props.zoom || 1) * 0.0625}rem;
${props =>
!props.died
diff --git a/src/containers/Snake.js b/src/containers/Snake.js
index 0df77a1..4a00475 100644
--- a/src/containers/Snake.js
+++ b/src/containers/Snake.js
@@ -11,7 +11,6 @@ import {
pauseSnake,
updateFrameSnake,
keyPressedSnake,
- keys,
zoomIn,
zoomOut
} from "../redux/snake.js";
@@ -41,7 +40,6 @@ class Snake extends React.Component {
constructor(props) {
super(props);
this.handleKeyDown = this.handleKeyDown.bind(this);
- this.supportedKeys = Object.values(keys);
window.me = this;
}
@@ -63,7 +61,6 @@ class Snake extends React.Component {
grid,
started,
paused,
- snake,
died,
fps,
setFps,
diff --git a/src/enums/directions.js b/src/enums/directions.js
new file mode 100644
index 0000000..9a706c4
--- /dev/null
+++ b/src/enums/directions.js
@@ -0,0 +1,8 @@
+export const directions = {
+ UP: "UP",
+ DOWN: "DOWN",
+ LEFT: "LEFT",
+ RIGHT: "RIGHT"
+};
+
+export default directions;
diff --git a/src/enums/keys.js b/src/enums/keys.js
new file mode 100644
index 0000000..44cb924
--- /dev/null
+++ b/src/enums/keys.js
@@ -0,0 +1,32 @@
+export const keys = {
+ UP: "ArrowUp",
+ RIGHT: "ArrowRight",
+ DOWN: "ArrowDown",
+ LEFT: "ArrowLeft",
+
+ EQUAL: "=",
+ PLUS: "+",
+ MINUS: "-",
+
+ h: "h",
+ j: "j",
+ k: "k",
+ l: "l",
+
+ p: "p",
+ s: "s",
+ r: "r",
+
+ 1: "1",
+ 2: "2",
+ 3: "3",
+ 4: "4",
+ 5: "5",
+ 6: "6",
+ 7: "7",
+ 8: "8",
+ 9: "9",
+ 0: "0"
+};
+
+export default keys;
diff --git a/src/redux/game.js b/src/redux/game.js
index a732695..5b67826 100644
--- a/src/redux/game.js
+++ b/src/redux/game.js
@@ -1,4 +1,5 @@
import Module from "./module.js";
+import keys from "../enums/keys.js";
export const MODULE_NAME = "GAME";
@@ -9,16 +10,6 @@ export const module = new Module(MODULE_NAME, {
fps: 8
});
-export const keys = {
- UP: "ArrowUp",
- RIGHT: "ArrowRight",
- DOWN: "ArrowDown",
- LEFT: "ArrowLeft",
- EQUAL: "=",
- PLUS: "+",
- MINUS: "-"
-};
-
export const [START_LOOP, startLoop] = module.action("START_LOOP");
export const [STOP_LOOP, stopLoop] = module.action("STOP_LOOP");
export const [LOOP, loop] = module.action("LOOP", ({ recur, skip } = {}) => ({ recur, skip }));
diff --git a/src/redux/snake.js b/src/redux/snake.js
index a82d4a2..2dfaa36 100644
--- a/src/redux/snake.js
+++ b/src/redux/snake.js
@@ -1,12 +1,7 @@
import Module from "./module.js";
-import {
- registerCaller,
- unregisterCaller,
- startLoop,
- stopLoop,
- subscribeKeyPressed,
- unsubscribeKeyPressed
-} from "./game.js";
+import keys from "../enums/keys.js";
+import directions from "../enums/directions.js";
+import { registerCaller, unregisterCaller, startLoop, stopLoop, subscribeKeyPressed } from "./game.js";
const MODULE_NAME = "SNAKE";
const DEFAULT_GRID_SIZE = 16;
@@ -28,40 +23,6 @@ const initialState = {
/* === Snake Helper Functions ================================================================== */
-export const directions = {
- UP: "UP",
- DOWN: "DOWN",
- LEFT: "LEFT",
- RIGHT: "RIGHT"
-};
-
-export const keys = {
- UP: "ArrowUp",
- RIGHT: "ArrowRight",
- DOWN: "ArrowDown",
- LEFT: "ArrowLeft",
-
- h: "h",
- j: "j",
- k: "k",
- l: "l",
-
- snakePart: "snakePart",
- s: "s",
- r: "r",
-
- 1: "1",
- 2: "2",
- 3: "3",
- 4: "4",
- 5: "5",
- 6: "6",
- 7: "7",
- 8: "8",
- 9: "9",
- 0: "0"
-};
-
function randomPosition(size) {
return [Math.round(Math.random() * (size - 1)), Math.round(Math.random() * (size - 1))];
}
@@ -195,7 +156,7 @@ module.reducer(UPDATE_FRAME_SNAKE, state => {
}
/* Check if the snake hits itself */
- if (newSnake.slice(0, -1).filter((snakePart, index) => comparePositions(snakePart, nextPosition)).length) {
+ if (newSnake.slice(0, -1).filter(snakePart => comparePositions(snakePart, nextPosition)).length) {
started = false;
died = true;
}
@@ -240,7 +201,7 @@ module.after(UPDATE_FRAME_SNAKE, (dispatch, { died }) => {
}
});
-module.middleware(START_SNAKE, (dispatch, { started }) => {
+module.middleware(START_SNAKE, dispatch => {
dispatch(resetSnake({ started: true, died: false }));
dispatch(registerCaller(UPDATE_FRAME_SNAKE));
dispatch(subscribeKeyPressed(KEY_PRESSED_SNAKE));
@@ -263,7 +224,6 @@ module.middleware(PAUSE_SNAKE, (dispatch, { paused }) => {
}
});
-// eslint-disable-next-line complexity
module.middleware(KEY_PRESSED_SNAKE, (dispatch, _, { key }) => {
if (key === keys.UP || key === keys.k) {
dispatch(changeDirection(directions.UP));
@@ -280,37 +240,16 @@ module.middleware(KEY_PRESSED_SNAKE, (dispatch, _, { key }) => {
if (key === keys.s) {
dispatch(stopSnake());
}
- if (key === keys.snakePart) {
+ if (key === keys.p) {
dispatch(pauseSnake());
}
if (key === keys.r) {
dispatch(startSnake());
}
- if (key === keys[1]) {
- dispatch(setZoomLevel(0.6));
- }
- if (key === keys[2]) {
- dispatch(setZoomLevel(0.8));
- }
- if (key === keys[3]) {
- dispatch(setZoomLevel(1));
- }
- if (key === keys[4]) {
- dispatch(setZoomLevel(1.2));
- }
- if (key === keys[5]) {
- dispatch(setZoomLevel(1.4));
- }
- if (key === keys[6]) {
- dispatch(setZoomLevel(1.6));
- }
- if (key === keys[7]) {
- dispatch(setZoomLevel(1.8));
- }
- if (key === keys[8]) {
- dispatch(setZoomLevel(2));
- }
- if (key === keys[9]) {
- dispatch(setZoomLevel(2.2));
+
+ /* Map the number keys to a zoom level */
+ const keyAsInt = parseInt(key, 10);
+ if (!isNaN(keyAsInt) && keyAsInt > 0 && keyAsInt <= 9) {
+ dispatch(setZoomLevel(0.6 + (keyAsInt - 1) * 0.2));
}
});
diff --git a/src/redux/ui.js b/src/redux/ui.js
index 4e92a63..e576149 100644
--- a/src/redux/ui.js
+++ b/src/redux/ui.js
@@ -6,25 +6,25 @@ export const showSpinner = () => ({ type: SHOW_SPINNER });
export const hideSpinner = () => ({ type: HIDE_SPINNER });
export const toggleSpinner = () => ({ type: TOGGLE_SPINNER });
-export const reducers = (ui = {}, action) => {
+export const reducers = (state = {}, action) => {
if (action.type === SHOW_SPINNER) {
return {
- ...ui,
+ ...state,
spinner: true
};
}
if (action.type === HIDE_SPINNER) {
return {
- ...ui,
+ ...state,
spinner: false
};
}
if (action.type === TOGGLE_SPINNER) {
return {
- ...ui,
- spinner: !ui.spinner
+ ...state,
+ spinner: !state.spinner
};
}
- return ui;
+ return state;
};