commit fe7fae2c19d7bdf0cb145b9be1e7fb14b01226b9 Author: Bart Riemens Date: Thu Aug 22 23:59:32 2019 +0200 Implemented a snake game with redux diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..2b7bafa --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env", "@babel/preset-react"] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5322b1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +public/main.js +*tar diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f59b775 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx +COPY public /usr/share/nginx/html +COPY default.conf /etc/nginx/conf.d/default.conf diff --git a/default.conf b/default.conf new file mode 100644 index 0000000..d2e2982 --- /dev/null +++ b/default.conf @@ -0,0 +1,44 @@ +server { + listen 80; + server_name localhost; + + #charset koi8-r; + #access_log /var/log/nginx/host.access.log main; + + location / { + alias /usr/share/nginx/html/; + try_files $uri /index.html; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + + # proxy the PHP scripts to Apache listening on 127.0.0.1:80 + # + #location ~ \.php$ { + # proxy_pass http://127.0.0.1; + #} + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + #location ~ \.php$ { + # root html; + # fastcgi_pass 127.0.0.1:9000; + # fastcgi_index index.php; + # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; + # include fastcgi_params; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + #location ~ /\.ht { + # deny all; + #} +} diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..bac70e7 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,31 @@ +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + include /etc/nginx/conf.d/*.conf; + } diff --git a/package.json b/package.json new file mode 100644 index 0000000..4ac12ae --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "name": "keybook-redux", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "dev": "webpack-dev-server --mode development --open", + "build": "webpack --optimize-minimize --config webpack.production.config.js", + "webpack": "webpack --config webpack.config.js --watch", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@babel/core": "^7.5.5", + "@babel/preset-env": "^7.5.5", + "@babel/preset-react": "^7.0.0", + "babel-loader": "^8.0.6", + "babel-plugin-styled-components": "^1.10.6", + "react-hot-loader": "^4.12.11", + "webpack": "^4.39.2", + "webpack-cli": "^3.3.7", + "webpack-dev-server": "^3.8.0" + }, + "dependencies": { + "connected-react-router": "^6.5.2", + "history": "^4.9.0", + "react": "^16.9.0", + "react-dom": "^16.9.0", + "react-redux": "^7.1.0", + "react-router": "^5.0.1", + "react-router-dom": "^5.0.1", + "redux": "^4.0.4", + "styled-components": "^4.3.2" + } +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..05bffa6 --- /dev/null +++ b/public/index.html @@ -0,0 +1,11 @@ + + + + + Redux Demo + + +
+ + + diff --git a/src/components/Button.js b/src/components/Button.js new file mode 100644 index 0000000..eea4e46 --- /dev/null +++ b/src/components/Button.js @@ -0,0 +1,60 @@ +import React from "react"; +import { NavLink } from "react-router-dom"; +import styled from "styled-components"; + +const SharedStyle = () => ` + border: 1px solid gray; + border-radius: .1875rem; + background-color: palevioletred; + color: papayawhip; + text-align: center; + padding: .3125rem; + font-size: 1rem; + display: inline-block; + vertical-align: top; + text-decoration: none; + user-select: none; + cursor: pointer; + + &:hover { + background-color: blue; + } +`; + +const StyledButton = styled.button` + ${SharedStyle} + -webkit-appearance: none; +`; + +const StyledAnchor = styled.a` + ${SharedStyle} +`; + +const StyledNavLink = styled(NavLink)` + ${SharedStyle} + &.active { + border-color: silver; + color: #828282; + background-color: #ecb1c5; + } +`; + +const Button = (props, refs) => { + const updatedProps = { ...props }; + + if (props.onClick) { + updatedProps.onClick = e => e.preventDefault() || props.onClick(); + } + + if (props.href) { + return StyledAnchor.render(updatedProps); + } + + if (props.to) { + return StyledNavLink.render(updatedProps); + } + + return StyledButton.render(updatedProps); +}; + +export default Button; diff --git a/src/components/HeaderMenu.js b/src/components/HeaderMenu.js new file mode 100644 index 0000000..86b4d69 --- /dev/null +++ b/src/components/HeaderMenu.js @@ -0,0 +1,48 @@ +import React from "react"; +import styled from "styled-components"; +import { NavLink } from "react-router-dom"; + +const MenuPanel = styled.ul` + display: flex; +`; + +const MenuItem = styled.li` + display: inline-block; +`; + +const MenuButton = styled(NavLink)` + display: inline-block; + text-align: center; + text-decoration: none; + border: 1px solid silver; + background: ${props => props.theme.header.menuButton.background}; + color: ${props => props.theme.header.menuButton.color}; + padding: 0.3125rem; + margin-right: 0.5rem; + border-radius: 0.125rem; + min-width: 3.125rem; + &.active { + background: ${props => props.theme.header.menuButton.active.background}; + color: ${props => props.theme.header.menuButton.active.color}; + } +`; + +const HeaderMenu = () => ( + + + + Home + + + { + // + // Keyboards + // + } + + Snake + + +); + +export default HeaderMenu; diff --git a/src/components/Link.js b/src/components/Link.js new file mode 100644 index 0000000..ada3712 --- /dev/null +++ b/src/components/Link.js @@ -0,0 +1,32 @@ +import styled from "styled-components"; +import { NavLink } from "react-router-dom"; + +const SharedStyle = () => ` + color: gray; + text-decoration: underline; + user-select: none; + cursor: pointer; +`; + +const StyledLink = styled.a` + ${SharedStyle} +`; + +const StyledNavLink = styled(NavLink)` + ${SharedStyle} + &.active { + color: black; + } +`; + +const Link = (props, refs) => { + const updatedProps = { ...props }; + + if (props.onClick) { + updatedProps.onClick = e => e.preventDefault() || props.onClick(); + } + + return props.to ? StyledNavLink.render(updatedProps) : StyledLink.render(updatedProps); +}; + +export default Link; diff --git a/src/components/List.js b/src/components/List.js new file mode 100644 index 0000000..881319f --- /dev/null +++ b/src/components/List.js @@ -0,0 +1,23 @@ +import React from "react"; +import styled from "styled-components"; + +const StyledList = styled.ul` + margin: 0; + padding: 0; + text-indent: 0; + list-style: none; +`; + +export const List = ({ items, Item, itemProps, Empty }) => { + if (items && items.length) { + return {items.map((item, index) => Item({ ...itemProps, item }))}; + } + if ((!items || !items.length) && Empty) { + return Empty({ ...itemProps }); + } + return
; +}; + +List.Item = styled.li``; + +export default List; diff --git a/src/components/Logo.js b/src/components/Logo.js new file mode 100644 index 0000000..047d057 --- /dev/null +++ b/src/components/Logo.js @@ -0,0 +1,30 @@ +import React from "react"; +import styled from "styled-components"; + +const LogoPanel = styled.div` + display: inline-block; + + h1, + h2 { + margin: 0; + padding: 0; + line-height: 1rem; + } + + h1 { + line-height: 2rem; + } + + h2 { + font-size: 1rem; + } +`; + +const Logo = () => ( + +

Hello Redux

+

Redux demo application

+
+); + +export default Logo; diff --git a/src/components/Page.js b/src/components/Page.js new file mode 100644 index 0000000..df91bf0 --- /dev/null +++ b/src/components/Page.js @@ -0,0 +1,9 @@ +import styled from "styled-components"; + +const Page = styled.div` + max-width: 60rem; + margin: 0 auto; + padding: 0.5em; +`; + +export default Page; diff --git a/src/components/Spinner.js b/src/components/Spinner.js new file mode 100644 index 0000000..34efb8d --- /dev/null +++ b/src/components/Spinner.js @@ -0,0 +1,60 @@ +import styled from "styled-components"; + +const Spinner = styled.div` + position: relative; + width: 1.875rem; + height: 1.875rem; + display: inline-block; + + &::before { + display: block; + border-radius: 50%; + content: ""; + position: absolute; + border: 0.4rem solid ${props => props.theme.spinner.shadow}; + top: 0; + right: 0; + bottom: 0; + left: 0; + } + + &::after { + display: block; + content: ""; + position: absolute; + transform: translateZ(0); + border-top: 0.4rem solid ${props => props.theme.spinner.highlight}30; + border-right: 0.4rem solid ${props => props.theme.spinner.highlight}30; + border-bottom: 0.4rem solid ${props => props.theme.spinner.highlight}30; + border-left: 0.4rem solid ${props => props.theme.spinner.highlight}; + border-radius: 50%; + top: 0; + right: 0; + bottom: 0; + left: 0; + animation: load8 1.1s infinite linear; + } + + @-webkit-keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } + } + @keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } + } +`; + +export default Spinner; diff --git a/src/components/Title.js b/src/components/Title.js new file mode 100644 index 0000000..d839d65 --- /dev/null +++ b/src/components/Title.js @@ -0,0 +1,7 @@ +import styled from "styled-components"; + +const Title = styled.h1` + font-size: ${props => (props.large ? "3rem" : "1.5rem")}; +`; + +export default Title; diff --git a/src/containers/App.js b/src/containers/App.js new file mode 100644 index 0000000..ac88cc8 --- /dev/null +++ b/src/containers/App.js @@ -0,0 +1,44 @@ +import React from "react"; +import { Route, Switch } from "react-router"; // react-router v4/v5 +import { connect } from "react-redux"; +import { hot } from "react-hot-loader/root"; + +/* Containers */ +import Header from "./Header"; +import Footer from "./Footer"; +import Page from "../components/Page"; +import Home from "./Home"; +import Keyboards from "./Keyboards"; +import KeyboardDetails from "./KeyboardDetails"; +import Snake from "./Snake"; + +const App = ({ title, onNewTitle, getKeyboards, keyboards }) => ( + +
+ + + + + + + + + +