feat(web): responsive design
- fix mobile accessibility
This commit is contained in:
+115
-83
@@ -15,7 +15,7 @@
|
||||
} from "./solver/types.ts";
|
||||
import SolverOutput from "./components/SolverOutput.svelte";
|
||||
import { FolderGit2 } from "@lucide/svelte";
|
||||
import { tick } from "svelte";
|
||||
import { tick, onMount } from "svelte";
|
||||
|
||||
let guesses = $state([
|
||||
{
|
||||
@@ -45,6 +45,19 @@
|
||||
let w_lines: WordleLine[] = $state([]);
|
||||
let cursor = $state(0);
|
||||
|
||||
let is_desktop = $state(false);
|
||||
|
||||
onMount(() => {
|
||||
const update = () => {
|
||||
is_desktop = window.innerWidth >= 768;
|
||||
};
|
||||
|
||||
update();
|
||||
window.addEventListener("resize", update);
|
||||
|
||||
return () => window.removeEventListener("resize", update);
|
||||
});
|
||||
|
||||
async function toggleSolver() {
|
||||
if (solving) {
|
||||
await stopSolver();
|
||||
@@ -136,92 +149,111 @@
|
||||
<svelte:window onkeydown={handleKey} />
|
||||
|
||||
<div
|
||||
class="min-h-screen w-full max-w-full
|
||||
class="h-dvh w-full max-w-full
|
||||
bg-zinc-950 text-zinc-100
|
||||
flex flex-wrap
|
||||
items-center justify-center p-10 gap-2
|
||||
overflow-x-hidden
|
||||
select-none
|
||||
"
|
||||
"
|
||||
>
|
||||
<a
|
||||
class="fixed top-4 right-4"
|
||||
href="https://git.jroeger.de/jonas/wordle-solver-rs"
|
||||
target="_blank"
|
||||
<div
|
||||
class="h-full overflow-y-auto
|
||||
flex flex-wrap md:flex-row
|
||||
items-center justify-center p-2 md:p-10 gap-4
|
||||
overflow-hidden select-none"
|
||||
>
|
||||
<FolderGit2 />
|
||||
</a>
|
||||
<div class="text-center">
|
||||
<h1 class="mb-4 text-3xl font-bold">Wordle Solver</h1>
|
||||
|
||||
<p class="text-sm text-zinc-500">
|
||||
Use Wordle-Answers:
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={use_default_wordle_answers}
|
||||
onfocus={(e) => {
|
||||
if (e.currentTarget) {
|
||||
e.currentTarget.blur();
|
||||
}
|
||||
}}
|
||||
onchange={reset}
|
||||
/>
|
||||
</p>
|
||||
|
||||
<p class="mt-0 text-sm text-zinc-500">
|
||||
{#await solution_space}
|
||||
loading
|
||||
{:then s}
|
||||
Solution-space: {s.size}, Uncertainty: {s.uncertainty.toFixed(
|
||||
2,
|
||||
)}bits
|
||||
{:catch e}
|
||||
{e}
|
||||
{/await}
|
||||
</p>
|
||||
|
||||
<div class="ml-16 mt-2 flex flex-col gap-2">
|
||||
{#each guesses as g, i (g)}
|
||||
<WordleLine
|
||||
active={i === guesses.length - 1}
|
||||
on_guess_pressed={i === guesses.length - 1 ? doGuess : null}
|
||||
bind:this={w_lines[i]}
|
||||
bind:cursor
|
||||
bind:letters={guesses[i].letters}
|
||||
bind:colors={guesses[i].colors}
|
||||
info_gained={infos_gained[i]}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<p class="mt-4 text-sm text-zinc-500 mx-auto w-3/4">
|
||||
Type letters · ← → navigate · Space cycle color · Backspace delete ·
|
||||
Enter apply · Shift+Enter solve · Escape abort solver · Ctrl+Esc
|
||||
reset
|
||||
</p>
|
||||
<button
|
||||
tabindex="-1"
|
||||
class="mt-2 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full"
|
||||
onclick={(e) => {
|
||||
e.currentTarget.blur();
|
||||
toggleSolver();
|
||||
}}
|
||||
<a
|
||||
class="fixed top-4 right-4"
|
||||
href="https://git.jroeger.de/jonas/wordle-solver-rs"
|
||||
target="_blank"
|
||||
>
|
||||
{#if solving}
|
||||
Cancel
|
||||
{:else}
|
||||
Solve
|
||||
<FolderGit2 />
|
||||
</a>
|
||||
<div class="text-center">
|
||||
<h1 class="mb-4 text-3xl font-bold">Wordle Solver</h1>
|
||||
|
||||
<p class="text-sm text-zinc-500">
|
||||
Use Wordle-Answers:
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={use_default_wordle_answers}
|
||||
onfocus={(e) => {
|
||||
if (e.currentTarget) {
|
||||
e.currentTarget.blur();
|
||||
}
|
||||
}}
|
||||
onchange={reset}
|
||||
/>
|
||||
</p>
|
||||
|
||||
<p class="mt-0 text-sm text-zinc-500">
|
||||
{#await solution_space}
|
||||
loading
|
||||
{:then s}
|
||||
Solution-space: {s.size}, Uncertainty: {s.uncertainty.toFixed(
|
||||
2,
|
||||
)}bits
|
||||
{:catch e}
|
||||
{e}
|
||||
{/await}
|
||||
</p>
|
||||
|
||||
<div class="mt-2 flex flex-col gap-2">
|
||||
{#each guesses as g, i (g)}
|
||||
<WordleLine
|
||||
active={i === guesses.length - 1}
|
||||
on_guess_pressed={i === guesses.length - 1
|
||||
? doGuess
|
||||
: null}
|
||||
bind:this={w_lines[i]}
|
||||
bind:cursor
|
||||
bind:letters={guesses[i].letters}
|
||||
bind:colors={guesses[i].colors}
|
||||
info_gained={infos_gained[i]}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{#if is_desktop}
|
||||
<p class="mt-4 text-sm text-zinc-500 mx-auto w-3/4">
|
||||
Type letters · ← → navigate · Space cycle color · Backspace
|
||||
delete · Enter apply · Shift+Enter solve · Escape abort
|
||||
solver · Ctrl+Esc reset
|
||||
</p>
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
tabindex="-1"
|
||||
class="mt-4 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full"
|
||||
onclick={(e) => {
|
||||
e.currentTarget.blur();
|
||||
toggleSolver();
|
||||
}}
|
||||
>
|
||||
{#if solving}
|
||||
Cancel
|
||||
{:else}
|
||||
Solve
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
{#if best_words}
|
||||
<SolverOutput
|
||||
data={best_words}
|
||||
progress={best_words_progress}
|
||||
insert_guess={(g) => {
|
||||
guesses[guesses.length - 1].letters = g;
|
||||
}}
|
||||
bind:solving
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{#if best_words}
|
||||
<SolverOutput
|
||||
data={best_words}
|
||||
progress={best_words_progress}
|
||||
insert_guess={(g) => {
|
||||
guesses[guesses.length - 1].letters = g;
|
||||
}}
|
||||
bind:solving
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:global(body) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
overscroll-behavior: none;
|
||||
background: #09090b;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
if (event.key === "Backspace") {
|
||||
if (letters[cursor] === "" && cursor > 0) {
|
||||
cursor--;
|
||||
inputs[cursor].focus();
|
||||
}
|
||||
|
||||
if (active) {
|
||||
@@ -69,7 +70,7 @@
|
||||
disabled={!active}
|
||||
tabindex="-1"
|
||||
class="
|
||||
flex h-16 w-16 items-center justify-center
|
||||
flex aspect-square max-w-16 w-1/6 items-center justify-center
|
||||
rounded-lg border-2
|
||||
text-3xl font-bold
|
||||
transition-all text-center caret-transparent
|
||||
@@ -111,7 +112,7 @@
|
||||
/>
|
||||
{/each}
|
||||
<span
|
||||
class="w-16 text-sm text-zinc-500 self-center flex items-center justify-center"
|
||||
class="max-w-14 w-1/6 text-sm text-zinc-500 self-center flex items-center justify-center"
|
||||
onclick={info_gained === null ? on_guess_pressed : null}
|
||||
>
|
||||
{#if info_gained === null}
|
||||
|
||||
Reference in New Issue
Block a user