first commit
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import js from '@eslint/js'
|
||||||
|
import globals from 'globals'
|
||||||
|
import reactHooks from 'eslint-plugin-react-hooks'
|
||||||
|
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||||
|
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
globalIgnores(['dist']),
|
||||||
|
{
|
||||||
|
files: ['**/*.{js,jsx}'],
|
||||||
|
extends: [
|
||||||
|
js.configs.recommended,
|
||||||
|
reactHooks.configs.flat.recommended,
|
||||||
|
reactRefresh.configs.vite,
|
||||||
|
],
|
||||||
|
languageOptions: {
|
||||||
|
globals: globals.browser,
|
||||||
|
parserOptions: { ecmaFeatures: { jsx: true } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Hanken+Grotesk:ital,wght@0,100..900;1,100..900&display=swap"
|
||||||
|
rel="stylesheet">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="/index.css" />
|
||||||
|
<title>Assembly Endgame</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/index.jsx"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
Generated
+2486
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "scrimba---assembly-endgame",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"react": "^19.2.6",
|
||||||
|
"react-confetti": "^6.4.0",
|
||||||
|
"react-dom": "^19.2.6"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^10.0.1",
|
||||||
|
"@types/react": "^19.2.14",
|
||||||
|
"@types/react-dom": "^19.2.3",
|
||||||
|
"@vitejs/plugin-react": "^6.0.1",
|
||||||
|
"eslint": "^10.3.0",
|
||||||
|
"eslint-plugin-react-hooks": "^7.1.1",
|
||||||
|
"eslint-plugin-react-refresh": "^0.5.2",
|
||||||
|
"globals": "^17.6.0",
|
||||||
|
"vite": "^8.0.12"
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.3 KiB |
@@ -0,0 +1,24 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<symbol id="bluesky-icon" viewBox="0 0 16 17">
|
||||||
|
<g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
|
||||||
|
<defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="discord-icon" viewBox="0 0 20 19">
|
||||||
|
<path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="documentation-icon" viewBox="0 0 21 20">
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="github-icon" viewBox="0 0 19 19">
|
||||||
|
<path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="social-icon" viewBox="0 0 20 20">
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="x-icon" viewBox="0 0 19 19">
|
||||||
|
<path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
|
||||||
|
</symbol>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.9 KiB |
+140
@@ -0,0 +1,140 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { clsx } from "clsx"
|
||||||
|
import Confetti from "react-confetti"
|
||||||
|
import { languages } from "./languages"
|
||||||
|
import { getFarewellText, getRandomWord } from "./utils"
|
||||||
|
|
||||||
|
export default function AssemblyEndgame() {
|
||||||
|
const [currentWord, setCurrentWord] = React.useState(() => getRandomWord())
|
||||||
|
const [guessedLetters, setGuessedLetters] = React.useState([])
|
||||||
|
|
||||||
|
const nbOfGuessesLeft = languages.length - 1
|
||||||
|
const wrongGuessCount = guessedLetters.filter(letter => (!currentWord.includes(letter))).length
|
||||||
|
const isGameWon = Array.from(currentWord).every(letter => guessedLetters.includes(letter))
|
||||||
|
const isGameLost = wrongGuessCount >= languages.length - 1
|
||||||
|
const isGameOver = isGameWon || isGameLost
|
||||||
|
const lastGuess = guessedLetters[guessedLetters.length - 1]
|
||||||
|
const isLastGuessIncorrect = lastGuess && !currentWord.includes(lastGuess)
|
||||||
|
|
||||||
|
const alphabet = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
const languageChips = languages.map((language, index) => {
|
||||||
|
const style = { backgroundColor: language.backgroundColor, color: language.color }
|
||||||
|
const className = clsx("chip", {
|
||||||
|
lost: index < wrongGuessCount
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key={language.name}
|
||||||
|
className={className}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
{language.name}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const letterElements = Array.from(currentWord).map((letter, index) => {
|
||||||
|
const letterClassName = clsx({
|
||||||
|
missing: isGameLost && !guessedLetters.includes(letter)
|
||||||
|
})
|
||||||
|
return <span className={letterClassName} key={index}>{(guessedLetters.includes(letter) || isGameLost) && letter.toUpperCase()}</span>
|
||||||
|
})
|
||||||
|
|
||||||
|
const keyboardElements = Array.from(alphabet).map(letter => {
|
||||||
|
const isGuessed = guessedLetters.includes(letter)
|
||||||
|
const isRight = isGuessed && currentWord.includes(letter)
|
||||||
|
const isWrong = isGuessed && !currentWord.includes(letter)
|
||||||
|
const className = clsx({
|
||||||
|
right: isRight,
|
||||||
|
wrong: isWrong
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={letter}
|
||||||
|
disabled={isGameOver}
|
||||||
|
aria-disabled={guessedLetters.includes(letter)}
|
||||||
|
aria-label={`̀Letter ${letter}`}
|
||||||
|
onClick={() => addLetter(letter)}
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
{letter.toUpperCase()}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
function addLetter(letter) {
|
||||||
|
setGuessedLetters(prevLetters => (!prevLetters.includes(letter) ? [...prevLetters, letter] : prevLetters))
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetGame() {
|
||||||
|
setCurrentWord(getRandomWord())
|
||||||
|
setGuessedLetters([])
|
||||||
|
}
|
||||||
|
|
||||||
|
const gameStatusClassName = clsx("game-status", {
|
||||||
|
lost: isGameLost,
|
||||||
|
won: isGameWon,
|
||||||
|
farewell: !isGameOver && isLastGuessIncorrect
|
||||||
|
})
|
||||||
|
|
||||||
|
function renderGameStatus() {
|
||||||
|
if (!isGameOver) {
|
||||||
|
if (!isLastGuessIncorrect) return null;
|
||||||
|
|
||||||
|
const goneLanguage = languages[wrongGuessCount - 1]
|
||||||
|
return (
|
||||||
|
<p>"{getFarewellText(goneLanguage.name)}" 🫡</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2>{isGameWon ? "You win!" : isGameLost ? "Game over!" : ""}</h2>
|
||||||
|
<p>{isGameWon ? "Well done! 🎉" : isGameLost ? "You lose! Better start learning Assembly 😭" : ""}</p>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main>
|
||||||
|
{isGameWon && <Confetti recycle={false} numberOfPieces={1000} />}
|
||||||
|
<header>
|
||||||
|
<h1>Assembly: Endgame</h1>
|
||||||
|
<p>Guess the word in under 8 attempts to keep the programming world safe from Assembly!</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section aria-live="polite" role="status" className={gameStatusClassName}>
|
||||||
|
{renderGameStatus()}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="language-chips">
|
||||||
|
{languageChips}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="current-word">
|
||||||
|
{letterElements}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Visually-hidden aria-live section for status updates */}
|
||||||
|
<section className="sr-only" aria-live="polite" role="status">
|
||||||
|
<p>
|
||||||
|
{
|
||||||
|
isLastGuessIncorrect ?
|
||||||
|
`Sorry, the letter ${lastGuess} is not in the word`
|
||||||
|
: `Correct! The letter ${lastGuess} is in the word`
|
||||||
|
}
|
||||||
|
You have {nbOfGuessesLeft} guesses left.
|
||||||
|
</p>
|
||||||
|
<p>Current word : {Array.from(currentWord).map(letter => guessedLetters.includes(letter) ? letter + "." : "blank").join(" ")}</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="keyboard">
|
||||||
|
{keyboardElements}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{isGameOver && <button className="new-game" onClick={() => resetGame()}>New Game</button>}
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
+182
@@ -0,0 +1,182 @@
|
|||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: "Hanken Grotesk", Arial, sans-serif;
|
||||||
|
background-color: #262626;
|
||||||
|
color: #D9D9D9;
|
||||||
|
padding: 20px;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-family: "Hanken Grotesk", Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
header>h1 {
|
||||||
|
color: #F9F4DA;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header>p {
|
||||||
|
color: #8E8E8E;
|
||||||
|
max-width: 350px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.game-status {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
max-width: 350px;
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #F9F4DA;
|
||||||
|
margin-block: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.game-status.won {
|
||||||
|
background-color: #10A95B;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.game-status.lost {
|
||||||
|
background-color: #BA2A2A;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.game-status.farewell {
|
||||||
|
background-color: #7A5EA7;
|
||||||
|
font-style: italic;
|
||||||
|
border: 1px dashed #323232;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.game-status>h2 {
|
||||||
|
font-weight: 400;
|
||||||
|
margin: 5px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.game-status>p {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.language-chips {
|
||||||
|
max-width: 350px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.language-chips>span.chip {
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 4px 5px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
section.language-chips>span.chip.lost::before {
|
||||||
|
content: "💀";
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
section.current-word {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-block: 35px;
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.current-word>span {
|
||||||
|
border-bottom: 1px solid #F9F4DA;
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background-color: #323232;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.current-word>span.missing {
|
||||||
|
color: #EC5D49;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.keyboard {
|
||||||
|
max-width: 450px;
|
||||||
|
margin-block: 35px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.keyboard>button {
|
||||||
|
background-color: #FCBA29;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #d7d7d7;
|
||||||
|
height: 35px;
|
||||||
|
width: 35px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.new-game {
|
||||||
|
background-color: #11B5E5;
|
||||||
|
border: 1px solid #D7D7D7;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 225px;
|
||||||
|
height: 40px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
display: block;
|
||||||
|
margin-inline: auto;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.keyboard>button.right {
|
||||||
|
background-color: #10A95B;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.keyboard>button.wrong {
|
||||||
|
background-color: #EC5D49;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { StrictMode } from 'react'
|
||||||
|
import { createRoot } from 'react-dom/client'
|
||||||
|
import './index.css'
|
||||||
|
import App from './App.jsx'
|
||||||
|
|
||||||
|
createRoot(document.getElementById('root')).render(
|
||||||
|
<StrictMode>
|
||||||
|
<App />
|
||||||
|
</StrictMode>,
|
||||||
|
)
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
export const languages = [
|
||||||
|
{
|
||||||
|
name: "HTML",
|
||||||
|
backgroundColor: "#E2680F",
|
||||||
|
color: "#F9F4DA",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CSS",
|
||||||
|
backgroundColor: "#328AF1",
|
||||||
|
color: "#F9F4DA",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JavaScript",
|
||||||
|
backgroundColor: "#F4EB13",
|
||||||
|
color: "#1E1E1E",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "React",
|
||||||
|
backgroundColor: "#2ED3E9",
|
||||||
|
color: "#1E1E1E",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TypeScript",
|
||||||
|
backgroundColor: "#298EC6",
|
||||||
|
color: "#F9F4DA",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Node.js",
|
||||||
|
backgroundColor: "#599137",
|
||||||
|
color: "#F9F4DA",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Python",
|
||||||
|
backgroundColor: "#FFD742",
|
||||||
|
color: "#1E1E1E",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Ruby",
|
||||||
|
backgroundColor: "#D02B2B",
|
||||||
|
color: "#F9F4DA",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Assembly",
|
||||||
|
backgroundColor: "#2D519F",
|
||||||
|
color: "#F9F4DA",
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { words } from "./words"
|
||||||
|
|
||||||
|
export function getFarewellText(language) {
|
||||||
|
const options = [
|
||||||
|
`Farewell, ${language}`,
|
||||||
|
`Adios, ${language}`,
|
||||||
|
`R.I.P., ${language}`,
|
||||||
|
`We'll miss you, ${language}`,
|
||||||
|
`Oh no, not ${language}!`,
|
||||||
|
`${language} bites the dust`,
|
||||||
|
`Gone but not forgotten, ${language}`,
|
||||||
|
`The end of ${language} as we know it`,
|
||||||
|
`Off into the sunset, ${language}`,
|
||||||
|
`${language}, it's been real`,
|
||||||
|
`${language}, your watch has ended`,
|
||||||
|
`${language} has left the building`
|
||||||
|
];
|
||||||
|
|
||||||
|
const randomIndex = Math.floor(Math.random() * options.length);
|
||||||
|
return options[randomIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRandomWord() {
|
||||||
|
const randomIndex = Math.floor(Math.random() * words.length)
|
||||||
|
return words[randomIndex]
|
||||||
|
}
|
||||||
+484
@@ -0,0 +1,484 @@
|
|||||||
|
export const words = [
|
||||||
|
"about",
|
||||||
|
"account",
|
||||||
|
"across",
|
||||||
|
"addition",
|
||||||
|
"after",
|
||||||
|
"again",
|
||||||
|
"against",
|
||||||
|
"agreement",
|
||||||
|
"almost",
|
||||||
|
"among",
|
||||||
|
"amount",
|
||||||
|
"amusement",
|
||||||
|
"angle",
|
||||||
|
"angry",
|
||||||
|
"animal",
|
||||||
|
"answer",
|
||||||
|
"apparatus",
|
||||||
|
"apple",
|
||||||
|
"approval",
|
||||||
|
"argument",
|
||||||
|
"attack",
|
||||||
|
"attempt",
|
||||||
|
"attention",
|
||||||
|
"authority",
|
||||||
|
"automatic",
|
||||||
|
"awake",
|
||||||
|
"balance",
|
||||||
|
"basin",
|
||||||
|
"basket",
|
||||||
|
"beautiful",
|
||||||
|
"because",
|
||||||
|
"before",
|
||||||
|
"behaviour",
|
||||||
|
"belief",
|
||||||
|
"berry",
|
||||||
|
"between",
|
||||||
|
"birth",
|
||||||
|
"bitter",
|
||||||
|
"black",
|
||||||
|
"blade",
|
||||||
|
"blood",
|
||||||
|
"board",
|
||||||
|
"boiling",
|
||||||
|
"bottle",
|
||||||
|
"brain",
|
||||||
|
"brake",
|
||||||
|
"branch",
|
||||||
|
"brass",
|
||||||
|
"bread",
|
||||||
|
"breath",
|
||||||
|
"brick",
|
||||||
|
"bridge",
|
||||||
|
"bright",
|
||||||
|
"broken",
|
||||||
|
"brother",
|
||||||
|
"brown",
|
||||||
|
"brush",
|
||||||
|
"bucket",
|
||||||
|
"building",
|
||||||
|
"burst",
|
||||||
|
"business",
|
||||||
|
"butter",
|
||||||
|
"button",
|
||||||
|
"camera",
|
||||||
|
"canvas",
|
||||||
|
"carriage",
|
||||||
|
"cause",
|
||||||
|
"certain",
|
||||||
|
"chain",
|
||||||
|
"chalk",
|
||||||
|
"chance",
|
||||||
|
"change",
|
||||||
|
"cheap",
|
||||||
|
"cheese",
|
||||||
|
"chemical",
|
||||||
|
"chest",
|
||||||
|
"chief",
|
||||||
|
"church",
|
||||||
|
"circle",
|
||||||
|
"clean",
|
||||||
|
"clear",
|
||||||
|
"clock",
|
||||||
|
"cloth",
|
||||||
|
"cloud",
|
||||||
|
"collar",
|
||||||
|
"colour",
|
||||||
|
"comfort",
|
||||||
|
"committee",
|
||||||
|
"common",
|
||||||
|
"company",
|
||||||
|
"complete",
|
||||||
|
"complex",
|
||||||
|
"condition",
|
||||||
|
"conscious",
|
||||||
|
"control",
|
||||||
|
"copper",
|
||||||
|
"cotton",
|
||||||
|
"cough",
|
||||||
|
"country",
|
||||||
|
"cover",
|
||||||
|
"crack",
|
||||||
|
"credit",
|
||||||
|
"crime",
|
||||||
|
"cruel",
|
||||||
|
"crush",
|
||||||
|
"current",
|
||||||
|
"curtain",
|
||||||
|
"curve",
|
||||||
|
"cushion",
|
||||||
|
"damage",
|
||||||
|
"danger",
|
||||||
|
"daughter",
|
||||||
|
"death",
|
||||||
|
"decision",
|
||||||
|
"degree",
|
||||||
|
"delicate",
|
||||||
|
"dependent",
|
||||||
|
"design",
|
||||||
|
"desire",
|
||||||
|
"detail",
|
||||||
|
"different",
|
||||||
|
"digestion",
|
||||||
|
"direction",
|
||||||
|
"dirty",
|
||||||
|
"discovery",
|
||||||
|
"disease",
|
||||||
|
"disgust",
|
||||||
|
"distance",
|
||||||
|
"division",
|
||||||
|
"doubt",
|
||||||
|
"drain",
|
||||||
|
"drawer",
|
||||||
|
"dress",
|
||||||
|
"drink",
|
||||||
|
"driving",
|
||||||
|
"early",
|
||||||
|
"earth",
|
||||||
|
"education",
|
||||||
|
"effect",
|
||||||
|
"elastic",
|
||||||
|
"electric",
|
||||||
|
"engine",
|
||||||
|
"enough",
|
||||||
|
"equal",
|
||||||
|
"error",
|
||||||
|
"event",
|
||||||
|
"every",
|
||||||
|
"example",
|
||||||
|
"exchange",
|
||||||
|
"existence",
|
||||||
|
"expansion",
|
||||||
|
"expert",
|
||||||
|
"false",
|
||||||
|
"family",
|
||||||
|
"father",
|
||||||
|
"feather",
|
||||||
|
"feeble",
|
||||||
|
"feeling",
|
||||||
|
"female",
|
||||||
|
"fertile",
|
||||||
|
"fiction",
|
||||||
|
"field",
|
||||||
|
"fight",
|
||||||
|
"finger",
|
||||||
|
"first",
|
||||||
|
"fixed",
|
||||||
|
"flame",
|
||||||
|
"flight",
|
||||||
|
"floor",
|
||||||
|
"flower",
|
||||||
|
"foolish",
|
||||||
|
"force",
|
||||||
|
"forward",
|
||||||
|
"frame",
|
||||||
|
"frequent",
|
||||||
|
"friend",
|
||||||
|
"front",
|
||||||
|
"fruit",
|
||||||
|
"future",
|
||||||
|
"garden",
|
||||||
|
"general",
|
||||||
|
"glass",
|
||||||
|
"glove",
|
||||||
|
"grain",
|
||||||
|
"grass",
|
||||||
|
"great",
|
||||||
|
"green",
|
||||||
|
"group",
|
||||||
|
"growth",
|
||||||
|
"guide",
|
||||||
|
"hammer",
|
||||||
|
"hanging",
|
||||||
|
"happy",
|
||||||
|
"harbour",
|
||||||
|
"harmony",
|
||||||
|
"healthy",
|
||||||
|
"hearing",
|
||||||
|
"heart",
|
||||||
|
"history",
|
||||||
|
"hollow",
|
||||||
|
"horse",
|
||||||
|
"hospital",
|
||||||
|
"house",
|
||||||
|
"humour",
|
||||||
|
"important",
|
||||||
|
"impulse",
|
||||||
|
"increase",
|
||||||
|
"industry",
|
||||||
|
"insect",
|
||||||
|
"insurance",
|
||||||
|
"interest",
|
||||||
|
"invention",
|
||||||
|
"island",
|
||||||
|
"jelly",
|
||||||
|
"jewel",
|
||||||
|
"journey",
|
||||||
|
"judge",
|
||||||
|
"kettle",
|
||||||
|
"knife",
|
||||||
|
"knowledge",
|
||||||
|
"language",
|
||||||
|
"laugh",
|
||||||
|
"learning",
|
||||||
|
"leather",
|
||||||
|
"letter",
|
||||||
|
"level",
|
||||||
|
"library",
|
||||||
|
"light",
|
||||||
|
"limit",
|
||||||
|
"linen",
|
||||||
|
"liquid",
|
||||||
|
"little",
|
||||||
|
"living",
|
||||||
|
"loose",
|
||||||
|
"machine",
|
||||||
|
"manager",
|
||||||
|
"market",
|
||||||
|
"married",
|
||||||
|
"match",
|
||||||
|
"material",
|
||||||
|
"measure",
|
||||||
|
"medical",
|
||||||
|
"meeting",
|
||||||
|
"memory",
|
||||||
|
"metal",
|
||||||
|
"middle",
|
||||||
|
"military",
|
||||||
|
"minute",
|
||||||
|
"mixed",
|
||||||
|
"money",
|
||||||
|
"monkey",
|
||||||
|
"month",
|
||||||
|
"morning",
|
||||||
|
"mother",
|
||||||
|
"motion",
|
||||||
|
"mountain",
|
||||||
|
"mouth",
|
||||||
|
"muscle",
|
||||||
|
"music",
|
||||||
|
"narrow",
|
||||||
|
"nation",
|
||||||
|
"natural",
|
||||||
|
"necessary",
|
||||||
|
"needle",
|
||||||
|
"nerve",
|
||||||
|
"night",
|
||||||
|
"noise",
|
||||||
|
"normal",
|
||||||
|
"north",
|
||||||
|
"number",
|
||||||
|
"offer",
|
||||||
|
"office",
|
||||||
|
"operation",
|
||||||
|
"opinion",
|
||||||
|
"opposite",
|
||||||
|
"orange",
|
||||||
|
"order",
|
||||||
|
"ornament",
|
||||||
|
"other",
|
||||||
|
"owner",
|
||||||
|
"paint",
|
||||||
|
"paper",
|
||||||
|
"parallel",
|
||||||
|
"parcel",
|
||||||
|
"paste",
|
||||||
|
"payment",
|
||||||
|
"peace",
|
||||||
|
"pencil",
|
||||||
|
"person",
|
||||||
|
"physical",
|
||||||
|
"picture",
|
||||||
|
"place",
|
||||||
|
"plane",
|
||||||
|
"plant",
|
||||||
|
"plate",
|
||||||
|
"please",
|
||||||
|
"pleasure",
|
||||||
|
"plough",
|
||||||
|
"pocket",
|
||||||
|
"point",
|
||||||
|
"poison",
|
||||||
|
"polish",
|
||||||
|
"political",
|
||||||
|
"porter",
|
||||||
|
"position",
|
||||||
|
"possible",
|
||||||
|
"potato",
|
||||||
|
"powder",
|
||||||
|
"power",
|
||||||
|
"present",
|
||||||
|
"price",
|
||||||
|
"print",
|
||||||
|
"prison",
|
||||||
|
"private",
|
||||||
|
"probable",
|
||||||
|
"process",
|
||||||
|
"produce",
|
||||||
|
"profit",
|
||||||
|
"property",
|
||||||
|
"prose",
|
||||||
|
"protest",
|
||||||
|
"public",
|
||||||
|
"purpose",
|
||||||
|
"quality",
|
||||||
|
"question",
|
||||||
|
"quick",
|
||||||
|
"quiet",
|
||||||
|
"quite",
|
||||||
|
"range",
|
||||||
|
"reaction",
|
||||||
|
"reading",
|
||||||
|
"ready",
|
||||||
|
"reason",
|
||||||
|
"receipt",
|
||||||
|
"record",
|
||||||
|
"regret",
|
||||||
|
"regular",
|
||||||
|
"relation",
|
||||||
|
"religion",
|
||||||
|
"request",
|
||||||
|
"respect",
|
||||||
|
"reward",
|
||||||
|
"rhythm",
|
||||||
|
"right",
|
||||||
|
"river",
|
||||||
|
"rough",
|
||||||
|
"round",
|
||||||
|
"scale",
|
||||||
|
"school",
|
||||||
|
"science",
|
||||||
|
"scissors",
|
||||||
|
"screw",
|
||||||
|
"second",
|
||||||
|
"secret",
|
||||||
|
"secretary",
|
||||||
|
"selection",
|
||||||
|
"sense",
|
||||||
|
"separate",
|
||||||
|
"serious",
|
||||||
|
"servant",
|
||||||
|
"shade",
|
||||||
|
"shake",
|
||||||
|
"shame",
|
||||||
|
"sharp",
|
||||||
|
"sheep",
|
||||||
|
"shelf",
|
||||||
|
"shirt",
|
||||||
|
"shock",
|
||||||
|
"short",
|
||||||
|
"silver",
|
||||||
|
"simple",
|
||||||
|
"sister",
|
||||||
|
"skirt",
|
||||||
|
"sleep",
|
||||||
|
"slope",
|
||||||
|
"small",
|
||||||
|
"smash",
|
||||||
|
"smell",
|
||||||
|
"smile",
|
||||||
|
"smoke",
|
||||||
|
"smooth",
|
||||||
|
"snake",
|
||||||
|
"sneeze",
|
||||||
|
"society",
|
||||||
|
"solid",
|
||||||
|
"sound",
|
||||||
|
"south",
|
||||||
|
"space",
|
||||||
|
"spade",
|
||||||
|
"special",
|
||||||
|
"sponge",
|
||||||
|
"spoon",
|
||||||
|
"spring",
|
||||||
|
"square",
|
||||||
|
"stage",
|
||||||
|
"stamp",
|
||||||
|
"start",
|
||||||
|
"statement",
|
||||||
|
"station",
|
||||||
|
"steam",
|
||||||
|
"steel",
|
||||||
|
"stick",
|
||||||
|
"sticky",
|
||||||
|
"stiff",
|
||||||
|
"still",
|
||||||
|
"stitch",
|
||||||
|
"stocking",
|
||||||
|
"stomach",
|
||||||
|
"stone",
|
||||||
|
"store",
|
||||||
|
"story",
|
||||||
|
"straight",
|
||||||
|
"strange",
|
||||||
|
"street",
|
||||||
|
"stretch",
|
||||||
|
"strong",
|
||||||
|
"structure",
|
||||||
|
"substance",
|
||||||
|
"sudden",
|
||||||
|
"sugar",
|
||||||
|
"summer",
|
||||||
|
"support",
|
||||||
|
"surprise",
|
||||||
|
"sweet",
|
||||||
|
"system",
|
||||||
|
"table",
|
||||||
|
"taste",
|
||||||
|
"teaching",
|
||||||
|
"tendency",
|
||||||
|
"theory",
|
||||||
|
"there",
|
||||||
|
"thick",
|
||||||
|
"thing",
|
||||||
|
"thought",
|
||||||
|
"thread",
|
||||||
|
"throat",
|
||||||
|
"through",
|
||||||
|
"through",
|
||||||
|
"thumb",
|
||||||
|
"thunder",
|
||||||
|
"ticket",
|
||||||
|
"tight",
|
||||||
|
"tired",
|
||||||
|
"together",
|
||||||
|
"tomorrow",
|
||||||
|
"tongue",
|
||||||
|
"tooth",
|
||||||
|
"touch",
|
||||||
|
"trade",
|
||||||
|
"train",
|
||||||
|
"transport",
|
||||||
|
"trick",
|
||||||
|
"trouble",
|
||||||
|
"trousers",
|
||||||
|
"twist",
|
||||||
|
"umbrella",
|
||||||
|
"under",
|
||||||
|
"value",
|
||||||
|
"verse",
|
||||||
|
"vessel",
|
||||||
|
"violent",
|
||||||
|
"voice",
|
||||||
|
"waiting",
|
||||||
|
"waste",
|
||||||
|
"watch",
|
||||||
|
"water",
|
||||||
|
"weather",
|
||||||
|
"weight",
|
||||||
|
"wheel",
|
||||||
|
"where",
|
||||||
|
"while",
|
||||||
|
"whistle",
|
||||||
|
"white",
|
||||||
|
"window",
|
||||||
|
"winter",
|
||||||
|
"woman",
|
||||||
|
"wound",
|
||||||
|
"writing",
|
||||||
|
"wrong",
|
||||||
|
"yellow",
|
||||||
|
"yesterday",
|
||||||
|
"young"
|
||||||
|
];
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
|
// https://vite.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user