mirror of
https://codeberg.org/likwid/likwid.git
synced 2026-02-09 13:03:10 +00:00
ux: improve proposals states
This commit is contained in:
parent
a946fc6b85
commit
5b5a11a96d
2 changed files with 111 additions and 6 deletions
|
|
@ -44,7 +44,7 @@ import { API_BASE as apiBase } from '../lib/api';
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="proposals-list" class="list">
|
||||
<div id="proposals-list" class="list" aria-live="polite">
|
||||
<div class="state-card ui-card"><p class="loading">Loading proposals...</p></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -78,6 +78,62 @@ import { API_BASE as apiBase } from '../lib/api';
|
|||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
function renderErrorState(message) {
|
||||
const container = document.getElementById('proposals-list');
|
||||
if (!container) return;
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="state-card ui-card">
|
||||
<p class="error">${message}</p>
|
||||
<p class="hint">Check your connection and try again.</p>
|
||||
<div class="state-actions">
|
||||
<button type="button" class="ui-btn ui-btn-primary" id="retry-load">Retry</button>
|
||||
<a class="ui-btn ui-btn-secondary" href="/communities">Browse communities</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('retry-load')?.addEventListener('click', loadProposals);
|
||||
}
|
||||
|
||||
function renderEmptyState(isFiltered) {
|
||||
const container = document.getElementById('proposals-list');
|
||||
if (!container) return;
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="state-card ui-card">
|
||||
<p class="empty">${isFiltered ? 'No proposals match your filters.' : 'No proposals found.'}</p>
|
||||
<p class="hint">Try adjusting search, status, or sort.</p>
|
||||
<div class="state-actions">
|
||||
<button type="button" class="ui-btn ui-btn-secondary" id="reset-filters">Reset filters</button>
|
||||
<a class="ui-btn ui-btn-primary" href="/communities">Go to communities</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('reset-filters')?.addEventListener('click', () => {
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const statusFilter = document.getElementById('status-filter');
|
||||
const sortFilter = document.getElementById('sort-filter');
|
||||
if (searchInput) searchInput.value = '';
|
||||
if (statusFilter) statusFilter.value = '';
|
||||
if (sortFilter) sortFilter.value = 'newest';
|
||||
filterProposals();
|
||||
});
|
||||
}
|
||||
|
||||
function hasActiveFilters() {
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const statusFilter = document.getElementById('status-filter');
|
||||
const sortFilter = document.getElementById('sort-filter');
|
||||
|
||||
const query = searchInput?.value.toLowerCase().trim() || '';
|
||||
const status = statusFilter?.value || '';
|
||||
const sort = sortFilter?.value || 'newest';
|
||||
|
||||
return Boolean(query || status || sort !== 'newest');
|
||||
}
|
||||
|
||||
async function loadProposals() {
|
||||
const container = document.getElementById('proposals-list');
|
||||
if (!container) return;
|
||||
|
|
@ -88,7 +144,7 @@ import { API_BASE as apiBase } from '../lib/api';
|
|||
allProposals = await res.json();
|
||||
renderProposals(allProposals);
|
||||
} catch (error) {
|
||||
container.innerHTML = '<div class="error"><p>Failed to load proposals.</p></div>';
|
||||
renderErrorState('Failed to load proposals.');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +153,7 @@ import { API_BASE as apiBase } from '../lib/api';
|
|||
if (!container) return;
|
||||
|
||||
if (proposals.length === 0) {
|
||||
container.innerHTML = '<div class="state-card ui-card"><p class="empty">No proposals found.</p></div>';
|
||||
renderEmptyState(hasActiveFilters());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -171,6 +227,14 @@ import { API_BASE as apiBase } from '../lib/api';
|
|||
gap: 1rem;
|
||||
}
|
||||
|
||||
.state-actions {
|
||||
margin-top: 1.25rem;
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.proposal-card {
|
||||
display: block;
|
||||
padding: 1.1rem;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,24 @@ const proposalId = id ?? '';
|
|||
let quadraticAllocations = {};
|
||||
let starRatings = {};
|
||||
|
||||
function renderProposalErrorState(message) {
|
||||
const container = document.getElementById('proposal-content');
|
||||
if (!container) return;
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="state-card ui-card">
|
||||
<p class="error">${escapeHtml(message)}</p>
|
||||
<p class="hint">It may have been deleted, or you may not have access.</p>
|
||||
<div class="state-actions">
|
||||
<button type="button" class="ui-btn ui-btn-primary" id="retry-proposal">Retry</button>
|
||||
<a class="ui-btn ui-btn-secondary" href="/proposals">Back to proposals</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('retry-proposal')?.addEventListener('click', loadProposal);
|
||||
}
|
||||
|
||||
function escapeHtml(value) {
|
||||
return String(value || '').replace(/[&<>"']/g, function(ch) {
|
||||
switch (ch) {
|
||||
|
|
@ -407,7 +425,7 @@ const proposalId = id ?? '';
|
|||
}
|
||||
|
||||
} catch (error) {
|
||||
container.innerHTML = '<div class="error">Proposal not found</div>';
|
||||
renderProposalErrorState('Proposal not found.');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -600,7 +618,12 @@ const proposalId = id ?? '';
|
|||
const comments = await res.json();
|
||||
|
||||
if (comments.length === 0) {
|
||||
container.innerHTML = '<p class="empty-comments">No comments yet. Be the first to share your thoughts!</p>';
|
||||
container.innerHTML = `
|
||||
<div class="state-card ui-card ui-card-soft">
|
||||
<p class="empty">No comments yet.</p>
|
||||
<p class="hint">Be the first to share your thoughts.</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -619,7 +642,17 @@ const proposalId = id ?? '';
|
|||
`;
|
||||
}).join('');
|
||||
} catch (e) {
|
||||
container.innerHTML = '<p class="error-small">Failed to load comments</p>';
|
||||
container.innerHTML = `
|
||||
<div class="state-card ui-card ui-card-soft">
|
||||
<p class="error">Failed to load comments.</p>
|
||||
<p class="hint">Try again in a moment.</p>
|
||||
<div class="state-actions">
|
||||
<button type="button" class="ui-btn ui-btn-secondary" id="retry-comments">Retry</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('retry-comments')?.addEventListener('click', loadComments);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -659,6 +692,14 @@ const proposalId = id ?? '';
|
|||
max-width: 880px;
|
||||
}
|
||||
|
||||
.state-actions {
|
||||
margin-top: 1.25rem;
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.results-chart-host {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue