Skip to content

Commit

Permalink
chore: migrate to vite & add eslint
Browse files Browse the repository at this point in the history
  • Loading branch information
ByteWither committed Aug 17, 2024
1 parent b0c1395 commit f750d3c
Show file tree
Hide file tree
Showing 21 changed files with 2,913 additions and 10,312 deletions.
8 changes: 8 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"printWidth": 100,
"tabWidth": 4,
"useTabs": false,
"semi": false,
"trailingComma": "all",
"htmlWhitespaceSensitivity": "ignore"
}
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Minesweeper
The Minesswipper game is developed with React & TypeScript. The project uses React Hooks and React Memo. Webpack and Component Approach were also used.

The Minesswipper game is developed with React & TypeScript
25 changes: 25 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import js from "@eslint/js"
import globals from "globals"
import reactHooks from "eslint-plugin-react-hooks"
import reactRefresh from "eslint-plugin-react-refresh"
import tseslint from "typescript-eslint"

export default tseslint.config(
{ ignores: ["dist"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
},
},
)
4 changes: 2 additions & 2 deletions src/App/index.html → index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<title>Minesweeper</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/App/index.tsx"></script>
</body>
</html>
12,927 changes: 2,738 additions & 10,189 deletions package-lock.json

Large diffs are not rendered by default.

50 changes: 21 additions & 29 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,34 @@
{
"name": "minesweeper",
"version": "1.0.0",
"description": "",
"main": "index.js",
"description": "The Minesswipper game",
"type": "module",
"scripts": {
"build": "webpack --mode production",
"watch": "webpack serve --mode development",
"test": "exit 0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Moloko20/minesweeper.git"
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/Moloko20/minesweeper/issues"
},
"homepage": "https://github.com/Moloko20/minesweeper#readme",
"devDependencies": {
"@types/lodash": "^4.14.172",
"@types/react": "^17.0.20",
"@types/react-dom": "^17.0.9",
"css-loader": "^6.2.0",
"html-webpack-plugin": "^5.3.2",
"node-sass": "^7.0.0",
"react-dom": "^17.0.2",
"sass-loader": "^12.1.0",
"style-loader": "^3.2.1",
"ts-loader": "^9.2.5",
"tsconfig-paths-webpack-plugin": "^3.5.1",
"typescript": "^4.4.2",
"webpack": "^5.52.0",
"webpack-cli": "^4.8.0",
"webpack-dev-server": "^4.1.0"
"@types/node": "^22.4.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"eslint": "^9.9.0",
"eslint-plugin-react-hooks": "^5.1.0-rc-1eaccd82-20240816",
"eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0",
"prettier": "^3.3.3",
"sass-embedded": "^1.77.8",
"typescript": "^5.5.4",
"typescript-eslint": "^8.1.0",
"vite": "^5.4.1"
},
"dependencies": {
"lodash.clonedeep": "^4.5.0",
"react": "^17.0.2"
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
}
8 changes: 0 additions & 8 deletions prettier.config.js

This file was deleted.

34 changes: 16 additions & 18 deletions src/App/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from "react"
import ReactDOM from "react-dom"
import { Board } from "Components/Board"
import { Face, FaceTypes } from "Components/Face"
import { Select } from "Components/Select"
import { Timer } from "Components/Timer"
import { StrictMode, useCallback, useRef, useState } from "react"
import { createRoot } from "react-dom/client"
import { Board } from "@/Components/Board"
import { Face, FaceTypes } from "@/Components/Face"
import { Select } from "@/Components/Select"
import { Timer } from "@/Components/Timer"
import "./index.sass"

const DIFFICULTIES: Select = [
{ value: "easy", title: "Easy" },
Expand All @@ -12,28 +13,26 @@ const DIFFICULTIES: Select = [
]

function App() {
const [diff, setDiff] = React.useState<string>("easy")
const [gameState, setGameState] = React.useState<FaceTypes>("start")
const gameResetFn = React.useRef<() => void>()
const [diff, setDiff] = useState<string>("easy")
const [gameState, setGameState] = useState<FaceTypes>("start")
const gameResetFn = useRef<() => void>()

const changeDifficulty = React.useCallback((value: string) => {
const changeDifficulty = useCallback((value: string) => {
setDiff(value)
}, [])

const changeEmoji = React.useCallback((value: FaceTypes) => {
const changeEmoji = useCallback((value: FaceTypes) => {
setGameState(value)
}, [])

const gameResetter = React.useCallback((resetter) => {
const gameResetter = useCallback((resetter) => {
gameResetFn.current = resetter
}, [])

const resetHandler = () => {
gameResetFn.current()
}

require("./index.sass")

return (
<>
<div className="menu">
Expand All @@ -46,9 +45,8 @@ function App() {
)
}

ReactDOM.render(
<React.StrictMode>
createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root"),
</StrictMode>,
)
1 change: 1 addition & 0 deletions src/App/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
40 changes: 19 additions & 21 deletions src/Components/Board/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react"
import { Field, States } from "Components/Field"
import { cloneDeep } from "lodash"
import { memo, useCallback, useEffect, useRef, useState } from "react"
import { Field, States } from "@/Components/Field"
import "./index.sass"

type boardItem = {
isMine: boolean
Expand Down Expand Up @@ -97,14 +97,14 @@ type boardProps = {
}

function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps) {
const firstStep = React.useRef<boolean>(true)
const [userBoard, setUserBoard] = React.useState<board>([])
const firstStep = useRef<boolean>(true)
const [userBoard, setUserBoard] = useState<board>([])

const rows = React.useRef<number>(9)
const cells = React.useRef<number>(9)
const minesCount = React.useRef<number>(10)
const rows = useRef<number>(9)
const cells = useRef<number>(9)
const minesCount = useRef<number>(10)

const countOpenCells = React.useRef(rows.current * cells.current - minesCount.current)
const countOpenCells = useRef(rows.current * cells.current - minesCount.current)

const boardFill = () => {
clearBoard()
Expand All @@ -125,7 +125,7 @@ function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps
setUserBoard(board)
}

React.useEffect(() => {
useEffect(() => {
switch (difficulty) {
case "easy":
rows.current = 9
Expand All @@ -147,7 +147,7 @@ function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps
boardFill()
}, [difficulty])

React.useEffect(() => {
useEffect(() => {
if (userBoard.length) {
if (userBoard.some((row) => row.some((cell) => cell.isMine && cell.opened))) {
onGameState("lose")
Expand All @@ -166,7 +166,7 @@ function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps
onGameState("start")

setUserBoard((prevState) => {
const mutateBoard = cloneDeep(prevState)
const mutateBoard = structuredClone(prevState)

mutateBoard.map((item) => {
item.map((cell) => {
Expand All @@ -181,7 +181,7 @@ function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps
})
}

React.useEffect(() => {
useEffect(() => {
if (getReset) getReset(clearBoard)
}, [getReset])

Expand All @@ -208,7 +208,7 @@ function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps
minesCount.current = countMines

setUserBoard((prevState) => {
const mutateBoard = cloneDeep(prevState)
const mutateBoard = structuredClone(prevState)

minesData.forEach(([mineX, mineY]) => {
mutateBoard[mineX][mineY].isMine = true
Expand All @@ -223,7 +223,7 @@ function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps
})
}

const leftHandle = React.useCallback((x: number, y: number) => {
const leftHandle = useCallback((x: number, y: number) => {
if (firstStep.current) {
setMines(x, y)
onGameState("game")
Expand All @@ -232,7 +232,7 @@ function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps

setUserBoard((prevState) => {
if (!prevState[x][y].opened && !prevState[x][y].flagged) {
const mutateBoard = cloneDeep(prevState)
const mutateBoard = structuredClone(prevState)
mutateBoard[x][y].opened = true

if (mutateBoard[x][y].isMine) {
Expand All @@ -248,10 +248,10 @@ function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps
})
}, [])

const rightHandle = React.useCallback((x: number, y: number) => {
const rightHandle = useCallback((x: number, y: number) => {
setUserBoard((prevState) => {
if (!prevState[x][y].opened) {
const mutateBoard = cloneDeep(prevState)
const mutateBoard = structuredClone(prevState)

mutateBoard[x][y].flagged = !mutateBoard[x][y].flagged

Expand Down Expand Up @@ -284,8 +284,6 @@ function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps
return null
}

require("./index.sass")

return (
<div className="board">
{userBoard.map((cells, rowIndex) => (
Expand All @@ -308,4 +306,4 @@ function BoardComponent({ difficulty, onGameState, getReset = null }: boardProps
)
}

export const Board = React.memo(BoardComponent)
export const Board = memo(BoardComponent)
4 changes: 1 addition & 3 deletions src/Components/Face/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react"
import "./index.sass"

export type FaceTypes = "lose" | "win" | "game" | "start"

Expand All @@ -19,8 +19,6 @@ type faceProps = {
}

export function Face({ state, onResetGame }: faceProps) {
require("./index.sass")

const onClick = () => {
onResetGame()
}
Expand Down
2 changes: 2 additions & 0 deletions src/Components/Field/index.sass
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import ./../../Shared/Styles/_vars

.field
background-color: $field-bg-blue
border: 1px solid #696969
Expand Down
7 changes: 3 additions & 4 deletions src/Components/Field/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from "react"
import { memo } from "react"
import "./index.sass"

export type States = "flag" | "opened" | "bomb"
type FieldProps = {
Expand Down Expand Up @@ -45,13 +46,11 @@ function FieldComponent({
if (state === "bomb") className += " field--bomb"
if (state === "opened") className += " field--opened"

require("./index.sass")

return (
<button className={className} onClick={leftClickHandle} onContextMenu={rightClickHandle}>
{getState()}
</button>
)
}

export const Field = React.memo(FieldComponent)
export const Field = memo(FieldComponent)
8 changes: 2 additions & 6 deletions src/Components/Select/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react"
import "./index.sass"

type value = string

Expand All @@ -13,13 +13,11 @@ type selectProps = {
onChange?: (value: value) => void
}

function SelectComponent({ value = null, options = [], onChange = null }: selectProps) {
export function Select({ value = null, options = [], onChange = null }: selectProps) {
const changeHandler = (e: React.ChangeEvent<HTMLSelectElement>) => {
if (onChange) onChange(e.target.value)
}

require("./index.sass")

return (
<div className="select">
<select value={value} onChange={changeHandler}>
Expand All @@ -34,5 +32,3 @@ function SelectComponent({ value = null, options = [], onChange = null }: select
</div>
)
}

export const Select = React.memo(SelectComponent)
Empty file removed src/Components/Timer/index.sass
Empty file.
Loading

0 comments on commit f750d3c

Please sign in to comment.