aboutsummaryrefslogtreecommitdiff
path: root/app.py
diff options
context:
space:
mode:
authorMichael McVady <michaelm@telnyx.com>2026-02-26 10:55:14 -0500
committerMichael McVady <michaelm@telnyx.com>2026-02-26 11:03:59 -0500
commit239928ede767501438d1cae2c55793adb8c3923d (patch)
treeaeec65256c3d3a4296533291885328ee50b4cdf9 /app.py
parentfe21d3eb2b9eedbf5971f2445358e32756acf7b4 (diff)
add color picker
Diffstat (limited to 'app.py')
-rw-r--r--app.py75
1 files changed, 67 insertions, 8 deletions
diff --git a/app.py b/app.py
index 89a16cc..4db2c24 100644
--- a/app.py
+++ b/app.py
@@ -1,5 +1,5 @@
import logging
-from colorsys import hsv_to_rgb
+from colorsys import hsv_to_rgb, rgb_to_hsv
from dataclasses import dataclass
from random import randint
@@ -8,7 +8,9 @@ from lifxlan import LifxLAN, Light
from litestar import Litestar, get, post
from litestar.contrib.jinja import JinjaTemplateEngine
from litestar.di import Provide
+from litestar.enums import RequestEncodingType
from litestar.logging import LoggingConfig
+from litestar.params import Body
from litestar.response import Template
from litestar.template import TemplateConfig
@@ -17,9 +19,25 @@ TEMPLATE_STR = """<!DOCTYPE html>
<html lang="zxx">
<head>
<title>lux</title>
+<style>
+ body { margin: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; }
+ h1 { font-family: monospace; }
+ input[type=color] {
+ width: 200px; height: 200px; border: none; border-radius: 50%; cursor: pointer; padding: 0;
+ background: radial-gradient(circle, white 0%, transparent 70%),
+ conic-gradient(hsl(0,100%,50%), hsl(60,100%,50%), hsl(120,100%,50%),
+ hsl(180,100%,50%), hsl(240,100%,50%), hsl(300,100%,50%), hsl(360,100%,50%));
+ }
+ input[type=color]::-webkit-color-swatch-wrapper { padding: 0; }
+ input[type=color]::-webkit-color-swatch { border: none; border-radius: 50%; opacity: 0; }
+ input[type=color]::-moz-color-swatch { border: none; border-radius: 50%; opacity: 0; }
+</style>
</head>
<body style="background-color: {{ background_color }};">
-<h1 style="color: {{ color }}; font-family: monospace">{{ message }}</h1>
+<h1 style="color: {{ color }};">{{ message }}</h1>
+<form method="post">
+<input type="color" name="color" value="{{ current_color }}" onchange="this.form.submit()">
+</form>
<script data-goatcounter="https://test.bunkergate.org/count" async src="https://test.bunkergate.org/count.js"></script>
</body>
</html>
@@ -37,11 +55,30 @@ class RGBColor:
green: int
blue: int
+ @classmethod
+ def from_hex(cls, hex_str: str) -> "RGBColor":
+ hex_str = hex_str.lstrip("#")
+ return cls(
+ red=int(hex_str[0:2], 16),
+ green=int(hex_str[2:4], 16),
+ blue=int(hex_str[4:6], 16),
+ )
+
@property
def hex(self) -> str:
return "#%02X%02X%02X" % (self.red, self.green, self.blue)
@property
+ def hsbk(self) -> "HSBKColor":
+ h, s, v = rgb_to_hsv(self.red / 255, self.green / 255, self.blue / 255)
+ return HSBKColor(
+ hue=int(h * 65535),
+ saturation=int(s * 65535),
+ brightness=int(v * 65535),
+ kelvin=3500,
+ )
+
+ @property
def yit(self) -> int:
yit = ((self.red * 299) + (self.green * 587) + (self.blue * 114)) // 1000
log.info(f"yit: {yit}")
@@ -93,8 +130,7 @@ def get_random_hsbk_color() -> HSBKColor:
)
-def random_color(lux: Light) -> Template:
- hsbk = get_random_hsbk_color()
+def _set_light_color(lux: Light, hsbk: HSBKColor) -> Template:
log.info(f"Setting color to {hsbk} {hsbk.rgb}")
try:
@@ -105,7 +141,12 @@ def random_color(lux: Light) -> Template:
log.exception("Error setting color")
return Template(
template_str=TEMPLATE_STR,
- context={"color": DEFAULT_COLOR, "message": f"error: {str(e)}"},
+ context={
+ "background_color": DEFAULT_COLOR,
+ "color": "white",
+ "message": f"error: {str(e)}",
+ "current_color": DEFAULT_COLOR,
+ },
)
rgb = hsbk.rgb
@@ -117,20 +158,38 @@ def random_color(lux: Light) -> Template:
"background_color": rgb_hex,
"color": text_color,
"message": rgb_hex,
+ "current_color": rgb_hex,
},
)
+def random_color(lux: Light) -> Template:
+ return _set_light_color(lux, get_random_hsbk_color())
+
+
+def chosen_color(lux: Light, hex_color: str) -> Template:
+ rgb = RGBColor.from_hex(hex_color)
+ return _set_light_color(lux, rgb.hsbk)
+
+
@get("/")
async def get_index(lux: Light = Provide(get_lux)) -> Template:
"""Return index"""
return random_color(lux)
+@dataclass
+class ColorForm:
+ color: str
+
+
@post("/")
-async def post_index(lux: Light = Provide(get_lux)) -> Template:
- """Update index"""
- return random_color(lux)
+async def post_index(
+ data: ColorForm = Body(media_type=RequestEncodingType.URL_ENCODED),
+ lux: Light = Provide(get_lux),
+) -> Template:
+ """Set light to chosen color"""
+ return chosen_color(lux, data.color)
app = Litestar(