mirror of
https://github.com/jakejarvis/stanza.git
synced 2026-07-16 18:05:58 -04:00
feat: integrate @number-flow/react for enhanced number formatting in stats page
- Added @number-flow/react as a dependency to improve number display. - Replaced the custom formatCount function with NumberFlow for projectsScaffolded and modulesInstalled stats, ensuring better formatting and handling of loading states. - Updated LastRefreshed component's styling for improved readability.
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
"@base-ui/react": "^1.5.0",
|
||||
"@fontsource-variable/geist": "^5.2.9",
|
||||
"@fontsource-variable/geist-mono": "^5.2.8",
|
||||
"@number-flow/react": "^0.6.0",
|
||||
"@orama/orama": "^3.1.18",
|
||||
"@pierre/trees": "1.0.0-beta.4",
|
||||
"@stanza/registry": "workspace:*",
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { ReactNode } from "react";
|
||||
export function Section({ title, children }: { title: string; children: ReactNode }) {
|
||||
return (
|
||||
<section>
|
||||
<h3 className="mb-2 text-xs font-medium tracking-tight text-muted-foreground">{title}</h3>
|
||||
<h3 className="mb-2 text-[13px] font-medium tracking-tight text-muted-foreground">{title}</h3>
|
||||
{children}
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -84,7 +84,7 @@ function TooltipContent({
|
||||
<Popup
|
||||
data-slot="tooltip-content"
|
||||
className={cn(
|
||||
"relative z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 overflow-visible rounded-none bg-foreground px-2 py-1.5 text-xs text-background shadow-md selection:bg-background selection:text-foreground has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-none data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
||||
"relative z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 overflow-visible rounded-none bg-foreground px-2 py-1 text-xs text-background shadow-md selection:bg-background selection:text-foreground has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-none data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import NumberFlow from "@number-flow/react";
|
||||
import type { CategoryId, ModuleMetadata } from "@stanza/registry";
|
||||
import { categoryLabel, KNOWN_CATEGORIES } from "@stanza/registry";
|
||||
import { createFileRoute, Link, useLoaderData } from "@tanstack/react-router";
|
||||
@@ -30,11 +31,6 @@ const percentFormatter = new Intl.NumberFormat("en-US", {
|
||||
maximumFractionDigits: 0,
|
||||
});
|
||||
|
||||
function formatCount(value: number): string {
|
||||
if (value <= 0) return "—";
|
||||
return numberFormatter.format(value);
|
||||
}
|
||||
|
||||
function formatGeneratedAt(iso: string): string {
|
||||
const date = new Date(iso);
|
||||
if (Number.isNaN(date.getTime())) return iso;
|
||||
@@ -48,14 +44,14 @@ function formatGeneratedAt(iso: string): string {
|
||||
function LastRefreshed({ iso }: { iso: string }) {
|
||||
const ago = useTimeAgo(iso);
|
||||
return (
|
||||
<p>
|
||||
<p className="text-xs leading-4">
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
nativeButton={false}
|
||||
render={
|
||||
<time
|
||||
dateTime={iso}
|
||||
className="cursor-help font-mono text-xs text-muted-foreground/70 tabular-nums"
|
||||
className="cursor-help font-mono text-muted-foreground/70 tabular-nums"
|
||||
/>
|
||||
}
|
||||
>
|
||||
@@ -122,7 +118,7 @@ function StatsPage() {
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="font-mono text-4xl font-medium tracking-tight tabular-nums">
|
||||
{formatCount(stats?.projectsScaffolded ?? 0)}
|
||||
{isLoading ? "—" : <NumberFlow value={stats.projectsScaffolded} locales="en-US" />}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -134,7 +130,7 @@ function StatsPage() {
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="font-mono text-4xl font-medium tracking-tight tabular-nums">
|
||||
{formatCount(stats?.modulesInstalled ?? 0)}
|
||||
{isLoading ? "—" : <NumberFlow value={stats.modulesInstalled} locales="en-US" />}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Generated
+30
-92
@@ -98,6 +98,9 @@ importers:
|
||||
'@fontsource-variable/geist-mono':
|
||||
specifier: ^5.2.8
|
||||
version: 5.2.8
|
||||
'@number-flow/react':
|
||||
specifier: ^0.6.0
|
||||
version: 0.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
'@orama/orama':
|
||||
specifier: ^3.1.18
|
||||
version: 3.1.18
|
||||
@@ -242,10 +245,10 @@ importers:
|
||||
version: '@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3)'
|
||||
vite-plus:
|
||||
specifier: 'catalog:'
|
||||
version: 0.1.22(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)
|
||||
version: 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
|
||||
vitest:
|
||||
specifier: npm:@voidzero-dev/vite-plus-test@^0.1.22
|
||||
version: '@voidzero-dev/vite-plus-test@0.1.22(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)'
|
||||
version: '@voidzero-dev/vite-plus-test@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))'
|
||||
|
||||
packages/codemods:
|
||||
dependencies:
|
||||
@@ -1154,6 +1157,12 @@ packages:
|
||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@number-flow/react@0.6.0':
|
||||
resolution: {integrity: sha512-77Yfc9+zkV2UDSP8phhZzxJGuwxi/Tt1TikmipL+1r3e9GFKEYDZ1XwInj67NoSt3OnOB0KLvvcl3lfPZgBHVQ==}
|
||||
peerDependencies:
|
||||
react: ^18 || ^19
|
||||
react-dom: ^18 || ^19
|
||||
|
||||
'@oozcitak/dom@2.0.2':
|
||||
resolution: {integrity: sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==}
|
||||
engines: {node: '>=20.0'}
|
||||
@@ -3240,6 +3249,9 @@ packages:
|
||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
esm-env@1.2.2:
|
||||
resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
|
||||
|
||||
esprima@4.0.1:
|
||||
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -4333,6 +4345,9 @@ packages:
|
||||
nth-check@2.1.1:
|
||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||
|
||||
number-flow@0.6.0:
|
||||
resolution: {integrity: sha512-K8flNq2Wqus53vjp/btVo3qXFkagF8dIdYavreBfE7hlvFFG/b1HMGEH6nZL+mlrJ+4lbLP9OmPv3t2rmRkpSQ==}
|
||||
|
||||
object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -6243,6 +6258,13 @@ snapshots:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
fastq: 1.20.1
|
||||
|
||||
'@number-flow/react@0.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
|
||||
dependencies:
|
||||
esm-env: 1.2.2
|
||||
number-flow: 0.6.0
|
||||
react: 19.2.6
|
||||
react-dom: 19.2.6(react@19.2.6)
|
||||
|
||||
'@oozcitak/dom@2.0.2':
|
||||
dependencies:
|
||||
'@oozcitak/infra': 2.0.2
|
||||
@@ -7338,47 +7360,6 @@ snapshots:
|
||||
'@voidzero-dev/vite-plus-linux-x64-musl@0.1.22':
|
||||
optional: true
|
||||
|
||||
'@voidzero-dev/vite-plus-test@0.1.22(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
'@types/chai': 5.2.3
|
||||
'@voidzero-dev/vite-plus-core': 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3)
|
||||
es-module-lexer: 1.7.0
|
||||
obug: 2.1.1
|
||||
pixelmatch: 7.2.0
|
||||
pngjs: 7.0.0
|
||||
sirv: 3.0.2
|
||||
std-env: 4.1.0
|
||||
tinybench: 2.9.0
|
||||
tinyexec: 1.2.2
|
||||
tinyglobby: 0.2.16
|
||||
vite: '@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3)'
|
||||
ws: 8.21.0
|
||||
optionalDependencies:
|
||||
'@types/node': 25.9.1
|
||||
jsdom: 29.1.1(@noble/hashes@1.8.0)
|
||||
transitivePeerDependencies:
|
||||
- '@arethetypeswrong/core'
|
||||
- '@tsdown/css'
|
||||
- '@tsdown/exe'
|
||||
- '@vitejs/devtools'
|
||||
- bufferutil
|
||||
- esbuild
|
||||
- jiti
|
||||
- less
|
||||
- publint
|
||||
- sass
|
||||
- sass-embedded
|
||||
- stylus
|
||||
- sugarss
|
||||
- terser
|
||||
- tsx
|
||||
- typescript
|
||||
- unplugin-unused
|
||||
- unrun
|
||||
- utf-8-validate
|
||||
- yaml
|
||||
|
||||
'@voidzero-dev/vite-plus-test@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))':
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
@@ -7924,6 +7905,8 @@ snapshots:
|
||||
|
||||
escape-string-regexp@5.0.0: {}
|
||||
|
||||
esm-env@1.2.2: {}
|
||||
|
||||
esprima@4.0.1: {}
|
||||
|
||||
estree-util-attach-comments@3.0.0:
|
||||
@@ -9298,6 +9281,10 @@ snapshots:
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
|
||||
number-flow@0.6.0:
|
||||
dependencies:
|
||||
esm-env: 1.2.2
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
||||
object-inspect@1.13.4: {}
|
||||
@@ -10374,55 +10361,6 @@ snapshots:
|
||||
d3-time: 3.1.0
|
||||
d3-timer: 3.0.1
|
||||
|
||||
vite-plus@0.1.22(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3):
|
||||
dependencies:
|
||||
'@oxc-project/types': 0.129.0
|
||||
'@oxlint/plugins': 1.61.0
|
||||
'@voidzero-dev/vite-plus-core': 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3)
|
||||
'@voidzero-dev/vite-plus-test': 0.1.22(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)
|
||||
oxfmt: 0.48.0
|
||||
oxlint: 1.63.0(oxlint-tsgolint@0.22.1)
|
||||
oxlint-tsgolint: 0.22.1
|
||||
optionalDependencies:
|
||||
'@voidzero-dev/vite-plus-darwin-arm64': 0.1.22
|
||||
'@voidzero-dev/vite-plus-darwin-x64': 0.1.22
|
||||
'@voidzero-dev/vite-plus-linux-arm64-gnu': 0.1.22
|
||||
'@voidzero-dev/vite-plus-linux-arm64-musl': 0.1.22
|
||||
'@voidzero-dev/vite-plus-linux-x64-gnu': 0.1.22
|
||||
'@voidzero-dev/vite-plus-linux-x64-musl': 0.1.22
|
||||
'@voidzero-dev/vite-plus-win32-arm64-msvc': 0.1.22
|
||||
'@voidzero-dev/vite-plus-win32-x64-msvc': 0.1.22
|
||||
transitivePeerDependencies:
|
||||
- '@arethetypeswrong/core'
|
||||
- '@edge-runtime/vm'
|
||||
- '@opentelemetry/api'
|
||||
- '@tsdown/css'
|
||||
- '@tsdown/exe'
|
||||
- '@types/node'
|
||||
- '@vitejs/devtools'
|
||||
- '@vitest/coverage-istanbul'
|
||||
- '@vitest/coverage-v8'
|
||||
- '@vitest/ui'
|
||||
- bufferutil
|
||||
- esbuild
|
||||
- happy-dom
|
||||
- jiti
|
||||
- jsdom
|
||||
- less
|
||||
- publint
|
||||
- sass
|
||||
- sass-embedded
|
||||
- stylus
|
||||
- sugarss
|
||||
- terser
|
||||
- tsx
|
||||
- typescript
|
||||
- unplugin-unused
|
||||
- unrun
|
||||
- utf-8-validate
|
||||
- vite
|
||||
- yaml
|
||||
|
||||
vite-plus@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)):
|
||||
dependencies:
|
||||
'@oxc-project/types': 0.129.0
|
||||
|
||||
Reference in New Issue
Block a user