diff --git a/src/lib/setting.ts b/src/lib/setting.ts
index 998fab60..6a643617 100644
--- a/src/lib/setting.ts
+++ b/src/lib/setting.ts
@@ -1,6 +1,85 @@
import type { Action } from "svelte/action";
import { changes, ChangeType, settings } from "$lib/undo-redo";
+/**
+ * https://gist.github.com/mjackson/5311256
+ */
+function rgbToHsv(r: number, g: number, b: number): [number, number, number] {
+ r /= 255;
+ g /= 255;
+ b /= 255;
+
+ const max = Math.max(r, g, b);
+ const min = Math.min(r, g, b);
+ let h = 0;
+ const v = max;
+
+ const d = max - min;
+ const s = max == 0 ? 0 : d / max;
+
+ if (max == min) {
+ h = 0; // achromatic
+ } else {
+ switch (max) {
+ case r:
+ h = (g - b) / d + (g < b ? 6 : 0);
+ break;
+ case g:
+ h = (b - r) / d + 2;
+ break;
+ case b:
+ h = (r - g) / d + 4;
+ break;
+ }
+
+ h /= 6;
+ }
+
+ return [Math.floor(h * 0xffff), Math.floor(s * 0xff), Math.floor(v * 0xff)];
+}
+
+/**
+ * https://gist.github.com/mjackson/5311256
+ */
+function hsvToRgb(h: number, s: number, v: number): [number, number, number] {
+ h /= 0xffff;
+ s /= 0xff;
+ v /= 0xff;
+
+ let r = 0;
+ let g = 0;
+ let b = 0;
+
+ const i = Math.floor(h * 6);
+ const f = h * 6 - i;
+ const p = v * (1 - s);
+ const q = v * (1 - f * s);
+ const t = v * (1 - (1 - f) * s);
+
+ switch (i % 6) {
+ case 0:
+ (r = v), (g = t), (b = p);
+ break;
+ case 1:
+ (r = q), (g = v), (b = p);
+ break;
+ case 2:
+ (r = p), (g = v), (b = t);
+ break;
+ case 3:
+ (r = p), (g = q), (b = v);
+ break;
+ case 4:
+ (r = t), (g = p), (b = v);
+ break;
+ case 5:
+ (r = v), (g = p), (b = q);
+ break;
+ }
+
+ return [Math.floor(r * 0xff), Math.floor(g * 0xff), Math.floor(b * 0xff)];
+}
+
export const setting: Action<
HTMLInputElement | HTMLSelectElement,
{ id: number; inverse?: number; scale?: number }
@@ -9,7 +88,12 @@ export const setting: Action<
{ id, inverse, scale },
) {
node.setAttribute("disabled", "");
- const type = node.getAttribute("type") as "number" | "checkbox" | "range";
+ const type = node.getAttribute("type") as
+ | "number"
+ | "checkbox"
+ | "range"
+ | "color";
+ const isColor = type === "color";
const isNumeric =
type === "number" || type === "range" || node instanceof HTMLSelectElement;
const min = node.hasAttribute("min")
@@ -30,6 +114,13 @@ export const setting: Action<
? scale * value
: value
).toString();
+ } else if (isColor) {
+ const rgb = hsvToRgb(
+ settings[id]!.value,
+ settings[id + 1]!.value,
+ settings[id + 2]!.value,
+ );
+ node.value = `#${rgb.map((c) => c.toString(16).padStart(2, "0")).join("")}`;
} else {
node.checked = value !== 0;
}
@@ -58,6 +149,22 @@ export const setting: Action<
? value / scale
: value,
);
+ } else if (isColor) {
+ const r = parseInt(node.value.slice(1, 3), 16);
+ const g = parseInt(node.value.slice(3, 5), 16);
+ const b = parseInt(node.value.slice(5, 7), 16);
+ const hsv = rgbToHsv(r, g, b);
+ changes.update((changes) => {
+ changes.push(
+ hsv.map((value, i) => ({
+ type: ChangeType.Setting,
+ id: id + i,
+ setting: value,
+ })),
+ );
+ return changes;
+ });
+ return;
} else {
value = node.checked ? 1 : 0;
}
diff --git a/src/routes/(app)/config/settings/+page.svelte b/src/routes/(app)/config/settings/+page.svelte
index 7c0b8681..2e33e63d 100644
--- a/src/routes/(app)/config/settings/+page.svelte
+++ b/src/routes/(app)/config/settings/+page.svelte
@@ -117,43 +117,49 @@
{/if}
{#each category.items as item}
{#if item.name !== "enable"}
-
+ {#if item.unit === "H"}
+
+ {:else if item.unit !== "S" && item.unit !== "B"}
+
+ {/if}
{/if}
{/each}