Fix sidebar unit navigation to include reverse conversion pairs
This commit is contained in:
@@ -23,35 +23,75 @@
|
|||||||
|
|
||||||
type UnitGroup = {
|
type UnitGroup = {
|
||||||
label: string;
|
label: string;
|
||||||
conversions: CalculatorDef[];
|
conversions: UnitConversionLink[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type UnitBucket = {
|
type UnitBucket = {
|
||||||
label: string;
|
label: string;
|
||||||
conversions: CalculatorDef[];
|
conversions: UnitConversionLink[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortConversionsForUnit = (conversions: CalculatorDef[]) =>
|
type UnitConversionLink = {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
sortKey: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sortConversionsForUnit = (conversions: UnitConversionLink[]) =>
|
||||||
conversions.slice().sort((a, b) => a.name.localeCompare(b.name));
|
conversions.slice().sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
|
const toPairKey = (unitA: string, unitB: string) =>
|
||||||
|
[unitA.toLowerCase(), unitB.toLowerCase()].sort().join('::');
|
||||||
|
|
||||||
|
const toDirectionKey = (fromUnit: string, toUnit: string) =>
|
||||||
|
`${fromUnit.toLowerCase()}::${toUnit.toLowerCase()}`;
|
||||||
|
|
||||||
|
function addConversion(
|
||||||
|
buckets: Map<string, UnitBucket>,
|
||||||
|
fromUnit: string,
|
||||||
|
toUnit: string,
|
||||||
|
slug: string
|
||||||
|
) {
|
||||||
|
const bucketKey = fromUnit.toLowerCase();
|
||||||
|
const directionKey = toDirectionKey(fromUnit, toUnit);
|
||||||
|
const conversion: UnitConversionLink = {
|
||||||
|
name: `${fromUnit} to ${toUnit}`,
|
||||||
|
slug,
|
||||||
|
sortKey: directionKey,
|
||||||
|
};
|
||||||
|
|
||||||
|
const existing = buckets.get(bucketKey);
|
||||||
|
if (existing) {
|
||||||
|
if (!existing.conversions.some(link => link.sortKey === directionKey)) {
|
||||||
|
existing.conversions.push(conversion);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buckets.set(bucketKey, {
|
||||||
|
label: fromUnit,
|
||||||
|
conversions: [conversion],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$: categoryUnitGroups = Object.entries(categories).map(([key, meta]) => {
|
$: categoryUnitGroups = Object.entries(categories).map(([key, meta]) => {
|
||||||
const buckets = new Map<string, UnitBucket>();
|
const buckets = new Map<string, UnitBucket>();
|
||||||
const calcs = getCalculatorsByCategory(key);
|
const calcs = getCalculatorsByCategory(key);
|
||||||
|
const canonicalByPair = new Map<string, CalculatorDef>();
|
||||||
|
|
||||||
calcs.forEach(calc => {
|
calcs.forEach(calc => {
|
||||||
const unit = calc.labels.in1;
|
const pairKey = toPairKey(calc.labels.in1, calc.labels.in2);
|
||||||
const bucketKey = unit.toLowerCase();
|
const existing = canonicalByPair.get(pairKey);
|
||||||
const existing = buckets.get(bucketKey);
|
if (!existing || calc.slug.localeCompare(existing.slug) < 0) {
|
||||||
if (existing) {
|
canonicalByPair.set(pairKey, calc);
|
||||||
existing.conversions.push(calc);
|
|
||||||
} else {
|
|
||||||
buckets.set(bucketKey, {
|
|
||||||
label: unit,
|
|
||||||
conversions: [calc],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
canonicalByPair.forEach(calc => {
|
||||||
|
addConversion(buckets, calc.labels.in1, calc.labels.in2, calc.slug);
|
||||||
|
addConversion(buckets, calc.labels.in2, calc.labels.in1, calc.slug);
|
||||||
|
});
|
||||||
|
|
||||||
const units = [...buckets.entries()]
|
const units = [...buckets.entries()]
|
||||||
.sort(([a], [b]) => a.localeCompare(b))
|
.sort(([a], [b]) => a.localeCompare(b))
|
||||||
.map(([, bucket]) => ({
|
.map(([, bucket]) => ({
|
||||||
@@ -178,14 +218,14 @@
|
|||||||
</button>
|
</button>
|
||||||
{#if expandedUnits[group.key] === unit.label}
|
{#if expandedUnits[group.key] === unit.label}
|
||||||
<ul class="unit-list">
|
<ul class="unit-list">
|
||||||
{#each unit.conversions as calc}
|
{#each unit.conversions as conversion}
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="/{calc.slug}"
|
href="/{conversion.slug}"
|
||||||
class:current={currentPath === `/${calc.slug}`}
|
class:current={currentPath === `/${conversion.slug}`}
|
||||||
aria-current={currentPath === `/${calc.slug}` ? 'page' : undefined}
|
aria-current={currentPath === `/${conversion.slug}` ? 'page' : undefined}
|
||||||
>
|
>
|
||||||
{calc.name}
|
{conversion.name}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
Reference in New Issue
Block a user