Skip to content

Commit c7341a7

Browse files
parameterize colors
Signed-off-by: Jonathan Irvin <djfoxyslpr@gmail.com>
1 parent bebfc98 commit c7341a7

2 files changed

Lines changed: 113 additions & 62 deletions

File tree

main.py

Lines changed: 111 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,24 @@
1111
# Global variable to track phrases.txt modification time.
1212
last_phrases_mtime = os.path.getmtime("phrases.txt")
1313

14+
FREE_SPACE_TEXT = "FREE MEAT"
15+
FREE_SPACE_TEXT_COLOR = "#FF7f33"
16+
1417
# --- New: Color constants and font ---
1518
TILE_CLICKED_BG_COLOR = "#3b82f6" # Blue background for clicked tiles
1619
TILE_CLICKED_TEXT_COLOR = "white"
1720
TILE_UNCLICKED_BG_COLOR = "#facc15" # Yellow background for unclicked tiles
1821
TILE_UNCLICKED_TEXT_COLOR = "black"
19-
FREE_MEAT_TEXT_COLOR = "#FF7f33" # Color for the FREE MEAT tile
22+
2023

2124
HOME_BG_COLOR = "#100079" # Background for home page
2225
STREAM_BG_COLOR = "#00FF00" # Background for stream page
2326
HEADER_TEXT_COLOR = "#0CB2B3" # Color for header text
2427

25-
FONT_FAMILY = "'Super Carnival', sans-serif"
26-
27-
# New constants for line-height adjustments
28-
LINE_HEIGHT_SHORT = "1.5em"
29-
LINE_HEIGHT_DEFAULT = "1em"
28+
HEADER_FONT_FAMILY = "'Super Carnival', sans-serif"
29+
BOARD_TILE_FONT = "Inter" # Set the desired Google Font for board tiles
30+
BOARD_TILE_FONT_WEIGHT = "600" # Default weight for board tiles; adjust as needed.
31+
BOARD_TILE_FONT_STYLE = "normal" # Default font style for board tiles; for example, "normal" or "italic"
3032

3133
def get_line_style_for_lines(line_count: int, default_text_color: str) -> str:
3234
"""
@@ -39,10 +41,10 @@ def get_line_style_for_lines(line_count: int, default_text_color: str) -> str:
3941
elif line_count == 2:
4042
lh = "1.2em" # Slightly reduced spacing for two lines.
4143
elif line_count == 3:
42-
lh = "0.75em" # Even tighter spacing for three lines.
44+
lh = "0.9em" # Even tighter spacing for three lines.
4345
else:
4446
lh = "0.7em" # For four or more lines.
45-
return f"font-family: {FONT_FAMILY}; padding: 0; margin: 0; color: {default_text_color}; line-height: {lh};"
47+
return f"font-family: '{BOARD_TILE_FONT}', sans-serif; font-weight: {BOARD_TILE_FONT_WEIGHT}; font-style: {BOARD_TILE_FONT_STYLE}; padding: 0; margin: 0; color: {default_text_color}; line-height: {lh};"
4648

4749
# Read phrases from a text file and convert them to uppercase.
4850
with open("phrases.txt", "r") as f:
@@ -54,7 +56,7 @@ def get_line_style_for_lines(line_count: int, default_text_color: str) -> str:
5456

5557
# Shuffle and create the 5x5 board:
5658
shuffled_phrases = random.sample(phrases, 24) # Random but fixed order per day
57-
shuffled_phrases.insert(12, "FREE MEAT") # Center slot
59+
shuffled_phrases.insert(12, FREE_SPACE_TEXT) # Center slot
5860
board = [shuffled_phrases[i:i+5] for i in range(0, 25, 5)]
5961

6062
# Track clicked tiles and store chip references
@@ -166,23 +168,32 @@ def create_bingo_board():
166168
for row_idx, row in enumerate(board):
167169
for col_idx, phrase in enumerate(row):
168170
# Create a clickable card for this cell with reduced padding and centered content. Added 'relative' class for icon overlay.
169-
card = ui.card().classes("relative p-2 bg-yellow-500 rounded-lg w-full h-full flex items-center justify-center").style("cursor: pointer;")
171+
card = ui.card().classes("relative p-2 rounded-lg w-full h-full flex items-center justify-center").style("cursor: pointer;")
172+
labels_list = [] # initialize list for storing label metadata
170173
with card:
171174
with ui.column().classes("flex flex-col items-center justify-center gap-0 w-full"):
172175
# Set text color: free meat gets #FF7f33, others black
173-
default_text_color = FREE_MEAT_TEXT_COLOR if phrase.upper() == "FREE MEAT" else TILE_UNCLICKED_TEXT_COLOR
176+
default_text_color = FREE_SPACE_TEXT_COLOR if phrase.upper() == FREE_SPACE_TEXT else TILE_UNCLICKED_TEXT_COLOR
174177
lines = split_phrase_into_lines(phrase)
175178
line_count = len(lines)
176179
for line in lines:
177180
with ui.row().classes("w-full"):
178181
if len(line) <= 3:
179-
ui.label(line).classes("fit-text-small text-center select-none").style(get_line_style_for_lines(line_count, default_text_color))
182+
base_class = "fit-text-small text-center select-none"
180183
else:
181-
ui.label(line).classes("fit-text text-center select-none").style(get_line_style_for_lines(line_count, default_text_color))
184+
base_class = "fit-text text-center select-none"
185+
# Create the label with initial inline style using get_line_style_for_lines().
186+
lbl = ui.label(line).classes(base_class).style(get_line_style_for_lines(line_count, default_text_color))
187+
# Instead of just storing the label, store its metadata.
188+
labels_list.append({
189+
"ref": lbl,
190+
"base_classes": base_class,
191+
"base_style": get_line_style_for_lines(line_count, default_text_color)
192+
})
182193

183194
tile_buttons[(row_idx, col_idx)] = card
184195

185-
if phrase.upper() == "FREE MEAT":
196+
if phrase.upper() == FREE_SPACE_TEXT:
186197
clicked_tiles.add((row_idx, col_idx))
187198
card.style("color: #FF7f33; border: none;")
188199
else:
@@ -200,6 +211,7 @@ def toggle_tile(row, col):
200211
else:
201212
logging.debug(f"Tile at {key} clicked")
202213
clicked_tiles.add(key)
214+
203215
check_winner()
204216
sync_board_state()
205217

@@ -246,24 +258,37 @@ def admin_checkbox_change(e, key):
246258
clicked_tiles.discard(key)
247259
sync_board_state()
248260

261+
def create_board_view(background_color: str, is_global: bool):
262+
"""
263+
Creates a board page view based on the background color and a flag.
264+
If is_global is True, the board uses global variables (home page)
265+
otherwise it uses a local board (stream page).
266+
"""
267+
setup_head(background_color)
268+
# Create the board container.
269+
container = ui.element("div").classes("flex justify-center items-center w-full")
270+
if is_global:
271+
global home_board_container, tile_buttons
272+
home_board_container = container
273+
tile_buttons = {} # Start with an empty dictionary.
274+
build_board(home_board_container, tile_buttons, toggle_tile)
275+
# Add timers for synchronizing the global board.
276+
ui.timer(0.1, sync_board_state)
277+
ui.timer(1, check_phrases_file_change)
278+
else:
279+
local_tile_buttons = build_board(container, {}, toggle_tile)
280+
ui.timer(0.1, lambda: update_tile_styles(local_tile_buttons))
281+
# Display the seed beneath the board.
282+
with ui.element("div").classes("w-full mt-4"):
283+
ui.label(f"Seed: {today_seed}").classes("text-md text-gray-300 text-center")
284+
249285
@ui.page("/")
250286
def home_page():
251-
# Set up NiceGUI page and head elements
252-
setup_head(HOME_BG_COLOR)
253-
254-
global home_board_container, tile_buttons
255-
home_board_container = ui.element("div").classes("flex justify-center items-center w-full")
256-
tile_buttons = {} # Start with an empty dictionary.
257-
build_board(home_board_container, tile_buttons, toggle_tile)
287+
create_board_view(HOME_BG_COLOR, True)
258288

259-
# Add a timer that calls sync_board_state every 0.1 second to push state updates to all clients
260-
ui.timer(0.1, sync_board_state)
261-
262-
# Add a timer to check if phrases.txt has changed
263-
ui.timer(1, check_phrases_file_change)
264-
265-
with ui.element("div").classes("w-full mt-4"):
266-
ui.label(f"Seed: {today_seed}").classes("text-md text-gray-300 text-center")
289+
@ui.page("/stream")
290+
def stream_page():
291+
create_board_view(STREAM_BG_COLOR, False)
267292

268293
@ui.page("/admin")
269294
def admin_page():
@@ -303,27 +328,12 @@ def on_checkbox_change(e, key=key):
303328
build_admin_panel()
304329
ui.timer(0.1, sync_admin_checkboxes)
305330

306-
@ui.page("/stream")
307-
def stream_page():
308-
# Set up NiceGUI page and head elements
309-
setup_head(STREAM_BG_COLOR)
310-
311-
312-
313-
# Build the board using the common function (use a local dictionary here)
314-
local_tile_buttons = build_board(ui.element("div").classes("flex justify-center items-center w-full"), {}, toggle_tile)
315-
316-
# Timer to update ONLY the stream view's board (using its local_tile_buttons)
317-
ui.timer(0.1, lambda: update_tile_styles(local_tile_buttons))
318-
319-
with ui.element("div").classes("w-full mt-4"):
320-
ui.label(f"Seed: {today_seed}").classes("text-md text-gray-300 text-center")
321-
322331
def setup_head(background_color: str):
323332
"""
324333
Set up common head elements: fonts, fitty JS, and background color.
325334
"""
326335
ui.add_head_html(f'<link href="https://fonts.cdnfonts.com/css/super-carnival" rel="stylesheet">')
336+
ui.add_head_html(f'<link href="https://fonts.googleapis.com/css2?family={BOARD_TILE_FONT.replace(" ", "+")}&display=swap" rel="stylesheet">')
327337
ui.add_head_html('<script src="https://cdn.jsdelivr.net/npm/fitty@2.3.6/dist/fitty.min.js"></script>')
328338
ui.add_head_html(f'<style>body {{ background-color: {background_color}; }}</style>')
329339
ui.add_head_html("""<script>
@@ -341,7 +351,7 @@ def setup_head(background_color: str):
341351

342352
# Use full width with padding so the header spans edge-to-edge
343353
with ui.element("div").classes("w-full"):
344-
ui.label("COMMIT !BINGO").classes("fit-header text-center").style(f"font-family: {FONT_FAMILY}; color: {HEADER_TEXT_COLOR};")
354+
ui.label("COMMIT !BINGO").classes("fit-header text-center").style(f"font-family: {HEADER_FONT_FAMILY}; color: {HEADER_TEXT_COLOR};")
345355

346356
def build_board(parent, tile_buttons_dict: dict, on_tile_click):
347357
"""
@@ -355,40 +365,77 @@ def build_board(parent, tile_buttons_dict: dict, on_tile_click):
355365
for row_idx, row in enumerate(board):
356366
for col_idx, phrase in enumerate(row):
357367
card = ui.card().classes(
358-
"relative p-2 bg-yellow-500 rounded-lg w-full h-full flex items-center justify-center"
368+
"relative p-2 rounded-lg w-full h-full flex items-center justify-center"
359369
).style("cursor: pointer;")
370+
labels_list = [] # initialize list for storing label metadata
360371
with card:
361372
with ui.column().classes("flex flex-col items-center justify-center gap-0 w-full"):
362-
default_text_color = FREE_MEAT_TEXT_COLOR if phrase.upper() == "FREE MEAT" else TILE_UNCLICKED_TEXT_COLOR
373+
# Set text color: FREE MEAT uses FREE_MEAT_TEXT_COLOR, others use TILE_UNCLICKED_TEXT_COLOR
374+
default_text_color = FREE_SPACE_TEXT_COLOR if phrase.upper() == FREE_SPACE_TEXT else TILE_UNCLICKED_TEXT_COLOR
363375
lines = split_phrase_into_lines(phrase)
364376
line_count = len(lines)
365377
for line in lines:
366378
with ui.row().classes("w-full"):
367379
if len(line) <= 3:
368-
ui.label(line).classes("fit-text-small text-center select-none").style(get_line_style_for_lines(line_count, default_text_color))
380+
base_class = "fit-text-small text-center select-none"
369381
else:
370-
ui.label(line).classes("fit-text text-center select-none").style(get_line_style_for_lines(line_count, default_text_color))
371-
tile_buttons_dict[(row_idx, col_idx)] = card
372-
if phrase.upper() == "FREE MEAT":
382+
base_class = "fit-text text-center select-none"
383+
# Create the label with initial inline style using get_line_style_for_lines().
384+
lbl = ui.label(line).classes(base_class).style(get_line_style_for_lines(line_count, default_text_color))
385+
# Instead of just storing the label, store its metadata.
386+
labels_list.append({
387+
"ref": lbl,
388+
"base_classes": base_class,
389+
"base_style": get_line_style_for_lines(line_count, default_text_color)
390+
})
391+
# Store both the card and its labels in the global tile_buttons dict.
392+
tile_buttons_dict[(row_idx, col_idx)] = {"card": card, "labels": labels_list}
393+
if phrase.upper() == FREE_SPACE_TEXT:
373394
clicked_tiles.add((row_idx, col_idx))
374-
card.style(f"color: {FREE_MEAT_TEXT_COLOR}; border: none;")
395+
card.style(f"color: {FREE_SPACE_TEXT_COLOR}; border: none;")
375396
else:
376397
card.on("click", lambda e, r=row_idx, c=col_idx: on_tile_click(r, c))
377398
return tile_buttons_dict
378399

379400
def update_tile_styles(tile_buttons_dict: dict):
380401
"""
381-
Update styles for each tile in the given dictionary based on the global clicked_tiles.
402+
Update styles for each tile and its text labels based on the global clicked_tiles.
382403
"""
383-
for (r, c), card in tile_buttons_dict.items():
384-
if board[r][c].upper() == "FREE MEAT":
404+
for (r, c), tile in tile_buttons_dict.items():
405+
# tile is a dict with keys "card" and "labels"
406+
phrase = board[r][c]
407+
if phrase.upper() == FREE_SPACE_TEXT:
385408
continue
409+
386410
if (r, c) in clicked_tiles:
387-
new_style = f"background-color: {TILE_CLICKED_BG_COLOR}; color: {TILE_CLICKED_TEXT_COLOR}; border: none;"
411+
new_card_style = f"background-color: {TILE_CLICKED_BG_COLOR}; color: {TILE_CLICKED_TEXT_COLOR}; border: none;"
412+
new_label_color = TILE_CLICKED_TEXT_COLOR
388413
else:
389-
new_style = f"background-color: {TILE_UNCLICKED_BG_COLOR}; color: {TILE_UNCLICKED_TEXT_COLOR}; border: none;"
390-
card.style(new_style)
391-
card.update()
414+
new_card_style = f"background-color: {TILE_UNCLICKED_BG_COLOR}; color: {TILE_UNCLICKED_TEXT_COLOR}; border: none;"
415+
new_label_color = TILE_UNCLICKED_TEXT_COLOR
416+
417+
# Update the card style.
418+
tile["card"].style(new_card_style)
419+
tile["card"].update()
420+
421+
# Recalculate the line count for the current phrase.
422+
lines = split_phrase_into_lines(phrase)
423+
line_count = len(lines)
424+
# Recalculate label style based on the new color.
425+
new_label_style = get_line_style_for_lines(line_count, new_label_color)
426+
427+
# Update all label elements for this tile.
428+
for label_info in tile["labels"]:
429+
lbl = label_info["ref"]
430+
# Reapply the stored base classes.
431+
lbl.classes(label_info["base_classes"])
432+
# Update inline style (which may now use a new color due to tile click state).
433+
lbl.style(new_label_style)
434+
lbl.update()
435+
ui.run_javascript(
436+
"fitty('.fit-text', { multiLine: true, minSize: 10, maxSize: 1000 });"
437+
"fitty('.fit-text-small', { multiLine: true, minSize: 10, maxSize: 72 });"
438+
)
392439

393440
def check_phrases_file_change():
394441
"""
@@ -416,6 +463,10 @@ def check_phrases_file_change():
416463
tile_buttons.clear() # Clear global dictionary.
417464
build_board(home_board_container, tile_buttons, toggle_tile)
418465
home_board_container.update() # Force update so new styles are applied immediately.
466+
ui.run_javascript(
467+
"fitty('.fit-text', { multiLine: true, minSize: 10, maxSize: 1000 });"
468+
"fitty('.fit-text-small', { multiLine: true, minSize: 10, maxSize: 72 });"
469+
)
419470

420471
# Run the NiceGUI app
421472
ui.run(port=8080, title="Commit Bingo", dark=False)

phrases.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
can't have nice things
1+
Can't have nice things
22
Techno babble
33
Hell yeah!
44
We get a raid
5-
that's so Noice
5+
That's so Noice
66
Position one
77
Hows my audio
88
Someone redeems hydrate

0 commit comments

Comments
 (0)