mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
* chore(landing): cleanup pass — size-* shorthand, drop redundant refs/memos, changelog useInfiniteQuery
- emcn: collapse 29 square h-N w-N pairs to size-* across models/integrations/blog/faq/landing-preview
- landing-preview: remove redundant animationKeyRef (functional setState) + dead isDesktopRef
- model-directory: hoist static provider options to a module const
- auth-modal: drop useMemo over the cheap getBrandConfig() call
- changelog: replace useState+fetch pagination with a co-located useInfiniteQuery hook (first page stays SSR-seeded via initialData)
* feat(landing): URL-state filters via nuqs (SSR-friendly) + stars fallback bump
- integrations grid, models directory: search + category/provider filters now
live in the URL (nuqs useQueryStates), server-parsed via createSearchParamsCache
so filtered views render server-side (crawlable, shareable) — mirrors the blog
index SSR pattern. Search URL writes debounced; in-memory filtering stays instant.
- pricing: billing-period toggle moves to ?billing=annual (shareable, no flash).
- co-located search-params.ts per page as the single source of truth (server + client).
- stars: bump fallback floor 28800 -> 28900 to track the current count.
* fix(landing): use the light sim mark (not green) in the integration CTA
Replace brandbook/logo/small.png — referenced only by the 'Start automating
{service} today' CTA on integration pages — with the black-on-light sim mark so
the tile reads as a neutral brand mark beside the partner icon instead of a green
block.
* fix(landing): calmer release-timeline dot hover
Drop the scale-150 + brightness-75 hover (a 50% size jump plus a muddy darken)
for an understated opacity-fill (0.85 -> 1) with a slight scale-110, matching the
comparison chart's opacity-driven hover language.
* fix(landing): keep changelog load-more when initial page is empty; drop inline comments
- changelog: getNextPageParam no longer treats an empty server-seeded page 1 as
end-of-feed, so a failed/empty initial GitHub fetch still surfaces 'Show more'
(addresses Cursor Bugbot).
- replace the inline comments added in this branch with TSDoc on the search-param
caches (documents the dynamic-render → SSR-filtered behavior), per the
codebase's TSDoc-only convention.
* revert(landing): keep the original changelog timeline (drop useInfiniteQuery)
The React Query conversion of an SSR-seeded, cross-origin, infrequently-changing
paginated list introduced caching edge cases (empty-seed load-more, singleton
cache serving stale page 1 on client-side nav) without real benefit. Restore the
original useState(initialEntries)+fetch timeline, which is simpler, correct, and
already review-clean from #5181.
56 lines
1.8 KiB
TypeScript
56 lines
1.8 KiB
TypeScript
import { createLogger } from '@sim/logger'
|
|
import { env } from '@/lib/core/config/env'
|
|
|
|
const logger = createLogger('GitHubStars')
|
|
|
|
/**
|
|
* Floor shown only when the live GitHub count can't be fetched. Kept a touch
|
|
* below the real count (~28.9k as of 2026-06) so it never overstates, and
|
|
* bumped periodically.
|
|
*/
|
|
const FALLBACK_STAR_COUNT = 28900
|
|
|
|
/**
|
|
* Formats a raw star count for display (e.g. 28900 → "28.9k").
|
|
*/
|
|
export function formatStarCount(num: number): string {
|
|
if (num < 1000) return String(num)
|
|
const formatted = (Math.round(num / 100) / 10).toFixed(1)
|
|
return formatted.endsWith('.0') ? `${formatted.slice(0, -2)}k` : `${formatted}k`
|
|
}
|
|
|
|
/**
|
|
* Fetches the Sim repository's GitHub star count, formatted for display.
|
|
*
|
|
* Server-only. The upstream fetch is cached for 1 hour via Next.js fetch
|
|
* caching, so statically rendered pages (landing) and the `/api/stars`
|
|
* route share one cached value. Falls back to a static count on failure —
|
|
* never throws.
|
|
*/
|
|
export async function getGitHubStars(): Promise<string> {
|
|
try {
|
|
const token = env.GITHUB_TOKEN
|
|
const response = await fetch('https://api.github.com/repos/simstudioai/sim', {
|
|
headers: {
|
|
Accept: 'application/vnd.github+json',
|
|
'X-GitHub-Api-Version': '2022-11-28',
|
|
'User-Agent': 'Sim/1.0',
|
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
},
|
|
next: { revalidate: 3600 },
|
|
cache: 'force-cache',
|
|
})
|
|
|
|
if (!response.ok) {
|
|
logger.warn('GitHub API request failed:', response.status)
|
|
return formatStarCount(FALLBACK_STAR_COUNT)
|
|
}
|
|
|
|
const data = await response.json()
|
|
return formatStarCount(Number(data?.stargazers_count ?? FALLBACK_STAR_COUNT))
|
|
} catch (error) {
|
|
logger.warn('Error fetching GitHub stars:', error)
|
|
return formatStarCount(FALLBACK_STAR_COUNT)
|
|
}
|
|
}
|