Skip to content

Commit

Permalink
fix stats counter, move to separate file (#325)
Browse files Browse the repository at this point in the history
  • Loading branch information
erquhart authored Dec 28, 2024
1 parent c02b47f commit 880cd91
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 184 deletions.
149 changes: 149 additions & 0 deletions app/components/OpenSourceStats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { convexQuery } from '@convex-dev/react-query'
import { useNpmDownloadCounter } from '@erquhart/convex-oss-stats/react'
import NumberFlow from '@number-flow/react'
import { useSuspenseQuery } from '@tanstack/react-query'
import { api } from 'convex/_generated/api'
import { FaCube, FaStar, FaUsers } from 'react-icons/fa'
import { FaDownload } from 'react-icons/fa'
import convexImageWhite from '~/images/convex-white.svg'
import convexImageDark from '~/images/convex-dark.svg'

const counterIntervalMs = 500

const StableCounter = ({ value }: { value?: number }) => {
const dummyString = Number(
Array(value?.toString().length ?? 1)
.fill('8')
.join('')
).toLocaleString()

return (
<>
{/* Dummy span to prevent layout shift */}
<span className="opacity-0">{dummyString}</span>
<span className="absolute -top-0.5 left-0">
<NumberFlow
transformTiming={{
duration: counterIntervalMs,
easing: 'linear',
}}
value={value}
trend={1}
continuous
isolate
willChange
/>
</span>
</>
)
}

const NpmDownloadCounter = ({
npmData,
}: {
npmData: Parameters<typeof useNpmDownloadCounter>[0]
}) => {
const liveNpmDownloadCount = useNpmDownloadCounter(npmData, {
intervalMs: counterIntervalMs,
})
return <StableCounter value={liveNpmDownloadCount} />
}

export default function OssStats() {
const { data: github } = useSuspenseQuery(
convexQuery(api.stats.getGithubOwner, {
owner: 'tanstack',
})
)
const { data: npm } = useSuspenseQuery(
convexQuery(api.stats.getNpmOrg, {
name: 'tanstack',
})
)

return (
<div>
<div className="p-8 grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-8 items-center justify-center xl:place-items-center bg-white/50 dark:bg-gray-700/30 dark:shadow-none rounded-xl shadow-xl">
<a
href="https://www.npmjs.com/org/tanstack"
target="_blank"
rel="noreferrer"
className="group flex gap-4 items-center"
>
<FaDownload className="text-2xl group-hover:text-emerald-500 transition-colors duration-200" />
<div>
<div className="text-2xl font-bold opacity-80 relative group-hover:text-emerald-500 transition-colors duration-200">
<NpmDownloadCounter npmData={npm} />
</div>
<div className="text-sm opacity-50 font-medium italic group-hover:text-emerald-500 transition-colors duration-200">
NPM Downloads
</div>
</div>
</a>
<a
href="https://github.com/orgs/TanStack/repositories?q=sort:stars"
target="_blank"
rel="noreferrer"
className="group flex gap-4 items-center"
>
<FaStar className="group-hover:text-yellow-500 text-2xl transition-colors duration-200" />
<div>
<div className="text-2xl font-bold opacity-80 leading-none group-hover:text-yellow-500 transition-colors duration-200">
<NumberFlow value={github?.starCount} />
</div>
<div className="text-sm opacity-50 font-medium italic -mt-1 group-hover:text-yellow-500 transition-colors duration-200">
Stars on Github
</div>
</div>
</a>
<div className="flex gap-4 items-center">
<FaUsers className="text-2xl" />
<div className="">
<div className="text-2xl font-bold opacity-80">
<NumberFlow value={github?.contributorCount} />
</div>
<div className="text-sm opacity-50 font-medium italic -mt-1">
Contributors on GitHub
</div>
</div>
</div>
<div className="flex gap-4 items-center">
<FaCube className="text-2xl" />
<div className="">
<div className="text-2xl font-bold opacity-80 relative">
<NumberFlow value={github?.dependentCount} />
</div>
<div className="text-sm opacity-50 font-medium italic -mt-1">
Dependents on GitHub
</div>
</div>
</div>
</div>
<div className="px-4 py-2 flex justify-end">
<a
href="https://www.convex.dev/?utm_source=tanstack"
className="group flex items-center gap-2"
>
<div className="h-2 w-2 animate-pulse rounded-full bg-green-500"></div>
<div className="flex items-center gap-1">
<span className="text-[.75rem] opacity-30 relative -top-px">
Powered by
</span>
<img
className="dark:hidden opacity-30 group-hover:opacity-50"
src={convexImageDark}
alt="Convex Logo"
width={80}
/>
<img
className="hidden dark:block opacity-30 group-hover:opacity-50"
src={convexImageWhite}
alt="Convex Logo"
width={80}
/>
</div>
</a>
</div>
</div>
)
}
148 changes: 2 additions & 146 deletions app/routes/_libraries/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,12 @@ import {
createFileRoute,
getRouteApi,
} from '@tanstack/react-router'
import { useSuspenseQuery } from '@tanstack/react-query'
import { convexQuery } from '@convex-dev/react-query'
import { useNpmDownloadCounter } from '@erquhart/convex-oss-stats/react'
import NumberFlow from '@number-flow/react'
import { api } from '../../../convex/_generated/api'
import { Carbon } from '~/components/Carbon'
import { twMerge } from 'tailwind-merge'
import { CgSpinner } from 'react-icons/cg'
import { Footer } from '~/components/Footer'
import SponsorPack from '~/components/SponsorPack'
import discordImage from '~/images/discord-logo-white.svg'
import convexImageWhite from '~/images/convex-white.svg'
import convexImageDark from '~/images/convex-dark.svg'
import { useMutation } from '~/hooks/useMutation'
import { sample } from '~/utils/utils'
import { libraries } from '~/libraries'
Expand All @@ -27,7 +20,7 @@ import bytesImage from '~/images/bytes.svg'
// import waves from '~/images/waves.png'
// import background from '~/images/background.jpg'
import { partners } from '../../utils/partners'
import { FaCube, FaDownload, FaStar, FaUsers } from 'react-icons/fa'
import OpenSourceStats from '~/components/OpenSourceStats'

export const textColors = [
`text-rose-500`,
Expand Down Expand Up @@ -79,143 +72,6 @@ async function bytesSignupServerFn({ email }: { email: string }) {

const librariesRouteApi = getRouteApi('/_libraries')

const StableCounter = ({ value }: { value?: number }) => {
const dummyString = Number(
Array(value?.toString().length ?? 1)
.fill('8')
.join('')
).toLocaleString()

return (
<>
{/* Dummy span to prevent layout shift */}
<span className="opacity-0">{dummyString}</span>
<span className="absolute -top-0.5 left-0">
<NumberFlow
transformTiming={{
duration: 1000,
easing: 'linear',
}}
value={value}
trend={1}
continuous
isolate
willChange
/>
</span>
</>
)
}

const NpmDownloadCounter = ({
npmData,
}: {
npmData: Parameters<typeof useNpmDownloadCounter>[0]
}) => {
const liveNpmDownloadCount = useNpmDownloadCounter(npmData)
return <StableCounter value={liveNpmDownloadCount} />
}

const OssStats = () => {
const { data: github } = useSuspenseQuery(
convexQuery(api.stats.getGithubOwner, {
owner: 'tanstack',
})
)
console.log('github', github)
const { data: npm } = useSuspenseQuery(
convexQuery(api.stats.getNpmOrg, {
name: 'tanstack',
})
)

return (
<div>
<div className="p-8 grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-8 items-center justify-center xl:place-items-center bg-white/50 dark:bg-gray-700/30 dark:shadow-none rounded-xl shadow-xl">
<a
href="https://www.npmjs.com/org/tanstack"
target="_blank"
rel="noreferrer"
className="group flex gap-4 items-center"
>
<FaDownload className="text-2xl group-hover:text-emerald-500 transition-colors duration-200" />
<div>
<div className="text-2xl font-bold opacity-80 relative group-hover:text-emerald-500 transition-colors duration-200">
<NpmDownloadCounter npmData={npm} />
</div>
<div className="text-sm opacity-50 font-medium italic group-hover:text-emerald-500 transition-colors duration-200">
NPM Downloads
</div>
</div>
</a>
<a
href="https://github.com/orgs/TanStack/repositories?q=sort:stars"
target="_blank"
rel="noreferrer"
className="group flex gap-4 items-center"
>
<FaStar className="group-hover:text-yellow-500 text-2xl transition-colors duration-200" />
<div>
<div className="text-2xl font-bold opacity-80 leading-none group-hover:text-yellow-500 transition-colors duration-200">
<NumberFlow value={github?.starCount} />
</div>
<div className="text-sm opacity-50 font-medium italic -mt-1 group-hover:text-yellow-500 transition-colors duration-200">
Stars on Github
</div>
</div>
</a>
<div className="flex gap-4 items-center">
<FaUsers className="text-2xl" />
<div className="">
<div className="text-2xl font-bold opacity-80">
<NumberFlow value={github?.contributorCount} />
</div>
<div className="text-sm opacity-50 font-medium italic -mt-1">
Contributors on GitHub
</div>
</div>
</div>
<div className="flex gap-4 items-center">
<FaCube className="text-2xl" />
<div className="">
<div className="text-2xl font-bold opacity-80 relative">
<NumberFlow value={github?.dependentCount} />
</div>
<div className="text-sm opacity-50 font-medium italic -mt-1">
Dependents on GitHub
</div>
</div>
</div>
</div>
<div className="px-4 py-2 flex justify-end">
<a
href="https://www.convex.dev/?utm_source=tanstack"
className="group flex items-center gap-2"
>
<div className="h-2 w-2 animate-pulse rounded-full bg-green-500"></div>
<div className="flex items-center gap-1">
<span className="text-[.75rem] opacity-30 relative -top-px">
Powered by
</span>
<img
className="dark:hidden opacity-30 group-hover:opacity-50"
src={convexImageDark}
alt="Convex Logo"
width={80}
/>
<img
className="hidden dark:block opacity-30 group-hover:opacity-50"
src={convexImageWhite}
alt="Convex Logo"
width={80}
/>
</div>
</a>
</div>
</div>
)
}

function Index() {
const bytesSignupMutation = useMutation({
fn: bytesSignupServerFn,
Expand Down Expand Up @@ -281,7 +137,7 @@ function Index() {
</div>
<div className="h-8" />
<div className="w-fit mx-auto">
<OssStats />
<OpenSourceStats />
</div>
<div className="h-24" />
<div className="px-4 lg:max-w-screen-lg md:mx-auto">
Expand Down
Loading

0 comments on commit 880cd91

Please sign in to comment.