Private
Public Access
1
0

chg: usr: add filter to the Profile page's recent plays and an infite list too #7

This commit is contained in:
2026-04-19 22:11:58 +02:00
parent e0495d182e
commit 5f856e4d70
4 changed files with 120 additions and 3 deletions

View File

@@ -427,10 +427,88 @@
} }
} }
.profile-games__filter-wrap {
position: relative;
display: flex;
align-items: center;
margin-bottom: 4px;
}
.profile-games__filter-icon {
position: absolute;
left: 14px;
font-size: 12px;
color: rgba(149, 207, 245, 0.4);
pointer-events: none;
}
.profile-games__filter {
width: 100%;
background: rgba(255, 255, 255, 0.025);
border: 1px solid rgba(255, 255, 255, 0.07);
border-radius: 6px;
padding: 9px 14px 9px 36px;
font: 500 13px 'Rajdhani', sans-serif;
color: #fff;
letter-spacing: 0.5px;
transition: border-color 200ms ease, background 200ms ease;
&::placeholder {
color: rgba(255, 255, 255, 0.3);
}
&:focus {
outline: none;
background: rgba(255, 255, 255, 0.045);
border-color: rgba(35, 111, 135, 0.55);
}
}
.profile-games { .profile-games {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 6px; gap: 6px;
&.is-filtering + .profile-games__load-more {
display: none;
}
&.is-filtering .profile-game--hidden:not(.profile-game--filtered-out) {
display: grid;
}
.profile-game--filtered-out {
display: none;
}
&__load-more {
align-self: center;
margin-top: 14px;
background: rgba(35, 111, 135, 0.12);
color: rgba(149, 207, 245, 0.75);
border: 1px solid rgba(35, 111, 135, 0.3);
border-radius: 6px;
padding: 9px 20px;
font: 600 12px 'Rajdhani', sans-serif;
text-transform: uppercase;
letter-spacing: 1.5px;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 8px;
transition: background 200ms ease, border-color 200ms ease, color 200ms ease;
i {
font-size: 11px;
opacity: 0.8;
}
&:hover {
background: rgba(35, 111, 135, 0.22);
border-color: rgba(35, 111, 135, 0.55);
color: rgba(149, 207, 245, 1);
}
}
} }
.profile-game { .profile-game {
@@ -469,6 +547,10 @@
border-left-color: rgba(255, 193, 7, 0.4); border-left-color: rgba(255, 193, 7, 0.4);
opacity: 0.85; opacity: 0.85;
} }
&--hidden {
display: none;
}
} }
.profile-game__badge { .profile-game__badge {

View File

@@ -29,3 +29,28 @@ if (battleRoot) {
<BattleDialog games={JSON.parse(battleRoot.dataset.games)} />, <BattleDialog games={JSON.parse(battleRoot.dataset.games)} />,
); );
} }
const list = document.querySelector('.profile-games');
const loadMoreBtn = document.querySelector('[data-load-more]');
if (list && loadMoreBtn) {
const batchSize = parseInt(list.dataset.batchSize, 10) || 5;
loadMoreBtn.addEventListener('click', () => {
const hidden = list.querySelectorAll('.profile-game--hidden');
Array.from(hidden).slice(0, batchSize).forEach((el) => el.classList.remove('profile-game--hidden'));
if (list.querySelectorAll('.profile-game--hidden').length === 0) {
loadMoreBtn.remove();
}
});
}
const filterInput = document.querySelector('[data-filter]');
if (list && filterInput) {
filterInput.addEventListener('input', () => {
const term = filterInput.value.trim().toLowerCase();
list.classList.toggle('is-filtering', term.length > 0);
list.querySelectorAll('.profile-game').forEach((card) => {
const opp = card.querySelector('.profile-game__opponent')?.textContent.trim().toLowerCase() ?? '';
card.classList.toggle('profile-game--filtered-out', term.length > 0 && !opp.includes(term));
});
});
}

View File

@@ -129,7 +129,7 @@ class ProfileController extends AbstractController
'blindHits' => $bonus['totalBlindHits'], 'blindHits' => $bonus['totalBlindHits'],
'edgeMines' => $bonus['totalEdgeMines'], 'edgeMines' => $bonus['totalEdgeMines'],
], ],
'recent' => ($recent = $this->repo->findRecentFinishedForUser($user)), 'recent' => ($recent = $this->repo->findRecentFinishedForUser($user, 30)),
'gamesData' => array_map(function (PlayedGame $game) use ($userId, $cacheManager): array { 'gamesData' => array_map(function (PlayedGame $game) use ($userId, $cacheManager): array {
$isRed = $game->getRed()?->getId() === $userId; $isRed = $game->getRed()?->getId() === $userId;
$resign = $game->getResign(); $resign = $game->getResign();

View File

@@ -120,7 +120,12 @@
<h2 class="profile-section__title"> <h2 class="profile-section__title">
<i class="fas fa-clock-rotate-left"></i> Recent battles <i class="fas fa-clock-rotate-left"></i> Recent battles
</h2> </h2>
<div class="profile-games"> <div class="profile-games__filter-wrap">
<i class="fas fa-search profile-games__filter-icon"></i>
<input type="text" class="profile-games__filter" data-filter
placeholder="Filter by opponent…" autocomplete="off">
</div>
<div class="profile-games" data-batch-size="5">
{% for game in recent %} {% for game in recent %}
{% set is_red = game.red and game.red.id == app.user.id %} {% set is_red = game.red and game.red.id == app.user.id %}
{% set my_points = is_red ? game.redPoints : game.bluePoints %} {% set my_points = is_red ? game.redPoints : game.bluePoints %}
@@ -149,7 +154,7 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
<div class="profile-game profile-game--{{ result }}{% if not is_finished and not is_anonymous %} profile-game--ongoing{% elseif is_anonymous %} profile-game--abandoned{% endif %}" data-game-index="{{ loop.index0 }}"> <div class="profile-game profile-game--{{ result }}{% if not is_finished and not is_anonymous %} profile-game--ongoing{% elseif is_anonymous %} profile-game--abandoned{% endif %}{% if loop.index0 >= 5 %} profile-game--hidden{% endif %}" data-game-index="{{ loop.index0 }}">
<span class="profile-game__badge"> <span class="profile-game__badge">
{% if is_finished %} {% if is_finished %}
{{ result == 'win' ? 'Win' : (result == 'loss' ? 'Loss' : 'Draw') }} {{ result == 'win' ? 'Win' : (result == 'loss' ? 'Loss' : 'Draw') }}
@@ -181,6 +186,11 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
{% if recent|length > 5 %}
<button type="button" class="profile-games__load-more" data-load-more>
<i class="fas fa-chevron-down"></i> Load more
</button>
{% endif %}
</div> </div>
{% else %} {% else %}
<div class="profile-empty"> <div class="profile-empty">