├── .config └── configstore │ ├── update-notifier-npm.json.2701252402 │ └── update-notifier-npm.json ├── .gitattributes ├── gifs ├── 01_Run.gif ├── 02_Remix.gif └── 03_Publish.gif ├── .tutorial ├── gifs │ ├── 01_Run.gif │ ├── 02_Remix.gif │ └── 03_Publish.gif └── README.md ├── replit.nix ├── reference.md ├── targetWords.js ├── LICENSE ├── README.md ├── index.html ├── .cache └── replit │ └── nix │ └── env.json ├── styles.css ├── script.js └── .replit /.config/configstore/update-notifier-npm.json.2701252402: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /gifs/01_Run.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshat-jn-crypto/Wordle-clone/HEAD/gifs/01_Run.gif -------------------------------------------------------------------------------- /gifs/02_Remix.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshat-jn-crypto/Wordle-clone/HEAD/gifs/02_Remix.gif -------------------------------------------------------------------------------- /gifs/03_Publish.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshat-jn-crypto/Wordle-clone/HEAD/gifs/03_Publish.gif -------------------------------------------------------------------------------- /.config/configstore/update-notifier-npm.json: -------------------------------------------------------------------------------- 1 | { 2 | "optOut": false, 3 | "lastUpdateCheck": 1661606148651 4 | } -------------------------------------------------------------------------------- /.tutorial/gifs/01_Run.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshat-jn-crypto/Wordle-clone/HEAD/.tutorial/gifs/01_Run.gif -------------------------------------------------------------------------------- /.tutorial/gifs/02_Remix.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshat-jn-crypto/Wordle-clone/HEAD/.tutorial/gifs/02_Remix.gif -------------------------------------------------------------------------------- /.tutorial/gifs/03_Publish.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshat-jn-crypto/Wordle-clone/HEAD/.tutorial/gifs/03_Publish.gif -------------------------------------------------------------------------------- /replit.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: { 2 | deps = [ 3 | pkgs.nodePackages.vscode-langservers-extracted 4 | pkgs.nodePackages.typescript-language-server 5 | ]; 6 | } -------------------------------------------------------------------------------- /reference.md: -------------------------------------------------------------------------------- 1 | - Source: https://github.com/WebDevSimplified/wordle-clone 2 | - Modified CSS slightly to get it to fit in the output window. 3 | - Modifed JS logic to join targetWords + dictionary to form a list of all words - targetWords no longer need to be in the dictionary. 4 | -------------------------------------------------------------------------------- /targetWords.js: -------------------------------------------------------------------------------- 1 | const targetWords = [ 2 | "rebut", 3 | "humph", 4 | "awake", 5 | "blush", 6 | "focal", 7 | "evade", 8 | "naval", 9 | "serve", 10 | "heath", 11 | "dwarf", 12 | "model", 13 | "karma", 14 | "stink", 15 | "grade", 16 | "quiet", 17 | "adieu", 18 | "alert", 19 | "alien", 20 | "atone", 21 | "audio", 22 | "blind", 23 | "canoe", 24 | "fraud", 25 | "haunt", 26 | "media", 27 | "minor", 28 | "odium", 29 | "orate", 30 | "pause", 31 | "plane", 32 | "raise", 33 | "resin", 34 | "rouse", 35 | "route", 36 | "shade" 37 | ]; 38 | 39 | export default targetWords; 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 WebDevSimplified 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /.tutorial/README.md: -------------------------------------------------------------------------------- 1 | # Make Your Own Wordle Game 2 | 3 | ### Step 1: Run 4 | 5 | Check out the "Output" panel to see your game in action. 6 | 7 | ![](/gifs/01_Run.gif) 8 | 9 | ### Step 2: Customize 10 | 11 | Look at the left hand side vertical panel with the icons 12 | - You are currently in the `Tutorial` (the icon with the open book) 13 | - Below this is the `Files` icon (page with the corner folded) 14 | - You can switch back and forth through this panel of icons 15 | 16 | To modify a file you will need to go to the `Files` icon (the page with the folded corner) 17 | - Here right click on `targetWords.json` file and choose "Open Tab" 18 | - This will open the file side by side with `index.html` 19 | - Modify `targetwords.json` to customize which words could show up as the randomly choosen word for a round of the game. 20 | - Refresh the browser or hit the "run" button and test it out. 21 | 22 | ![](/gifs/02_Remix.gif) 23 | 24 | ## Step 3: Share 25 | 26 | Share your game with the community. 27 | 28 | ![](/gifs/03_Publish.gif) 29 | 30 | ## Step 4: Remix 31 | 32 | Dig into web development [here](https://docs.replit.com/tutorials/building-a-game-with-pygame) and remix the rules of the game to create your own word puzzle. 33 | 34 | # 🎉 Good job! 35 | 36 | # Challenge! 37 | - Can you make a 6-letter wordle game? -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wordle clone 2 | Hackoberfest repo 3 | Hacktoberfest-2022🔥 4 | 5 |
6 |

7 | 8 |

9 | 10 | ## This repository aims to help code beginners with their first successful pull request and open source contribution. :partying_face: 11 | 12 | :star: Feel free to use this project to make your first contribution to an open-source project on GitHub. Practice making your first pull request to a public repository before doing the real thing! 13 | 14 | :star: Make sure to grab some cool swags during Hacktoberfest by getting involved in the open-source community. 15 | 16 | ### This repository is open to all members of the GitHub community. Any member can contribute to this project! 17 | # Guidelines 18 | 19 | # Steps For Contribution 20 | 21 | 0. Star 22 | 23 | 1. Fork 24 | 25 | 2. Clone the forked repository. 26 | ```css 27 | git clone https://github.com//Wordle-clone 28 | ``` 29 | 30 | 3. Navigate to the project directory. 31 | ```py 32 | cd Wordle-clone 33 | ``` 34 | 35 | 4. Create a new branch. 36 | ```css 37 | git checkout -b 38 | ``` 39 | 40 | 5. Make changes. 41 | 42 | 6. Stage your changes and commit 43 | ```css 44 | git add -A 45 | 46 | git commit -m "" 47 | ``` 48 | 49 | 7. Push your local commits to the remote repo. 50 | ```css 51 | git push -u origin "" 52 | ``` 53 | 54 | 8. Create a Pull Request. 55 | 56 | 9. Congratulations! 🎉 you've made your contribution. 57 | 58 | 59 | --- 60 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Wordle Clone 10 | 11 | 12 |
13 |

WORDLE CLONE

14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 83 |
84 | 85 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /.cache/replit/nix/env.json: -------------------------------------------------------------------------------- 1 | {"entries":{"replit.nix":{"env":{"AR":"ar","AS":"as","CC":"gcc","CONFIG_SHELL":"/nix/store/bm7jr70d9ghn5cczb3q0w90apsm05p54-bash-5.1-p8/bin/bash","CXX":"g++","HOST_PATH":"/nix/store/mj9madzlh0xwcccb30qsnsclfjxr5k1s-vscode-langservers-extracted-3.0.1/bin:/nix/store/rszcnphk27fvfr2hq5pcr07jccf2dqy1-typescript-language-server-0.9.6/bin:/nix/store/jd1y449cf66yx5d1hwyjvc4562b1p1am-coreutils-9.0/bin:/nix/store/jjvw20r6pz3ff7pn91yhvfx8s7izsqan-findutils-4.8.0/bin:/nix/store/ndd6gh8zigjy0j68arj7nyrbcw4kcw01-diffutils-3.8/bin:/nix/store/bpg0ia8nkavzw7s66avi1f9nz72i1p3r-gnused-4.8/bin:/nix/store/df3ff57sbkgbdhc4ar19zs4y0hrhggii-gnugrep-3.7/bin:/nix/store/4fv981732jqzirah3h2y6ynmlsfbxb37-gawk-5.1.1/bin:/nix/store/k5ifa08z0qlkknnb8s1bdh2kdrx0qmd0-gnutar-1.34/bin:/nix/store/dcird3wn9xywy49w3qq1hpjwvjfn3lph-gzip-1.11/bin:/nix/store/s85iyc3p9nbinwvwx9rcqirf1m68zpmm-bzip2-1.0.6.0.2-bin/bin:/nix/store/msncxcf5lgy5by9cqjyxchxd26x47d64-gnumake-4.3/bin:/nix/store/bm7jr70d9ghn5cczb3q0w90apsm05p54-bash-5.1-p8/bin:/nix/store/gi3psbgxbf2fmvgi36pmw77nnh58vq3l-patch-2.7.6/bin:/nix/store/sqb20f4rk80lw21j4is85qwljlphmn3g-xz-5.2.5-bin/bin","LD":"ld","LOCALE_ARCHIVE":"/usr/lib/locale/locale-archive","NIX_BINTOOLS":"/nix/store/spm7d6ncyx2k5w8yl6clzynv2s4wf1kp-binutils-wrapper-2.35.2","NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu":"1","NIX_BUILD_CORES":"16","NIX_BUILD_TOP":"/tmp","NIX_CC":"/nix/store/2qwnn6lizc9d119kp3zig3q19gbfm4n6-gcc-wrapper-10.3.0","NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu":"1","NIX_CFLAGS_COMPILE":" -frandom-seed=qfbj2w45kl","NIX_ENFORCE_NO_NATIVE":"1","NIX_HARDENING_ENABLE":"fortify stackprotector pic strictoverflow format relro bindnow","NIX_INDENT_MAKE":"1","NIX_LDFLAGS":"-rpath /nix/store/qfbj2w45kliilxjmvsvz3iqm4mxk1qf1-nix-shell/lib64 -rpath /nix/store/qfbj2w45kliilxjmvsvz3iqm4mxk1qf1-nix-shell/lib ","NIX_STORE":"/nix/store","NM":"nm","OBJCOPY":"objcopy","OBJDUMP":"objdump","PATH":"/nix/store/bccsypsvjskpzsgzww8bzjgqmck4bjbf-bash-interactive-5.1-p8/bin:/nix/store/bqmg7l0jn6nhgjlfc981g1imzb6ny8xl-patchelf-0.13/bin:/nix/store/2qwnn6lizc9d119kp3zig3q19gbfm4n6-gcc-wrapper-10.3.0/bin:/nix/store/6r5h4h7nqx73m87j5b9sjwy2x9kyri0k-gcc-10.3.0/bin:/nix/store/csz8v8xi2f644j26n84i20dnqmq43sih-glibc-2.33-117-bin/bin:/nix/store/jd1y449cf66yx5d1hwyjvc4562b1p1am-coreutils-9.0/bin:/nix/store/spm7d6ncyx2k5w8yl6clzynv2s4wf1kp-binutils-wrapper-2.35.2/bin:/nix/store/h19zwlkrp6b0hp3ypbqdcggnyarn3af6-binutils-2.35.2/bin:/nix/store/mj9madzlh0xwcccb30qsnsclfjxr5k1s-vscode-langservers-extracted-3.0.1/bin:/nix/store/rszcnphk27fvfr2hq5pcr07jccf2dqy1-typescript-language-server-0.9.6/bin:/nix/store/jd1y449cf66yx5d1hwyjvc4562b1p1am-coreutils-9.0/bin:/nix/store/jjvw20r6pz3ff7pn91yhvfx8s7izsqan-findutils-4.8.0/bin:/nix/store/ndd6gh8zigjy0j68arj7nyrbcw4kcw01-diffutils-3.8/bin:/nix/store/bpg0ia8nkavzw7s66avi1f9nz72i1p3r-gnused-4.8/bin:/nix/store/df3ff57sbkgbdhc4ar19zs4y0hrhggii-gnugrep-3.7/bin:/nix/store/4fv981732jqzirah3h2y6ynmlsfbxb37-gawk-5.1.1/bin:/nix/store/k5ifa08z0qlkknnb8s1bdh2kdrx0qmd0-gnutar-1.34/bin:/nix/store/dcird3wn9xywy49w3qq1hpjwvjfn3lph-gzip-1.11/bin:/nix/store/s85iyc3p9nbinwvwx9rcqirf1m68zpmm-bzip2-1.0.6.0.2-bin/bin:/nix/store/msncxcf5lgy5by9cqjyxchxd26x47d64-gnumake-4.3/bin:/nix/store/bm7jr70d9ghn5cczb3q0w90apsm05p54-bash-5.1-p8/bin:/nix/store/gi3psbgxbf2fmvgi36pmw77nnh58vq3l-patch-2.7.6/bin:/nix/store/sqb20f4rk80lw21j4is85qwljlphmn3g-xz-5.2.5-bin/bin","RANLIB":"ranlib","READELF":"readelf","SIZE":"size","SOURCE_DATE_EPOCH":"315532800","STRINGS":"strings","STRIP":"strip","XDG_DATA_DIRS":"/nix/store/bqmg7l0jn6nhgjlfc981g1imzb6ny8xl-patchelf-0.13/share","_":"/nix/store/jd1y449cf66yx5d1hwyjvc4562b1p1am-coreutils-9.0/bin/env","__ETC_PROFILE_SOURCED":"1","buildInputs":"/nix/store/mj9madzlh0xwcccb30qsnsclfjxr5k1s-vscode-langservers-extracted-3.0.1 /nix/store/rszcnphk27fvfr2hq5pcr07jccf2dqy1-typescript-language-server-0.9.6","builder":"/nix/store/bm7jr70d9ghn5cczb3q0w90apsm05p54-bash-5.1-p8/bin/bash","configureFlags":"","depsBuildBuild":"","depsBuildBuildPropagated":"","depsBuildTarget":"","depsBuildTargetPropagated":"","depsHostHost":"","depsHostHostPropagated":"","depsTargetTarget":"","depsTargetTargetPropagated":"","doCheck":"","doInstallCheck":"","name":"nix-shell","nativeBuildInputs":"","nobuildPhase":"echo\necho \"This derivation is not meant to be built, aborting\";\necho\nexit 1\n","out":"/nix/store/qfbj2w45kliilxjmvsvz3iqm4mxk1qf1-nix-shell","outputs":"out","patches":"","phases":"nobuildPhase","propagatedBuildInputs":"","propagatedNativeBuildInputs":"","shell":"/nix/store/bm7jr70d9ghn5cczb3q0w90apsm05p54-bash-5.1-p8/bin/bash","shellHook":"","stdenv":"/nix/store/z7wz8q1i0j4jmfpn87wpakwma6q0k90n-stdenv-linux","strictDeps":"","system":"x86_64-linux"},"dependencies":[{"path":"replit.nix","mod_time":"2022-03-14T23:31:45.35298035Z"}],"channel":"stable-21_11","channel_nix_path":"/nix/store/1m2fssfawvn6krbv3rc6hmq7xaa45v5a-nixpkgs-stable-21_11-21.11.tar.gz/nixpkgs-stable-21_11"}}} -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | *, *::after, *::before { 2 | box-sizing: border-box; 3 | font-family: Arial; 4 | } 5 | 6 | body { 7 | background-color: hsl(240, 3%, 7%); 8 | display: flex; 9 | flex-direction: column; 10 | min-height: 100vh; 11 | margin: 0; 12 | padding: 3em 10em 10em 10em; 13 | font-size: clamp(.5rem, 2.5vmin, 1.5rem); 14 | } 15 | .heading { 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | margin-bottom: 1em; 20 | } 21 | 22 | .title { 23 | color: hsl(204, 7%, 85%); 24 | } 25 | 26 | .keyboard { 27 | display: grid; 28 | grid-template-columns: repeat(20, minmax(auto, 1em)); 29 | grid-auto-rows: 3em; 30 | gap: .25em; 31 | justify-content: center; 32 | } 33 | 34 | .key { 35 | font-size: inherit; 36 | grid-column: span 2; 37 | border: none; 38 | padding: 0; 39 | display: flex; 40 | justify-content: center; 41 | align-items: center; 42 | background-color: hsl( 43 | var(--hue, 200), 44 | var(--saturation, 1%), 45 | calc(var(--lightness-offset, 0%) + var(--lightness, 51%)) 46 | ); 47 | color: white; 48 | fill: white; 49 | text-transform: uppercase; 50 | border-radius: .25em; 51 | cursor: pointer; 52 | user-select: none; 53 | } 54 | .key:hover{ 55 | background-color: hsl( 56 | var(--hue, 198), 57 | var(--saturation, 1%), 58 | calc(var(--lightness-offset, 0%) + var(--lightness, 52%)) 59 | ); 60 | } 61 | 62 | .key.large { 63 | grid-column: span 3; 64 | } 65 | 66 | .key > svg { 67 | width: 1.75em; 68 | height: 1.75em; 69 | } 70 | 71 | .key:hover, .key:focus { 72 | --lightness-offset: 10%; 73 | } 74 | 75 | .key.wrong { 76 | --lightness: 23%; 77 | } 78 | 79 | .key.wrong-location { 80 | --hue: 49; 81 | --saturation: 51%; 82 | --lightness: 47%; 83 | } 84 | 85 | .key.correct { 86 | --hue: 115; 87 | --saturation: 29%; 88 | --lightness: 43%; 89 | } 90 | 91 | .guess-grid { 92 | display: grid; 93 | justify-content: center; 94 | align-content: start; 95 | grid-template-columns: repeat(5, 2em); 96 | grid-template-rows: repeat(6, 2em); 97 | gap: .25em; 98 | margin-bottom: 1em; 99 | } 100 | 101 | .tile { 102 | font-size: 1em; 103 | color: white; 104 | border: .05em solid hsl(240, 2%, 23%); 105 | text-transform: uppercase; 106 | font-weight: bold; 107 | display: flex; 108 | justify-content: center; 109 | align-items: center; 110 | user-select: none; 111 | transition: transform 250ms linear; 112 | } 113 | 114 | .tile[data-state="active"] { 115 | border-color: hsl(200, 1%, 34%); 116 | } 117 | 118 | .tile[data-state="wrong"] { 119 | border: none; 120 | background-color: hsl(240, 2%, 23%); 121 | } 122 | 123 | .tile[data-state="wrong-location"] { 124 | border: none; 125 | background-color: hsl(49, 51%, 47%); 126 | } 127 | 128 | .tile[data-state="correct"] { 129 | border: none; 130 | background-color: hsl(115, 29%, 43%); 131 | } 132 | 133 | .tile.shake { 134 | animation: shake 250ms ease-in-out; 135 | } 136 | 137 | .tile.dance { 138 | animation: dance 500ms ease-in-out; 139 | } 140 | 141 | .tile.flip { 142 | transform: rotateX(90deg); 143 | } 144 | 145 | @keyframes shake { 146 | 10% { 147 | transform: translateX(-5%); 148 | } 149 | 150 | 30% { 151 | transform: translateX(5%); 152 | } 153 | 154 | 50% { 155 | transform: translateX(-7.5%); 156 | } 157 | 158 | 70% { 159 | transform: translateX(7.5%); 160 | } 161 | 162 | 90% { 163 | transform: translateX(-5%); 164 | } 165 | 166 | 100% { 167 | transform: translateX(0); 168 | } 169 | } 170 | 171 | @keyframes dance { 172 | 20% { 173 | transform: translateY(-50%); 174 | } 175 | 176 | 40% { 177 | transform: translateY(5%); 178 | } 179 | 180 | 60% { 181 | transform: translateY(-25%); 182 | } 183 | 184 | 80% { 185 | transform: translateY(2.5%); 186 | } 187 | 188 | 90% { 189 | transform: translateY(-5%); 190 | } 191 | 192 | 100% { 193 | transform: translateY(0); 194 | } 195 | } 196 | 197 | .alert-container { 198 | position: fixed; 199 | top: 6vh; 200 | left: 50vw; 201 | transform: translateX(-50%); 202 | z-index: 1; 203 | display: flex; 204 | flex-direction: column; 205 | align-items: center; 206 | } 207 | 208 | .alert { 209 | pointer-events: none; 210 | background-color: hsl(204, 7%, 85%); 211 | padding: .75em; 212 | border-radius: .25em; 213 | opacity: 1; 214 | transition: opacity 500ms ease-in-out; 215 | margin-bottom: .5em; 216 | } 217 | 218 | .alert:last-child { 219 | margin-bottom: 0; 220 | } 221 | 222 | .alert.hide { 223 | opacity: 0; 224 | } 225 | 226 | 227 | .footer { 228 | display: flex; 229 | justify-content: center; 230 | align-items: center; 231 | margin-top: 1.5em; 232 | color: white; 233 | } 234 | 235 | .footer a { 236 | color: hsl(197, 59%, 64%); 237 | text-decoration: none; 238 | .new-game { 239 | width: 10%; 240 | margin: 5% auto 0; 241 | padding: 8px; 242 | transition: display 500ms ease-in-out; 243 | background-color: hsl(115, 29%, 43%); 244 | } 245 | 246 | .new-game.hidden { 247 | display: none; 248 | } -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | import targetWords from "./targetWords.js"; 2 | import dictionary from "./dictionary.js"; 3 | 4 | const WORD_LENGTH = 5; 5 | const FLIP_ANIMATION_DURATION = 500; 6 | const DANCE_ANIMATION_DURATION = 500; 7 | const keyboard = document.querySelector("[data-keyboard]"); 8 | const alertContainer = document.querySelector("[data-alert-container]"); 9 | const guessGrid = document.querySelector("[data-guess-grid]"); 10 | const newGameButton = document.getElementById("newGameButton"); 11 | const offsetFromDate = new Date(2022, 0, 1); 12 | const msOffset = Date.now() - offsetFromDate; 13 | const dayOffset = msOffset / 1000 / 60 / 60 / 24; 14 | let targetWord = targetWords[Math.floor(dayOffset) % targetWords.length]; 15 | const allWords = Array.from(new Set([...targetWords, ...dictionary])); 16 | 17 | startInteraction(); 18 | 19 | function startInteraction() { 20 | newGameButton.classList.add("hidden"); 21 | document.addEventListener("click", handleMouseClick); 22 | document.addEventListener("keydown", handleKeyPress); 23 | } 24 | 25 | function stopInteraction() { 26 | document.removeEventListener("click", handleMouseClick); 27 | document.removeEventListener("keydown", handleKeyPress); 28 | } 29 | 30 | function handleMouseClick(e) { 31 | if (e.target.matches("[data-key]")) { 32 | pressKey(e.target.dataset.key); 33 | return; 34 | } 35 | 36 | if (e.target.matches("[data-enter]")) { 37 | submitGuess(); 38 | return; 39 | } 40 | 41 | if (e.target.matches("[data-delete]")) { 42 | deleteKey(); 43 | return; 44 | } 45 | } 46 | 47 | function handleKeyPress(e) { 48 | if (e.key === "Enter") { 49 | submitGuess(); 50 | return; 51 | } 52 | 53 | if (e.key === "Backspace" || e.key === "Delete") { 54 | deleteKey(); 55 | return; 56 | } 57 | 58 | if (e.key.match(/^[a-z]|[A-Z]$/)) { 59 | pressKey(e.key.toLowerCase()); 60 | return; 61 | } 62 | } 63 | 64 | function pressKey(key) { 65 | const activeTiles = getActiveTiles(); 66 | if (activeTiles.length >= WORD_LENGTH) return; 67 | const nextTile = guessGrid.querySelector(":not([data-letter])"); 68 | nextTile.dataset.letter = key.toLowerCase(); 69 | nextTile.textContent = key; 70 | nextTile.dataset.state = "active"; 71 | } 72 | 73 | function deleteKey() { 74 | const activeTiles = getActiveTiles(); 75 | const lastTile = activeTiles[activeTiles.length - 1]; 76 | if (lastTile == null) return; 77 | lastTile.textContent = ""; 78 | delete lastTile.dataset.state; 79 | delete lastTile.dataset.letter; 80 | } 81 | 82 | function submitGuess() { 83 | const activeTiles = [...getActiveTiles()]; 84 | if (activeTiles.length !== WORD_LENGTH) { 85 | showAlert("Not enough letters"); 86 | shakeTiles(activeTiles); 87 | return; 88 | } 89 | 90 | const guess = activeTiles.reduce((word, tile) => { 91 | return word + tile.dataset.letter; 92 | }, ""); 93 | 94 | if (!allWords.includes(guess)) { 95 | showAlert("Not in word list"); 96 | shakeTiles(activeTiles); 97 | return; 98 | } 99 | 100 | stopInteraction(); 101 | let used = [0, 0, 0, 0, 0]; 102 | let marker = [0, 0, 0, 0, 0]; 103 | activeTiles.forEach((...params) => markCorrect(...params, used, marker)); 104 | activeTiles.forEach((...params) => 105 | markWrongLocation(...params, used, marker) 106 | ); 107 | activeTiles.forEach((...params) => flipTile(...params, guess, marker)); 108 | } 109 | 110 | function markCorrect(tile, index, array, used, marker) { 111 | const letter = tile.dataset.letter; 112 | if (targetWord[index] === letter) { 113 | marker[index] = 1; 114 | used[index] = 1; 115 | } 116 | } 117 | 118 | function markWrongLocation(tile, index, array, used, marker) { 119 | const letter = tile.dataset.letter; 120 | for (let i = 0; i < 5; i++) { 121 | if (targetWord[i] === letter && used[i] === 0) { 122 | marker[index] = 2; 123 | used[i] = 1; 124 | break; 125 | } 126 | } 127 | } 128 | 129 | function flipTile(tile, index, array, guess, marker) { 130 | const letter = tile.dataset.letter; 131 | const key = keyboard.querySelector(`[data-key="${letter}"i]`); 132 | setTimeout(() => { 133 | tile.classList.add("flip"); 134 | }, (index * FLIP_ANIMATION_DURATION) / 2); 135 | 136 | tile.addEventListener( 137 | "transitionend", 138 | () => { 139 | tile.classList.remove("flip"); 140 | if (marker[index] === 1) { 141 | tile.dataset.state = "correct"; 142 | key.classList.add("correct"); 143 | } else if (marker[index] === 2) { 144 | tile.dataset.state = "wrong-location"; 145 | key.classList.add("wrong-location"); 146 | } else { 147 | tile.dataset.state = "wrong"; 148 | key.classList.add("wrong"); 149 | } 150 | 151 | if (index === array.length - 1) { 152 | tile.addEventListener( 153 | "transitionend", 154 | () => { 155 | startInteraction(); 156 | checkWinLose(guess, array); 157 | }, 158 | { once: true } 159 | ); 160 | } 161 | }, 162 | { once: true } 163 | ); 164 | } 165 | 166 | function getActiveTiles() { 167 | return guessGrid.querySelectorAll('[data-state="active"]'); 168 | } 169 | 170 | function showAlert(message, duration = 1000) { 171 | const alert = document.createElement("div"); 172 | alert.textContent = message; 173 | alert.classList.add("alert"); 174 | alertContainer.prepend(alert); 175 | if (duration == null) return; 176 | 177 | setTimeout(() => { 178 | alert.classList.add("hide"); 179 | alert.addEventListener("transitionend", () => { 180 | alert.remove(); 181 | }); 182 | }, duration); 183 | } 184 | 185 | function shakeTiles(tiles) { 186 | tiles.forEach((tile) => { 187 | tile.classList.add("shake"); 188 | tile.addEventListener( 189 | "animationend", 190 | () => { 191 | tile.classList.remove("shake"); 192 | }, 193 | { once: true } 194 | ); 195 | }); 196 | } 197 | 198 | function checkWinLose(guess, tiles) { 199 | if (guess === targetWord) { 200 | showAlert("You Win", 5000); 201 | danceTiles(tiles); 202 | newGameButton.classList.remove("hidden"); 203 | stopInteraction(); 204 | return; 205 | } 206 | 207 | const remainingTiles = guessGrid.querySelectorAll(":not([data-letter])"); 208 | if (remainingTiles.length === 0) { 209 | showAlert(targetWord.toUpperCase(), null); 210 | stopInteraction(); 211 | newGameButton.classList.remove("hidden"); 212 | } 213 | } 214 | 215 | function danceTiles(tiles) { 216 | tiles.forEach((tile, index) => { 217 | setTimeout(() => { 218 | tile.classList.add("dance"); 219 | tile.addEventListener( 220 | "animationend", 221 | () => { 222 | tile.classList.remove("dance"); 223 | }, 224 | { once: true } 225 | ); 226 | }, (index * DANCE_ANIMATION_DURATION) / 5); 227 | }); 228 | } 229 | 230 | newGameButton.addEventListener("click", startNewGame); 231 | 232 | function startNewGame() { 233 | const tiles = Array.from(document.getElementsByClassName("tile")); 234 | tiles.forEach((e) => { 235 | setTimeout(() => { 236 | e.classList.add("flip"); 237 | }, FLIP_ANIMATION_DURATION / 2); 238 | e.addEventListener( 239 | "transitionend", 240 | () => { 241 | e.classList.remove("flip"); 242 | e.textContent = ""; 243 | delete e.dataset.state; 244 | delete e.dataset.letter; 245 | }, 246 | { once: true } 247 | ); 248 | }); 249 | const keys = Array.from(document.getElementsByClassName("key")); 250 | keys.forEach((e) => { 251 | e.classList.remove("correct"); 252 | e.classList.remove("wrong-location"); 253 | e.classList.remove("wrong"); 254 | }); 255 | 256 | targetWord = allWords[Math.floor(Math.random() * allWords.length)]; 257 | startInteraction(); 258 | } 259 | -------------------------------------------------------------------------------- /.replit: -------------------------------------------------------------------------------- 1 | hidden=[".config", ".tutorial", "reference.md"] 2 | 3 | entrypoint="README.md" 4 | 5 | # hosting is currently hardcoded for this language 6 | # [hosting] 7 | # route = "/" 8 | # directory= "/" 9 | 10 | [nix] 11 | channel = "stable-21_11" 12 | 13 | [languages.html] 14 | pattern = "**/*.html" 15 | [languages.html.languageServer] 16 | start = ["vscode-html-language-server", "--stdio"] 17 | [languages.html.languageServer.initializationOptions] 18 | provideFormatter = true 19 | [languages.html.languageServer.configuration.html] 20 | customData = [ ] 21 | autoCreateQuotes = true 22 | autoClosingTags = true 23 | mirrorCursorOnMatchingTag = false 24 | 25 | [languages.html.languageServer.configuration.html.completion] 26 | attributeDefaultValue = "doublequotes" 27 | 28 | [languages.html.languageServer.configuration.html.format] 29 | enable = true 30 | wrapLineLength = 120 31 | unformatted = "wbr" 32 | contentUnformatted = "pre,code,textarea" 33 | indentInnerHtml = false 34 | preserveNewLines = true 35 | indentHandlebars = false 36 | endWithNewline = false 37 | extraLiners = "head, body, /html" 38 | wrapAttributes = "auto" 39 | templating = false 40 | unformattedContentDelimiter = "" 41 | 42 | [languages.html.languageServer.configuration.html.suggest] 43 | html5 = true 44 | 45 | [languages.html.languageServer.configuration.html.validate] 46 | scripts = true 47 | styles = true 48 | 49 | [languages.html.languageServer.configuration.html.hover] 50 | documentation = true 51 | references = true 52 | 53 | [languages.html.languageServer.configuration.html.trace] 54 | server = "off" 55 | 56 | [languages.javascript] 57 | pattern = "**/{*.js,*.jsx,*.ts,*.tsx,*.mjs,*.cjs}" 58 | [languages.javascript.languageServer] 59 | start = ["typescript-language-server", "--stdio"] 60 | 61 | # TODO autocomplete relies on snippet support, which we don't advertise to LSP servers. 62 | # For now CSS autocomplete will use built-in codemirror, which is not perfect but good enough 63 | [languages.css] 64 | pattern = "**/{*.less,*.scss,*.css}" 65 | [languages.css.languageServer] 66 | start = ["vscode-css-language-server", "--stdio"] 67 | [languages.css.languageServer.configuration.css] 68 | customData = [ ] 69 | validate = true 70 | 71 | [languages.css.languageServer.configuration.css.completion] 72 | triggerPropertyValueCompletion = true 73 | completePropertyWithSemicolon = true 74 | 75 | [languages.css.languageServer.configuration.css.hover] 76 | documentation = true 77 | references = true 78 | 79 | [languages.css.languageServer.configuration.css.lint] 80 | # Configure linting 81 | # ignore = don't show any warning or error 82 | # warning = show yellow underline 83 | # error = show red underline 84 | argumentsInColorFunction = "error" # Invalid number of parameters 85 | boxModel = "ignore" # Do not use width or height when using padding or border 86 | compatibleVendorPrefixes = "ignore" # When using a vendor-specific prefix make sure to also include all other vendor-specific properties" 87 | duplicateProperties = "warning" # Do not use duplicate style definitions 88 | emptyRules = "warning" # Do not use empty rulesets 89 | float = "ignore" # Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes. 90 | fontFaceProperties = "warning" # @font-face rule must define 'src' and 'font-family' properties 91 | hexColorLength = "error" # Hex colors must consist of three, four, six or eight hex numbers 92 | idSelector = "ignore" # Selectors should not contain IDs because these rules are too tightly coupled with the HTML. 93 | ieHack = "ignore" # IE hacks are only necessary when supporting IE7 and older 94 | important = "ignore" # Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored. 95 | importStatement = "ignore" # Import statements do not load in parallel 96 | propertyIgnoredDueToDisplay = "warning" # Property is ignored due to the display 97 | universalSelector = "ignore" # The universal selector (*) is known to be slow 98 | unknownAtRules = "warning" # Unknown at-rule 99 | unknownProperties = "warning" # Unknown property. 100 | validProperties = [ ] # add some properties that the linter doesn't know about 101 | unknownVendorSpecificProperties = "ignore" # Unknown vendor specific property. 102 | vendorPrefix = "warning" # When using a vendor-specific prefix also include the standard property 103 | zeroUnits = "ignore" # No unit for zero needed 104 | 105 | [languages.css.languageServer.configuration.css.trace] 106 | server = "off" 107 | 108 | [languages.css.languageServer.configuration.scss] 109 | validate = true 110 | 111 | [languages.css.languageServer.configuration.scss.completion] 112 | triggerPropertyValueCompletion = true 113 | completePropertyWithSemicolon = true 114 | 115 | [languages.css.languageServer.configuration.scss.hover] 116 | documentation = true 117 | references = true 118 | 119 | [languages.css.languageServer.configuration.scss.lint] 120 | # Configure linting 121 | # ignore = don't show any warning or error 122 | # warning = show yellow underline 123 | # error = show red underline 124 | argumentsInColorFunction = "error" # Invalid number of parameters 125 | boxModel = "ignore" # Do not use width or height when using padding or border 126 | compatibleVendorPrefixes = "ignore" # When using a vendor-specific prefix make sure to also include all other vendor-specific properties" 127 | duplicateProperties = "warning" # Do not use duplicate style definitions 128 | emptyRules = "warning" # Do not use empty rulesets 129 | float = "ignore" # Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes. 130 | fontFaceProperties = "warning" # @font-face rule must define 'src' and 'font-family' properties 131 | hexColorLength = "error" # Hex colors must consist of three, four, six or eight hex numbers 132 | idSelector = "ignore" # Selectors should not contain IDs because these rules are too tightly coupled with the HTML. 133 | ieHack = "ignore" # IE hacks are only necessary when supporting IE7 and older 134 | important = "ignore" # Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored. 135 | importStatement = "ignore" # Import statements do not load in parallel 136 | propertyIgnoredDueToDisplay = "warning" # Property is ignored due to the display 137 | universalSelector = "ignore" # The universal selector (*) is known to be slow 138 | unknownAtRules = "warning" # Unknown at-rule 139 | unknownProperties = "warning" # Unknown property. 140 | validProperties = [ ] # add some properties that the linter doesn't know about 141 | unknownVendorSpecificProperties = "ignore" # Unknown vendor specific property. 142 | vendorPrefix = "warning" # When using a vendor-specific prefix also include the standard property 143 | zeroUnits = "ignore" # No unit for zero needed" 144 | 145 | [languages.css.languageServer.configuration.less] 146 | validate = true 147 | 148 | [languages.css.languageServer.configuration.less.completion] 149 | triggerPropertyValueCompletion = true 150 | completePropertyWithSemicolon = true 151 | 152 | [languages.css.languageServer.configuration.less.hover] 153 | documentation = true 154 | references = true 155 | 156 | [languages.css.languageServer.configuration.less.lint] 157 | # Configure linting 158 | # ignore = don't show any warning or error 159 | # warning = show yellow underline 160 | # error = show red underline 161 | argumentsInColorFunction = "error" # Invalid number of parameters 162 | boxModel = "ignore" # Do not use width or height when using padding or border 163 | compatibleVendorPrefixes = "ignore" # When using a vendor-specific prefix make sure to also include all other vendor-specific properties" 164 | duplicateProperties = "warning" # Do not use duplicate style definitions 165 | emptyRules = "warning" # Do not use empty rulesets 166 | float = "ignore" # Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes. 167 | fontFaceProperties = "warning" # @font-face rule must define 'src' and 'font-family' properties 168 | hexColorLength = "error" # Hex colors must consist of three, four, six or eight hex numbers 169 | idSelector = "ignore" # Selectors should not contain IDs because these rules are too tightly coupled with the HTML. 170 | ieHack = "ignore" # IE hacks are only necessary when supporting IE7 and older 171 | important = "ignore" # Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored. 172 | importStatement = "ignore" # Import statements do not load in parallel 173 | propertyIgnoredDueToDisplay = "warning" # Property is ignored due to the display 174 | universalSelector = "ignore" # The universal selector (*) is known to be slow 175 | unknownAtRules = "warning" # Unknown at-rule 176 | unknownProperties = "warning" # Unknown property. 177 | validProperties = [ ] # add some properties that the linter doesn't know about 178 | unknownVendorSpecificProperties = "ignore" # Unknown vendor specific property. 179 | vendorPrefix = "warning" # When using a vendor-specific prefix also include the standard property 180 | zeroUnits = "ignore" # No unit for zero needed" 181 | --------------------------------------------------------------------------------