From dcf8794047b1eb72d9e8c767c969d26a4168b945 Mon Sep 17 00:00:00 2001 From: Anso Date: Sun, 26 Apr 2026 18:56:09 -0400 Subject: [PATCH] feat(app-store): sort grid by stars and rotate featured weekly (#787) Grid templates are now sorted by star count (descending) so popular apps surface naturally rather than appearing in registry fetch order. Featured hero rotates weekly among the top 5 starred apps instead of always pinning the single highest-starred entry. Rotation is seeded by week number so all nodes show the same featured app throughout a given week. Registries with no star data gracefully skip the featured hero and preserve their natural ordering. --- backend/src/routes/templates.ts | 18 +++++++++--------- frontend/src/components/AppStoreView.tsx | 6 ++++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/backend/src/routes/templates.ts b/backend/src/routes/templates.ts index 78b66674..f9af25c9 100644 --- a/backend/src/routes/templates.ts +++ b/backend/src/routes/templates.ts @@ -25,15 +25,15 @@ templatesRouter.get('/', authMiddleware, async (req: Request, res: Response) => const imageRefs = templates.map(t => t.image).filter((i): i is string => !!i); const scanSummary = DatabaseService.getInstance().getLatestScanSummaryByImageRefs(req.nodeId, imageRefs); - let featuredIndex = -1; - let featuredStars = 0; - templates.forEach((t, i) => { - const s = t.stars ?? 0; - if (s > featuredStars) { - featuredStars = s; - featuredIndex = i; - } - }); + const topCandidates = templates + .map((t, i) => ({ t, i })) + .filter(({ t }) => (t.stars ?? 0) > 0) + .sort((a, b) => (b.t.stars ?? 0) - (a.t.stars ?? 0)) + .slice(0, 5); + const weekIndex = Math.floor(Date.now() / (7 * 86_400_000)); + const featuredIndex = topCandidates.length > 0 + ? topCandidates[weekIndex % topCandidates.length].i + : -1; const enriched = templates.map((t, i) => { const summary = t.image ? scanSummary.get(t.image) : undefined; diff --git a/frontend/src/components/AppStoreView.tsx b/frontend/src/components/AppStoreView.tsx index 9bc546fb..f85841b4 100644 --- a/frontend/src/components/AppStoreView.tsx +++ b/frontend/src/components/AppStoreView.tsx @@ -247,8 +247,10 @@ export function AppStoreView({ onDeploySuccess }: AppStoreViewProps) { }, [filtered, searchQuery]); const gridTemplates = useMemo(() => { - if (!featuredTemplate) return filtered; - return filtered.filter(t => t.title !== featuredTemplate.title); + const base = featuredTemplate + ? filtered.filter(t => t.title !== featuredTemplate.title) + : filtered; + return [...base].sort((a, b) => (b.stars ?? 0) - (a.stars ?? 0)); }, [filtered, featuredTemplate]); return (