@dogsbay/docs-layout 0.2.0-beta.74 → 0.2.0-beta.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/search-facets.ts +89 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/docs-layout",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.75",
|
|
4
4
|
"description": "Standard documentation layout components for Dogsbay",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"./json-ld": "./src/json-ld.ts"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@dogsbay/ui": "0.2.0-beta.
|
|
33
|
-
"@dogsbay/primitives": "0.2.0-beta.
|
|
32
|
+
"@dogsbay/ui": "0.2.0-beta.75",
|
|
33
|
+
"@dogsbay/primitives": "0.2.0-beta.75"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"vitest": "^3.0.0"
|
package/src/search-facets.ts
CHANGED
|
@@ -376,7 +376,16 @@ export function buildFacetTree(
|
|
|
376
376
|
|
|
377
377
|
const slashEncoded = entries.some((e) => e.value.includes("/"));
|
|
378
378
|
if (slashEncoded) {
|
|
379
|
-
|
|
379
|
+
// When nav is supplied, derive document-order. Otherwise fall
|
|
380
|
+
// back to count-desc + alpha. The map keys are full cumulative
|
|
381
|
+
// paths (matching Pagefind entry values 1:1).
|
|
382
|
+
const navOrder = options.nav
|
|
383
|
+
? buildNavOrderMap(
|
|
384
|
+
options.nav,
|
|
385
|
+
new Set(entries.map((e) => e.value)),
|
|
386
|
+
)
|
|
387
|
+
: undefined;
|
|
388
|
+
return buildSlashTree(facetName, entries, options.display, navOrder);
|
|
380
389
|
}
|
|
381
390
|
return buildSegmentTree(facetName, entries, options.nav, options.display);
|
|
382
391
|
}
|
|
@@ -387,11 +396,20 @@ export function buildFacetTree(
|
|
|
387
396
|
* nodes. Synthetic intermediate nodes (a path component used by a
|
|
388
397
|
* descendant but absent from `entries`) get `hasValue: false` and
|
|
389
398
|
* `count: 0` so they render but don't contribute to selection.
|
|
399
|
+
*
|
|
400
|
+
* Sort order at every depth:
|
|
401
|
+
* 1. `navOrder` index if present (document order from nav.json).
|
|
402
|
+
* Without this, deep API-reference subtrees with high page
|
|
403
|
+
* counts would dominate the top of the tree even though they
|
|
404
|
+
* sit at the BOTTOM of the rendered nav.
|
|
405
|
+
* 2. Count desc (more pages → higher).
|
|
406
|
+
* 3. Alpha (final tiebreak).
|
|
390
407
|
*/
|
|
391
408
|
function buildSlashTree(
|
|
392
409
|
facetName: string,
|
|
393
410
|
entries: FacetEntry[],
|
|
394
411
|
display?: TaxonomyDisplayMap,
|
|
412
|
+
navOrder?: Map<string, number>,
|
|
395
413
|
): FacetTreeNode[] {
|
|
396
414
|
// Trie keyed by full slash-path. Children are tracked on each
|
|
397
415
|
// node's own `children` array (built unsorted in pass 1, sorted
|
|
@@ -428,26 +446,86 @@ function buildSlashTree(
|
|
|
428
446
|
}
|
|
429
447
|
}
|
|
430
448
|
|
|
431
|
-
// Pass 2: sort children at every depth.
|
|
432
|
-
|
|
449
|
+
// Pass 2: sort children at every depth.
|
|
450
|
+
const cmp = (a: FacetTreeNode, b: FacetTreeNode): number => {
|
|
451
|
+
if (navOrder) {
|
|
452
|
+
const oa = navOrder.get(a.value);
|
|
453
|
+
const ob = navOrder.get(b.value);
|
|
454
|
+
if (oa !== undefined && ob !== undefined && oa !== ob) return oa - ob;
|
|
455
|
+
// Nodes IN the nav sort before nodes not in nav
|
|
456
|
+
if (oa !== undefined && ob === undefined) return -1;
|
|
457
|
+
if (oa === undefined && ob !== undefined) return 1;
|
|
458
|
+
}
|
|
459
|
+
if (a.count !== b.count) return b.count - a.count;
|
|
460
|
+
return a.value.localeCompare(b.value);
|
|
461
|
+
};
|
|
433
462
|
const sortChildren = (node: FacetTreeNode): void => {
|
|
434
463
|
if (node.children.length === 0) return;
|
|
435
|
-
node.children.sort(
|
|
436
|
-
if (a.count !== b.count) return b.count - a.count;
|
|
437
|
-
return a.value.localeCompare(b.value);
|
|
438
|
-
});
|
|
464
|
+
node.children.sort(cmp);
|
|
439
465
|
for (const c of node.children) sortChildren(c);
|
|
440
466
|
};
|
|
441
467
|
|
|
442
468
|
const rootList = rootValues.map((v) => byPath.get(v)!);
|
|
443
|
-
rootList.sort(
|
|
444
|
-
if (a.count !== b.count) return b.count - a.count;
|
|
445
|
-
return a.value.localeCompare(b.value);
|
|
446
|
-
});
|
|
469
|
+
rootList.sort(cmp);
|
|
447
470
|
for (const r of rootList) sortChildren(r);
|
|
448
471
|
return rootList;
|
|
449
472
|
}
|
|
450
473
|
|
|
474
|
+
/**
|
|
475
|
+
* Walk `nav` and assign each cumulative slash-path (matching a
|
|
476
|
+
* Pagefind facet value in `knownValues`) a sequential index in
|
|
477
|
+
* first-encounter order. Used by `buildSlashTree` to sort children
|
|
478
|
+
* in document order rather than count-desc.
|
|
479
|
+
*
|
|
480
|
+
* Auto-detects and strips a leading basePath: for each nav leaf, we
|
|
481
|
+
* try each starting offset of the href's parent segments. The first
|
|
482
|
+
* offset whose initial cumulative path is in `knownValues` is the
|
|
483
|
+
* "real" content root; the dropped prefix is the basePath. This way
|
|
484
|
+
* the helper works on any site without needing the basePath threaded
|
|
485
|
+
* through explicitly.
|
|
486
|
+
*
|
|
487
|
+
* Hrefs whose parents don't match anything in `knownValues` at any
|
|
488
|
+
* offset are skipped (e.g. top-level pages with no auto-derived
|
|
489
|
+
* category, or pages outside the indexed corpus).
|
|
490
|
+
*
|
|
491
|
+
* Exported for use by `buildFacetTree`. Pure — no I/O.
|
|
492
|
+
*/
|
|
493
|
+
export function buildNavOrderMap(
|
|
494
|
+
nav: NavLike[],
|
|
495
|
+
knownValues: Set<string>,
|
|
496
|
+
): Map<string, number> {
|
|
497
|
+
const order = new Map<string, number>();
|
|
498
|
+
let n = 0;
|
|
499
|
+
const walk = (items: NavLike[]): void => {
|
|
500
|
+
for (const item of items) {
|
|
501
|
+
if (item.href) {
|
|
502
|
+
const parents = hrefToCategorySegments(item.href);
|
|
503
|
+
// Try each starting offset; first one whose initial cumulative
|
|
504
|
+
// path is in knownValues wins (auto-detects basePath).
|
|
505
|
+
for (let start = 0; start < parents.length; start++) {
|
|
506
|
+
const first = parents[start];
|
|
507
|
+
if (!knownValues.has(first)) continue;
|
|
508
|
+
// Record all cumulative paths starting from `start` that
|
|
509
|
+
// exist in knownValues. The check at line below filters out
|
|
510
|
+
// synthetic intermediates the corpus didn't tag (e.g. a
|
|
511
|
+
// user-supplied frontmatter category that skipped a level).
|
|
512
|
+
let cumulative = "";
|
|
513
|
+
for (let i = start; i < parents.length; i++) {
|
|
514
|
+
cumulative = cumulative ? `${cumulative}/${parents[i]}` : parents[i];
|
|
515
|
+
if (knownValues.has(cumulative) && !order.has(cumulative)) {
|
|
516
|
+
order.set(cumulative, n++);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (item.children && item.children.length > 0) walk(item.children);
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
walk(nav);
|
|
526
|
+
return order;
|
|
527
|
+
}
|
|
528
|
+
|
|
451
529
|
/**
|
|
452
530
|
* Segment-encoded tree builder. Walks `nav` to discover the
|
|
453
531
|
* canonical document hierarchy, then attaches Pagefind counts to
|