+ );
+}
+
function Header({
mode,
setMode,
@@ -310,8 +342,8 @@ function Row({
}}
>
nsid.startsWith(p));
}
/** First two segments — `app.bsky.feed.post` -> `app.bsky`. Single-segment
@@ -487,12 +534,13 @@ function namespaceKey(nsid: string): string {
function filterAndDedup(
rows: T[],
- dropBluesky: boolean,
+ mode: Mode,
): T[] {
+ const hidden = mode === 'trending' ? TRENDING_HIDDEN_PREFIXES : TOP_HIDDEN_PREFIXES;
const seen = new Set();
const out: T[] = [];
for (const r of rows) {
- if (dropBluesky && isBluesky(r.nsid)) continue;
+ if (hasHiddenPrefix(r.nsid, hidden)) continue;
const key = namespaceKey(r.nsid);
if (seen.has(key)) continue;
seen.add(key);
@@ -501,6 +549,27 @@ function filterAndDedup(
return out;
}
+/**
+ * Convention: an NSID like `..<...>` maps to `.`
+ * as the publisher's handle. `net.anisota.harvest.minigame` ->
+ * `anisota.net`, `app.bsky.feed.post` -> `bsky.app`, etc. Used to build
+ * the deep link into the explorer's lexicon-schema record for an NSID.
+ */
+function publisherForNsid(nsid: string): string {
+ const parts = nsid.split('.');
+ if (parts.length < 2) return nsid;
+ return `${parts[1]}.${parts[0]}`;
+}
+
+/** Lexicon-schema records live at this collection on the publisher's repo,
+ * keyed by the full NSID. The explorer's record page renders them nicely
+ * via RecordPreview, and falls through to a not-found message when the
+ * publisher hasn't published a schema. */
+function schemaPathFor(nsid: string): string {
+ const publisher = publisherForNsid(nsid);
+ return `/explore/${publisher}/com.atproto.lexicon.schema/${encodeURIComponent(nsid)}`;
+}
+
// ─── Fetching ──────────────────────────────────────────────────────────────
type RawCollection = {
@@ -552,8 +621,8 @@ async function fetchRanking(
orderForMetric(metric),
);
- // 2) Filter (bsky dropped only in trending) + dedup by top-2-segment ns.
- const filtered = filterAndDedup(candidates, mode === 'trending');
+ // 2) Filter (mode-specific) + dedup by top-2-segment namespace.
+ const filtered = filterAndDedup(candidates, mode);
if (filtered.length === 0) return [];
// 3) Score by the chosen metric. /collections gives us creates +