feat: add Holo-work recommendations and responsive member grids
Publish GitHub Pages output / publish (push) Successful in 30s
Publish GitHub Pages output / publish (push) Successful in 30s
This commit is contained in:
@@ -1,11 +1,38 @@
|
||||
export type HoloWorkSort = 'member' | 'asc' | 'desc';
|
||||
export type HoloWorkSort = 'member' | 'asc' | 'desc' | 'achievement';
|
||||
type Thresholds = Readonly<Record<string, readonly number[]>>;
|
||||
|
||||
export function remainingWork(id: string, counts: Readonly<Record<string, number>>, thresholds: Thresholds): number {
|
||||
const count = counts[id] ?? 0;
|
||||
const target = thresholds[id]?.find((value) => value > count);
|
||||
return target === undefined ? Infinity : target - count;
|
||||
}
|
||||
|
||||
/** A fresh ordering snapshot; subsequent count edits do not move its rows. */
|
||||
export function sortHoloWorkMembers<T extends { id: string; order: number }>(
|
||||
members: readonly T[], counts: Readonly<Record<string, number>>, sort: HoloWorkSort
|
||||
members: readonly T[], counts: Readonly<Record<string, number>>, sort: HoloWorkSort, thresholds: Thresholds = {}
|
||||
): T[] {
|
||||
return [...members].sort((a, b) => {
|
||||
const difference = (counts[a.id] ?? 0) - (counts[b.id] ?? 0);
|
||||
if (sort === 'achievement') {
|
||||
return (remainingWork(a.id, counts, thresholds) - remainingWork(b.id, counts, thresholds)) || difference || a.order - b.order;
|
||||
}
|
||||
return (sort === 'asc' ? difference : sort === 'desc' ? -difference : 0) || a.order - b.order;
|
||||
});
|
||||
}
|
||||
|
||||
/** Keep pinned slots and fill the others with distinct members with unfinished achievements. */
|
||||
export function recommendWorkMembers<T extends { id: string; order: number }>(
|
||||
members: readonly T[], counts: Readonly<Record<string, number>>, thresholds: Thresholds,
|
||||
selected: readonly string[], pinned: readonly boolean[]
|
||||
): string[] {
|
||||
const used = new Set<string>();
|
||||
const result = Array.from({ length: 5 }, (_, index) => {
|
||||
const id = selected[index];
|
||||
if (!pinned[index] || !members.some((member) => member.id === id) || used.has(id)) return '';
|
||||
used.add(id);
|
||||
return id;
|
||||
});
|
||||
const candidates = sortHoloWorkMembers(members, counts, 'achievement', thresholds)
|
||||
.filter((member) => !used.has(member.id) && Number.isFinite(remainingWork(member.id, counts, thresholds)));
|
||||
return result.map((id) => id || candidates.shift()?.id || '');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user