diff --git a/src/App.js b/src/App.js
index 6ca4350..8677d85 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,12 +1,114 @@
-import React from 'react';
+import React, { useState, useEffect } from 'react';
-import { Header } from 'components';
+import { Board, Header } from 'components';
function App() {
+ const [rows, setRows] = useState(10);
+ const [cols, setCols] = useState(10);
+ const [mines, setMines] = useState(5);
+ const [flags, setFlags] = useState(5);
+ const [mounted, setMounted] = useState(false);
+ const [dummyBoard, setDummyBoard] = useState([]);
+ const [updateDummyBoard, setUpdateDummyBoard] = useState(true);
+
+ const handleSetRows = value => {
+ // TODO can't be less than 3
+ setRows(value);
+ setUpdateDummyBoard(true);
+ };
+
+ const handleSetCols = value => {
+ // TODO can't be less than 3
+ setCols(value);
+ setUpdateDummyBoard(true);
+ };
+
+ const generateDummyBoard = () => {
+ const board = [];
+
+ for (let row = 0; row < rows; row++) {
+ board.push(
+ Array(cols)
+ .join(0)
+ .split(0)
+ );
+ }
+
+ setDummyBoard(board);
+ };
+
+ const handleSetMines = event => {
+ // TODO can't be less than 1
+ setMines(parseInt(event.target.value));
+ setFlags(parseInt(event.target.value));
+ generateDummyBoard();
+ };
+
+ useEffect(() => {
+ function bootstrap() {
+ setMounted(true);
+ generateDummyBoard();
+ }
+
+ if (!mounted) {
+ bootstrap();
+ }
+
+ if (updateDummyBoard) {
+ setUpdateDummyBoard(false);
+ generateDummyBoard();
+ }
+ });
+
+ const handleCellClick = (row, col) => {
+ const cell = document.getElementById(`cell_${row}_${col}`);
+ if (cell.classList.contains('flagged')) {
+ return;
+ }
+
+ if (!cell.classList.contains('revealed')) {
+ cell.classList.add('revealed');
+ }
+ };
+
+ const handleCellContextMenu = (event, row, col) => {
+ event.preventDefault();
+ const cell = document.getElementById(`cell_${row}_${col}`);
+ if (cell.classList.contains('revealed')) {
+ return;
+ }
+
+ if (cell.classList.contains('flagged')) {
+ cell.classList.remove('flagged');
+ } else {
+ cell.classList.add('flagged');
+ }
+ };
+
+ if (!mounted) {
+ return null;
+ }
+
return (
);
diff --git a/src/assets/images/flag.svg b/src/assets/images/flag.svg
new file mode 100644
index 0000000..955a5a0
--- /dev/null
+++ b/src/assets/images/flag.svg
@@ -0,0 +1,7 @@
+
diff --git a/src/assets/scss/_variables.scss b/src/assets/scss/_variables.scss
index 2aa1e95..7148243 100644
--- a/src/assets/scss/_variables.scss
+++ b/src/assets/scss/_variables.scss
@@ -3,3 +3,5 @@ $gray-mid: #e3e3e3;
$gray-dark: #333;
$gray: #d1d1d1;
$red: #ec433c;
+
+$cell-size: 20px;
diff --git a/src/assets/scss/styles.scss b/src/assets/scss/styles.scss
index a9d5e5e..1a0fe73 100644
--- a/src/assets/scss/styles.scss
+++ b/src/assets/scss/styles.scss
@@ -4,18 +4,19 @@
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 14px;
- background-color: $gray-light;
+
+ background-color: $gray-mid;
}
.canvas {
max-width: 1000px;
width: 100%;
min-width: 500px;
- background-color: $gray-mid;
margin: 0 auto;
border-radius: 3px;
display: flex;
justify-content: center;
+ flex-direction: column;
}
.box {
diff --git a/src/components/Board/Board.js b/src/components/Board/Board.js
index 88e9e60..4298ef8 100644
--- a/src/components/Board/Board.js
+++ b/src/components/Board/Board.js
@@ -1,8 +1,37 @@
import React from 'react';
+import PropTypes from 'prop-types';
+
import './styles.scss';
-const Board = () => {
- return Board here
;
+const Board = ({ dummyBoard, handleCellClick, handleCellContextMenu }) => {
+ return (
+
+ {dummyBoard.map((cols, rowId) => (
+
+ {cols.map((col, colId) => (
+
handleCellClick(rowId, colId)}
+ onContextMenu={event =>
+ handleCellContextMenu(event, rowId, colId)
+ }
+ key={`cell_${rowId}_${colId}`}>
+ {' '}
+
+ ))}
+
+ ))}
+
+ );
+};
+
+Board.propTypes = {
+ cols: PropTypes.number.isRequired,
+ dummyBoard: PropTypes.array.isRequired,
+ handleCellClick: PropTypes.func.isRequired,
+ rows: PropTypes.number.isRequired,
+ handleCellContextMenu: PropTypes.func.isRequired
};
export default Board;
diff --git a/src/components/Board/styles.scss b/src/components/Board/styles.scss
index 04999c1..bbda6e0 100644
--- a/src/components/Board/styles.scss
+++ b/src/components/Board/styles.scss
@@ -1 +1,27 @@
@import '../../assets/scss/variables';
+
+.board {
+ display: flex;
+ flex-direction: column;
+ &-row {
+ display: flex;
+ justify-content: center;
+
+ &-cell.flagged {
+ background-image: url(../../assets/images/flag.svg);
+ background-repeat: no-repeat;
+ background-position: center center;
+ }
+
+ &-cell.revealed {
+ margin: 1px;
+ border: 2px solid $gray-dark;
+ }
+
+ &-cell {
+ width: $cell-size;
+ height: $cell-size;
+ line-height: $cell-size;
+ }
+ }
+}
diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js
index b5f3af7..11d39e9 100644
--- a/src/components/Header/Header.js
+++ b/src/components/Header/Header.js
@@ -1,95 +1,69 @@
-import React, { useState } from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
+
import './styles.scss';
-const difficulty = {
- custom: {
- rows: 10,
- cols: 10,
- mines: 5,
- flags: 5
- },
- beginner: {
- rows: 20,
- cols: 20,
- mines: 5,
- flags: 5
- },
- intermediate: {
- rows: 50,
- cols: 50,
- mines: 15,
- flags: 15
- },
- expert: {
- rows: 100,
- cols: 100,
- mines: 50,
- flags: 50
- }
-};
-
-const Header = () => {
- const [selectedDifficulty, setSelectedDifficulty] = useState('beginner');
- const [rows, setRows] = useState(difficulty.beginner.rows);
- const [cols, setCols] = useState(difficulty.beginner.cols);
- const [mines, setMines] = useState(difficulty.beginner.mines);
- const [flags, setFlags] = useState(5);
- const [resetContent] = useState('🙂');
-
- const handleSetDifficulty = event => {
- setSelectedDifficulty(event.target.value);
- setRows(difficulty[event.target.value].rows);
- setCols(difficulty[event.target.value].cols);
- setMines(difficulty[event.target.value].mines);
- setFlags(difficulty[event.target.value].flags);
- };
-
- const handleSetMines = event => {
- setMines(parseInt(event.target.value));
- setFlags(parseInt(event.target.value));
- };
-
+const Header = ({
+ cols,
+ flags,
+ handleSetMines,
+ mines,
+ rows,
+ setCols,
+ setRows
+}) => {
return (
{flags}
-
{resetContent}
+
{
+ event.target.innerHTML = '😮';
+ console.log('onmousedown');
+ }}
+ onMouseUp={event => {
+ event.target.innerHTML = '🙂';
+ console.log('onMouseUp');
+ }}>
+ 🙂
+
000
);
};
+Header.propTypes = {
+ cols: PropTypes.number,
+ flags: PropTypes.number,
+ handleSetMines: PropTypes.func.isRequired,
+ mines: PropTypes.number,
+ rows: PropTypes.number,
+ setCols: PropTypes.func.isRequired,
+ setMines: PropTypes.func.isRequired,
+ setRows: PropTypes.func.isRequired
+};
+
export default Header;
diff --git a/src/components/Header/styles.scss b/src/components/Header/styles.scss
index 312ec79..9d645d3 100644
--- a/src/components/Header/styles.scss
+++ b/src/components/Header/styles.scss
@@ -6,6 +6,7 @@
display: flex;
justify-content: space-between;
padding: 5px;
+ margin: 0 auto;
.led-panel {
font-family: 'Space Mono', monospace;