games: active vs non-active games (games.library.active, owner toggles on the dashboard and each game ⋯ menu; nothing deleted). Header flyout and mobile menu list every game split into active / non-active; /trackers and home tiles show active chips and open both sections on hover; /start shows active with a non-active toggle. Games dashboard moved from /projects/game-tracker to /trackers/games (dashboard of active games only; old URL and /credits 301); deep trackers stay put
All checks were successful
Deploy production / deploy (push) Successful in 1m13s
All checks were successful
Deploy production / deploy (push) Successful in 1m13s
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
|
||||
// Same list, order and icons as the header Trackers dropdown (owner-only ones only when
|
||||
// the header shows them). Spotting is a group tile with one-click chips per sub-tracker.
|
||||
const trackers = $derived(visibleTrackers(data.isOwner));
|
||||
const trackers = $derived(visibleTrackers(data.isOwner, data.inactiveGames));
|
||||
// Search-only shortcuts that aren't trackers of their own.
|
||||
const extraHits = [
|
||||
{ name: 'Weigh-in', href: '/trackers/health#body' },
|
||||
@@ -249,6 +249,20 @@
|
||||
? (t.children ?? []).filter((c) => c.featured)
|
||||
: (t.children ?? []);
|
||||
const hiddenChildren = (t: Group) => (t.children?.length ?? 0) - tileChildren(t).length;
|
||||
// Games split like the header's Trackers dropdown: "active" (my pick, always shown) and
|
||||
// "non-active" (behind its own toggle, shown while filtering).
|
||||
type Child = NonNullable<Group['children']>[number];
|
||||
const splitGroup = (t: Group) => (t.children ?? []).some((c) => c.inactive);
|
||||
const chipSections = (t: Group): { label: string; items: readonly Child[] }[] => {
|
||||
const all = t.children ?? [];
|
||||
if (!splitGroup(t)) return [{ label: '', items: tileChildren(t) }];
|
||||
const off = all.filter((c) => c.inactive);
|
||||
return [
|
||||
{ label: 'active', items: all.filter((c) => !c.inactive) },
|
||||
{ label: 'non-active', items: filtering || expandedGroups[t.name] ? off : [] }
|
||||
];
|
||||
};
|
||||
const inactiveCount = (t: Group) => (t.children ?? []).filter((c) => c.inactive).length;
|
||||
// The links filter (f) also narrows the trackers; a group stays if it or a chip matches.
|
||||
const shownTrackers = $derived.by(() => {
|
||||
const q = linkFilter.trim().toLowerCase();
|
||||
@@ -571,12 +585,35 @@
|
||||
<span class="tname">{t.name}</span>{#if t.locked}<PrivateLock tight />{/if}
|
||||
</a>
|
||||
<span class="tchips">
|
||||
{#each tileChildren(t) as c (c.name)}
|
||||
<a class="tchip" href={c.href} title={c.subtitle}
|
||||
><TrackerIcon name={c.icon ?? c.name} class="t-icon size-5" />{c.name}</a
|
||||
>
|
||||
{#each chipSections(t) as section (section.label)}
|
||||
{#if section.label === 'non-active' && !filtering}
|
||||
<button
|
||||
type="button"
|
||||
class="tlabel toggle"
|
||||
aria-expanded={!!expandedGroups[t.name]}
|
||||
onclick={() =>
|
||||
(expandedGroups = {
|
||||
...expandedGroups,
|
||||
[t.name]: !expandedGroups[t.name]
|
||||
})}
|
||||
>non-active <span>{inactiveCount(t)}</span>{expandedGroups[t.name]
|
||||
? ' ▾'
|
||||
: ' ▸'}</button
|
||||
>
|
||||
{:else if section.label && section.items.length}
|
||||
<span class="tlabel">{section.label} <span>{section.items.length}</span></span
|
||||
>
|
||||
{/if}
|
||||
{#each section.items as c (c.name)}
|
||||
<a
|
||||
class={['tchip', c.inactive && 'inactive']}
|
||||
href={c.href}
|
||||
title={c.subtitle}
|
||||
><TrackerIcon name={c.icon ?? c.name} class="t-icon size-5" />{c.name}</a
|
||||
>
|
||||
{/each}
|
||||
{/each}
|
||||
{#if !filtering && (hiddenChildren(t) > 0 || expandedGroups[t.name])}
|
||||
{#if !filtering && !splitGroup(t) && (hiddenChildren(t) > 0 || expandedGroups[t.name])}
|
||||
<button
|
||||
type="button"
|
||||
class="tchip more"
|
||||
@@ -1670,6 +1707,38 @@
|
||||
.stretched:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.tlabel {
|
||||
flex-basis: 100%;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.35rem;
|
||||
font-size: 0.62rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: var(--site-muted);
|
||||
background: none;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
}
|
||||
.tlabel span {
|
||||
letter-spacing: 0;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.tlabel:not(:first-child) {
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
button.tlabel {
|
||||
cursor: pointer;
|
||||
}
|
||||
button.tlabel:hover {
|
||||
color: inherit;
|
||||
}
|
||||
.tchip.inactive :global(.t-icon) {
|
||||
filter: grayscale(0.6);
|
||||
opacity: 0.75;
|
||||
}
|
||||
.tchips {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
Reference in New Issue
Block a user