Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 38 additions & 16 deletions sites/web/src/components/Header.astro
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
---
import { formatStarCount, getStarCount } from '~/lib/github'
import { MobileNav } from './MobileNav'
import { ThemeToggle } from './ThemeToggle'

const starsLabel = formatStarCount(await getStarCount())

const navItems = [
{ href: '/why', label: 'Why' },
{ href: '/examples', label: 'Examples' },
Expand Down Expand Up @@ -79,32 +82,51 @@ const mobileLinks = [...navItems, referenceLink]
{referenceLink.label}
</a>
</div>
{/* Segmented "GitHub | count" on desktop (the familiar GitHub pattern);
collapses to a compact icon + count on mobile — no divider, no
second segment background. */}
<a
href="https://github.com/desko27/react-call"
target="_blank"
rel="noopener noreferrer"
aria-label="Star react-call on GitHub"
aria-label={`Star react-call on GitHub — ${starsLabel} stars`}
class="
inline-flex items-center justify-center gap-1.5 rounded-md
group inline-flex items-stretch overflow-hidden rounded-md
border border-[var(--color-border-strong)]
h-9 w-9 px-0 py-0
md:h-auto md:w-auto md:px-3 md:py-1.5
h-9 md:h-auto
text-sm text-[var(--color-fg-muted)]
transition-colors
hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-fg)]
transition-colors hover:text-[var(--color-fg)]
hover:bg-[var(--color-bg-muted)] md:hover:bg-transparent
"
>
<svg
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
class="h-3.5 w-3.5 text-[var(--color-accent)]"
<span
class="
flex items-center gap-1.5
pl-2.5 pr-1 md:px-3 md:py-1.5
transition-colors md:group-hover:bg-[var(--color-bg-muted)]
"
>
<svg
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
class="h-3.5 w-3.5 text-[var(--color-accent)]"
>
<path
d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z"
></path>
</svg>
<span class="hidden md:inline">GitHub</span>
</span>
<span
class="
flex items-center tabular-nums
pl-1 pr-2.5 md:border-l md:border-[var(--color-border-strong)]
md:bg-[var(--color-bg-muted)] md:px-2.5 md:py-1.5
"
>
<path
d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z"
></path>
</svg>
<span class="hidden md:inline">Star</span>
{starsLabel}
</span>
</a>
<ThemeToggle client:load />
<div class="md:hidden">
Expand Down
31 changes: 31 additions & 0 deletions sites/web/src/lib/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const REPO = 'desko27/react-call'

// Used when the build-time fetch fails (offline CI, GitHub down, rate limit).
// Roughly tracks the real count so the UI never shows an absurd number — it
// only matters on the rare failed build, and refreshes on the next deploy.
const FALLBACK_STARS = 1200

// Astro renders Header on every page, so memoize: one network request per
// build regardless of how many pages/components ask for the count.
let cached: Promise<number> | undefined

export function getStarCount(): Promise<number> {
if (!cached) {
cached = fetch(`https://api.github.com/repos/${REPO}`, {
headers: { Accept: 'application/vnd.github+json' },
})
.then((res) => {
if (!res.ok) throw new Error(`GitHub API ${res.status}`)
return res.json() as Promise<{ stargazers_count: number }>
})
.then((data) => data.stargazers_count)
.catch(() => FALLBACK_STARS)
}
return cached
}

// 1215 -> "1.2k", 980 -> "980", 12345 -> "12.3k". Trailing ".0" is dropped.
export function formatStarCount(n: number): string {
if (n < 1000) return String(n)
return `${(n / 1000).toFixed(1).replace(/\.0$/, '')}k`
}
8 changes: 6 additions & 2 deletions sites/web/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import { HowItLives } from '~/components/landing/HowItLives'
import { MutationFlowSection } from '~/components/landing/MutationFlowSection'
import { NotJustConfirmations } from '~/components/landing/NotJustConfirmations'
import { StackSection } from '~/components/landing/StackSection'
import { formatStarCount, getStarCount } from '~/lib/github'
import Base from '~/layouts/Base.astro'
import { getAllExamples } from '~/lib/examples'

const exampleCount = getAllExamples().length
const starsLabel = formatStarCount(await getStarCount())
---

<Base>
Expand Down Expand Up @@ -134,7 +136,7 @@ const onDelete = async () => {
href="https://github.com/desko27/react-call"
target="_blank"
rel="noopener noreferrer"
aria-label="Star react-call on GitHub"
aria-label={`Star react-call on GitHub — ${starsLabel} stars`}
class="inline-flex items-center gap-2 rounded-md border border-[var(--color-border-strong)] bg-[var(--color-bg)] px-4 py-2 font-medium text-[var(--color-fg)] transition-colors hover:bg-[var(--color-bg-muted)]"
>
<svg
Expand All @@ -147,7 +149,9 @@ const onDelete = async () => {
d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z"
></path>
</svg>
Star on GitHub
<span>Star on GitHub</span>
<span class="text-[var(--color-fg-subtle)]" aria-hidden="true">·</span>
<span class="tabular-nums">{starsLabel}</span>
</a>
</div>
</div>
Expand Down
Loading