tracks lexicons and how many times they appeared on the jetstream

feat(client): make stat cards numbers animated, rename text

ptr.pet f065b614 a13ddcde

verified
Changed files
+23 -14
client
+7
client/bun.lock
···
"workspaces": {
"": {
"name": "nsid-tracker",
+
"dependencies": {
+
"@number-flow/svelte": "^0.3.9",
+
},
"devDependencies": {
"@eslint/compat": "^1.2.5",
"@eslint/js": "^9.18.0",
···
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
+
+
"@number-flow/svelte": ["@number-flow/svelte@0.3.9", "", { "dependencies": { "esm-env": "^1.1.4", "number-flow": "0.5.8" }, "peerDependencies": { "svelte": "^4 || ^5" } }, "sha512-CTw1+e0074GzbPX2IHcNCaK8nqxGNCOIUnQUjEjhcmBwBxOAhN3GYLQ6cJHvhQnWwplVe4eQ3z+c25Vttr2stQ=="],
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
···
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
+
+
"number-flow": ["number-flow@0.5.8", "", { "dependencies": { "esm-env": "^1.1.4" } }, "sha512-FPr1DumWyGi5Nucoug14bC6xEz70A1TnhgSHhKyfqjgji2SOTz+iLJxKtv37N5JyJbteGYCm6NQ9p1O4KZ7iiA=="],
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
+4 -1
client/package.json
···
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "eslint ."
},
-
"type": "module"
+
"type": "module",
+
"dependencies": {
+
"@number-flow/svelte": "^0.3.9"
+
}
}
+3 -2
client/src/lib/components/StatsCard.svelte
···
<script lang="ts">
import { formatNumber } from "$lib/format";
+
import NumberFlow from "@number-flow/svelte";
const colorClasses = {
green: {
···
</script>
<div
-
class="min-w-fit bg-gradient-to-r {colors.bg} p-3 md:p-6 rounded-lg border {colors.border}"
+
class="bg-gradient-to-r {colors.bg} p-3 md:p-6 rounded-lg border {colors.border}"
>
<h3 class="text-base font-medium {colors.titleText} mb-2">
{title}
</h3>
<p class="text-xl md:text-3xl font-bold {colors.valueText}">
-
{formatNumber(value)}
+
<NumberFlow {value} />
</p>
</div>
+9 -11
client/src/routes/+page.svelte
···
</script>
<svelte:head>
-
<title>bluesky jetstream tracker</title>
+
<title>lexicon tracker</title>
<meta
name="description"
content="tracks bluesky jetstream events by collection"
···
<div class="md:max-w-[61vw] mx-auto p-2">
<header class="text-center mb-8">
-
<h1 class="text-4xl font-bold mb-2 text-gray-900">
-
bluesky event tracker
-
</h1>
-
<p class="text-gray-600">
-
tracking of bluesky events by collection from the jetstream
+
<h1 class="text-4xl font-bold mb-2 text-gray-900">lexicon tracker</h1>
+
<p class="text-lg text-gray-600">
+
tracks lexicons seen on the jetstream
</p>
</header>
-
<div class="min-w-fit grid grid-cols-2 xl:grid-cols-4 gap-2 2xl:gap-6 mb-8">
+
<div
+
class="min-w-fit grid grid-cols-2 xl:grid-cols-4 gap-2 2xl:gap-6 2xl:mx-16 mb-8"
+
>
<StatsCard
title="total creation"
value={all.count}
···
{#if eventsList.length > 0}
<div class="mb-8">
<div class="flex flex-wrap items-center gap-3 mb-3">
-
<h2 class="text-2xl font-bold text-gray-900">
-
events by collection
-
</h2>
+
<h2 class="text-2xl font-bold text-gray-900">seen lexicons</h2>
<StatusBadge status={websocketStatus} />
</div>
<FilterControls
···
{:else}
<div class="text-center py-12 bg-gray-50 rounded-lg">
<div class="text-gray-400 text-4xl mb-4">📊</div>
-
<p class="text-gray-600">no events tracked yet.</p>
+
<p class="text-gray-600">no events tracked yet. try refreshing?</p>
</div>
{/if}
</div>