v0.2 – the persistence

- modular data model
- localStorage for persistence
This commit is contained in:
Rüdiger Diedrich 2021-08-20 13:39:37 +02:00
parent bcd99f0181
commit b67adb823d
6 changed files with 127 additions and 66 deletions

View File

@ -1,6 +1,8 @@
# colorer
Play around with hsla color
Play around with hsla color!
Try it online: https://colorer.vercel.app/
## Usage

View File

@ -1,59 +1,14 @@
import { createSignal } from "solid-js";
import { HslaProvider } from "/@/hsla-context";
import Colorer from "/@lib/colorer";
function Colorer(props) {
const [h, setH] = createSignal(1);
const [s, setS] = createSignal(50);
const [l, setL] = createSignal(50);
const [a, setA] = createSignal(1);
const hslColor = () => `hsla(${h()}, ${s()}%, ${l()}%, ${a()})`;
const startHsla = { h: 1, s: 50, l: 50, a: 1 };
const changeH = (e) => setH(e.currentTarget.value);
const changeS = (e) => setS(e.currentTarget.value);
const changeL = (e) => setL(e.currentTarget.value);
const changeA = (e) => setA(e.currentTarget.value);
return (
<div class="main-container">
<div id="colorer">
<label>H <input type="number" min="0" max="359"
value={h()} onInput={changeH} />
<input type="range" min="0" max="359"
value={h()} onInput={changeH} />
</label>
<label>S <input type="number" min="0" max="100"
value={s()} onInput={changeS} />
<input type="range" min="0" max="100"
value={s()} onInput={changeS} />
</label>
<label>L <input type="number" min="0" max="100"
value={l()} onInput={changeL} />
<input type="range" min="0" max="100"
value={l()} onInput={changeL} />
</label>
<label>A <input type="number" min="0" max="1" step="0.01"
value={a()} onInput={changeA} />
<input type="range" min="0" max="1" step="0.01"
value={a()} onInput={changeA} />
</label>
</div>
<div class="color-box" style={{
"background-color": hslColor()
}}></div>
</div>
);
}
function App() {
return (
<>
<header>
<h1>colorer</h1>
</header>
<main>
<Colorer />
</main>
</>
);
};
export default App;
export default () =>
<HslaProvider hsla={startHsla}>
<header>
<h1>colorer</h1>
</header>
<main>
<Colorer />
</main>
</HslaProvider>

View File

@ -0,0 +1,26 @@
import { mergeProps } from "solid-js";
function ColorInput(props) {
const options = mergeProps({ step: 1 }, props);
const setValue = (e) => {
let value = parseFloat(e.currentTarget.value);
options.onInput(value);
}
return (
<div class="color-input">
<label>
<span>{options.label}</span>
<input type="number"
min={options.min} max={options.max} step={options.step}
value={options.value} onInput={setValue} />
<input type="range"
min={options.min} max={options.max} step={options.step}
value={options.value} onInput={setValue} />
</label>
</div>
)
}
export default ColorInput;

View File

@ -0,0 +1,25 @@
import { useHslaContext } from "/@/hsla-context";
import ColorInput from "/@lib/color-input";
function Colorer(props) {
const [hsla, { setH, setS, setL, setA }] = useHslaContext();
const hslColor = () => `hsla(${hsla().h}, ${hsla().s}%, ${hsla().l}%, ${hsla().a})`;
return (
<div class="main-container">
<div id="colorer">
<ColorInput label="H" min="1" max="360" value={hsla().h} onInput={setH} />
<ColorInput label="S" min="0" max="100" value={hsla().s} onInput={setS} />
<ColorInput label="L" min="0" max="100" value={hsla().l} onInput={setL} />
<ColorInput label="A" min="0" max="1" step={0.05} value={hsla().a} onInput={setA} />
</div>
<div class="color-box" style={{
"background-color": hslColor()
}}></div>
<pre>{hslColor()}</pre>
</div>
);
}
export default Colorer;

53
src/hsla-context.tsx Normal file
View File

@ -0,0 +1,53 @@
import { createSignal, createEffect, createContext, useContext } from "solid-js";
const HslaContext = createContext();
export function HslaProvider(props) {
const defaultHsla = { h: 1, s: 50, l: 50, a: 1 };
const [hsla, setHsla] = createSignal(props.hsla || defaultHsla),
store = [
hsla,
{
setHsla(value) {
setHsla(value)
},
setH(value) {
setHsla({ ...hsla(), h: value })
},
setS(value) {
setHsla({ ...hsla(), s: value })
},
setL(value) {
setHsla({ ...hsla(), l: value })
},
setA(value) {
setHsla({ ...hsla(), a: value })
}
}
];
return (
<HslaContext.Provider value={store}>
{props.children}
</HslaContext.Provider>
);
}
export function useHslaContext() {
const context = useContext(HslaContext);
const storageName = "hsla"
const [hsla, { setHsla, ...rest }] = context;
if (window.localStorage) {
const storedHsla = window.localStorage.getItem(storageName);
if (storedHsla != null) {
setHsla(JSON.parse(storedHsla))
}
createEffect(() => {
window.localStorage.setItem(storageName, JSON.stringify(hsla()));
});
}
return context;
}

View File

@ -12,6 +12,7 @@ body {
-moz-osx-font-smoothing: grayscale;
@apply bg-gray-700;
height: 100vh;
font-size: 12pt;
}
code {
@ -30,21 +31,19 @@ code {
"main";
}
#colorer {
@apply flex flex-col;
}
header { grid-area: header; color: white; }
header h1 { @apply font-mono text-4xl text-center mt-2; }
main {
@apply bg-white m-16 mx-auto p-4;
@apply bg-white mt-8 mx-auto p-4 pb-5;
@apply flex justify-center content-center;
grid-area: main;
width: min(50%, 75vw);
height: min(75%, 50vh);
}
main pre { @apply float-right; }
.main-container { width: 100%; }
label { @apply bg-white p-1 pl-0; }
@ -53,8 +52,9 @@ label > input { @apply font-mono text-right; }
#colorer { float: left; }
input[type=number] {
width: 6ch;
}
.color-input label { @apply flex gap-0.5; }
.color-input label span { @apply inline-block w-4; }
.color-input input[type=number] { width: 6ch; }
.color-input input[type=range] { @apply flex-shrink; }
.color-box { width: 100%; height: 100%; }