4
\$\begingroup\$

The objective of the game is to guess the hue, saturation, and lightness values of a given color swatch across ten rounds.

This being my first svelte project, I'd like some insight into best practices, especially svelte-specific ones.

Versions

  • svelte: ^3.0.0

Specific questions

  1. Are my choices of abstraction adequate? Are there things that should or shouldn't be components of their own?
  2. In src/components/swatch.svelte, is it okay to style just div (as opposed to adding a class .swatch to the div and styling that), given that svelte scopes styles to the file?
  3. In src/components/results.svelte, I'm a bit concerned about how complicated the score calculation line looks. Is there a way to clean that up a little bit? To my best knowledge I can't assign variables in svelte's template syntax.
  4. Is it standard/acceptable to use an array of length 3 to represent an HSL colour or should I switch to an object with three keys, say h, s, and l?
  5. I was considering using a @svelte/store to store the solution and input history, but eventually decided against it because I thought it was overkill for this. When would one use @svelte/store?

I'm using prettier for linting, so please avoid feedback on code formatting.

Any other feedback is also welcome.

File structure

.
├── package-lock.json
├── package.json
├── public
│  ├── build
│  │  └── ...
│  ├── favicon.png
│  ├── global.css
│  └── index.html
├── readme.md
├── rollup.config.js
└── src
 ├── app.svelte
 ├── components
 │  ├── results.svelte
 │  ├── slider.svelte
 │  └── swatch.svelte
 └── main.js

Code

I have replaced the contents of <style> tags with ... for brevity.

src/main.js

import App from "./app.svelte";
const app = new App({
 target: document.body,
 props: {}
});
export default app;

src/app.svelte

<script>
 import Swatch from "./components/swatch.svelte";
 import Slider from "./components/slider.svelte";
 import Results from "./components/results.svelte";
 import random from "random-int";
 import "../node_modules/milligram/dist/milligram.min.css";
 let solution = randomColor();
 let input = [0, 0, 0];
 let history = [];
 const totalRounds = 10;
 let round = 1;
 function save() {
 const solutionCopy = [...solution];
 const inputCopy = [...input];
 history.push({
 solution: solutionCopy,
 input: inputCopy
 });
 round++;
 solution = randomColor();
 }
 function randomColor() {
 return [random(0, 255), random(0, 100), random(0, 100)];
 }
</script>
<style>
 ...
</style>
<h1>Guess the HSL</h1>
{#if round <= totalRounds}
 <label for="progress">Round {round} / {totalRounds}</label>
 <progress id="progress" value={round} max={totalRounds} />
 <div class="main">
 <Swatch color={solution} inline={false} />
 <Slider name="Hue" bind:value={input[0]} range={[0, 360]} step={1} />
 <Slider
 name="Saturation"
 bind:value={input[1]}
 range={[0, 100]}
 step={1} />
 <Slider
 name="Lightness"
 bind:value={input[2]}
 range={[0, 100]}
 step={1} />
 </div>
 <input type="submit" on:click={save} value="Submit" />
{:else}
 <Results {history} />
{/if}

src/components/swatch.svelte

<script>
 export let width = 50;
 export let color = [0, 0, 0];
 export let inline = true;
</script>
<style>
 ...
</style>
<div
 style=" width: {width}px; height: {width}px; background: hsl({color[0]}, {color[1]}%,
 {color[2]}%);"
 class={inline ? '' : 'display'} />

src/components/slider.svelte

<script>
 export let name;
 export let value;
 export let range = [0, 100];
 export let step = 1;
</script>
<style>
 ...
</style>
<fieldset>
 <legend>{name}</legend>
 <input
 type="range"
 {name}
 bind:value
 min={range[0]}
 max={range[1]}
 {step} />
 <input
 type="number"
 name="hue"
 bind:value
 min={range[0]}
 max={range[1]}
 {step} />
</fieldset>

src/components/results.svelte

<script>
 import Swatch from "./swatch.svelte";
 import round from "round-to";
 import convert from "color-convert";
 import { differenceCiede2000 as ciede2000 } from "d3-color-difference";
 export let history = [];
</script>
<style>
 ...
</style>
<table>
 <thead>
 <th>Solution</th>
 <th>Input</th>
 <th>Score</th>
 </thead>
 {#each history as { solution, input }}
 <tr>
 <td>
 <Swatch color={solution} width="25" />
 <code>hsl({solution[0]}, {solution[1]}%, {solution[2]}%)</code>
 </td>
 <td>
 <Swatch color={input} width="25" />
 <code>hsl({input[0]}, {input[1]}%, {input[2]}%)</code>
 </td>
 <td>
 {round(100 - ciede2000(`#${convert.hsl.hex(solution)}`, `#${convert.hsl.hex(input)}`), 2)}
 </td>
 </tr>
 {/each}
</table>
```
Sᴀᴍ Onᴇᴌᴀ
29.5k16 gold badges45 silver badges201 bronze badges
asked Mar 6, 2020 at 19:48
\$\endgroup\$

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.