from fasthtml.common import * # using https://www.fastht.ml/docs/tutorials/by_example.html app,rt = fast_app(pico=True) ## From HF ## Initial set of scores information scores = { # Team A 'A_goals': 0, # goals 'A_points': 0, # points # Team B 'B_goals': 0, # goals 'B_points': 0, # points } # Track scores time series in memory scores_ts = {} scores_id = len(scores_ts)+1 scores_ts[scores_id] = {"scores": scores.copy()} # Default team names team_A = "Bishopstown" team_B = "Other Team" def create_score_button(team_code, score_type): # Determine the unique ID for the button's target span span_id = f"{team_code}_{score_type}" # Determine the key to pass to the increment function counter_name = f"{team_code}_{score_type}" return Button( Span(f"{scores[counter_name]}", id=span_id), hx_post="/increment", hx_target=f"#{span_id}", hx_vals=f'{{"counter": "{counter_name}"}}', hx_swap="innerHTML" ) def create_score_section(team_code): return ( H1(create_score_button(f"{team_code}", "goals"), Span(" "), create_score_button(f"{team_code}", "points"), cls="card-title"), ) verbose = False @app.post("/increment") def increment(counter: str): if verbose: print("incrementing") global scores if counter in scores: scores[counter] += 1 ## Add new score to time series global scores_ts scores_id = len(scores_ts) scores_ts[scores_id+1] = {"scores": scores.copy()} ## Return the text that is expected for the button update return f"{scores[counter]}" @app.post("/reset") def reset_scores_and_page(): if verbose: print("reseting") global scores scores = { # Team A 'A_goals': 0, # goals 'A_points': 0, # points # Team B 'B_goals': 0, # goals 'B_points': 0, # points } global scores_ts scores_ts = {} scores_id = len(scores_ts)+1 scores_ts[scores_id] = {"scores": scores.copy()} # Return a response to reload the table return set_table(team_A, team_B) @app.post("/reset_recent") def reset_to_last_score_and_page(): if verbose: print("reseting to recent") global scores global scores_ts ## previous index scores_id = len(scores_ts) if scores_id > 1: scores = scores_ts[scores_id-1]["scores"] ## Drop the latest entry in the score time series #scores_ts[scores_id+1] = {"scores": scores.copy()} scores_ts.pop(scores_id) # Return a response to reload the score table return set_table(team_A, team_B) @rt def index(): return Titled('GAA Score Keeper', Div( P('Enter the team names'), Form(Input(name='team_name_A', value=team_A), Input(name='team_name_B', value=team_B), Button('Click'), hx_post='/set_table', hx_target='#main'), id='main')) @rt def set_table(team_name_A:str, team_name_B:str): global team_A global team_B team_A = team_name_A ## Update global team_B = team_name_B ## Update global print("set_table called"+team_A+team_B) return Main( Div( Table( Tr( Th(H2(team_A)), Th(H2(team_B)) ), Tr( Td(create_score_section(team_code = "A"),style="text-align: center;"), Td(create_score_section(team_code = "B"),style="text-align: center;") ) ), Br(), Br(), Div( id="timer_display", hx_get="/timer", hx_trigger="every 1s", style="text-align: center; margin-top: 20px; cursor: pointer;" ), style="flex-grow: 1;" ), Div( Button( Span("Undo"), hx_post="/reset_recent", hx_target='#main' ), Button( Span("Toggle Clock"), hx_post="/timer_toggle", hx_target='#timer_display' ), Button( Span("Full Reset"), hx_post="/reset", hx_target='#main' ), style = "display: flex; justify-content: space-between;" ), style="display: flex; flex-direction: column; min-height: 80vh;" ) # Timer state timer_state = { 'start_time': None, 'is_running': False } @app.get("/timer") def get_timer(): import time if timer_state['is_running'] and timer_state['start_time']: elapsed = time.time() - timer_state['start_time'] minutes = int(elapsed // 60) seconds = int(elapsed % 60) color = "red" if minutes >= 30 else "green" return Span(f"{minutes:02d}:{seconds:02d}", style=f"color: {color}; font-size: 2em;") return Span("00:00", style="color: green; font-size: 2em;") @app.post("/timer_toggle") def toggle_timer(): import time if timer_state['is_running']: timer_state['is_running'] = False else: timer_state['start_time'] = time.time() timer_state['is_running'] = True return get_timer() serve(port=7860)