├── .prettierrc
├── .gitignore
├── src
├── pages
│ ├── index.js
│ └── Home.jsx
├── assets
│ ├── img
│ │ ├── waves.gif
│ │ ├── linkedin.svg
│ │ ├── twitter.svg
│ │ └── github.svg
│ └── styles
│ │ ├── fonts
│ │ ├── Pacifico-Regular.woff
│ │ ├── ClearSans-Bold-webfont.eot
│ │ ├── ClearSans-Bold-webfont.woff
│ │ ├── ClearSans-Light-webfont.eot
│ │ ├── ClearSans-Light-webfont.woff
│ │ ├── ClearSans-Regular-webfont.eot
│ │ ├── ClearSans-Regular-webfont.woff
│ │ └── font.scss
│ │ └── app.scss
├── hoc
│ ├── index.js
│ └── keyboardManager
│ │ └── index.js
├── utils
│ ├── transition.js
│ ├── index.js
│ ├── elevation.js
│ ├── portal.js
│ ├── color.js
│ ├── keyframes.js
│ └── game.js
├── components
│ ├── index.js
│ ├── Header
│ │ └── index.jsx
│ ├── Score
│ │ └── index.js
│ ├── Details
│ │ └── index.js
│ ├── Cell
│ │ └── index.js
│ ├── Grid
│ │ └── index.js
│ ├── Instructions
│ │ └── index.jsx
│ └── Game
│ │ └── index.jsx
├── elements
│ ├── index.js
│ ├── Text.js
│ ├── Modal.js
│ ├── Button.js
│ ├── Icon.js
│ ├── GameFactory.js
│ └── Container.js
└── App.jsx
├── screenshots
├── 1.png
├── 2.png
├── game.gif
└── game-logo.png
├── dist
├── waves.0ff540f5.gif
├── icon-72x72.64199dc3.png
├── icon-96x96.f16e8aa9.png
├── favicon-16x16.48376abf.png
├── favicon-32x32.7038d02b.png
├── favicon-96x96.b441a26b.png
├── icon-128x128.bdc5b571.png
├── icon-144x144.357081de.png
├── icon-152x152.bc4c1001.png
├── icon-192x192.52b953b7.png
├── icon-384x384.b9e62e98.png
├── icon-512x512.e3a8497e.png
├── apple-icon-57x57.c7df9d0f.png
├── apple-icon-60x60.1c9552b0.png
├── apple-icon-72x72.e98825e6.png
├── apple-icon-76x76.dd21d491.png
├── ms-icon-144x144.9c1d6372.png
├── Pacifico-Regular.c0c32478.woff
├── apple-icon-114x114.12757dc0.png
├── apple-icon-120x120.c7598235.png
├── apple-icon-144x144.9c1d6372.png
├── apple-icon-152x152.c259a454.png
├── apple-icon-180x180.ce6023f9.png
├── android-icon-192x192.cf567ee1.png
├── ClearSans-Bold-webfont.6a6f5f3f.eot
├── ClearSans-Bold-webfont.ae49b717.woff
├── ClearSans-Light-webfont.fe3992bc.eot
├── ClearSans-Light-webfont.fb98e0ac.woff
├── ClearSans-Regular-webfont.662fe67c.eot
├── ClearSans-Regular-webfont.7edfc781.woff
├── manifest.1a627359.webmanifest
├── 15Puzzle.b3ebf31c.css
└── index.html
├── public
└── images
│ └── icons
│ ├── favicon.ico
│ ├── apple-icon.png
│ ├── icon-72x72.png
│ ├── icon-96x96.png
│ ├── icon-128x128.png
│ ├── icon-144x144.png
│ ├── icon-152x152.png
│ ├── icon-192x192.png
│ ├── icon-384x384.png
│ ├── icon-512x512.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon-96x96.png
│ ├── ms-icon-144x144.png
│ ├── ms-icon-150x150.png
│ ├── ms-icon-310x310.png
│ ├── ms-icon-70x70.png
│ ├── apple-icon-57x57.png
│ ├── apple-icon-60x60.png
│ ├── apple-icon-72x72.png
│ ├── apple-icon-76x76.png
│ ├── android-icon-144x144.png
│ ├── android-icon-192x192.png
│ ├── android-icon-36x36.png
│ ├── android-icon-48x48.png
│ ├── android-icon-72x72.png
│ ├── android-icon-96x96.png
│ ├── apple-icon-114x114.png
│ ├── apple-icon-120x120.png
│ ├── apple-icon-144x144.png
│ ├── apple-icon-152x152.png
│ ├── apple-icon-180x180.png
│ └── apple-icon-precomposed.png
├── index.js
├── .babelrc
├── package.json
├── LICENSE
├── manifest.webmanifest
├── README.md
└── index.html
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .cache
3 | *-lock.json
4 | .lock
--------------------------------------------------------------------------------
/src/pages/index.js:
--------------------------------------------------------------------------------
1 | import Home from './Home';
2 | export { Home };
3 |
--------------------------------------------------------------------------------
/screenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/screenshots/1.png
--------------------------------------------------------------------------------
/screenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/screenshots/2.png
--------------------------------------------------------------------------------
/screenshots/game.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/screenshots/game.gif
--------------------------------------------------------------------------------
/dist/waves.0ff540f5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/waves.0ff540f5.gif
--------------------------------------------------------------------------------
/src/assets/img/waves.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/src/assets/img/waves.gif
--------------------------------------------------------------------------------
/src/hoc/index.js:
--------------------------------------------------------------------------------
1 | import KeyBoardManagar from './keyboardManager';
2 |
3 | export { KeyBoardManagar };
4 |
--------------------------------------------------------------------------------
/screenshots/game-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/screenshots/game-logo.png
--------------------------------------------------------------------------------
/dist/icon-72x72.64199dc3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/icon-72x72.64199dc3.png
--------------------------------------------------------------------------------
/dist/icon-96x96.f16e8aa9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/icon-96x96.f16e8aa9.png
--------------------------------------------------------------------------------
/dist/favicon-16x16.48376abf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/favicon-16x16.48376abf.png
--------------------------------------------------------------------------------
/dist/favicon-32x32.7038d02b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/favicon-32x32.7038d02b.png
--------------------------------------------------------------------------------
/dist/favicon-96x96.b441a26b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/favicon-96x96.b441a26b.png
--------------------------------------------------------------------------------
/dist/icon-128x128.bdc5b571.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/icon-128x128.bdc5b571.png
--------------------------------------------------------------------------------
/dist/icon-144x144.357081de.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/icon-144x144.357081de.png
--------------------------------------------------------------------------------
/dist/icon-152x152.bc4c1001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/icon-152x152.bc4c1001.png
--------------------------------------------------------------------------------
/dist/icon-192x192.52b953b7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/icon-192x192.52b953b7.png
--------------------------------------------------------------------------------
/dist/icon-384x384.b9e62e98.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/icon-384x384.b9e62e98.png
--------------------------------------------------------------------------------
/dist/icon-512x512.e3a8497e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/icon-512x512.e3a8497e.png
--------------------------------------------------------------------------------
/public/images/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/favicon.ico
--------------------------------------------------------------------------------
/dist/apple-icon-57x57.c7df9d0f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/apple-icon-57x57.c7df9d0f.png
--------------------------------------------------------------------------------
/dist/apple-icon-60x60.1c9552b0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/apple-icon-60x60.1c9552b0.png
--------------------------------------------------------------------------------
/dist/apple-icon-72x72.e98825e6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/apple-icon-72x72.e98825e6.png
--------------------------------------------------------------------------------
/dist/apple-icon-76x76.dd21d491.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/apple-icon-76x76.dd21d491.png
--------------------------------------------------------------------------------
/dist/ms-icon-144x144.9c1d6372.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/ms-icon-144x144.9c1d6372.png
--------------------------------------------------------------------------------
/public/images/icons/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon.png
--------------------------------------------------------------------------------
/public/images/icons/icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/icon-72x72.png
--------------------------------------------------------------------------------
/public/images/icons/icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/icon-96x96.png
--------------------------------------------------------------------------------
/dist/Pacifico-Regular.c0c32478.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/Pacifico-Regular.c0c32478.woff
--------------------------------------------------------------------------------
/dist/apple-icon-114x114.12757dc0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/apple-icon-114x114.12757dc0.png
--------------------------------------------------------------------------------
/dist/apple-icon-120x120.c7598235.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/apple-icon-120x120.c7598235.png
--------------------------------------------------------------------------------
/dist/apple-icon-144x144.9c1d6372.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/apple-icon-144x144.9c1d6372.png
--------------------------------------------------------------------------------
/dist/apple-icon-152x152.c259a454.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/apple-icon-152x152.c259a454.png
--------------------------------------------------------------------------------
/dist/apple-icon-180x180.ce6023f9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/apple-icon-180x180.ce6023f9.png
--------------------------------------------------------------------------------
/public/images/icons/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/icon-128x128.png
--------------------------------------------------------------------------------
/public/images/icons/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/icon-144x144.png
--------------------------------------------------------------------------------
/public/images/icons/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/icon-152x152.png
--------------------------------------------------------------------------------
/public/images/icons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/icon-192x192.png
--------------------------------------------------------------------------------
/public/images/icons/icon-384x384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/icon-384x384.png
--------------------------------------------------------------------------------
/public/images/icons/icon-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/icon-512x512.png
--------------------------------------------------------------------------------
/dist/android-icon-192x192.cf567ee1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/android-icon-192x192.cf567ee1.png
--------------------------------------------------------------------------------
/public/images/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/images/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/images/icons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/favicon-96x96.png
--------------------------------------------------------------------------------
/public/images/icons/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/ms-icon-144x144.png
--------------------------------------------------------------------------------
/public/images/icons/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/ms-icon-150x150.png
--------------------------------------------------------------------------------
/public/images/icons/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/ms-icon-310x310.png
--------------------------------------------------------------------------------
/public/images/icons/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/ms-icon-70x70.png
--------------------------------------------------------------------------------
/dist/ClearSans-Bold-webfont.6a6f5f3f.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/ClearSans-Bold-webfont.6a6f5f3f.eot
--------------------------------------------------------------------------------
/dist/ClearSans-Bold-webfont.ae49b717.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/ClearSans-Bold-webfont.ae49b717.woff
--------------------------------------------------------------------------------
/dist/ClearSans-Light-webfont.fe3992bc.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/ClearSans-Light-webfont.fe3992bc.eot
--------------------------------------------------------------------------------
/public/images/icons/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon-57x57.png
--------------------------------------------------------------------------------
/public/images/icons/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon-60x60.png
--------------------------------------------------------------------------------
/public/images/icons/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon-72x72.png
--------------------------------------------------------------------------------
/public/images/icons/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon-76x76.png
--------------------------------------------------------------------------------
/dist/ClearSans-Light-webfont.fb98e0ac.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/ClearSans-Light-webfont.fb98e0ac.woff
--------------------------------------------------------------------------------
/dist/ClearSans-Regular-webfont.662fe67c.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/ClearSans-Regular-webfont.662fe67c.eot
--------------------------------------------------------------------------------
/dist/ClearSans-Regular-webfont.7edfc781.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/dist/ClearSans-Regular-webfont.7edfc781.woff
--------------------------------------------------------------------------------
/public/images/icons/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/android-icon-144x144.png
--------------------------------------------------------------------------------
/public/images/icons/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/android-icon-192x192.png
--------------------------------------------------------------------------------
/public/images/icons/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/android-icon-36x36.png
--------------------------------------------------------------------------------
/public/images/icons/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/android-icon-48x48.png
--------------------------------------------------------------------------------
/public/images/icons/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/android-icon-72x72.png
--------------------------------------------------------------------------------
/public/images/icons/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/android-icon-96x96.png
--------------------------------------------------------------------------------
/public/images/icons/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon-114x114.png
--------------------------------------------------------------------------------
/public/images/icons/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon-120x120.png
--------------------------------------------------------------------------------
/public/images/icons/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon-144x144.png
--------------------------------------------------------------------------------
/public/images/icons/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon-152x152.png
--------------------------------------------------------------------------------
/public/images/icons/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon-180x180.png
--------------------------------------------------------------------------------
/public/images/icons/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/public/images/icons/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/src/assets/styles/fonts/Pacifico-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/src/assets/styles/fonts/Pacifico-Regular.woff
--------------------------------------------------------------------------------
/src/assets/styles/fonts/ClearSans-Bold-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/src/assets/styles/fonts/ClearSans-Bold-webfont.eot
--------------------------------------------------------------------------------
/src/assets/styles/fonts/ClearSans-Bold-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/src/assets/styles/fonts/ClearSans-Bold-webfont.woff
--------------------------------------------------------------------------------
/src/assets/styles/fonts/ClearSans-Light-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/src/assets/styles/fonts/ClearSans-Light-webfont.eot
--------------------------------------------------------------------------------
/src/utils/transition.js:
--------------------------------------------------------------------------------
1 | export default ({ property = 'all', length = '0.3s', ease = 'ease' }) => `
2 | transition: ${property} ${length} ${ease};
3 | `;
4 |
--------------------------------------------------------------------------------
/src/assets/styles/fonts/ClearSans-Light-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/src/assets/styles/fonts/ClearSans-Light-webfont.woff
--------------------------------------------------------------------------------
/src/assets/styles/fonts/ClearSans-Regular-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/src/assets/styles/fonts/ClearSans-Regular-webfont.eot
--------------------------------------------------------------------------------
/src/assets/styles/fonts/ClearSans-Regular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imshubhamsingh/15-puzzle/HEAD/src/assets/styles/fonts/ClearSans-Regular-webfont.woff
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import Game from './Game';
2 | import Instruction from './Instructions';
3 | import Header from './Header';
4 | import Details from './Details';
5 |
6 | export { Game, Instruction, Header, Details };
7 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 |
4 | import App from '@Src';
5 |
6 | const rootEl = document.getElementById('root');
7 |
8 | const renderComponent = Component => {
9 | render( , rootEl);
10 | };
11 |
12 | renderComponent(App);
13 |
--------------------------------------------------------------------------------
/src/elements/index.js:
--------------------------------------------------------------------------------
1 | import GameFactory from './GameFactory';
2 | import Modal from './Modal';
3 |
4 | export * from './Button';
5 | export * from './Container';
6 | export * from './Text';
7 | export * from './Icon';
8 | export * from './GameFactory';
9 |
10 | export { GameFactory, Modal };
11 |
--------------------------------------------------------------------------------
/src/components/Header/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { HeaderText } from '@Elements';
3 |
4 | export default class Header extends Component {
5 | render() {
6 | return (
7 |
8 | 15 Puzzle
9 |
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/utils/index.js:
--------------------------------------------------------------------------------
1 | import color from './color';
2 | import transition from './transition';
3 | import Portal from './portal';
4 | import elevation from './elevation';
5 |
6 | export * from './color';
7 | export * from './game';
8 | export * from './keyframes';
9 |
10 | export { color, transition, Portal, elevation };
11 |
--------------------------------------------------------------------------------
/src/utils/elevation.js:
--------------------------------------------------------------------------------
1 | export default [
2 | 'box-shadow: inset 0 7px 9px -7px rgba(0,0,0.7);',
3 | 'box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);',
4 | 'box-shadow: 0 3px 6px rgba(0,0,0,0.10), 0 6px 6px rgba(0,0,0,0.10);',
5 | 'box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);',
6 | 'box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22);'
7 | ];
8 |
--------------------------------------------------------------------------------
/src/utils/portal.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { createPortal } from 'react-dom';
3 |
4 | const portalRoot = document.getElementById('portal');
5 |
6 | export default class Portal extends Component {
7 | constructor() {
8 | super();
9 | this.el = document.createElement('div');
10 | }
11 |
12 | componentDidMount() {
13 | portalRoot.appendChild(this.el);
14 | }
15 |
16 | componentWillUnmount() {
17 | portalRoot.removeChild(this.el);
18 | }
19 |
20 | render() {
21 | const { children } = this.props;
22 | return createPortal(children, this.el);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/assets/img/linkedin.svg:
--------------------------------------------------------------------------------
1 | LinkedIn icon
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import { BrowserRouter, Route, Redirect } from 'react-router-dom';
3 |
4 | import '@Styles/App.scss';
5 |
6 | import { Home } from '@Pages';
7 | import { GameFactory } from '@Elements';
8 |
9 | export default class App extends PureComponent {
10 | render() {
11 | return (
12 |
13 |
14 |
15 |
16 | } />
17 |
18 |
19 |
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "babel-plugin-styled-components",
4 | "@babel/plugin-proposal-class-properties",
5 | "@babel/plugin-transform-runtime",
6 | [
7 | "module-resolver",
8 | {
9 | "root": "./src",
10 | "alias": {
11 | "@Src": "./src/App.jsx",
12 | "@Components": "./src/components",
13 | "@Pages": "./src/pages",
14 | "@Elements": "./src/elements",
15 | "@Styles": "./src/assets/styles",
16 | "@Utils": "./src/utils",
17 | "@HOC": "./src/hoc",
18 | "@Image": "./src/assets/img"
19 | }
20 | }
21 | ]
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/src/utils/color.js:
--------------------------------------------------------------------------------
1 | export const gridTileColor = '#3d2963';
2 | export const backgroundColor = '#57407c';
3 | export const primaryFontColor = (opacity = 1) =>
4 | `rgba(255, 255, 255, ${opacity})`;
5 | export const buttonHoverColor = '#d3386a';
6 | export const modalTextColor = '#534648';
7 | export const modalBackgroundColor = '#FFFFFF';
8 | export const overlayBackgroundColor = '#000000';
9 | export const gridOverlayBackground = '#412667b5';
10 |
11 | export default {
12 | backgroundColor,
13 | gridTileColor,
14 | primaryFontColor,
15 | buttonHoverColor,
16 | modalTextColor,
17 | modalBackgroundColor,
18 | overlayBackgroundColor,
19 | gridOverlayBackground
20 | };
21 |
--------------------------------------------------------------------------------
/dist/manifest.1a627359.webmanifest:
--------------------------------------------------------------------------------
1 | {"theme_color":"#57407c","background_color":"#57407c","display":"standalone","orientation":"portrait","Scope":"/","start_url":"/","icons":[{"src":"icon-72x72.64199dc3.png","sizes":"72x72","type":"image/png"},{"src":"icon-96x96.f16e8aa9.png","sizes":"96x96","type":"image/png"},{"src":"icon-128x128.bdc5b571.png","sizes":"128x128","type":"image/png"},{"src":"icon-144x144.357081de.png","sizes":"144x144","type":"image/png"},{"src":"icon-152x152.bc4c1001.png","sizes":"152x152","type":"image/png"},{"src":"icon-192x192.52b953b7.png","sizes":"192x192","type":"image/png"},{"src":"icon-384x384.b9e62e98.png","sizes":"384x384","type":"image/png"},{"src":"icon-512x512.e3a8497e.png","sizes":"512x512","type":"image/png"}],"splash_pages":null}
--------------------------------------------------------------------------------
/src/assets/img/twitter.svg:
--------------------------------------------------------------------------------
1 | Twitter icon
--------------------------------------------------------------------------------
/src/components/Score/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ScoreContainer } from '@Elements';
3 |
4 | const Score = ({ moves, seconds }) => {
5 | return (
6 |
7 |
8 |
Time
9 |
{seconds}s
10 |
11 |
12 |
Moves
13 |
{moves}
14 |
15 | {/*
16 |
best
17 |
123s 10Moves
18 |
*/}
19 |
20 | );
21 | };
22 |
23 | export default Score;
24 |
--------------------------------------------------------------------------------
/src/assets/styles/app.scss:
--------------------------------------------------------------------------------
1 | @import url(./fonts/font.scss);
2 |
3 | $break-small: 520px;
4 |
5 | * {
6 | box-sizing: border-box;
7 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
8 | -webkit-touch-callout: none;
9 | -webkit-text-size-adjust: none;
10 | }
11 |
12 | *:focus,
13 | textarea:focus,
14 | input:focus,
15 | button:focus {
16 | outline: none;
17 | }
18 |
19 | body {
20 | padding: 0;
21 | margin: 0;
22 | font-family: 'Clear Sans', Arial, sans-serif;
23 | background: #57407c;
24 | color: white;
25 | @media screen and (max-width: $break-small) {
26 | margin: 20px 0;
27 | padding: 0 20px;
28 | font-size: 12px;
29 | }
30 | }
31 | .app {
32 | width: 100%;
33 | margin: 0;
34 | padding: 0;
35 | top: 0;
36 | left: 0;
37 | & #home {
38 | padding: 15px;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/assets/img/github.svg:
--------------------------------------------------------------------------------
1 | GitHub icon
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "15puzzle",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "parcel index.html",
8 | "build": "parcel build index.html --public-url ./"
9 | },
10 | "author": "Shubham",
11 | "license": "ISC",
12 | "dependencies": {
13 | "parcel-bundler": "^1.10.3",
14 | "react": "^16.7.0-alpha.2",
15 | "react-dom": "^16.7.0-alpha.2",
16 | "react-router-dom": "^4.4.0-beta.6",
17 | "styled-components": "^4.1.1"
18 | },
19 | "devDependencies": {
20 | "@babel/core": "^7.1.6",
21 | "@babel/plugin-proposal-class-properties": "^7.1.0",
22 | "@babel/plugin-transform-runtime": "^7.1.0",
23 | "babel-plugin-module-resolver": "^3.1.1",
24 | "babel-plugin-styled-components": "^1.8.0",
25 | "react-hot-loader": "^4.3.12",
26 | "sass": "^1.15.0"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/Details/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | import { Footer, Profile, Icon } from '@Elements';
4 |
5 | const Details = ({ name, githubURL, linkedinURL, twitterURL, projectURL }) => (
6 |
27 | );
28 |
29 | export default Details;
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Shubham Singh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/src/components/Cell/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component, useState, useEffect } from 'react';
2 |
3 | import { CellContainer, NumberCellContainer } from '@Elements';
4 | const moveKey = ({ x, y }) => {
5 | const [moveX, handleX] = useState(0);
6 | const [moveY, handleY] = useState(0);
7 |
8 | useEffect(
9 | () => {
10 | handleX(currentX => currentX + x);
11 | handleY(currentY => currentY + y);
12 | },
13 | [moveX, moveY]
14 | );
15 |
16 | return { x, y };
17 | };
18 |
19 | export default class Cell extends Component {
20 | render() {
21 | //const { x, y } = moveKey(this.props.x, this.props.y);
22 | const { number, index } = this.props;
23 | return (
24 |
25 | {
29 | this.props.clickMove(index);
30 | }}
31 | >
32 |
33 |
34 | {number}
35 | {number}
36 |
37 |
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/elements/Text.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { color } from '@Utils';
3 |
4 | import Waves from '@Image/waves.gif';
5 |
6 | export const GameInstruction = styled.span`
7 | display: block;
8 | float: right;
9 | margin-top: 18px;
10 | font-size: 22px;
11 | line-height: 30px;
12 | color: ${color.primaryFontColor(0.5)};
13 | & strong {
14 | color: ${color.primaryFontColor()};
15 | font-size: inherit;
16 | }
17 | @media screen and (max-width: 520px) {
18 | margin-top: 10px;
19 | font-size: 18px;
20 | text-align: center;
21 | float: none;
22 | line-height: 24px;
23 | }
24 | `;
25 |
26 | export const HeaderText = styled.div`
27 | font-family: 'Pacifico', cursive;
28 | font-size: 60px;
29 | padding-left: 7px;
30 | margin-left: 2px;
31 | text-align: center;
32 | span {
33 | font-size: 85px;
34 | }
35 |
36 | background: url(${Waves}) repeat 0 0;
37 | width: 100%;
38 | text-align: center;
39 | color: ${color.primaryFontColor()};
40 | margin-top: 27px;
41 | @media screen and (max-width: 520px) {
42 | font-size: 44px;
43 | margin-left: -3px;
44 | margin-top: 5px;
45 | span {
46 | font-size: 58px;
47 | }
48 | }
49 | `;
50 |
--------------------------------------------------------------------------------
/src/components/Grid/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | GridContainer,
4 | GameFactoryConsumer,
5 | GridOverlay,
6 | Icon
7 | } from '@Elements';
8 | import { color, gameState } from '@Utils';
9 |
10 | import Cell from '../Cell';
11 |
12 | export default class Grid extends Component {
13 | cellRender(number = [], clickMove) {
14 | return number.map((i, _) => (
15 | |
16 | ));
17 | }
18 | render() {
19 | return (
20 |
21 | {({ values, methods }) => (
22 |
23 | {this.cellRender(values.numbers, methods.clickMove)}
24 | {values.gameState === gameState.GAME_PAUSED && (
25 |
26 |
27 |
35 |
36 |
37 | )}
38 |
39 | )}
40 |
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/manifest.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "theme_color": "#57407c",
3 | "background_color": "#57407c",
4 | "display": "standalone",
5 | "orientation": "portrait",
6 | "Scope": "/",
7 | "start_url": "/",
8 | "icons": [
9 | {
10 | "src": "public/images/icons/icon-72x72.png",
11 | "sizes": "72x72",
12 | "type": "image/png"
13 | },
14 | {
15 | "src": "public/images/icons/icon-96x96.png",
16 | "sizes": "96x96",
17 | "type": "image/png"
18 | },
19 | {
20 | "src": "public/images/icons/icon-128x128.png",
21 | "sizes": "128x128",
22 | "type": "image/png"
23 | },
24 | {
25 | "src": "public/images/icons/icon-144x144.png",
26 | "sizes": "144x144",
27 | "type": "image/png"
28 | },
29 | {
30 | "src": "public/images/icons/icon-152x152.png",
31 | "sizes": "152x152",
32 | "type": "image/png"
33 | },
34 | {
35 | "src": "public/images/icons/icon-192x192.png",
36 | "sizes": "192x192",
37 | "type": "image/png"
38 | },
39 | {
40 | "src": "public/images/icons/icon-384x384.png",
41 | "sizes": "384x384",
42 | "type": "image/png"
43 | },
44 | {
45 | "src": "public/images/icons/icon-512x512.png",
46 | "sizes": "512x512",
47 | "type": "image/png"
48 | }
49 | ],
50 | "splash_pages": null
51 | }
52 |
--------------------------------------------------------------------------------
/src/pages/Home.jsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { KeyBoardManagar } from '@HOC';
3 |
4 | import { Instruction, Header, Game, Details } from '@Components';
5 | import { Container, Wave, GameFactoryConsumer } from '@Elements';
6 |
7 | import Waves from '@Image/waves.gif';
8 |
9 | const Home = ({ eventType }) => {
10 | return (
11 |
12 |
13 | {({ values, methods }) => {
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
32 |
33 | );
34 | }}
35 |
36 |
37 | );
38 | };
39 |
40 | export default KeyBoardManagar(Home);
41 |
--------------------------------------------------------------------------------
/src/utils/keyframes.js:
--------------------------------------------------------------------------------
1 | import { keyframes } from 'styled-components';
2 |
3 | export const bounceIn = keyframes`
4 | from,
5 | 20%,
6 | 40%,
7 | 60%,
8 | 80%,
9 | to {
10 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
11 | }
12 |
13 | 0% {
14 | opacity: 0;
15 | transform: scale3d(0, 0, 0);
16 | }
17 |
18 | 20% {
19 | transform: scale3d(1.1, 1.1, 1.1);
20 | }
21 |
22 | 40% {
23 | transform: scale3d(0.9, 0.9, 0.9);
24 | }
25 |
26 | 60% {
27 | opacity: 1;
28 | transform: scale3d(1.03, 1.03, 1.03);
29 | }
30 |
31 | 80% {
32 | transform: scale3d(0.97, 0.97, 0.97);
33 | }
34 |
35 | to {
36 | opacity: 1;
37 | transform: scale3d(1, 1, 1);
38 | }
39 | `;
40 |
41 | export const bounceInUp = keyframes`
42 | from,
43 | 60%,
44 | 75%,
45 | 90%,
46 | to {
47 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
48 | }
49 |
50 | from {
51 | opacity: 0;
52 | transform: translate3d(0, 3000px, 0);
53 | }
54 |
55 | 60% {
56 | opacity: 1;
57 | transform: translate3d(0, -20px, 0);
58 | }
59 |
60 | 75% {
61 | transform: translate3d(0, 10px, 0);
62 | }
63 |
64 | 90% {
65 | transform: translate3d(0, -5px, 0);
66 | }
67 |
68 | to {
69 | transform: translate3d(0, 0, 0);
70 | }
71 | `;
72 |
73 | export const fadeIn = keyframes`
74 | from{
75 | opacity: 0;
76 | }
77 | tp{
78 | opacity:1;
79 | }
80 | `;
81 |
--------------------------------------------------------------------------------
/src/elements/Modal.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import styled from 'styled-components';
3 |
4 | import { Portal, elevation, bounceInUp, fadeIn, color } from '@Utils';
5 |
6 | export default class Modal extends Component {
7 | render() {
8 | const { children, on } = this.props;
9 | return (
10 |
11 | {on && (
12 |
13 | {children}
14 |
15 |
16 | )}
17 |
18 | );
19 | }
20 | }
21 |
22 | const ModalWrapper = styled.div`
23 | position: absolute;
24 | top: 0;
25 | left: 0;
26 | width: 100%;
27 | height: 100%;
28 | display: flex;
29 | justify-content: center;
30 | align-items: center;
31 | `;
32 |
33 | const ModalCard = styled.div`
34 | color: ${color.modalTextColor};
35 | position: relative;
36 | z-index: 10000;
37 | animation-duration: 0.75s;
38 | animation-name: ${bounceInUp};
39 |
40 | border-radius: 10px;
41 | padding: 15px;
42 | min-width: 320px;
43 | background-color: ${color.modalBackgroundColor};
44 | height: 200px;
45 | ${elevation}
46 | @media screen and (max-width: 520px) {
47 | min-width: 284px;
48 | }
49 | `;
50 |
51 | const Background = styled.div`
52 | position: absolute;
53 | top: 0;
54 | left: 0;
55 | width: 100%;
56 | z-index: 1000;
57 | animation-duration: 0.75s;
58 | animation-name: ${fadeIn};
59 | height: 100%;
60 | opacity: 0.3;
61 | background: ${color.overlayBackgroundColor};
62 | `;
63 |
--------------------------------------------------------------------------------
/src/elements/Button.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { color, transition } from '@Utils';
3 |
4 | export const Button = styled.button`
5 | font-size: 22px;
6 | width: ${props => (props.type === 'big' ? '100%' : '150px')};
7 | display: block;
8 | border-radius: 8px;
9 | border: none;
10 | cursor: pointer;
11 | font-weight: bold;
12 | outline: none;
13 | text-decoration: none;
14 | line-height: 60px;
15 | text-align: center;
16 | background-color: ${color.gridTileColor};
17 | color: ${props =>
18 | props.textColor ? props.textColor : color.primaryFontColor(0.5)};
19 | ${transition({ property: 'color' })};
20 | ${transition({ property: 'background-color' })};
21 | ${transition({ property: 'opacity' })};
22 | &:active {
23 | transform: scale(0.99);
24 | }
25 | &:hover {
26 | background-color: ${color.buttonHoverColor};
27 | color: ${color.primaryFontColor()};
28 | }
29 |
30 | &:disabled {
31 | opacity: 0.5;
32 | cursor: not-allowed;
33 | &:hover {
34 | background-color: ${color.gridTileColor};
35 | color: ${color.primaryFontColor(0.5)};
36 | }
37 | }
38 |
39 | @media (hover: none), (hover: on-demand) {
40 | &:hover {
41 | background-color: ${color.gridTileColor};
42 | color: ${color.primaryFontColor(0.5)};
43 | }
44 | }
45 | @media only screen and (max-width: 520px) {
46 | font-size: 16px;
47 | width: ${props => (props.type === 'big' ? '100%' : '112px')};
48 | height: 100%;
49 | border-radius: 5px;
50 | padding: 0 5px;
51 | line-height: 42px;
52 | }
53 | `;
54 |
--------------------------------------------------------------------------------
/dist/15Puzzle.b3ebf31c.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:Clear Sans;src:url(ClearSans-Light-webfont.fe3992bc.eot);src:url(ClearSans-Light-webfont.fe3992bc.eot?#iefix) format("embedded-opentype"),url(ClearSans-Light-webfont.95af1afc.svg#clear_sans_lightregular) format("svg"),url(ClearSans-Light-webfont.fb98e0ac.woff) format("woff");font-weight:200;font-style:normal}@font-face{font-family:Clear Sans;src:url(ClearSans-Regular-webfont.662fe67c.eot);src:url(ClearSans-Regular-webfont.662fe67c.eot?#iefix) format("embedded-opentype"),url(ClearSans-Regular-webfont.3abd45a8.svg#clear_sansregular) format("svg"),url(ClearSans-Regular-webfont.7edfc781.woff) format("woff");font-weight:400;font-style:normal}@font-face{font-family:Clear Sans;src:url(ClearSans-Bold-webfont.6a6f5f3f.eot);src:url(ClearSans-Bold-webfont.6a6f5f3f.eot?#iefix) format("embedded-opentype"),url(ClearSans-Bold-webfont.be59597a.svg#clear_sansbold) format("svg"),url(ClearSans-Bold-webfont.ae49b717.woff) format("woff");font-weight:700;font-style:normal}@font-face{font-family:Pacifico;font-style:normal;font-weight:400;src:url(Pacifico-Regular.c0c32478.woff) format("woff2");unicode-range:U+00??,U+0131,U+0152-0153,U+02bb-02bc,U+02c6,U+02da,U+02dc,U+2000-206f,U+2074,U+20ac,U+2122,U+2191,U+2193,U+2212,U+2215,U+feff,U+fffd}*{box-sizing:border-box;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-touch-callout:none;-webkit-text-size-adjust:none}:focus,button:focus,input:focus,textarea:focus{outline:none}body{padding:0;margin:0;font-family:Clear Sans,Arial,sans-serif;background:#57407c;color:#fff}@media screen and (max-width:520px){body{margin:20px 0;padding:0 20px;font-size:12px}}.app{width:100%;margin:0;padding:0;top:0;left:0}.app #home{padding:15px}
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 15 Puzzle
6 |
7 |
8 | My first Game using React.js
9 |
10 |
11 |
12 | > This is a classic _15_-_puzzle_. To play you first scramble the tiles and then try to put them back in order. To move a tile you simply click on it
13 |
14 |
15 |
16 |
17 |
18 |
19 | ## Gameplay
20 |
21 |
22 |
23 |
24 |
25 | >The app uses React.js alpha API likes hooks etc..
26 | ## Development
27 |
28 | ### Run app
29 |
30 | 1. Clone repo ```git@github.com:imshubhamsingh/15-puzzle.git```
31 | 2. ```cd 15-puzzle```
32 | 3. ```npm install && npm start ```
33 |
34 |
35 | or
36 |
37 | View a live demo of this project on [netlify](https://15puzzle.netlify.com)
38 |
39 |
40 |
41 | ## License [](https://github.com/imshubhamsingh/15-puzzle/blob/master/LICENSE)
42 |
43 | Copyright (c) 2018 Shubham Singh, This software is licensed under the [MIT License](https://github.com/imshubhamsingh/15-puzzle/blob/master/LICENSE).
44 |
--------------------------------------------------------------------------------
/src/components/Instructions/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import {
3 | GameInstruction,
4 | Icon,
5 | Keys,
6 | GameInstructionContainer
7 | } from '@Elements';
8 | import { color } from '@Utils';
9 |
10 | const KeyButton = ({ currentKey, index }) => {
11 | return (
12 |
28 | );
29 | };
30 | const Instructions = () => {
31 | const [key, moveKey] = useState(null);
32 |
33 | useEffect(() => {
34 | let timer1 = index => setTimeout(() => moveKey(index), index * 350);
35 | for (let i = 1; i <= 5; i++) {
36 | timer1(i);
37 | }
38 | return () => {
39 | clearTimeout(timer1);
40 | };
41 | }, []);
42 |
43 | return (
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | Move tiles in grid to order them from 1 to 15.
56 |
57 |
58 | );
59 | };
60 |
61 | export default Instructions;
62 |
--------------------------------------------------------------------------------
/src/assets/styles/fonts/font.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Clear Sans Webfont
3 | //
4 | // Webfont conversion of the Clear Sans typeface, designed by the
5 | // Intel Open Source Technology Center
6 | //
7 | // Original font file released under the Apache 2.0 License
8 | //
9 | //
10 | // Webfont version by Resi Respati
11 | // Released under the MIT License.
12 | //
13 |
14 | @font-face {
15 | font-family: 'Clear Sans';
16 | src: url('ClearSans-Light-webfont.eot');
17 | src: url('ClearSans-Light-webfont.eot?#iefix') format('embedded-opentype'),
18 | url('ClearSans-Light-webfont.svg#clear_sans_lightregular') format('svg'),
19 | url('ClearSans-Light-webfont.woff') format('woff');
20 | font-weight: 200;
21 | font-style: normal;
22 | }
23 |
24 | @font-face {
25 | font-family: 'Clear Sans';
26 | src: url('ClearSans-Regular-webfont.eot');
27 | src: url('ClearSans-Regular-webfont.eot?#iefix') format('embedded-opentype'),
28 | url('ClearSans-Regular-webfont.svg#clear_sansregular') format('svg'),
29 | url('ClearSans-Regular-webfont.woff') format('woff');
30 | font-weight: normal;
31 | font-style: normal;
32 | }
33 |
34 | @font-face {
35 | font-family: 'Clear Sans';
36 | src: url('ClearSans-Bold-webfont.eot');
37 | src: url('ClearSans-Bold-webfont.eot?#iefix') format('embedded-opentype'),
38 | url('ClearSans-Bold-webfont.svg#clear_sansbold') format('svg'),
39 | url('ClearSans-Bold-webfont.woff') format('woff');
40 | font-weight: 700;
41 | font-style: normal;
42 | }
43 |
44 | @font-face {
45 | font-family: 'Pacifico';
46 | font-style: normal;
47 | font-weight: 400;
48 | src: url('Pacifico-Regular.woff') format('woff2');
49 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
50 | U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
51 | U+FEFF, U+FFFD;
52 | }
53 |
--------------------------------------------------------------------------------
/src/components/Game/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | GameScore,
4 | Button,
5 | PlayPauseContainer,
6 | Modal,
7 | ModalContainer
8 | } from '@Elements';
9 | import Score from '../Score';
10 | import Grid from '../Grid';
11 |
12 | import { gameState } from '@Utils';
13 | export default class Game extends Component {
14 | componentDidUpdate(prevProps, prevState) {
15 | if (prevProps.eventType !== this.props.eventType) {
16 | const [_, move] = this.props.eventType || [null, null];
17 | const [row, col, location] = this.props.gettingEmptyBoxLocation();
18 | if (
19 | this.props.gameState === gameState.GAME_IDLE ||
20 | this.props.gameState === gameState.GAME_STARTED
21 | ) {
22 | this.props.moveCell(location, row, col, move);
23 | }
24 | }
25 | }
26 |
27 | render() {
28 | return (
29 |
30 |
31 | new game
32 |
33 |
34 |
35 |
36 |
37 |
38 |
43 | {this.props.gameState === gameState.GAME_PAUSED ? 'Play' : 'Pause'}
44 |
45 |
46 |
47 |
48 | Excellent!
49 |
50 | It took you {this.props.moves} moves
51 |
52 |
53 |
58 | Play Again
59 |
60 |
61 |
62 |
63 |
64 | );
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/utils/game.js:
--------------------------------------------------------------------------------
1 | export const gameState = {
2 | GAME_IDLE: '__game_idle__',
3 | GAME_STARTED: '__game_started__',
4 | GAME_OVER: '__game_over__',
5 | GAME_PAUSED: '__game_paused__'
6 | };
7 |
8 | export const swap = (arr, from, to) => {
9 | arr.splice(from, 1, arr.splice(to, 1, arr[from])[0]);
10 | return arr;
11 | };
12 |
13 | export const isNeighbour = (to, from) => {
14 | let emptyColumn = Math.floor(to % 4);
15 | let emptyRow = Math.floor(to / 4);
16 | let clickedColumn = Math.floor(from % 4);
17 | let clickedRow = Math.floor(from / 4);
18 |
19 | const sameRow = emptyRow === clickedRow;
20 | const sameColumn = emptyColumn === clickedColumn;
21 | const columnDiff = emptyColumn - clickedColumn;
22 | const rowDiff = emptyRow - clickedRow;
23 | const diffColumn = Math.abs(columnDiff) === 1;
24 | const diffRow = Math.abs(rowDiff) === 1;
25 | const sameRowDiffColumn = sameRow && diffColumn;
26 | const sameColumnDiffRow = sameColumn && diffRow;
27 | if (sameRowDiffColumn || sameColumnDiffRow) {
28 | return true;
29 | } else {
30 | return false;
31 | }
32 | };
33 |
34 | export const swapSpace = (arr, from, row, col, move) => {
35 | let yMove = move === 0 ? 1 : move === 2 ? -1 : 0;
36 | let xMove = move === 3 ? 1 : move === 1 ? -1 : 0;
37 | let newRow = row + yMove;
38 | let newCol = col + xMove;
39 | if (newRow <= -1 || newCol <= -1 || newRow >= 4 || newCol >= 4) {
40 | return [false, arr];
41 | }
42 | let to = newRow * 4 + newCol;
43 | return [true, swap(arr, from, to)];
44 | };
45 |
46 | export const shuffle = array_elements => {
47 | let i = array_elements.length,
48 | randomNumIndex,
49 | randomNum;
50 | while (--i > 0) {
51 | randomNumIndex = Math.floor(Math.random() * (i + 1));
52 | randomNum = array_elements[randomNumIndex];
53 | array_elements[randomNumIndex] = array_elements[i];
54 | array_elements[i] = randomNum;
55 | }
56 | return array_elements;
57 | };
58 |
59 | export const checkArray = arr => {
60 | let decision = true;
61 | arr.forEach((i, index) => {
62 | if (i !== index + 1 && i != 0) {
63 | decision = false;
64 | }
65 | });
66 | return decision;
67 | };
68 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 | 15 Puzzle You need to enable JavaScript to run this app.
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 15 Puzzle
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | You need to enable JavaScript to run this app.
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/elements/Icon.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | export const Icon = props => {
4 | const { size, color } = props;
5 | switch (props.name) {
6 | case 'key': {
7 | const { rotate, fillColor, move } = props;
8 | return (
9 |
15 |
24 |
29 |
37 |
38 | );
39 | }
40 | case 'play': {
41 | return (
42 |
48 |
52 |
53 | );
54 | }
55 | case 'github': {
56 | return (
57 |
58 |
59 |
60 | );
61 | }
62 | case 'twitter': {
63 | return (
64 |
65 |
66 |
67 | );
68 | }
69 | case 'linkedin': {
70 | return (
71 |
72 |
73 |
74 | );
75 | }
76 | }
77 | };
78 |
--------------------------------------------------------------------------------
/src/hoc/keyboardManager/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 |
3 | const useMovement = () => {
4 | const [event, handleEvent] = useState(null);
5 |
6 | const emit = (event, data) => {
7 | handleEvent([event, data]);
8 | };
9 |
10 | const map = {
11 | 38: 0, // Up
12 | 39: 1, // Right
13 | 40: 2, // Down
14 | 37: 3, // Left
15 | 75: 0, // Vim up
16 | 76: 1, // Vim right
17 | 74: 2, // Vim down
18 | 72: 3, // Vim left
19 | 87: 0, // W
20 | 68: 1, // D
21 | 83: 2, // S
22 | 65: 3 // A
23 | };
24 |
25 | // Respond to direction keys
26 | const handleKey = event => {
27 | const modifiers =
28 | event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
29 | const mapped = map[event.which];
30 | if (!modifiers) {
31 | if (mapped !== undefined) {
32 | event.preventDefault();
33 | emit('move', mapped);
34 | }
35 | }
36 |
37 | // R key restarts the game
38 | if (!modifiers && event.which === 82) {
39 | restart.call(self, event);
40 | }
41 | };
42 |
43 | const listenKey = () => {
44 | window.document.addEventListener('keydown', handleKey);
45 | };
46 |
47 | const restart = event => {
48 | event.preventDefault();
49 | emit('restart');
50 | };
51 |
52 | const keepPlaying = event => {
53 | event.preventDefault();
54 | emit('keepPlaying');
55 | };
56 |
57 | let eventTouchstart = null,
58 | eventTouchmove = null,
59 | eventTouchend = null,
60 | touchStartClientX = null,
61 | touchStartClientY = null;
62 |
63 | if (window.navigator.msPointerEnabled) {
64 | //Internet Explorer 10 style
65 | eventTouchstart = 'MSPointerDown';
66 | eventTouchmove = 'MSPointerMove';
67 | eventTouchend = 'MSPointerUp';
68 | } else {
69 | eventTouchstart = 'touchstart';
70 | eventTouchmove = 'touchmove';
71 | eventTouchend = 'touchend';
72 | }
73 |
74 | const eventTouchStartListner = event => {
75 | if (
76 | (!window.navigator.msPointerEnabled && event.touches.length > 1) ||
77 | event.targetTouches > 1
78 | ) {
79 | return; // Ignore if touching with more than 1 finger
80 | }
81 |
82 | if (window.navigator.msPointerEnabled) {
83 | touchStartClientX = event.pageX;
84 | touchStartClientY = event.pageY;
85 | } else {
86 | touchStartClientX = event.touches[0].clientX;
87 | touchStartClientY = event.touches[0].clientY;
88 | }
89 |
90 | //event.preventDefault();
91 | };
92 |
93 | const eventTouchmoveListner = event => {
94 | // event.preventDefault();
95 | };
96 |
97 | const eventTouchendListner = event => {
98 | if (
99 | (!window.navigator.msPointerEnabled && event.touches.length > 0) ||
100 | event.targetTouches > 0
101 | ) {
102 | return; // Ignore if still touching with one or more fingers
103 | }
104 |
105 | let touchEndClientX;
106 | let touchEndClientY;
107 |
108 | if (window.navigator.msPointerEnabled) {
109 | touchEndClientX = event.pageX;
110 | touchEndClientY = event.pageY;
111 | } else {
112 | touchEndClientX = event.changedTouches[0].clientX;
113 | touchEndClientY = event.changedTouches[0].clientY;
114 | }
115 |
116 | const dx = touchEndClientX - touchStartClientX;
117 | const absDx = Math.abs(dx);
118 |
119 | const dy = touchEndClientY - touchStartClientY;
120 | const absDy = Math.abs(dy);
121 |
122 | if (Math.max(absDx, absDy) > 10) {
123 | // (right : left) : (down : up)
124 | emit('move', absDx > absDy ? (dx > 0 ? 1 : 3) : dy > 0 ? 2 : 0);
125 | }
126 | };
127 |
128 | const listenSwipe = () => {
129 | window.document.addEventListener(eventTouchstart, eventTouchStartListner);
130 | window.document.addEventListener(eventTouchmove, eventTouchmoveListner);
131 | window.document.addEventListener(eventTouchend, eventTouchendListner);
132 | };
133 |
134 | const removeEventListeners = () => {
135 | window.document.removeEventListener('keydown', handleKey);
136 | window.document.removeEventListener(
137 | eventTouchstart,
138 | eventTouchStartListner
139 | );
140 | window.document.removeEventListener(eventTouchmove, eventTouchmoveListner);
141 | window.document.removeEventListener(eventTouchend, eventTouchendListner);
142 | };
143 |
144 | useEffect(() => {
145 | listenKey();
146 | listenSwipe();
147 | return () => removeEventListeners();
148 | });
149 |
150 | return event;
151 | };
152 |
153 | const KeyBoardManager = PassedComponent => props => {
154 | const eventType = useMovement();
155 | return ;
156 | };
157 |
158 | export default KeyBoardManager;
159 |
--------------------------------------------------------------------------------
/src/elements/GameFactory.js:
--------------------------------------------------------------------------------
1 | import React, { Component, createContext } from 'react';
2 |
3 | import {
4 | swap,
5 | isNeighbour,
6 | swapSpace,
7 | shuffle,
8 | checkArray,
9 | gameState
10 | } from '@Utils';
11 |
12 | const NEW_GAME = '__new_game__';
13 | const RESET_GAME = '__reset_game__';
14 |
15 | // [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
16 | const genrateArray = (num, add) => {
17 | let puzzle = [...Array(num)].map((_, i) => i + add);
18 | puzzle.push(0);
19 | return puzzle;
20 | };
21 |
22 | const ValuesContext = createContext({});
23 | const SetValueContext = createContext(() => {});
24 |
25 | const isSolvable = puzzle => {
26 | let parity = 0;
27 | let gridWidth = 4;
28 | let row = 0;
29 | let blankRow = 0;
30 | for (let i = 0; i < puzzle.length; i++) {
31 | if (i % gridWidth == 0) {
32 | // advance to next row
33 | row++;
34 | }
35 | if (puzzle[i] == 0) {
36 | blankRow = row;
37 | continue;
38 | }
39 | for (var j = i + 1; j < puzzle.length; j++) {
40 | if (puzzle[i] > puzzle[j] && puzzle[j] != 0) {
41 | parity++;
42 | }
43 | }
44 | }
45 |
46 | if (gridWidth % 2 == 0) {
47 | if (blankRow % 2 == 0) {
48 | return parity % 2 == 0;
49 | } else {
50 | return parity % 2 != 0;
51 | }
52 | } else {
53 | return parity % 2 == 0;
54 | }
55 | };
56 |
57 | const genratePuzzle = (arr, event) => {
58 | if (event === NEW_GAME) {
59 | if (isSolvable(arr)) {
60 | return arr;
61 | } else {
62 | return genratePuzzle(shuffle(genrateArray(15, 1)), NEW_GAME);
63 | }
64 | } else {
65 | return arr;
66 | }
67 | };
68 |
69 | class GameFactory extends Component {
70 | defaultState = (_event, num) => ({
71 | numbers:
72 | _event === NEW_GAME
73 | ? genratePuzzle(shuffle(genrateArray(15, num)), _event)
74 | : shuffle(genrateArray(15, num)),
75 | moves: 0,
76 | seconds: 0,
77 | gameState: gameState.GAME_IDLE
78 | });
79 |
80 | state = this.defaultState(NEW_GAME, 1);
81 |
82 | timerId = null;
83 |
84 | reset = () => {
85 | this.setState(this.defaultState(RESET_GAME));
86 | setTimeout(() => {
87 | this.setState(this.defaultState(NEW_GAME, 1));
88 | if (this.timerId) {
89 | clearInterval(this.timerId);
90 | }
91 | }, 100);
92 | };
93 |
94 | gettingEmptyBoxLocation = () => {
95 | let location = this.state.numbers.indexOf(0);
96 | let column = Math.floor(location % 4);
97 | let row = Math.floor(location / 4);
98 | return [row, column, location];
99 | };
100 |
101 | move = (from, row, col, moveType) => {
102 | this.setState(prevState => {
103 | let newState = null;
104 | const [updated, newNumList] = swapSpace(
105 | prevState.numbers,
106 | from,
107 | row,
108 | col,
109 | moveType
110 | );
111 | if (updated) {
112 | newState = {
113 | number: newNumList,
114 | moves: prevState.moves + 1
115 | };
116 | if (prevState.moves === 0) {
117 | this.setTimer();
118 | newState = {
119 | ...newState,
120 | gameState: gameState.GAME_STARTED
121 | };
122 | }
123 | if (checkArray(this.state.numbers)) {
124 | clearInterval(this.timerId);
125 | newState = {
126 | ...newState,
127 | gameState: gameState.GAME_OVER
128 | };
129 | }
130 | }
131 | return newState;
132 | });
133 | };
134 |
135 | addTimer = () => {
136 | this.setState(prevState => {
137 | return { seconds: prevState.seconds + 1 };
138 | });
139 | };
140 |
141 | setTimer = () => {
142 | this.timerId = setInterval(() => {
143 | this.addTimer();
144 | }, 1000);
145 | };
146 |
147 | clickMove = from => {
148 | this.setState(prevState => {
149 | let newState = null;
150 | let to = prevState.numbers.indexOf(0);
151 | if (isNeighbour(to, from)) {
152 | const newNumList = swap(prevState.numbers, to, from);
153 | newState = {
154 | number: newNumList,
155 | moves: prevState.moves + 1
156 | };
157 | if (prevState.moves === 0) {
158 | this.setTimer();
159 | newState = {
160 | ...newState,
161 | gameState: gameState.GAME_STARTED
162 | };
163 | }
164 | if (checkArray(this.state.numbers)) {
165 | clearInterval(this.timerId);
166 | newState = {
167 | ...newState,
168 | gameState: gameState.GAME_OVER
169 | };
170 | }
171 | }
172 | return newState;
173 | });
174 | };
175 |
176 | onPauseClick = () => {
177 | this.setState(prevState => {
178 | let newGameState = null;
179 |
180 | if (prevState.gameState === gameState.GAME_STARTED) {
181 | clearInterval(this.timerId);
182 | newGameState = gameState.GAME_PAUSED;
183 | } else {
184 | this.setTimer();
185 | newGameState = gameState.GAME_STARTED;
186 | }
187 |
188 | return {
189 | gameState: newGameState
190 | };
191 | });
192 | };
193 |
194 | render() {
195 | return (
196 |
197 |
207 | {this.props.children}
208 |
209 |
210 | );
211 | }
212 | }
213 |
214 | export const GameFactoryConsumer = ({ children }) => {
215 | return (
216 |
217 | {values => (
218 |
219 | {methods => children({ values, methods })}
220 |
221 | )}
222 |
223 | );
224 | };
225 |
226 | export default GameFactory;
227 |
--------------------------------------------------------------------------------
/src/elements/Container.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { color, transition, bounceIn, fadeIn } from '@Utils';
3 |
4 | export const Container = styled.div`
5 | width: 500px;
6 | margin: 0 auto;
7 | @media screen and (max-width: 520px) {
8 | width: 291px;
9 | margin: 0 auto;
10 | }
11 | `;
12 |
13 | export const GridContainer = styled.div`
14 | margin: 5px 0;
15 | grid-template-columns: auto auto auto auto;
16 | display: grid;
17 | position: relative;
18 | padding: 15px;
19 | cursor: default;
20 | touch-action: none;
21 | background: ${color.backgroundColor};
22 | border-radius: 12px;
23 | width: 500px;
24 | height: 500px;
25 | .grid-row {
26 | margin-bottom: 15px;
27 | display: flex;
28 | }
29 | @media screen and (max-width: 520px) {
30 | width: 292px;
31 | height: 292px;
32 | .grid-row {
33 | margin-bottom: 10px;
34 | }
35 | }
36 | `;
37 |
38 | export const GridOverlay = styled.div`
39 | display: flex;
40 | justify-content: center;
41 | align-items: center;
42 | position: absolute;
43 | padding: 15px;
44 | z-index: 100;
45 | background-color: ${color.gridOverlayBackground};
46 | float: left;
47 | margin-top: 3px;
48 | margin-left: 2px;
49 | border-radius: 10px;
50 | width: 499px;
51 | height: 487px;
52 | animation: ${fadeIn} 250ms;
53 | @media screen and (max-width: 520px) {
54 | width: 280px;
55 | height: 275px;
56 | margin-left: 6px;
57 | margin-top: 5px;
58 | }
59 | `;
60 |
61 | export const PlayPauseContainer = styled.div`
62 | padding: 0 15px;
63 | `;
64 |
65 | export const CellContainer = styled.div`
66 | width: 106.25px;
67 | height: 106.25px;
68 | margin-right: 15px;
69 | border-radius: 10px;
70 | background-color: ${color.gridTileColor};
71 | @media screen and (max-width: 520px) {
72 | width: 57.5px;
73 | height: 57.5px;
74 | margin-right: 10px;
75 | }
76 | &:last-child {
77 | margin-right: 0;
78 | }
79 | `;
80 |
81 | // 121px;
82 | // 67px;
83 | export const NumberCellContainer = styled.div`
84 | display: ${props =>
85 | props.number > 0 && props.number < 16 ? 'flex' : 'none'};
86 | border-radius: 10px;
87 | background: ${props =>
88 | props.index === props.number ? '#E88A45' : '#6ac6b8'};
89 | cursor: pointer;
90 | position: relative;
91 | user-select: none;
92 | justify-content: center;
93 | align-items: center;
94 | font-family: 'Pacifico', cursive;
95 | text-align: center;
96 | font-weight: bold;
97 | z-index: 10;
98 | font-size: 75px;
99 | width: 107px;
100 | ${transition({ property: 'transform' })};
101 |
102 | animation-duration: 0.75s;
103 | animation-name: ${bounceIn};
104 |
105 | height: 107px;
106 | transform: ${({ x = 0, y = 0 }) => `translate3d(${x}px, ${y}px, 0)`};
107 | .ball-1,
108 | .ball-2 {
109 | position: absolute;
110 | background-color: ${props =>
111 | props.index === props.number ? ' #CD583A' : '#499591'};
112 | opacity: 0.2;
113 | border-radius: 50%;
114 | }
115 | .ball-1 {
116 | height: 30px;
117 | width: 30px;
118 | top: 21px;
119 | left: 19px;
120 | }
121 |
122 | .ball-2 {
123 | height: 60px;
124 | width: 60px;
125 | bottom: 9px;
126 | right: 10px;
127 | }
128 | .shadow {
129 | color: ${props => (props.index === props.number ? ' #CD583A' : '#499591')};
130 | font-size: 90px;
131 | margin-left: ${props =>
132 | props.number.toString().length == 2
133 | ? props.number === 11
134 | ? -16
135 | : -6
136 | : props.number === 1
137 | ? -10
138 | : 0}px;
139 | margin-top: ${props => (props.number.toString().length == 2 ? -21 : -19)}px;
140 | }
141 | .number {
142 | color: white;
143 | z-index: 99;
144 | position: absolute;
145 | top: -22px;
146 | left: ${props => (props.number.toString().length == 2 ? 15 : 32)}px;
147 | }
148 |
149 | @media screen and (max-width: 520px) {
150 | width: 58px;
151 | height: 58px;
152 | line-height: 67.5px;
153 | font-size: 45px;
154 | padding-top: 9px;
155 | padding-left: ${props => (props.number === 1 ? 3 : 0)}px;
156 | border-radius: 5px;
157 | .ball-1 {
158 | height: 15px;
159 | width: 15px;
160 | top: 12px;
161 | left: 9px;
162 | }
163 |
164 | .ball-2 {
165 | height: 30px;
166 | width: 30px;
167 | bottom: 4px;
168 | right: 7px;
169 | }
170 | .shadow {
171 | font-size: 53px;
172 | margin-left: ${props =>
173 | props.number.toString().length == 2
174 | ? props.number === 11
175 | ? -6
176 | : -1
177 | : props.number === 1
178 | ? -7
179 | : 0}px;
180 | margin-top: ${props =>
181 | props.number.toString().length == 2 ? -20 : -19}px;
182 | }
183 | .number {
184 | top: -14px;
185 | left: ${props => (props.number.toString().length == 2 ? 7 : 16)}px;
186 | }
187 | }
188 | `;
189 |
190 | export const Keys = styled.span`
191 | width: 150px;
192 | float: left;
193 | height: 105px;
194 | display: flex;
195 | flex-direction: column;
196 | align-items: center;
197 | & span.bottom-keys {
198 | margin-top: -16px;
199 | }
200 | & rect {
201 | ${transition({ property: 'fill' })};
202 | }
203 | & path {
204 | ${transition({ property: 'transform' })};
205 | }
206 | @media screen and (max-width: 520px) {
207 | display: none;
208 | }
209 | `;
210 |
211 | export const GameScore = styled.div`
212 | padding: 0 15px;
213 | display: flex;
214 | justify-content: space-between;
215 | @media screen and (max-width: 520px) {
216 | padding: 20px 15px 0 15px;
217 | }
218 | `;
219 |
220 | export const ScoreContainer = styled.div`
221 | background: ${color.gridTileColor};
222 | display: flex;
223 | margin-left: 10px;
224 | padding-left: 15px;
225 | border-radius: 8px;
226 |
227 | .move,
228 | .best,
229 | .time {
230 | position: relative;
231 | display: inline-block;
232 | text-align: right;
233 | width: 97px;
234 | padding: 13px 20px 0 10px;
235 | float: right;
236 | }
237 | .score-title {
238 | text-transform: uppercase;
239 | font-size: 12px;
240 | line-height: 12px;
241 | color: ${color.primaryFontColor()};
242 | }
243 |
244 | .move-container,
245 | .best-container,
246 | .time-container {
247 | font-size: 21px;
248 | line-height: 25px;
249 | font-weight: bold;
250 | color: ${color.primaryFontColor()};
251 | }
252 |
253 | .best {
254 | opacity: 0.5;
255 | }
256 | @media screen and (max-width: 520px) {
257 | padding-left: 10px;
258 | border-radius: 5px;
259 |
260 | .move-container,
261 | .best-container,
262 | .time-container {
263 | font-size: 16px;
264 | line-height: 14px;
265 | font-weight: bold;
266 | }
267 |
268 | .move,
269 | .best,
270 | .time {
271 | position: relative;
272 | display: inline-block;
273 | text-align: right;
274 | padding: 8px 15px 0 10px;
275 | float: right;
276 | width: 65px;
277 | }
278 | .time {
279 | width: 80px;
280 | padding-right: 6px;
281 | }
282 | .best {
283 | display: none;
284 | }
285 | }
286 | `;
287 |
288 | export const GameInstructionContainer = styled.div`
289 | display: flex;
290 | padding: 0 17px 0 6px;
291 | justify-content: space-between;
292 | @media screen and (max-width: 520px) {
293 | display: block;
294 | }
295 | `;
296 |
297 | export const Wave = styled.img`
298 | margin-top: -30px;
299 | @media screen and (max-width: 520px) {
300 | max-width: 270px;
301 | height: auto;
302 | margin-left: 9px;
303 | }
304 | `;
305 |
306 | export const ModalContainer = styled.div`
307 | display: flex;
308 | flex-direction: column;
309 | align-content: space-around;
310 | width: 100%;
311 | height: 100%;
312 | text-align: center;
313 | justify-content: space-between;
314 | .text-1 {
315 | font-family: 'Pacifico', cursive;
316 | text-align: center;
317 | font-weight: bold;
318 | font-size: 37px;
319 | color: ${color.backgroundColor};
320 | }
321 | `;
322 |
323 | export const Footer = styled.div`
324 | width: 100%;
325 | height: 22px;
326 | background: ${color.backgroundColor};
327 | z-index: 10;
328 | display: flex;
329 | justify-content: center;
330 | flex-direction: column;
331 | margin-bottom: 9px;
332 | & .text {
333 | color: ${color.primaryFontColor()};
334 | font-family: 'Clear Sans', Arial, sans-serif;
335 | text-align: center;
336 | bottom: 0px;
337 | margin: 11px auto 0px;
338 | a {
339 | text-decoration: none;
340 | color: white;
341 | font-weight: bold;
342 | }
343 | }
344 |
345 | & .logos {
346 | display: flex;
347 | justify-content: center;
348 | align-items: center;
349 | width: 100%;
350 | margin-top: 29px;
351 | }
352 |
353 | @media (max-width: 520px) {
354 | height: 22px;
355 | margin-top: -10px;
356 | padding: 10px 4px;
357 | & .text {
358 | margin: 26px auto 0px;
359 | }
360 | & .logos {
361 | margin-top: 20px;
362 | }
363 | }
364 | `;
365 |
366 | export const Profile = styled.a`
367 | fill: ${color.gridTileColor};
368 | svg,
369 | path {
370 | ${transition({})};
371 | margin-right: 17px;
372 | height: 32px;
373 | width: 32px;
374 | }
375 | &:hover svg path,
376 | &:hover {
377 | fill: ${color.buttonHoverColor};
378 | color: ${color.buttonHoverColor};
379 | }
380 |
381 | @media (max-width: 520px) {
382 | svg,
383 | path {
384 | ${transition({})};
385 | margin-right: 7px;
386 | height: 22px;
387 | width: 22px;
388 | }
389 | }
390 | `;
391 |
--------------------------------------------------------------------------------