Skip to content

Commit 6f3fffb

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

1 file changed

Lines changed: 60 additions & 71 deletions

File tree

main.py

Lines changed: 60 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,24 @@
2727

2828
HEADER_FONT_FAMILY = "'Super Carnival', sans-serif"
2929
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.
30+
BOARD_TILE_FONT_WEIGHT = "700" # Default weight for board tiles; adjust as needed.
3131
BOARD_TILE_FONT_STYLE = "normal" # Default font style for board tiles; for example, "normal" or "italic"
3232

33+
# UI Class Constants
34+
BOARD_CONTAINER_CLASS = "flex justify-center items-center w-full"
35+
HEADER_CONTAINER_CLASS = "w-full"
36+
CARD_CLASSES = "relative p-2 rounded-xl w-full h-full flex items-center justify-center"
37+
COLUMN_CLASSES = "flex flex-col items-center justify-center gap-0 w-full"
38+
GRID_CONTAINER_CLASS = "w-full aspect-square p-4"
39+
GRID_CLASSES = "gap-2 h-full grid-rows-5"
40+
ROW_CLASSES = "w-full"
41+
LABEL_SMALL_CLASSES = "fit-text-small text-center select-none"
42+
LABEL_CLASSES = "fit-text text-center select-none"
43+
44+
# Global dictionary to store board view instances.
45+
# Keys can be "home" and "stream". Each value is a tuple: (container, tile_buttons).
46+
board_views = {}
47+
3348
def get_line_style_for_lines(line_count: int, default_text_color: str) -> str:
3449
"""
3550
Return a complete style string with an adjusted line-height based on the number of lines
@@ -157,51 +172,9 @@ def segment_length(segment):
157172
# fallback (should never happen)
158173
return [" ".join(words)]
159174

160-
# Function to create the Bingo board UI
161-
def create_bingo_board():
162-
# The header and seed label are handled outside this function.
163-
logging.info("Creating Bingo board")
164-
165-
with ui.element("div").classes("flex justify-center items-center w-full"):
166-
with ui.element("div").classes("w-full max-w-3xl aspect-square"):
167-
with ui.grid(columns=5).classes("gap-2 h-full grid-rows-5"):
168-
for row_idx, row in enumerate(board):
169-
for col_idx, phrase in enumerate(row):
170-
# Create a clickable card for this cell with reduced padding and centered content. Added 'relative' class for icon overlay.
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
173-
with card:
174-
with ui.column().classes("flex flex-col items-center justify-center gap-0 w-full"):
175-
# Set text color: free meat gets #FF7f33, others black
176-
default_text_color = FREE_SPACE_TEXT_COLOR if phrase.upper() == FREE_SPACE_TEXT else TILE_UNCLICKED_TEXT_COLOR
177-
lines = split_phrase_into_lines(phrase)
178-
line_count = len(lines)
179-
for line in lines:
180-
with ui.row().classes("w-full"):
181-
if len(line) <= 3:
182-
base_class = "fit-text-small text-center select-none"
183-
else:
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-
})
193-
194-
tile_buttons[(row_idx, col_idx)] = card
195-
196-
if phrase.upper() == FREE_SPACE_TEXT:
197-
clicked_tiles.add((row_idx, col_idx))
198-
card.style("color: #FF7f33; border: none;")
199-
else:
200-
card.on("click", lambda e, r=row_idx, c=col_idx: toggle_tile(r, c))
201-
202175
# Toggle tile click state (for example usage)
203176
def toggle_tile(row, col):
204-
# Do not allow toggling for the FREE MEAT cell (center cell)
177+
# Do not allow toggling for the FREE SPACE cell (center cell)
205178
if (row, col) == (2, 2):
206179
return
207180
key = (row, col)
@@ -271,12 +244,15 @@ def create_board_view(background_color: str, is_global: bool):
271244
global home_board_container, tile_buttons
272245
home_board_container = container
273246
tile_buttons = {} # Start with an empty dictionary.
274-
build_board(home_board_container, tile_buttons, toggle_tile)
247+
build_board(container, tile_buttons, toggle_tile)
248+
board_views["home"] = (container, tile_buttons)
275249
# Add timers for synchronizing the global board.
276250
ui.timer(0.1, sync_board_state)
277251
ui.timer(1, check_phrases_file_change)
278252
else:
279-
local_tile_buttons = build_board(container, {}, toggle_tile)
253+
local_tile_buttons = {}
254+
build_board(container, local_tile_buttons, toggle_tile)
255+
board_views["stream"] = (container, local_tile_buttons)
280256
ui.timer(0.1, lambda: update_tile_styles(local_tile_buttons))
281257
# Display the seed beneath the board.
282258
with ui.element("div").classes("w-full mt-4"):
@@ -294,7 +270,7 @@ def stream_page():
294270
def admin_page():
295271
def reset_board():
296272
clicked_tiles.clear()
297-
# Re-add FREE MEAT at the center (position (2,2))
273+
# Re-add FREE SPACE at the center (position (2,2))
298274
clicked_tiles.add((2, 2))
299275
sync_board_state()
300276
build_admin_panel() # rebuild panel to reflect state changes
@@ -333,9 +309,17 @@ def setup_head(background_color: str):
333309
Set up common head elements: fonts, fitty JS, and background color.
334310
"""
335311
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">')
312+
ui.add_head_html("""
313+
<link rel="preconnect" href="https://fonts.googleapis.com">
314+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
315+
<link href="https://fonts.googleapis.com/css2?family={BOARD_TILE_FONT.replace(" ", "+")}:opsz@10..1000&display=swap" rel="stylesheet">
316+
""")
317+
# Add CSS class for board tile fonts; you can later reference this class in your CSS.
318+
ui.add_head_html(get_google_font_css(BOARD_TILE_FONT, BOARD_TILE_FONT_WEIGHT, BOARD_TILE_FONT_STYLE, "board_tile"))
319+
337320
ui.add_head_html('<script src="https://cdn.jsdelivr.net/npm/fitty@2.3.6/dist/fitty.min.js"></script>')
338321
ui.add_head_html(f'<style>body {{ background-color: {background_color}; }}</style>')
322+
339323
ui.add_head_html("""<script>
340324
document.addEventListener('DOMContentLoaded', () => {
341325
fitty('.fit-text', { multiLine: true, minSize: 10, maxSize: 1000 });
@@ -353,42 +337,48 @@ def setup_head(background_color: str):
353337
with ui.element("div").classes("w-full"):
354338
ui.label("COMMIT !BINGO").classes("fit-header text-center").style(f"font-family: {HEADER_FONT_FAMILY}; color: {HEADER_TEXT_COLOR};")
355339

340+
def get_google_font_css(font_name: str, weight: str, style: str, uniquifier: str) -> str:
341+
"""
342+
Returns a CSS style block defining a class for the specified Google font.
343+
'uniquifier' is used as the CSS class name.
344+
"""
345+
return f"""
346+
<style>
347+
.{uniquifier} {{
348+
font-family: "{font_name}", serif;
349+
font-optical-sizing: auto;
350+
font-weight: {weight};
351+
font-style: {style};
352+
}}
353+
</style>
354+
"""
355+
356356
def build_board(parent, tile_buttons_dict: dict, on_tile_click):
357357
"""
358358
Build the common Bingo board in the given parent element.
359359
The resulting tile UI elements are added to tile_buttons_dict.
360360
"""
361361
with parent:
362-
# Use full width and add padding so the board touches the edges with a gap
363-
with ui.element("div").classes("w-full aspect-square p-4"):
364-
with ui.grid(columns=5).classes("gap-2 h-full grid-rows-5"):
362+
with ui.element("div").classes(GRID_CONTAINER_CLASS):
363+
with ui.grid(columns=5).classes(GRID_CLASSES):
365364
for row_idx, row in enumerate(board):
366365
for col_idx, phrase in enumerate(row):
367-
card = ui.card().classes(
368-
"relative p-2 rounded-lg w-full h-full flex items-center justify-center"
369-
).style("cursor: pointer;")
366+
card = ui.card().classes(CARD_CLASSES).style("cursor: pointer;")
370367
labels_list = [] # initialize list for storing label metadata
371368
with card:
372369
with ui.column().classes("flex flex-col items-center justify-center gap-0 w-full"):
373-
# Set text color: FREE MEAT uses FREE_MEAT_TEXT_COLOR, others use TILE_UNCLICKED_TEXT_COLOR
374370
default_text_color = FREE_SPACE_TEXT_COLOR if phrase.upper() == FREE_SPACE_TEXT else TILE_UNCLICKED_TEXT_COLOR
375371
lines = split_phrase_into_lines(phrase)
376372
line_count = len(lines)
377373
for line in lines:
378374
with ui.row().classes("w-full"):
379-
if len(line) <= 3:
380-
base_class = "fit-text-small text-center select-none"
381-
else:
382-
base_class = "fit-text text-center select-none"
383-
# Create the label with initial inline style using get_line_style_for_lines().
375+
base_class = LABEL_SMALL_CLASSES if len(line) <= 3 else LABEL_CLASSES
384376
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.
386377
labels_list.append({
387378
"ref": lbl,
388379
"base_classes": base_class,
389380
"base_style": get_line_style_for_lines(line_count, default_text_color)
390381
})
391-
# Store both the card and its labels in the global tile_buttons dict.
392382
tile_buttons_dict[(row_idx, col_idx)] = {"card": card, "labels": labels_list}
393383
if phrase.upper() == FREE_SPACE_TEXT:
394384
clicked_tiles.add((row_idx, col_idx))
@@ -404,8 +394,6 @@ def update_tile_styles(tile_buttons_dict: dict):
404394
for (r, c), tile in tile_buttons_dict.items():
405395
# tile is a dict with keys "card" and "labels"
406396
phrase = board[r][c]
407-
if phrase.upper() == FREE_SPACE_TEXT:
408-
continue
409397

410398
if (r, c) in clicked_tiles:
411399
new_card_style = f"background-color: {TILE_CLICKED_BG_COLOR}; color: {TILE_CLICKED_TEXT_COLOR}; border: none;"
@@ -442,7 +430,7 @@ def check_phrases_file_change():
442430
Check if phrases.txt has changed. If so, re-read the file, update the board,
443431
and re-render the board UI.
444432
"""
445-
global last_phrases_mtime, phrases, board, tile_buttons, home_board_container
433+
global last_phrases_mtime, phrases, board, board_views
446434
try:
447435
mtime = os.path.getmtime("phrases.txt")
448436
except Exception as e:
@@ -456,13 +444,14 @@ def check_phrases_file_change():
456444
phrases = [line.strip().upper() for line in f if line.strip()]
457445
# Rebuild board data: re-shuffle and re-create board structure.
458446
shuffled_phrases = random.sample(phrases, 24)
459-
shuffled_phrases.insert(12, "FREE MEAT")
447+
shuffled_phrases.insert(12, FREE_SPACE_TEXT)
460448
board = [shuffled_phrases[i:i+5] for i in range(0, 25, 5)]
461-
# Clear the board UI and rebuild it.
462-
home_board_container.clear()
463-
tile_buttons.clear() # Clear global dictionary.
464-
build_board(home_board_container, tile_buttons, toggle_tile)
465-
home_board_container.update() # Force update so new styles are applied immediately.
449+
# Update all board views (both home and stream)
450+
for view, (container, tile_buttons_local) in board_views.items():
451+
container.clear()
452+
tile_buttons_local.clear() # Clear local board dictionary.
453+
build_board(container, tile_buttons_local, toggle_tile)
454+
container.update() # Force update so new styles are applied immediately.
466455
ui.run_javascript(
467456
"fitty('.fit-text', { multiLine: true, minSize: 10, maxSize: 1000 });"
468457
"fitty('.fit-text-small', { multiLine: true, minSize: 10, maxSize: 72 });"

0 commit comments

Comments
 (0)