diff --git a/src/__tests__/home-listing-section.claw591.test.tsx b/src/__tests__/home-listing-section.claw591.test.tsx index 43b08d01..1537cdde 100644 --- a/src/__tests__/home-listing-section.claw591.test.tsx +++ b/src/__tests__/home-listing-section.claw591.test.tsx @@ -117,7 +117,7 @@ describe("HomeListingSection", () => { expect(screen.queryByText("skills.sh")).toBeNull(); }); - it("hides unavailable Trending and falls back to the native New feed", async () => { + it("hides unavailable Trending and falls back to the Featured feed", async () => { render(); expect(screen.queryByRole("tab", { name: "Trending" })).toBeNull(); @@ -126,12 +126,14 @@ describe("HomeListingSection", () => { "Official", "New", ]); - expect(screen.getByRole("tab", { name: "New" }).getAttribute("aria-selected")).toBe("true"); + expect(screen.getByRole("tab", { name: "Featured" }).getAttribute("aria-selected")).toBe( + "true", + ); expect(screen.queryByText("24-hour Trending unavailable")).toBeNull(); await waitFor(() => expect(convexQueryMock).toHaveBeenCalledWith( "skills:listPublicPageV4", - expect.objectContaining({ sort: "newest", createdAfter: expect.any(Number) }), + expect.objectContaining({ highlightedOnly: true }), ), ); }); @@ -150,12 +152,26 @@ describe("HomeListingSection", () => { "Official", "New", ]); - expect(screen.getByRole("tab", { name: "New" }).getAttribute("aria-selected")).toBe("true"); + expect(screen.getByRole("tab", { name: "Featured" }).getAttribute("aria-selected")).toBe( + "true", + ); expect(screen.queryByText("24-hour Trending unavailable")).toBeNull(); expect(fetchCanonicalTrendingPageMock).not.toHaveBeenCalled(); expect(convexQueryMock).toHaveBeenCalledWith( "skills:listPublicPageV4", - expect.objectContaining({ sort: "newest", createdAfter: expect.any(Number) }), + expect.objectContaining({ highlightedOnly: true }), + ); + }); + + it("returns from Plugins to Featured when Trending is unavailable", async () => { + render(); + + fireEvent.click(screen.getByRole("button", { name: "Plugins" })); + expect(screen.getByRole("tab", { name: "New" }).getAttribute("aria-selected")).toBe("true"); + + fireEvent.click(screen.getByRole("button", { name: "Skills" })); + expect(screen.getByRole("tab", { name: "Featured" }).getAttribute("aria-selected")).toBe( + "true", ); }); diff --git a/src/__tests__/skills-index.claw591.test.tsx b/src/__tests__/skills-index.claw591.test.tsx index a5b3a86b..e930e6f1 100644 --- a/src/__tests__/skills-index.claw591.test.tsx +++ b/src/__tests__/skills-index.claw591.test.tsx @@ -134,7 +134,7 @@ describe("SkillsIndex", () => { expect(screen.queryByText(/Not scanned by ClawHub/i)).toBeNull(); }); - it("hides disabled Trending and falls back to the native New feed", async () => { + it("hides disabled Trending and falls back to the Featured feed", async () => { fetchCatalogDiscoveryCapabilitiesMock.mockResolvedValue({ apiVersion: 0, canonicalTrendingEnabled: false, @@ -144,10 +144,14 @@ describe("SkillsIndex", () => { await waitFor(() => expect(screen.queryByRole("radio", { name: "Trending" })).toBeNull()); expect(tabLabels()).toEqual(["Featured", "Official", "New"]); - expect(screen.getByRole("radio", { name: "New" }).getAttribute("aria-checked")).toBe("true"); + expect(screen.getByRole("radio", { name: "Featured" }).getAttribute("aria-checked")).toBe( + "true", + ); expect(screen.queryByText("24-hour Trending unavailable")).toBeNull(); expect(fetchCanonicalTrendingPageMock).not.toHaveBeenCalled(); - expect(convexHttpMock.query).toHaveBeenCalled(); + await waitFor(() => + expect(getLastListPageArgs()).toEqual(expect.objectContaining({ highlightedOnly: true })), + ); }); it("hides stale Trending and falls back without a legacy retry", async () => { @@ -157,9 +161,13 @@ describe("SkillsIndex", () => { await waitFor(() => expect(screen.queryByRole("radio", { name: "Trending" })).toBeNull()); expect(tabLabels()).toEqual(["Featured", "Official", "New"]); - expect(screen.getByRole("radio", { name: "New" }).getAttribute("aria-checked")).toBe("true"); + expect(screen.getByRole("radio", { name: "Featured" }).getAttribute("aria-checked")).toBe( + "true", + ); expect(screen.queryByText("24-hour Trending unavailable")).toBeNull(); - expect(convexHttpMock.query).toHaveBeenCalled(); + await waitFor(() => + expect(getLastListPageArgs()).toEqual(expect.objectContaining({ highlightedOnly: true })), + ); }); it("labels an empty canonical 24-hour window honestly", async () => { diff --git a/src/components/HomeListingSection.tsx b/src/components/HomeListingSection.tsx index c5f212ca..dcedf4cc 100644 --- a/src/components/HomeListingSection.tsx +++ b/src/components/HomeListingSection.tsx @@ -471,7 +471,7 @@ export function HomeListingSection({ initialListing = null }: HomeListingSection const [kind, setKind] = useState(initialListing?.kind ?? "skills"); const initialTab = initialListing?.kind === "skills" && initialListing.trendingState === "unavailable" - ? "new" + ? "featured" : (initialListing?.tab ?? "trending"); const [tab, setTab] = useState(initialTab); const [view, setView] = useState("list"); @@ -577,7 +577,7 @@ export function HomeListingSection({ initialListing = null }: HomeListingSection if (tab === "trending") { const unavailable = cached.trendingState === "unavailable"; setCanonicalTrendingUnavailable(unavailable); - if (unavailable) setTab("new"); + if (unavailable) setTab("featured"); } } else { setPlugins(cached.items); @@ -616,7 +616,7 @@ export function HomeListingSection({ initialListing = null }: HomeListingSection if (tab === "trending") { const unavailable = result.trendingState === "unavailable"; setCanonicalTrendingUnavailable(unavailable); - if (unavailable) setTab("new"); + if (unavailable) setTab("featured"); } setListingHasMore(result.hasMore); setStatus("idle"); @@ -795,7 +795,9 @@ export function HomeListingSection({ initialListing = null }: HomeListingSection if (nextKind === kind) return; setKind(nextKind); setCategorySlugs([]); - setTab(nextKind === "skills" && !canonicalTrendingUnavailable ? "trending" : "new"); + setTab( + nextKind === "skills" ? (canonicalTrendingUnavailable ? "featured" : "trending") : "new", + ); }; const removeCategory = (slug: string) => { diff --git a/src/routes/skills/-useSkillsBrowseModel.ts b/src/routes/skills/-useSkillsBrowseModel.ts index beb4303f..62bfce62 100644 --- a/src/routes/skills/-useSkillsBrowseModel.ts +++ b/src/routes/skills/-useSkillsBrowseModel.ts @@ -130,7 +130,7 @@ export function useSkillsBrowseModel({ const requestedCatalogTab = normalizeSkillsCatalogTab(search.tab, search); const catalogTab = requestedCatalogTab === "trending" && canonicalTrendingUnavailable - ? "new" + ? "featured" : requestedCatalogTab; const requestedSort = hasQuery ? search.sort === "default"