## Implementation Plan: Fix leaderboard username squeeze when a title is equipped ### Root Cause In `devplacepy/static/css/game.css`, the leaderboard row uses flex layout. The username link (`.game-lb-name`) has `flex: 1; min-width: 0`, making it shrink to zero when the total row width is exceeded. The title (`.game-lb-title`) has `flex-shrink: 0`, so it never shrinks. When a long title like "Serial Refactorer" is present, the username collapses to ~1 pixel, becoming invisible (only an ellipsis shown). ### Change Summary Restructure the leaderboard row in the JavaScript template (`GameFarm.js`) and update corresponding CSS (`game.css`) so that the username and title are stacked vertically inside a flex column container, rather than competing on the same horizontal line. Specifically: - In the JS template, wrap the `` and the optional `` in a new `div` with a class `game-lb-name-group`. - Adjust the CSS so that `.game-lb-name-group` is a flex column (no gap), the name link retains clickable styling, and the title is a small italic line below the name. - Ensure the overall row still fits within the container and the username never gets hidden. ### Files to Modify 1. **`devplacepy/static/js/GameFarm.js`** – lines 370–374 Change the template literal to wrap the name and title in a container. 2. **`devplacepy/static/css/game.css`** – lines 224–271 Update `.game-lb-row`, `.game-lb-name`, `.game-lb-title` rules to accommodate the new structure. Remove the conflicting `flex: 1; min-width: 0` from `.game-lb-name`. Add `.game-lb-name-group` styling. 3. **Optional but recommended: `tests/e2e/game/index.py`** – add a new test case that equips a title and asserts the username link is visible and clickable. ### Detailed Steps #### Step 1: Modify the JavaScript template (`GameFarm.js`) **Current (lines 370–374):** ```javascript const title = entry.title ? `${entry.title}` : ""; const value = this._leaderboardValue(board, entry); return `
  • #${entry.rank} ${entry.username} ${title} Lv ${entry.level} ${value}
  • `; ``` **New:** ```javascript const title = entry.title ? `${entry.title}` : ""; const value = this._leaderboardValue(board, entry); return `
  • #${entry.rank}
    ${entry.username} ${title}
    Lv ${entry.level} ${value}
  • `; ``` #### Step 2: Update CSS (`game.css`) **Remove or replace the following:** - `.game-lb-name` (line 244–254): change `flex: 1` → remove flex properties, keep link styling (`font-weight: 600`, `text-decoration: none`, etc.). Add `white-space: nowrap; overflow: hidden; text-overflow: ellipsis;` so that if the username itself is very long it still truncates, but it will now have a minimum width via its container. - `.game-lb-title` (line 266–271): remove `flex-shrink: 0;` because it's no longer a direct child of the row. Keep `font-style: italic; color: var(--accent);` and add `display: block;` (or `inline-block`) and `font-size: 0.75rem;` to appear on a second line. **Add new rule:** ```css .game-lb-name-group { display: flex; flex-direction: column; align-items: flex-start; flex: 1; /* take remaining space */ min-width: 0; overflow: hidden; /* clip if name + title overflow horizontally */ } ``` **Adjust `.game-lb-row` (line 224):** no changes needed; still `display: flex; align-items: center; gap: var(--space-sm);`. **Adjust `.game-lb-rank`, `.game-lb-level`, `.game-lb-score`:** they keep their `flex-shrink: 0` and fixed widths. #### Step 3: Update E2E test (optional but recommended) Add a test in `tests/e2e/game/index.py` that: 1. Equips a known title (e.g., "Serial Refactorer" from cosmetics shop). 2. Opens the game page. 3. Asserts that the username link is visible, has the correct `href`, and that the title text is also visible. Example: ```python def test_leaderboard_shows_username_and_title(alice): page, _ = alice reset_farm("alice_test") # equip title "Serial Refactorer" page.goto("/game/farm/alice_test/shop") # ... (locate and click equip for that title) open_game(page) page.locator(".game-lb-row").first.wait_for(state="visible") # username must be visible and clickable link = page.locator("a.game-lb-name[href='/game/farm/alice_test']") expect(link).to_be_visible() expect(link).to_have_text("alice_test") # title must be rendered title_span = page.locator(".game-lb-title") expect(title_span).to_be_visible() expect(title_span).to_have_text("Serial Refactorer") ``` Place this test after `test_leaderboard_panel_populates` (line 290). ### Verification (Definition of Done) - [ ] The CSS change is applied correctly: inspect a row with a title equipped; the username is fully visible, forms a link to the player’s farm page, and the title is shown as an italic badge on a new line below the username. - [ ] All existing unit/integration tests pass when running the project’s own test command: `pip install -e '.[dev]' -q && python -m pytest tests/` (If any pre-existing failures occur, they are unrelated to this change; no new failures are introduced.) - [ ] The E2E test `test_leaderboard_shows_username_and_title` (if added) passes. - [ ] Manual verification in a browser: 1. Log in and equip a cosmetic title like "Serial Refactorer" via the shop. 2. Navigate to `/game`. 3. Confirm the player’s row on the leaderboard shows the clickable username link on the first line and the title on a second line. 4. Click the username link – it navigates to the player’s farm page. The above plan addresses the root CSS conflict without altering backend logic or the data schema. It ensures the username link always remains clearly visible and functional, even with the longest currently defined titles (e.g., "Serial Refactorer" at ~15 characters).