Linear design system: new admin UI + display design switcher (8 designs)
Admin UI: Linear.app dark theme — near-black canvas, indigo-violet accent, Inter font Display: Minimal, Minimal Color, Bold, Analog Clock, Magazine, Cards, Kiosk, Classic
This commit is contained in:
+4
-44
@@ -15,6 +15,7 @@ from PIL import Image, ImageDraw, ImageFont
|
||||
from palette import BG, FG, OK
|
||||
from plugins.base import all_widget_classes, Widget
|
||||
from layout import Item, GRID_COLS, GRID_ROWS, CELL_W, CELL_H, DISPLAY_W as LAYOUT_DISPLAY_W, pack, find_overlaps, find_out_of_bounds
|
||||
import renderer
|
||||
|
||||
import importlib, pkgutil
|
||||
import plugins as _plugins_pkg # ensure package is importable
|
||||
@@ -261,45 +262,7 @@ class Dashboard:
|
||||
self.widgets = widgets
|
||||
self.config_mtime = CONFIG_PATH.stat().st_mtime if CONFIG_PATH.exists() else 0
|
||||
self.display_theme = cfg.get("display_theme", "default")
|
||||
|
||||
def apply_display_theme(self, img):
|
||||
"""Überschreibe BG/FG des Bildes je nach display_theme."""
|
||||
theme = self.display_theme if hasattr(self, 'display_theme') else "default"
|
||||
if theme == "default":
|
||||
return
|
||||
# Map theme → palette overrides
|
||||
# For now only BG/FG swap makes sense for ACeP
|
||||
# dark/terminal invert, sepia/nord just shift
|
||||
themed_palette = {
|
||||
"dark": {"bg": (17, 17, 17), "fg": (240, 240, 240)},
|
||||
"sepia": {"bg": (244, 236, 216), "fg": (91, 70, 54)},
|
||||
"nord": {"bg": (236, 239, 244), "fg": (46, 52, 64)},
|
||||
"terminal": {"bg": (13, 13, 0), "fg": (232, 200, 64)},
|
||||
}
|
||||
if theme not in themed_palette:
|
||||
return
|
||||
overrides = themed_palette[theme]
|
||||
# Flood-fill BG areas with theme BG (simple but effective for flat designs)
|
||||
# We do an Image.paste to recolor the BG — for now just swap BG pixel
|
||||
bg_r, bg_g, bg_b = overrides["bg"]
|
||||
fg_color = overrides["fg"]
|
||||
# Replace WHITE pixels with theme BG, replace BLACK pixels with theme FG
|
||||
data = img.convert("RGB")
|
||||
w, h = img.size
|
||||
# Direct pixel access — only for flat BG designs
|
||||
for y in range(h):
|
||||
for x in range(w):
|
||||
r, g, b = data.getpixel((x, y))
|
||||
if r > 240 and g > 240 and b > 240:
|
||||
# WHITE → theme bg
|
||||
data.putpixel((x, y), (bg_r, bg_g, bg_b))
|
||||
elif r < 15 and g < 15 and b < 15:
|
||||
# BLACK → theme fg
|
||||
data.putpixel((x, y), fg_color)
|
||||
# Convert back to palette-compatible mode
|
||||
pal_img = img.copy()
|
||||
pal_img.paste(data)
|
||||
return pal_img
|
||||
self.display_design = cfg.get("display_design", "classic")
|
||||
|
||||
def maybe_reload_config(self):
|
||||
if not CONFIG_PATH.exists():
|
||||
@@ -327,11 +290,8 @@ class Dashboard:
|
||||
with self._lock:
|
||||
items = list(self.items)
|
||||
widgets = list(self.widgets)
|
||||
img = render_full(items, widgets, self.fonts)
|
||||
# Apply display theme (BG/FG color remap) — admin preview also uses this
|
||||
themed = self.apply_display_theme(img)
|
||||
if themed is not None:
|
||||
return themed
|
||||
design = getattr(self, 'display_design', 'classic')
|
||||
img = renderer.render_design(items, widgets, self.fonts, design=design)
|
||||
return img
|
||||
|
||||
def display(self, img: Image.Image):
|
||||
|
||||
Reference in New Issue
Block a user