Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,811 changes: 4,811 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"postcss": "8.4.31",
"postcss-clean": "1.1.0",
"postcss-import": "13.0.0",
"postcss-load-config": "3.0.0",
"postcss-load-config": "^2.1.0",
"reaver": "2.0.0",
"rimraf": "3.0.2",
"rollup": "2.33.3",
Expand All @@ -31,6 +31,8 @@
},
"dependencies": {
"@mattflow/sudoku-solver": "2.2.0",
"axios": "^1.9.0",
"cheerio": "^1.0.0",
"fake-sudoku-puzzle-generator": "1.2.1",
"sirv-cli": "1.0.0",
"tailwindcss": "1.9.6"
Expand Down
143 changes: 130 additions & 13 deletions src/components/Board/Candidates.svelte
Original file line number Diff line number Diff line change
@@ -1,25 +1,142 @@
<script>
import { CANDIDATE_COORDS } from '@sudoku/constants';
import game from '@sudoku/game';
import { validateSencode } from '@sudoku/sencode';
import { modal } from '@sudoku/stores/modal';
import { slide, fade } from 'svelte/transition';
import { DIFFICULTIES, DROPDOWN_DURATION, DIFFICULTY_CUSTOM } from '@sudoku/constants';
import { difficulty } from '@sudoku/stores/difficulty';

export let candidates = [];
let dropdownVisible = false;

function handleDifficulty(difficultyValue) {
dropdownVisible = false;
game.pause();

modal.show('confirm', {
title: 'New Game',
text: 'Start new game with difficulty "' + DIFFICULTIES[difficultyValue] + '"?',
button: 'Continue',
onHide: game.resume,
callback: () => {
game.startNew(difficultyValue);
},
});
}

function handleCreateOwn() {
dropdownVisible = false;
game.pause();

modal.show('confirm', {
title: 'Create Own',
text: 'Switch to the creator mode to create your own Sudoku puzzle?',
button: 'Continue',
onHide: game.resume,
callback: () => {
//game.startCreatorMode();
},
});
}

function handleEnterCode() {
dropdownVisible = false;
game.pause();

modal.show('prompt', {
title: 'Enter Code',
text: 'Please enter the code of the Sudoku puzzle you want to play:',
fontMono: true,
button: 'Start',
onHide: game.resume,
callback: (value) => {
game.startCustom(value);
},
validate: validateSencode
});
}

function showDropdown() {
dropdownVisible = true;
game.pause();
}

function hideDropdown() {
dropdownVisible = false;
setTimeout(game.resume, DROPDOWN_DURATION);
}
</script>

<div class="candidate-grid">
{#each CANDIDATE_COORDS as [row, col], index}
<div class="candidate row-start-{row} col-start-{col}"
class:invisible={!candidates.includes(index + 1)}
class:visible={candidates.includes(index + 1)}>
{index + 1}
<div class="dropdown">
<button class="dropdown-button" on:click={dropdownVisible ? hideDropdown : showDropdown} title="{dropdownVisible ? 'Close' : 'Open'} Menu">
<svg class="icon-outline mr-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8h16M4 16h12" />
</svg>

<span class="text-2xl tracking-wider">{$difficulty === DIFFICULTY_CUSTOM ? 'Custom' : DIFFICULTIES[$difficulty]}</span>
</button>

{#if dropdownVisible}
<button transition:fade={{duration: DROPDOWN_DURATION}} class="dropdown-overlay" on:click={hideDropdown} tabindex="-1"></button>

<div transition:slide={{duration: DROPDOWN_DURATION}} class="dropdown-menu">
{#each Object.entries(DIFFICULTIES) as [difficultyValue, difficultyLabel]}
<a class="dropdown-item" on:click|preventDefault={() => handleDifficulty(difficultyValue)} href="/difficulty-{difficultyValue}" title="Set difficulty to '{difficultyLabel}'">
<svg class="icon-solid" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
</svg>

<span class="align-middle">{difficultyLabel}</span>
</a>
{/each}

<hr class="my-1">

<a class="dropdown-item" on:click|preventDefault={handleCreateOwn} href="/create" title="Create your own Sudoku puzzle">
<svg class="icon-solid" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z" clip-rule="evenodd" />
</svg>

<span class="align-middle">Create Own</span>
</a>
<a class="dropdown-item" on:click|preventDefault={handleEnterCode} href="/enter-code" title="Enter a Sudoku puzzle code from a friend">
<svg class="icon-solid" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" />
<path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd" />
</svg>

<span class="align-middle">Enter Code</span>
</a>
</div>
{/each}
{/if}
</div>

<style>
.candidate-grid {
@apply grid h-full w-full p-1;
.dropdown {
@apply relative;
}

.dropdown-button {
@apply relative z-30 block flex outline-none items-center;
}

.dropdown-overlay {
@apply fixed z-20 inset-0 h-full w-full bg-black bg-opacity-50 outline-none cursor-default;
}

.dropdown-menu {
@apply absolute z-30 left-0 mt-2 py-2 w-48 bg-white rounded-lg shadow-xl;
}


.dropdown-item {
@apply block px-4 py-2 text-gray-800 transition-colors duration-100 text-lg tracking-wide font-semibold;
}

.dropdown-item:hover {
@apply bg-primary text-white;
}

.candidate {
@apply h-full w-full row-end-auto col-end-auto leading-full;
.dropdown-item:active {
@apply bg-primary-dark;
}
</style>
Loading