Compare commits
2 Commits
775aa83134
...
a56e33b9f2
Author | SHA1 | Date |
---|---|---|
blek | a56e33b9f2 | |
blek | 40eac5d01f |
|
@ -2,5 +2,5 @@
|
|||
<p align="center">
|
||||
<img src="https://jenkins.blek.codes/job/bWordle/badge/icon?style=plastic"></img>
|
||||
</p>
|
||||
OpenWordle is a completely open source and lightweight wordle game with no runtime dependencies
|
||||
OpenWordle is a completely open source and lightweight wordle game with very minimal set of runtime dependencies
|
||||
|
||||
|
|
|
@ -19,5 +19,9 @@
|
|||
"typescript": "^5.0.2",
|
||||
"vite": "^4.4.5",
|
||||
"vite-plugin-compression": "^0.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"copy-to-clipboard": "^3.3.3",
|
||||
"qr-creator": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
import { isIn, loadDict } from "./dictionary";
|
||||
import { onMount } from "svelte";
|
||||
import Keyboard from "./Keyboard.svelte";
|
||||
import GameCreator from "./GameCreator.svelte";
|
||||
import { decode } from "./lib/cipher";
|
||||
|
||||
let targets = getForNWord(5);
|
||||
|
||||
|
@ -23,12 +25,22 @@
|
|||
|
||||
let loading = true;
|
||||
let not_a_word = false;
|
||||
let game_creator = false;
|
||||
|
||||
let green_letters: string[] = [];
|
||||
let yellow_letters: string[] = [];
|
||||
let unfit_letters: string[] = [];
|
||||
|
||||
console.log(word);
|
||||
(
|
||||
function() {
|
||||
const urlprops = new URLSearchParams(window.location.search);
|
||||
const challenge = urlprops.get('challenge');
|
||||
if (challenge !== null) {
|
||||
word = decode(atob(decodeURIComponent(challenge)));
|
||||
console.log(word)
|
||||
}
|
||||
}
|
||||
)()
|
||||
|
||||
onMount(async () => {
|
||||
await loadDict();
|
||||
|
@ -130,6 +142,8 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<GameCreator bind:show={game_creator} />
|
||||
|
||||
{#if not_a_word}
|
||||
<Modal show animate={false}>
|
||||
<ModalTitle>
|
||||
|
@ -174,6 +188,10 @@
|
|||
Give up
|
||||
</button>
|
||||
|
||||
<button on:click={() => {game_creator = true}}>
|
||||
Create a game
|
||||
</button>
|
||||
|
||||
<p style='line-height:0;margin-top:48px'>
|
||||
{#each guessed as g1, i}
|
||||
{#each g1 as letter, ii}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<script lang='ts'>
|
||||
import { onMount } from "svelte";
|
||||
import Modal from "./modal/Modal.svelte";
|
||||
import ModalButton from "./modal/ModalButton.svelte";
|
||||
import ModalContent from "./modal/ModalContent.svelte";
|
||||
import ModalFooter from "./modal/ModalFooter.svelte";
|
||||
import ModalTitle from "./modal/ModalTitle.svelte";
|
||||
import { encode } from "./lib/cipher";
|
||||
import { getRandom } from "./targets";
|
||||
|
||||
export let show = false;
|
||||
|
||||
let word = getRandom(5);
|
||||
let qrurl: string | false = false;
|
||||
let wordurl = '';
|
||||
let qrcanvas: HTMLCanvasElement;
|
||||
|
||||
async function upd_qr() {
|
||||
if (word == '') return;
|
||||
if (!qrcanvas) return;
|
||||
wordurl = `${window.location.protocol}//${window.location.host}?challenge=${encodeURIComponent(btoa(encode(word)))}`;
|
||||
const QrCreator = (await import('qr-creator')).default;
|
||||
|
||||
QrCreator.render({
|
||||
text: wordurl,
|
||||
radius: 0.5,
|
||||
ecLevel: 'L',
|
||||
fill: '#000000',
|
||||
background: '#ffffff',
|
||||
size: 120
|
||||
}, qrcanvas);
|
||||
}
|
||||
|
||||
async function copylink() {
|
||||
const copy = (await import('copy-to-clipboard')).default;
|
||||
copy(wordurl);
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
await upd_qr();
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if show}
|
||||
<Modal show>
|
||||
<ModalTitle>
|
||||
Create a game
|
||||
</ModalTitle>
|
||||
<ModalContent>
|
||||
<p>
|
||||
Word:
|
||||
<input type='text' bind:value={word} on:input={upd_qr}>
|
||||
</p>
|
||||
<p style='min-height:160px'>
|
||||
<span style='border-radius:12px;padding:20px;background:white;display:inline-block'>
|
||||
<canvas bind:this={qrcanvas} width="120px" height="122px" style='border-radius:4px' />
|
||||
</span>
|
||||
</p>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<ModalButton style='width:50%;border-right:0;border-radius:0 0 0 16px' onclick={() => {show = false; word = getRandom(5); upd_qr()}}>
|
||||
Close
|
||||
</ModalButton>
|
||||
<ModalButton style='width:50%;border-radius:0 0 16px 0' onclick={copylink}>
|
||||
Copy link
|
||||
</ModalButton>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
{/if}
|
12
src/app.css
12
src/app.css
|
@ -43,6 +43,18 @@ button:active {
|
|||
background: #161616;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
background: #181818;
|
||||
border: 1px solid #343434;
|
||||
border-radius: 6px;
|
||||
margin: 0 4px;
|
||||
padding: 4px 6px;
|
||||
outline: none;
|
||||
min-width: 80px;
|
||||
width: 80px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import targets from "./targets";
|
||||
|
||||
let dict: string[] = [];
|
||||
let dict_loaded = false;
|
||||
|
||||
export async function loadDict(onprogress?: {(data: { loaded: number, total: number }): void}) {
|
||||
|
||||
if (dict_loaded) return dict;
|
||||
|
||||
const req = await fetch('/dictionary.csv', {
|
||||
cache: 'force-cache'
|
||||
});
|
||||
|
@ -24,6 +29,7 @@ export async function loadDict(onprogress?: {(data: { loaded: number, total: num
|
|||
}
|
||||
}))
|
||||
dict = data.split(',');
|
||||
dict = [ ...targets, ...dict ];
|
||||
dict_loaded = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import { random } from "./random";
|
||||
|
||||
export function encode(word: string) {
|
||||
let out = '';
|
||||
for (const letter of word) {
|
||||
out += String.fromCharCode(random(32, 128)) + letter;
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
export function decode(ciphertext: string) {
|
||||
let out = '';
|
||||
for (let i = 0; i != ciphertext.length; i++) {
|
||||
if (i % 2 == 1) {
|
||||
out += ciphertext[i];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
globalThis.encode = encode;
|
||||
globalThis.decode = decode;
|
|
@ -11,4 +11,14 @@ export function getForNWord(len: number) {
|
|||
return out
|
||||
}
|
||||
|
||||
export function getRandom(len: number | null = null) {
|
||||
const dataset = len ? getForNWord(len) : targets;
|
||||
for (const target of dataset) {
|
||||
if (random(0, Math.floor(dataset.length * 0.5)) == 0) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
return dataset[0];
|
||||
}
|
||||
|
||||
export default targets
|
|
@ -1,3 +1,4 @@
|
|||
/// <reference types="svelte" />
|
||||
/// <reference types="vite/client" />
|
||||
const TARGETS: string
|
||||
const TARGETS: string;
|
||||
declare module 'qr-creator';
|
17
yarn.lock
17
yarn.lock
|
@ -333,6 +333,13 @@ concat-map@0.0.1:
|
|||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
copy-to-clipboard@^3.3.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0"
|
||||
integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==
|
||||
dependencies:
|
||||
toggle-selection "^1.0.6"
|
||||
|
||||
css-tree@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20"
|
||||
|
@ -670,6 +677,11 @@ postcss@^8.4.27:
|
|||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
qr-creator@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/qr-creator/-/qr-creator-1.0.0.tgz#f350a8f0b5be02bd1fc1ef133a038a06ef8bc5ef"
|
||||
integrity sha512-C0cqfbS1P5hfqN4NhsYsUXePlk9BO+a45bAQ3xLYjBL3bOIFzoVEjs79Fado9u9BPBD3buHi3+vY+C8tHh4qMQ==
|
||||
|
||||
queue-microtask@^1.2.2:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||
|
@ -815,6 +827,11 @@ to-regex-range@^5.0.1:
|
|||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
toggle-selection@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
|
||||
integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==
|
||||
|
||||
tslib@^2.6.0:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
|
||||
|
|
Loading…
Reference in New Issue