From c97e1d2eaee6de00f4a37c2538361081b24cdf32 Mon Sep 17 00:00:00 2001 From: Daniel Nagel Date: Wed, 20 May 2026 14:16:20 +0000 Subject: [PATCH 1/2] =?UTF-8?q?Player=20Card=20f=C3=BCr=20Custom=20Leaderb?= =?UTF-8?q?oad=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/data_api.py | 18 ++++++++------- gui/league_statistic_gui.py | 32 +++++---------------------- gui/league_statistic_visitor_gui.py | 14 ++++++++++-- gui/main_gui.py | 4 +++- gui/templates/leaderboard.py | 24 ++++++++++++++++++++ gui/templates/player_card.py | 34 +++++++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 37 deletions(-) create mode 100644 gui/templates/leaderboard.py create mode 100644 gui/templates/player_card.py diff --git a/data/data_api.py b/data/data_api.py index c4badca..0cc3ae5 100644 --- a/data/data_api.py +++ b/data/data_api.py @@ -407,19 +407,21 @@ def get_gamesystems_data(): return rows + def get_leaderboard(system_name): """Holt alle Spieler eines Systems sortiert nach MMR für die Rangliste.""" connection = db_connection() cursor = connection.cursor(dictionary=True) - query = """ - SELECT p.id, p.display_name, p.discord_name, stat.mmr - FROM players p - JOIN player_game_statistic stat ON p.id = stat.player_id - JOIN gamesystems sys ON stat.gamesystem_id = sys.id - WHERE sys.name = %s AND stat.games_in_system > 0 - ORDER BY stat.mmr DESC - """ + query = query = """ + SELECT p.id, p.display_name, p.discord_name, p.discord_id, p.discord_avatar_url, + stat.mmr, stat.games_in_system, stat.wins, stat.loss, stat.avv_points + FROM players p + JOIN player_game_statistic stat ON p.id = stat.player_id + JOIN gamesystems sys ON stat.gamesystem_id = sys.id + WHERE sys.name = %s AND stat.games_in_system > 0 + ORDER BY stat.mmr DESC +""" cursor.execute(query, (system_name,)) rows = cursor.fetchall() diff --git a/gui/league_statistic_gui.py b/gui/league_statistic_gui.py index 3a76d03..21672f5 100644 --- a/gui/league_statistic_gui.py +++ b/gui/league_statistic_gui.py @@ -2,6 +2,7 @@ from nicegui import ui, app from gui import gui_style from data import data_api from gui.info_text import info_system +from gui.templates.leaderboard import Leaderboard def setup_routes(): @ui.page('/statistic/{systemname}', dark=True) @@ -30,6 +31,7 @@ def setup_routes(): last_played_raw = system_stat.get("last_played") last_played = str(last_played_raw)[:10] if last_played_raw else "-" + # Header with ui.header().classes('items-center justify-between bg-zinc-900 p-4 shadow-lg'): ui.button(icon="arrow_back", on_click=lambda: ui.navigate.to('/')).props("round") ui.button("Spiel eintragen", on_click=lambda: ui.navigate.to(f'/add-match/{systemname}')) @@ -38,28 +40,6 @@ def setup_routes(): ui.label(f'Deine Statistik in {systemname}').classes('text-3xl justify-center font-bold text-normaltext') # --- BLOCK 1 (MMR & Rang | Rangliste) --- - leaderboard_data = data_api.get_leaderboard(systemname) - table_rows = [] - my_rank = "-" - - for index, player in enumerate(leaderboard_data): - current_rank = index + 1 - if player['id'] == player_id: - my_rank = current_rank - table_rows.append({ - 'rank': current_rank, - 'trend': '➖', - 'name': f"{player['display_name']} 'aka' {player['discord_name']}", - 'mmr': player['mmr'] - }) - - table_columns = [ - {'name': 'rank', 'label': '#', 'field': 'rank', 'align': 'left'}, - {'name': 'trend', 'label': 'Trend', 'field': 'trend', 'align': 'center'}, - {'name': 'name', 'label': 'Spieler', 'field': 'name', 'align': 'left'}, - {'name': 'mmr', 'label': 'MMR', 'field': 'mmr', 'align': 'left'}, - ] - with ui.element('div').classes("w-full grid grid-cols-1 lg:grid-cols-3 gap-4 mt-4"): with ui.column().classes("w-full gap-4"): with ui.card().classes("w-full items-center justify-center text-center"): @@ -74,11 +54,11 @@ def setup_routes(): ui.label("Rang: ").classes('justify-center text-2xl font-bold text-normaltext') ui.space() info_system.create_info_button("rang_info") - ui.label(str(my_rank)).classes('text-4xl font-bold text-blue-100') + ui.label(str("my_rank")).classes('text-4xl font-bold text-blue-100') - with ui.card().classes("w-full lg:col-span-2"): - ui.label("Liga Rangliste").classes("text-xl font-bold text-white mb-2") - ui.table(columns=table_columns, rows=table_rows, row_key='rank').classes('w-full bg-zinc-900 text-white') + with ui.card().classes("w-full lg:col-span-2"): + ui.label("Liga Rangliste").classes("text-xl font-bold text-white mb-2") + Leaderboard(systemname) # --- BLOCK 2 (5 Karten) --- with ui.card().classes("w-full"): diff --git a/gui/league_statistic_visitor_gui.py b/gui/league_statistic_visitor_gui.py index a4bd196..5db40c8 100644 --- a/gui/league_statistic_visitor_gui.py +++ b/gui/league_statistic_visitor_gui.py @@ -3,12 +3,22 @@ from gui import gui_style from data import data_api from gui.info_text import info_system +from gui.templates.leaderboard import Leaderboard + + + def setup_routes(): @ui.page('/statistic/visitor/{systemname}', dark=True) def gamesystem_statistic_visitor_page(systemname: str): - if not app.storage.user.get('authenticated', False): ui.navigate.to('/') return - gui_style.apply_design() \ No newline at end of file + gui_style.apply_design() + + with ui.header().classes('items-center justify-between bg-zinc-900 p-4 shadow-lg'): + ui.button(icon="arrow_back", on_click=lambda: ui.navigate.to('/')).props("round") + + with ui.column().classes('w-full items-center justify-center mt-10'): + ui.label(f'Die aktuelle Statistik in {systemname}').classes('text-3xl justify-center font-bold text-normaltext') + Leaderboard(systemname) \ No newline at end of file diff --git a/gui/main_gui.py b/gui/main_gui.py index b088ee9..0f291d0 100644 --- a/gui/main_gui.py +++ b/gui/main_gui.py @@ -43,7 +43,7 @@ def setup_routes(admin_discord_id): # --- RECHTE SEITE --- if app.storage.user.get('authenticated', False): with ui.row().classes('items-center gap-4'): - ui.image(app.storage.user.get('discord_avatar_url')).classes('w-15 h-15 rounded-full') + ui.image(app.storage.user.get('discord_avatar_url')).classes('w-15 h-15 rounded-full border-1 border-red-900') discord_name = app.storage.user.get('discord_name') display_name = app.storage.user.get('display_name') player_id = app.storage.user.get('db_id') @@ -213,6 +213,8 @@ def setup_routes(admin_discord_id): # Prüfen: Ist diese sys_id in den Stats des Spielers? UND hat er ein MMR? if sys_id not in my_stats or my_stats[sys_id]['mmr'] is None: ui.label(text="Du bist noch nicht in dieser Liga.").classes("text-red-500 font-bold") + sys_card.classes("cursor-pointer hover:bg-zinc-800") + sys_card.on('click', lambda e, name=sys_name: ui.navigate.to(f'/statistic/visitor/{name}')) join_row = ui.row().classes('items-center gap-2') confirm_row = ui.row().classes('items-center gap-2') diff --git a/gui/templates/leaderboard.py b/gui/templates/leaderboard.py new file mode 100644 index 0000000..8bb0d8b --- /dev/null +++ b/gui/templates/leaderboard.py @@ -0,0 +1,24 @@ +from nicegui import ui +from data import data_api +from gui.templates.player_card import PlayerCard + +class Leaderboard: + def __init__(self, system_name: str): + # Daten holen + leaderboard_data = data_api.get_leaderboard(system_name) + + # Container + with ui.column().classes('w-full gap-2') as self.container: + for index, player in enumerate(leaderboard_data): + PlayerCard( + rank=index + 1, + display_name=player['display_name'], + discord_name=player['discord_name'], + mmr=player['mmr'], + discord_avatar_url=player.get('discord_avatar_url'), + discord_id=player.get('discord_id'), + games_in_system=player.get('games_in_system', 0), + wins=player.get('wins', 0), + loss=player.get('loss', 0), + avv_points=player.get('avv_points', 0) + ) diff --git a/gui/templates/player_card.py b/gui/templates/player_card.py new file mode 100644 index 0000000..5cab674 --- /dev/null +++ b/gui/templates/player_card.py @@ -0,0 +1,34 @@ +from nicegui import ui + +class PlayerCard: + def __init__(self, rank: int, display_name: str, discord_name: str, mmr: int, + discord_avatar_url: str = None, discord_id: str = None, + games_in_system: int = 0, wins: int = 0, loss: int = 0, avv_points: int = 0): + + # Rang links, Card rechts + with ui.row().classes('w-full items-center gap-2'): + ui.label(f'#{rank}').classes('text-2xl font-bold w-12 text-right') + + with ui.card().classes("w-flex1 no-shadow bg-zinc-900"): + with ui.row(): + if discord_avatar_url: + ui.image(discord_avatar_url).classes('w-10 h-10 rounded-full border-red-900 border-2') + with ui.column().classes('gap-0'): + if discord_id: + ui.link(display_name, + f'https://discord.com/users/{discord_id}', + new_tab=True).classes('text-lg font-bold no-underline') + else: + ui.label(display_name).classes('text font-bold') + ui.label(discord_name).classes('text-sm opacity-60') + + with ui.row().classes('w-full items-center'): + with ui.row().classes('flex-1 items-center gap-3'): + ui.label(f'{mmr} MMR').classes('font-bold') + ui.label(f'{games_in_system} Games').classes('font-bold') + ui.label(f'{avv_points} Øpts').classes('font-bold') + with ui.row().classes('flex-1 items-center gap-3'): + ui.image('gui/pictures/achievments/AchievementIcon_4_1Sieg.png').classes('w-5') + ui.image('gui/pictures/achievments/AchievementIcon_4_1Sieg.png').classes('w-5') + ui.image('gui/pictures/achievments/AchievementIcon_4_1Sieg.png').classes('w-5') + -- 2.43.0 From b398049c2e4fcd8fc18905b4a7c085dff282ba5f Mon Sep 17 00:00:00 2001 From: Daniel Nagel Date: Thu, 21 May 2026 14:00:51 +0000 Subject: [PATCH 2/2] gui und mobile user expirience verbessert. --- data/data_api.py | 30 +++++++- gui/league_statistic_gui.py | 136 ++++++++++++++++------------------- gui/main_gui.py | 14 ++-- gui/templates/player_card.py | 55 +++++++------- 4 files changed, 128 insertions(+), 107 deletions(-) diff --git a/data/data_api.py b/data/data_api.py index 0cc3ae5..cb88fb5 100644 --- a/data/data_api.py +++ b/data/data_api.py @@ -190,7 +190,7 @@ def get_player_statistic(player_id, system_id): SELECT sys.id AS gamesystem_id, sys.name AS gamesystem_name, - sys.*, + sys.description, stat.mmr, stat.games_in_system, stat.points, @@ -206,6 +206,7 @@ def get_player_statistic(player_id, system_id): ON sys.id = stat.gamesystem_id AND stat.player_id = %s WHERE sys.id = %s """ + cursor.execute(query, (player_id, system_id)) row = cursor.fetchone() @@ -214,6 +215,33 @@ def get_player_statistic(player_id, system_id): return row +def get_player_rank(player_id, system_id): + """Holt den Rang eines Spielers in einem System basierend auf MMR (absteigend).""" + connection = db_connection() + cursor = connection.cursor(dictionary=True) + + query = """ + SELECT COUNT(*) + 1 AS rank + FROM player_game_statistic stat + WHERE stat.gamesystem_id = %s + AND stat.games_in_system > 0 + AND stat.mmr > ( + SELECT stat2.mmr + FROM player_game_statistic stat2 + WHERE stat2.player_id = %s + AND stat2.gamesystem_id = %s + ) + """ + cursor.execute(query, (system_id, player_id, system_id)) + row = cursor.fetchone() + + cursor.close() + connection.close() + + if row and row['rank'] is not None: + return row['rank'] + return None + def join_league(player_id, gamesystem_id): connection = db_connection() cursor = connection.cursor() diff --git a/gui/league_statistic_gui.py b/gui/league_statistic_gui.py index 21672f5..00280e4 100644 --- a/gui/league_statistic_gui.py +++ b/gui/league_statistic_gui.py @@ -5,8 +5,8 @@ from gui.info_text import info_system from gui.templates.leaderboard import Leaderboard def setup_routes(): - @ui.page('/statistic/{systemname}', dark=True) - def gamesystem_statistic_page(systemname: str): + @ui.page('/statistic/{system_name}', dark=True) + def gamesystem_statistic_page(system_name: str): if not app.storage.user.get('authenticated', False): ui.navigate.to('/') @@ -15,91 +15,77 @@ def setup_routes(): gui_style.apply_design() player_id = app.storage.user.get('db_id') - all_stats = data_api.get_player_statistics(player_id) + system_id = data_api.get_gamesystem_id_by_name(system_name) + print(player_id, system_id) - # Passendes System anhand des Namens (case-insensitive) herausfiltern - system_stat = next( - (s for s in all_stats if s["gamesystem_name"].lower() == systemname.lower()), - None - ) + player_stats = data_api.get_player_statistic(player_id, system_id) + + # Header + with ui.header().classes('items-center justify-between bg-zinc-900 p-4 shadow-lg'): + ui.button(icon="arrow_back", on_click=lambda: ui.navigate.to('/')).props("round") + ui.button("Spiel eintragen", on_click=lambda: ui.navigate.to(f'/add-match/{system_name}')) - if system_stat: - mmr = system_stat["mmr"] or 0 - games = system_stat["games_in_system"] or 0 - points = system_stat["points"] or 0 - avv_points = system_stat.get("avv_points") or "-" - last_played_raw = system_stat.get("last_played") - last_played = str(last_played_raw)[:10] if last_played_raw else "-" + with ui.column().classes('w-full items-center justify-center mt-10'): + ui.label(f'Deine Statistik in {system_name}').classes('text-3xl justify-center font-bold text-normaltext') - # Header - with ui.header().classes('items-center justify-between bg-zinc-900 p-4 shadow-lg'): - ui.button(icon="arrow_back", on_click=lambda: ui.navigate.to('/')).props("round") - ui.button("Spiel eintragen", on_click=lambda: ui.navigate.to(f'/add-match/{systemname}')) + # --- BLOCK 1 (MMR & Rang | Rangliste) --- + with ui.element('div').classes("w-full grid grid-cols-1 lg:grid-cols-3 gap-4 mt-4"): + with ui.column().classes("w-full gap-4"): + with ui.card().classes("w-full items-center justify-center text-center"): + with ui.row().classes("w-full items-center text-center"): + ui.label("MMR Punkte: ").classes('justify-center text-2xl font-bold text-normaltext') + ui.space() + info_system.create_info_button("mmr_info") + ui.label(str(player_stats["mmr"])).classes('text-4xl font-bold text-accent') - with ui.column().classes('w-full items-center justify-center mt-10'): - ui.label(f'Deine Statistik in {systemname}').classes('text-3xl justify-center font-bold text-normaltext') + with ui.card().classes("w-full items-center justify-center text-center"): + with ui.row().classes("w-full items-center text-center"): + ui.label("Rang: ").classes('justify-center text-2xl font-bold text-normaltext') + ui.space() + info_system.create_info_button("rang_info") + ui.label(str(data_api.get_player_rank(player_id,system_id))).classes('text-4xl font-bold text-blue-100') - # --- BLOCK 1 (MMR & Rang | Rangliste) --- - with ui.element('div').classes("w-full grid grid-cols-1 lg:grid-cols-3 gap-4 mt-4"): - with ui.column().classes("w-full gap-4"): - with ui.card().classes("w-full items-center justify-center text-center"): - with ui.row().classes("w-full items-center text-center"): - ui.label("MMR Punkte: ").classes('justify-center text-2xl font-bold text-normaltext') - ui.space() - info_system.create_info_button("mmr_info") - ui.label(str(mmr)).classes('text-4xl font-bold text-accent') + + with ui.card().classes("w-full lg:col-span-2 max-h-[50vh] overflow-y-auto"): + ui.label("Liga Rangliste").classes("text-xl font-bold text-white mb-2 top-0 bg-zinc-900 z-10") + Leaderboard(system_name) - with ui.card().classes("w-full items-center justify-center text-center"): - with ui.row().classes("w-full items-center text-center"): - ui.label("Rang: ").classes('justify-center text-2xl font-bold text-normaltext') - ui.space() - info_system.create_info_button("rang_info") - ui.label(str("my_rank")).classes('text-4xl font-bold text-blue-100') + # --- BLOCK 2 (5 Karten) --- + with ui.card().classes("w-full"): + with ui.element('div').classes("w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"): - with ui.card().classes("w-full lg:col-span-2"): - ui.label("Liga Rangliste").classes("text-xl font-bold text-white mb-2") - Leaderboard(systemname) + with ui.card().classes("items-center justify-center text-center"): + ui.label("Spiele: ").classes('text-2xl font-bold') + ui.label(str(player_stats["games_in_system"])).classes('text-4xl font-bold text-blue-100') - # --- BLOCK 2 (5 Karten) --- - with ui.card().classes("w-full"): - with ui.element('div').classes("w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"): + with ui.card().classes("items-center justify-center text-center"): + ui.label("Ø Punkte pro Spiel: ").classes('text-2xl font-bold') + ui.label(str(player_stats["avv_points"])).classes('text-4xl font-bold text-blue-100') - with ui.card().classes("items-center justify-center text-center"): - ui.label("Spiele: ").classes('text-2xl font-bold') - ui.label(str(games)).classes('text-4xl font-bold text-blue-100') + with ui.card().classes("items-center justify-center text-center"): + ui.label("Win-Rate: ").classes('text-2xl font-bold') + ui.label("-").classes('text-4xl font-bold text-blue-100') - with ui.card().classes("items-center justify-center text-center"): - ui.label("Ø Punkte pro Spiel: ").classes('text-2xl font-bold') - ui.label(str(avv_points)).classes('text-4xl font-bold text-blue-100') + with ui.card().classes("items-center justify-center text-center"): + ui.label("Letztes Spiel am: ").classes('text-2xl font-bold') + ui.label(str(player_stats["last_played"])).classes('text-4xl font-bold text-blue-100') - with ui.card().classes("items-center justify-center text-center"): - ui.label("Win-Rate: ").classes('text-2xl font-bold') - ui.label("-").classes('text-4xl font-bold text-blue-100') + with ui.card().classes("items-center justify-center text-center"): + ui.label("Win-Streak: ").classes('text-2xl font-bold') + ui.label("-").classes('text-4xl font-bold text-blue-100') - with ui.card().classes("items-center justify-center text-center"): - ui.label("Letztes Spiel am: ").classes('text-2xl font-bold') - ui.label(last_played).classes('text-4xl font-bold text-blue-100') + # --- BLOCK 3 (3 Karten) --- + with ui.card().classes("w-full"): + with ui.element('div').classes("w-full grid grid-cols-1 md:grid-cols-3 lg:grid-cols-3 gap-4"): - with ui.card().classes("items-center justify-center text-center"): - ui.label("Win-Streak: ").classes('text-2xl font-bold') - ui.label("-").classes('text-4xl font-bold text-blue-100') + with ui.card().classes("items-center justify-center text-center"): + ui.label("Dein Nemesis: ").classes('text-2xl font-bold') + ui.label(str(player_stats["nemesis_id"])).classes('text-4xl font-bold text-blue-100') - # --- BLOCK 3 (3 Karten) --- - with ui.card().classes("w-full"): - with ui.element('div').classes("w-full grid grid-cols-1 md:grid-cols-3 lg:grid-cols-3 gap-4"): + with ui.card().classes("items-center justify-center text-center"): + ui.label("Meisten Spiele mit: ").classes('text-2xl font-bold') + ui.label(str(player_stats["nemesis_id"])).classes('text-4xl font-bold text-blue-100') - with ui.card().classes("items-center justify-center text-center"): - ui.label("Dein Nemesis: ").classes('text-2xl font-bold') - ui.label("-").classes('text-4xl font-bold text-blue-100') - - with ui.card().classes("items-center justify-center text-center"): - ui.label("Meisten Spiele mit: ").classes('text-2xl font-bold') - ui.label("-").classes('text-4xl font-bold text-blue-100') - - with ui.card().classes("items-center justify-center text-center"): - ui.label("Dein 'Prügelknabe': ").classes('text-2xl font-bold') - ui.label("-").classes('text-4xl font-bold text-blue-100') - - else: - with ui.column().classes('w-full items-center justify-center mt-10'): - ui.label(f'Keine Statistik für "{systemname}" gefunden.').classes('text-red-500 text-xl mt-4') + with ui.card().classes("items-center justify-center text-center"): + ui.label("Dein 'Prügelknabe': ").classes('text-2xl font-bold') + ui.label(str(player_stats["pushover_id"])).classes('text-4xl font-bold text-blue-100') \ No newline at end of file diff --git a/gui/main_gui.py b/gui/main_gui.py index 0f291d0..3f689fb 100644 --- a/gui/main_gui.py +++ b/gui/main_gui.py @@ -31,19 +31,19 @@ def setup_routes(admin_discord_id): # --- LINKE SEITE --- # Vereinslogo und den Titel in einer eigenen Reihe (Reihe 1) with ui.row().classes('items-center'): - ui.image("gui/pictures/wsdg.png").classes('w-15 h-15 rounded-full') - ui.label('Diceghost Liga').classes('text-2xl font-bold text-normaltext') + ui.image("gui/pictures/wsdg.png").classes('w-12 h-12 md:w-25 md:h-25 rounded-full') + ui.label('Westside Diceghost Liga').classes('text-lg md:text-3xl font-bold text-normaltext') # --- MITTE --- if app.storage.user.get('authenticated', False): discord_id = app.storage.user.get("discord_id") if discord_id == admin_discord_id: - ui.button(icon="hardware", on_click=lambda: ui.navigate.to('/admin')).props("round") + ui.button(icon="hardware", on_click=lambda: ui.navigate.to('/admin')).classes('w-2 h-2') # --- RECHTE SEITE --- if app.storage.user.get('authenticated', False): with ui.row().classes('items-center gap-4'): - ui.image(app.storage.user.get('discord_avatar_url')).classes('w-15 h-15 rounded-full border-1 border-red-900') + ui.image(app.storage.user.get('discord_avatar_url')).classes('w-10 h-10 md:w-25 md:h-25 rounded-full border-1 border-red-900') discord_name = app.storage.user.get('discord_name') display_name = app.storage.user.get('display_name') player_id = app.storage.user.get('db_id') @@ -57,10 +57,10 @@ def setup_routes(admin_discord_id): # --- ANSICHT 1: Der normale Text mit Edit-Button --- with ui.column().classes('items-center gap-0') as display_row: with ui.column(): - ui.label(display_name).classes('text-xl font-bold text-normaltext') + ui.label(display_name).classes('md:text-3xl font-bold text-normaltext') with ui.row().classes("items-center justify-between"): - ui.label("'aka'").classes('text-sm text-italic text-infotext') - ui.label(discord_name).classes('text-m text-bold text-infotext') + ui.label("'aka'").classes('md:text-lg text-xs text-italic text-infotext') + ui.label(discord_name).classes('text-sm md:text-xl text-bold text-infotext') edit_button = ui.button(icon='edit', color='accent', on_click=toggle_edit_mode).props('round dense') # --- ANSICHT 2: Das Eingabefeld (startet unsichtbar!) --- diff --git a/gui/templates/player_card.py b/gui/templates/player_card.py index 5cab674..1f6f799 100644 --- a/gui/templates/player_card.py +++ b/gui/templates/player_card.py @@ -6,29 +6,36 @@ class PlayerCard: games_in_system: int = 0, wins: int = 0, loss: int = 0, avv_points: int = 0): # Rang links, Card rechts - with ui.row().classes('w-full items-center gap-2'): - ui.label(f'#{rank}').classes('text-2xl font-bold w-12 text-right') + with ui.row().classes('w-full items-center gap-1 flex-nowrap'): + ui.label(f'#{rank}').classes('text-2xl font-bold w-10 text-center shrink-0') - with ui.card().classes("w-flex1 no-shadow bg-zinc-900"): - with ui.row(): - if discord_avatar_url: - ui.image(discord_avatar_url).classes('w-10 h-10 rounded-full border-red-900 border-2') - with ui.column().classes('gap-0'): - if discord_id: - ui.link(display_name, - f'https://discord.com/users/{discord_id}', - new_tab=True).classes('text-lg font-bold no-underline') - else: - ui.label(display_name).classes('text font-bold') - ui.label(discord_name).classes('text-sm opacity-60') + # Player Card + with ui.card().classes("flex-1 no-shadow bg-zinc-900 min-w-0 overflow-hidden"): + # Discord Block - klickbar + if discord_id: + with ui.link(target=f'https://discord.com/users/{discord_id}', new_tab=True).classes('no-underline w-full'): + self._discord_content(discord_avatar_url, display_name, discord_name) + else: + self._discord_content(discord_avatar_url, display_name, discord_name) - with ui.row().classes('w-full items-center'): - with ui.row().classes('flex-1 items-center gap-3'): - ui.label(f'{mmr} MMR').classes('font-bold') - ui.label(f'{games_in_system} Games').classes('font-bold') - ui.label(f'{avv_points} Øpts').classes('font-bold') - with ui.row().classes('flex-1 items-center gap-3'): - ui.image('gui/pictures/achievments/AchievementIcon_4_1Sieg.png').classes('w-5') - ui.image('gui/pictures/achievments/AchievementIcon_4_1Sieg.png').classes('w-5') - ui.image('gui/pictures/achievments/AchievementIcon_4_1Sieg.png').classes('w-5') - + # Stats und Achievments + with ui.row().classes('w-full items-center flex-nowrap'): + with ui.row().classes('flex-2 items-center gap-2 md:gap-3 md:justify-center shrink min-w-0'): + ui.label(f'{mmr} MMR').classes('font-bold md:text-lg') + with ui.row().classes('flex-1 justify-end items-center gap-1 md:gap-3 shrink-0'): + ui.image('gui/pictures/achievments/AchievementIcon_4_1Sieg.png').classes('w-5 md:w-15') + ui.image('gui/pictures/achievments/AchievementIcon_4_1Sieg.png').classes('w-5 md:w-15') + ui.image('gui/pictures/achievments/AchievementIcon_4_1Sieg.png').classes('w-5 md:w-15') + + + def _discord_content(self, avatar_url, display_name, discord_name): + short_name = display_name[:15] + '...' if len(display_name) > 15 else display_name + short_discord = discord_name[:15] + '...' if len(discord_name) > 15 else discord_name + + with ui.card().classes("w-full md:w-90 bg-indigo-950 no-shadow"): + with ui.row().classes('items-center gap-3 min-w-0'): + if avatar_url: + ui.image(avatar_url).classes('w-10 h-10 md:w-20 md:h-20 rounded-full border-red-900 border-2 shrink-0') + with ui.column().classes('gap-0 min-w-0'): + ui.label(short_name).classes('text-sm md:text-2xl font-bold whitespace-nowrap truncate') + ui.label(short_discord).classes('text-xs md:text-sm opacity-60 whitespace-nowrap truncate') -- 2.43.0