chore: format with prettier
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
3e4434c0bc
commit
b2d88bd1c2
14 changed files with 324 additions and 283 deletions
|
@ -21,6 +21,6 @@ module.exports = {
|
|||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
},
|
||||
settings: {
|
||||
jest: { version: 29 }
|
||||
}
|
||||
jest: { version: 29 },
|
||||
},
|
||||
};
|
||||
|
|
|
@ -12,8 +12,11 @@
|
|||
sizes="180x180"
|
||||
/>
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=ubuntu:500" rel="stylesheet" />
|
||||
<link rel="preconnect" href="https://fonts.bunny.net" />
|
||||
<link
|
||||
href="https://fonts.bunny.net/css?family=ubuntu:500"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
10
src/app.css
10
src/app.css
|
@ -110,7 +110,7 @@ button {
|
|||
}
|
||||
|
||||
button:hover {
|
||||
filter: brightness(.8);
|
||||
filter: brightness(0.8);
|
||||
}
|
||||
|
||||
button.primary {
|
||||
|
@ -126,7 +126,7 @@ button.warning {
|
|||
}
|
||||
|
||||
button:disabled {
|
||||
filter: saturate(25%) brightness(.85);
|
||||
filter: saturate(25%) brightness(0.85);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ a.warning {
|
|||
|
||||
input {
|
||||
margin: 8px 0;
|
||||
background-color: rgba(128, 128, 128, .25);
|
||||
background-color: rgba(128, 128, 128, 0.25);
|
||||
color: white;
|
||||
border: #888 2px solid;
|
||||
padding: 8px;
|
||||
|
@ -153,8 +153,8 @@ input {
|
|||
font-size: medium;
|
||||
}
|
||||
|
||||
input[type="text"]:focus-visible,
|
||||
input[type="password"]:focus-visible {
|
||||
input[type='text']:focus-visible,
|
||||
input[type='password']:focus-visible {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,11 @@ export function App() {
|
|||
<main>
|
||||
<h1>Secret Santa</h1>
|
||||
|
||||
{shuffled ? <DrawName names={shuffled} /> : <EnterNames start={start} names={names} />}
|
||||
{shuffled ? (
|
||||
<DrawName names={shuffled} />
|
||||
) : (
|
||||
<EnterNames start={start} names={names} />
|
||||
)}
|
||||
</main>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { render } from 'preact'
|
||||
import { App } from './app'
|
||||
import './index.css'
|
||||
import { render } from 'preact';
|
||||
import { App } from './app';
|
||||
import './index.css';
|
||||
|
||||
render(<App />, document.getElementById('app') as HTMLElement)
|
||||
render(<App />, document.getElementById('app') as HTMLElement);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { FunctionComponent } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
import { useWindowEvent } from "../util";
|
||||
import { FunctionComponent } from 'preact';
|
||||
import { useState } from 'preact/hooks';
|
||||
import { useWindowEvent } from '../util';
|
||||
|
||||
interface Props {
|
||||
names: [string, string][];
|
||||
|
@ -14,34 +14,44 @@ const DrawName: FunctionComponent<Props> = ({ names }) => {
|
|||
if (e.button !== 0) return;
|
||||
|
||||
if (currentPerson !== null) {
|
||||
setCompleted(completed => [...completed, currentPerson])
|
||||
setCompleted((completed) => [...completed, currentPerson]);
|
||||
setCurrentPerson(null);
|
||||
}
|
||||
});
|
||||
|
||||
if (currentPerson === null) {
|
||||
if (completed.length === names.length) {
|
||||
return <>
|
||||
<h2>
|
||||
All done!
|
||||
</h2>
|
||||
return (
|
||||
<>
|
||||
<h2>All done!</h2>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <>
|
||||
<div class="button-group">
|
||||
return (
|
||||
<>
|
||||
<div class='button-group'>
|
||||
{names.map(([name], i) => {
|
||||
if (completed.includes(i)) return null;
|
||||
return <button key={`${i}-${name}`} class="primary" onClick={() => setCurrentPerson(i)}>{name}</button>;
|
||||
return (
|
||||
<button
|
||||
key={`${i}-${name}`}
|
||||
class='primary'
|
||||
onClick={() => setCurrentPerson(i)}
|
||||
>
|
||||
{name}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return <>
|
||||
<div class="drawn-name">
|
||||
{names[currentPerson][1]}
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
<div class='drawn-name'>{names[currentPerson][1]}</div>
|
||||
</>
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default DrawName;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Signal } from "@preact/signals";
|
||||
import { FunctionComponent } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
import { Signal } from '@preact/signals';
|
||||
import { FunctionComponent } from 'preact';
|
||||
import { useState } from 'preact/hooks';
|
||||
|
||||
interface Props {
|
||||
names: Signal<string[]>;
|
||||
|
@ -20,19 +20,22 @@ const EnterNames: FunctionComponent<Props> = ({ names, start }) => {
|
|||
setName('');
|
||||
}
|
||||
|
||||
return <>
|
||||
return (
|
||||
<>
|
||||
<ul>
|
||||
{names.value.map((name, i) => <li key={`${i}-${name}`}>
|
||||
{name}
|
||||
</li>)}
|
||||
{names.value.map((name, i) => (
|
||||
<li key={`${i}-${name}`}>{name}</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Name..."
|
||||
type='text'
|
||||
placeholder='Name...'
|
||||
value={name}
|
||||
onInput={(e) => setName((e.target! as HTMLInputElement).value)}
|
||||
onInput={(e) =>
|
||||
setName((e.target! as HTMLInputElement).value)
|
||||
}
|
||||
onKeyPress={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
addName();
|
||||
|
@ -41,12 +44,21 @@ const EnterNames: FunctionComponent<Props> = ({ names, start }) => {
|
|||
}}
|
||||
/>
|
||||
|
||||
<div class="button-row">
|
||||
<button class="primary" onClick={addName}>Add name</button>
|
||||
<button class='confirm' disabled={names.value.length <= 1} onClick={start}>Start drawing</button>
|
||||
<div class='button-row'>
|
||||
<button class='primary' onClick={addName}>
|
||||
Add name
|
||||
</button>
|
||||
<button
|
||||
class='confirm'
|
||||
disabled={names.value.length <= 1}
|
||||
onClick={start}
|
||||
>
|
||||
Start drawing
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default EnterNames;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// https://stackoverflow.com/a/2450976
|
||||
function shuffle<T>(array: T[]) {
|
||||
let currentIndex = array.length, randomIndex;
|
||||
let currentIndex = array.length,
|
||||
randomIndex: number;
|
||||
|
||||
// While there remain elements to shuffle.
|
||||
while (currentIndex != 0) {
|
||||
|
@ -9,7 +10,10 @@ function shuffle<T>(array: T[]) {
|
|||
currentIndex--;
|
||||
|
||||
// And swap it with the current element.
|
||||
[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
|
||||
[array[currentIndex], array[randomIndex]] = [
|
||||
array[randomIndex],
|
||||
array[currentIndex],
|
||||
];
|
||||
}
|
||||
|
||||
return array;
|
||||
|
@ -44,7 +48,9 @@ function nonEqualShuffle<T>(input: T[]): T[] {
|
|||
return nw;
|
||||
}
|
||||
|
||||
export function buildNameMap(names: string[]): [person: string, target: string][] {
|
||||
export function buildNameMap(
|
||||
names: string[]
|
||||
): [person: string, target: string][] {
|
||||
const ret: [string, string][] = [];
|
||||
|
||||
const shuffled = nonEqualShuffle(names);
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import { useEffect } from "preact/hooks";
|
||||
import { useEffect } from 'preact/hooks';
|
||||
|
||||
export function useWindowEvent<K extends keyof WindowEventMap>(type: K, listener: (this: Window, ev: WindowEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void {
|
||||
export function useWindowEvent<K extends keyof WindowEventMap>(
|
||||
type: K,
|
||||
listener: (this: Window, ev: WindowEventMap[K]) => void,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): void {
|
||||
useEffect(() => {
|
||||
window.addEventListener(type, listener, options);
|
||||
return () => window.removeEventListener(type, listener);
|
||||
|
|
|
@ -2,7 +2,9 @@ import { expect, test } from 'vitest';
|
|||
import { buildNameMap } from '../src/shuffle';
|
||||
|
||||
test('shuffle does not include matching pairs', () => {
|
||||
const names = Array(10).fill(null).map((_, i) => `Test ${i}`);
|
||||
const names = Array(10)
|
||||
.fill(null)
|
||||
.map((_, i) => `Test ${i}`);
|
||||
for (let i = 0; i < 50000; i++) {
|
||||
const shuffled = buildNameMap(names);
|
||||
for (const pair of shuffled) {
|
||||
|
|
Loading…
Reference in a new issue