loads of mobile ui layout upgrades

This commit is contained in:
JCEEE
2026-09-10 11:27:27 +01:00
parent 097106fa69
commit f802113cd1
17 changed files with 501 additions and 123 deletions
+103 -22
View File
@@ -144,10 +144,19 @@
}
}
// Same "Bonus name – prize" split as the ledger, so prize rewards don't
// duplicate the full label in both columns of a claim row.
function rewardLabelParts(r: any): { name: string; prize: string } {
const label = r.label || '';
const idx = label.indexOf(' – ');
if (idx === -1) return { name: label, prize: label };
return { name: label.slice(0, idx), prize: label.slice(idx + 3) };
}
function rewardLabel(r: any): string {
if (r.rewardType === 'cash') return `£${Number(r.value).toFixed(2)}`;
if (r.rewardType === 'points') return `${r.value} pts`;
return r.label;
return rewardLabelParts(r).prize;
}
function manualConfigs() {
@@ -605,8 +614,14 @@
const existingReward = rewards.find(
(r) => r.bonusConfigId === cfg.id && r.memberId === memberId
);
// An earned reward only keeps lighting up the card while it's fresh
// (earned in the viewed week) or still outstanding (not yet claimed).
// Once claimed and the week rolls over, "Reward earned" disappears.
const rDate = (existingReward?.date || '').slice(0, 10);
const rewardInWeek = !!rDate && rDate >= weekStart && rDate <= weekEnd;
const rewardOutstanding = !!existingReward && existingReward.status !== 'claimed';
const achieved = existingReward
? true
? rewardInWeek || rewardOutstanding
: isPercent
? totalPotential > 0 && ratio * 100 >= configured
: target > 0 && current >= target;
@@ -729,6 +744,12 @@
function headDay(): number {
return headDate().getDate();
}
function headDayOrdinal(): string {
const n = headDay();
if (n % 100 >= 11 && n % 100 <= 13) return `${n}th`;
const s = ['th', 'st', 'nd', 'rd'];
return `${n}${s[n % 10] || s[0]}`;
}
function headWeekday(): string {
return headDate().toLocaleDateString(undefined, { weekday: 'long' });
}
@@ -914,7 +935,6 @@
</div>
<div class="gm-bottom">
<span class="gm-reward">{g.rewardText}</span>
<span class="gm-date">{formatDDMMYY(g.date)}</span>
</div>
</div>
{/each}
@@ -1047,7 +1067,7 @@
{/if}
</Card>
<Card cols={1} title="Claims" accent="#f59e0b">
<Card cols={1} title="Claims" accent="#f97316" class="claims-card">
{#if claimableRewards().length === 0}
<div class="claims-empty">
{@html checkCircleIcon}<span>No outstanding claims</span>
@@ -1106,7 +1126,7 @@
<p class="section-label">Requested</p>
{#each requested as r}
<form
class="flex justify-between items-center"
class="flex flex-wrap justify-between items-center"
method="POST"
action="?/claim"
use:enhance={() => {
@@ -1118,7 +1138,7 @@
<span class="claim-icon"
>{@html r.rewardType === 'cash' ? coinsIcon : giftIcon}</span
>
<span class="claim-label">{r.label}</span>
<span class="claim-label">{rewardLabelParts(r).name}</span>
<span class="claim-value">{rewardLabel(r)}</span>
</div>
<Button type="submit" size="sm" variant="primary">Issue</Button>
@@ -1133,7 +1153,7 @@
<span class="claim-icon"
>{@html r.rewardType === 'cash' ? coinsIcon : giftIcon}</span
>
<span class="claim-label">{r.label}</span>
<span class="claim-label">{rewardLabelParts(r).name}</span>
<span class="claim-value">
{rewardLabel(r)}
{#if paydayLocked(r)}
@@ -1265,8 +1285,8 @@
{/if}
</div>
<div class="hero-date">
<span class="hero-day">{headDay()}</span>
<span class="hero-weekday">{headWeekday()}</span>
<span class="hero-day">{headDayOrdinal()}</span>
<span class="hero-month">{headMonth()}</span>
</div>
</div>
@@ -2224,11 +2244,15 @@
color: rgba(255, 255, 255, 0.7);
}
.hero-days {
font-size: 0.85rem;
font-size: 1rem;
color: rgba(255, 255, 255, 0.9);
/* Own full-width line, centered under the hero content */
flex: 1 1 100%;
text-align: center;
margin-top: 0.25rem;
}
.hero-days b {
font-size: 1.4rem;
font-size: 1.5rem;
margin-right: 0.15rem;
}
.hero-nav {
@@ -2483,20 +2507,25 @@
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 639px) {
.goal-mini-grid {
grid-template-columns: 1fr;
}
}
.goal-mini {
background: linear-gradient(135deg, #d1d3fa, #ccfbf1);
border: 1px solid #a7f3d0;
border-radius: 12px;
padding: 0.55rem 0.7rem;
display: flex;
flex-direction: column;
gap: 0.4rem;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
min-width: 0;
/* Own width as a query container, so tight cards drop the member name */
container-type: inline-size;
}
/* Card narrower than 250px: hide the member name so the row doesn't squish */
@container (max-width: 249px) {
.gm-member {
display: none;
}
}
.gm-top {
display: flex;
@@ -2526,18 +2555,14 @@
.gm-bottom {
display: flex;
justify-content: space-between;
align-items: center;
gap: 0.4rem;
white-space: nowrap;
}
.gm-reward {
font-weight: 800;
color: #047857;
font-size: 0.85rem;
}
.gm-date {
color: #9ca3af;
font-size: 0.72rem;
}
/* Goal celebration notice (child view) */
.celebrate-card.goal {
@@ -2954,4 +2979,60 @@
font-size: 0.8rem;
opacity: 0.85;
}
/* Mobile: declared last so it wins over the base .goal-mini (.kanban)
rules (same specificity, source order decides). */
@media (max-width: 639px) {
.goal-mini-grid {
grid-template-columns: 1fr;
}
.kanban {
grid-template-columns: 1fr;
}
/* Admin overview cards flow full width on phones — same convention as
the chores kanban (no horizontal scroll). */
.kanban-scroll {
overflow-x: visible;
}
.kanban-inner {
min-width: 0;
}
/* Keep the orange wash visible: restore body padding for this card
only (the shared Card removes it on mobile). */
:global(.card.claims-card .card-body) {
padding: 0.75rem;
}
/* Claim rows: icon/label/value stay on one line (label truncates
with ellipsis) and the Issue button becomes a full-width action
below — no squishing or overflow under 450px. */
.member-claims form.flex {
flex-wrap: wrap;
row-gap: 0.5rem;
}
.member-claims form.flex > div {
flex: 1 1 100%;
min-width: 0;
flex-wrap: nowrap;
align-items: center;
}
/* :global — the button element is rendered by the shared Button
component, so a scoped selector never matches it. */
.member-claims form.flex :global(button) {
flex: 1 1 100%;
width: 100%;
margin-left: 0;
}
.member-claims .claim-label {
white-space: nowrap;
}
.member-claims .claim-item {
flex-wrap: wrap;
}
}
/* Claims card — orange wash so pending requests are impossible to miss.
:global + !important deliberately override the shared Card's white/
mobile-transparent backgrounds. */
:global(.card.claims-card) {
background: linear-gradient(135deg, #ffedd5, #fdba74 70%, #fb923c) !important;
border-color: #f97316;
}
</style>