Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stats to app #2386

Merged
merged 32 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a1c81ab
feat(app): stats queries
cor Jul 2, 2024
8ae083f
feat(app): show stats in explorer
cor Jul 2, 2024
0b257ca
feat(app): scaffold logo
cor Jul 2, 2024
211a945
feat(app): in flux spinning animation
cor Jul 2, 2024
f824876
feat(app): pixel graph
Swepool Jul 2, 2024
d445e63
feat(app): add rotating cubes
cor Jul 2, 2024
19a9f7a
fix(app): move comp
Swepool Jul 2, 2024
05af11a
feat(app): get data for chart
Swepool Jul 2, 2024
9674c86
feat(app): save, add more stats
Swepool Jul 2, 2024
8133565
feat(app): border and width
Swepool Jul 2, 2024
622cd75
fix(app): padding acc to figma
Swepool Jul 3, 2024
932638f
fix(app): scroll
Swepool Jul 3, 2024
43b1cbf
fix(app): flip according to figma
Swepool Jul 3, 2024
890f7e5
fix(app): 30 days data
Swepool Jul 3, 2024
4871960
feat(app): reduce strokeWidth
cor Jul 3, 2024
f0d1d4e
feat(app): add stats bar animation
cor Jul 3, 2024
7610e77
feat(app): zoom effect for spinning logo
cor Jul 3, 2024
a2e1ebb
feat(app): device width store
Swepool Jul 3, 2024
932b838
feat(app): better logo
cor Jul 3, 2024
c084987
feat(app): add statbar mobile comp
Swepool Jul 3, 2024
94d16f5
feat(app): put cubes in containers
cor Jul 3, 2024
815cbaf
feat(app): roatting cubes
cor Jul 3, 2024
345ab66
feat(app): loop stats
Swepool Jul 3, 2024
2c79fca
fix(app): move stuff around and size
Swepool Jul 3, 2024
e7521a7
fix(app): fix duplicate render
Swepool Jul 3, 2024
2ffa58d
feat(app): sliding logo animation
cor Jul 3, 2024
bf3c0a0
fix(app): use shadcn separator instead
Swepool Jul 3, 2024
a0b687d
feat(app): improve css animation
cor Jul 3, 2024
e86a15b
fix(app): cleanup
cor Jul 3, 2024
b643fd4
fix(app): comment out spinning outline logo
cor Jul 3, 2024
02a9332
feat(app): live data and copy
Swepool Jul 3, 2024
2b092bd
fix(app): rm bg fix later
Swepool Jul 3, 2024
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: 54 additions & 0 deletions app/src/lib/components/spinning-logo/square.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<script lang="ts">
export let size: number
export let x: number
export let y: number
export let strokeWidth: number
</script>


<!-- front !-->
<div class="cube-container" style={`top: ${y}px; left: ${x}px; width: ${size}px; height: ${size}px;`}>
<svg class="absolute" stroke-width={strokeWidth} style={`transform: translateZ(-${size/2}px)`} width={`${size}px`} height={`${size}px`} viewBox={`0 0 ${size} ${size}`} fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x=0 y=0 width={size} height={size} stroke="black"/>
</svg>

<!-- left !-->
<svg class="absolute" stroke-width={strokeWidth} style={`transform: rotateY(90deg) translateZ(-${size/2}px)`} width={`${size}px`} height={`${size}px`} viewBox={`0 0 ${size} ${size}`} fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x=0 y=0 width={size} height={size} stroke="black"/>
</svg>

<!-- top !-->
<svg class="absolute" stroke-width={strokeWidth} style={`transform: rotateX(-90deg) translateZ(-${size/2}px)`} width={`${size}px`} height={`${size}px`} viewBox={`0 0 ${size} ${size}`} fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x=0 y=0 width={size} height={size} stroke="black"/>
</svg>

<!-- back !-->
<svg class="absolute" stroke-width={strokeWidth} style={`transform: translateZ(${size/2}px)`} width={`${size}px`} height={`${size}px`} viewBox={`0 0 ${size} ${size}`} fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x=0 y=0 width={size} height={size} stroke="black"/>
</svg>

<!-- right !-->
<svg class="absolute" stroke-width={strokeWidth} style={`transform: rotateY(-90deg) translateZ(-${size/2}px)`} width={`${size}px`} height={`${size}px`} viewBox={`0 0 ${size} ${size}`} fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x=0 y=0 width={size} height={size} stroke="black"/>
</svg>

<!-- bottom !-->
<svg class="absolute" stroke-width={strokeWidth} style={`transform: rotateX(90deg) translateZ(-${size/2}px)`} width={`${size}px`} height={`${size}px`} viewBox={`0 0 ${size} ${size}`} fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x=0 y=0 width={size} height={size} stroke="black"/>
</svg>
</div>


<style lang="postcss">

@keyframes rotating-cube {
0% {transform: rotateZ(0deg);}
100% {transform: rotateZ(360deg);}
}

.cube-container {
position: absolute;
transform-style: preserve-3d;
animation: rotating-cube 8s linear 0s infinite ;
}
</style>
52 changes: 52 additions & 0 deletions app/src/lib/components/spinning-outline-logo.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<script lang="ts">
import Square from './spinning-logo/square.svelte';
let cubeWidth = 64;
let cubeCount = 12;
let gap = 64;
let logoWidth= cubeWidth * cubeCount + gap * (cubeCount - 1);
let cubesY = cubeWidth * 2 + gap;
$: cubeDelta = (20 - cubeWidth) / 2;
let strokeWidth = 4;
</script>


<div class="overflow-hidden max-size-full flex-1">
<div class="logo-scene max-size-full overflow-hidden size-full">
<div class="logo absolute" style={`left: calc(50% - (${logoWidth}px / 2)); top: calc(50% - (${cubeWidth}px / 2)); width: ${logoWidth}px; height: ${cubeWidth}px`};}>
{#each {length: cubeCount} as _, i}
<Square {strokeWidth} size={cubeWidth} x={(cubeWidth + gap) * i} y={0}/>
{/each}
</div>
</div>
</div>

<style lang="postcss">

@keyframes spinning-logo {
0% {transform: rotateY(0deg) translateX(0);}
10% {transform: rotateY(90deg) translateX(200px);}
30% {transform: rotateY(90deg) translateX(-1000px);}
60% {transform: rotateY(90deg) translateX(200);}
80% {transform: rotateY(360deg);}
100% {transform: rotateY(0deg);}
}

@keyframes sliding-logo {
0% {transform: translateX(800px);}
40% {transform: translateX(-800px);}
50% {transform: rotateY(-90deg) translateX(-1000px); }
100% {transform: rotateY(-90deg) translateX(1200px);}
}


.logo-scene {
perspective: 500px;
position: relative;
}

.logo {
animation: sliding-logo 8s linear 0s infinite alternate;
position: absolute;
transform-style: preserve-3d;
}
</style>
25 changes: 25 additions & 0 deletions app/src/lib/components/stats-bar-stat.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script lang="ts">
import { deviceWidth } from "$lib/utilities/device.ts"
import { cn } from "$lib/utilities/shadcn.ts"

export let label: string
export let value: number | string

function formatValue(value: number | string): string {
if (typeof value === "number") {
value = value.toLocaleString()
}
return value
}
</script>

<div class={cn("uppercase flex px-6 py-4 border-none", $deviceWidth >= 888 ? "w-fit" : "w-full")}>
<div class="text-xl pt-2 font-bold divide-y" on:copy={(event) => {
event?.clipboardData?.setData('text/plain', value.toString());
event.preventDefault();
}}>
<h3 class="text-sm pb-2">{label}</h3>
<div class="text-xl pt-2 font-bold">{formatValue(value)}</div>
</div>
<slot />
</div>
38 changes: 38 additions & 0 deletions app/src/lib/graphql/documents/stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { graphql } from "gql.tada"

export const transferCountQueryDocument = graphql(/* GraphQL */ `
query TransferCountQuery @cached(ttl: 5) {
v0_transfers_aggregate {
aggregate {
count
}
}
}
`)

export const packetCountQueryDocument = graphql(/* GraphQL */ `
query PacketCountQuery @cached(ttl: 5) {
v0_packets_aggregate {
aggregate {
count
}
}
}
`)

export const transfersPerDayQueryDocument = graphql(/* GraphQL */ `
query TransfersPerDay($limit: Int!) @cached(ttl: 60) {
v0_daily_transfers(limit: $limit, order_by: {day: desc}) {
count
day
}
}
`)

export const packetsPerDayQueryDocument = graphql(/* GraphQL */ `
query PacketsPerDay($limit: Int!) {
v0_daily_packets(limit: $limit, order_by: {day: desc}) {
count
}
}
`)
39 changes: 39 additions & 0 deletions app/src/lib/queries/stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { createQuery } from "@tanstack/svelte-query"
import {
packetCountQueryDocument,
transfersPerDayQueryDocument,
transferCountQueryDocument
} from "$lib/graphql/documents/stats.ts"

import { request } from "graphql-request"
import { URLS } from "$lib/constants"

export const transfersPerDayQuery = limit =>
createQuery({
queryKey: ["transfer-per-day"],
queryFn: async () =>
(await request(URLS.GRAPHQL, transfersPerDayQueryDocument, { limit })).v0_daily_transfers,
enabled: true,
refetchInterval: 6_000,
refetchOnWindowFocus: false
})

export const packetCountQuery = () =>
createQuery({
queryKey: ["packet-count"],
queryFn: async () =>
(await request(URLS.GRAPHQL, packetCountQueryDocument, {})).v0_packets_aggregate,
enabled: true,
refetchInterval: 6_000,
refetchOnWindowFocus: false
})

export const transferCountQuery = () =>
createQuery({
queryKey: ["packet-count"],
queryFn: async () =>
(await request(URLS.GRAPHQL, transferCountQueryDocument, {})).v0_transfers_aggregate,
enabled: true,
refetchInterval: 6_000,
refetchOnWindowFocus: false
})
3 changes: 3 additions & 0 deletions app/src/lib/utilities/device.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { writable } from "svelte/store"

export const deviceWidth = writable<number>()
20 changes: 20 additions & 0 deletions app/src/lib/utilities/user-time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { writable } from "svelte/store"

const pad = (num: number): string => num.toString().padStart(2, "0")

const formatTime = (date: Date): string => {
const hours = pad(date.getHours())
const minutes = pad(date.getMinutes())
const seconds = pad(date.getSeconds())
return `${hours}:${minutes}:${seconds}`
}

export const userTime = writable(formatTime(new Date()))

const updateClock = (): void => {
setInterval(() => {
userTime.set(formatTime(new Date()))
}, 1000)
}

updateClock()
2 changes: 2 additions & 0 deletions app/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import LoadingBar from "$lib/components/loading-bar.svelte"
import { SvelteQueryDevtools } from "@tanstack/svelte-query-devtools"
import { PersistQueryClientProvider } from "@tanstack/svelte-query-persist-client"
import { disablePinchToZoom } from "$lib/utilities/disable-pinch-to-zoom.ts"
import { deviceWidth } from "$lib/utilities/device.ts"

const { queryClient, localStoragePersister } = createQueryClient()
if (browser) notifyManager.setScheduler(window.requestAnimationFrame)
Expand All @@ -40,6 +41,7 @@ if (browser) notifyManager.setScheduler(window.requestAnimationFrame)
</svelte:head>

<svelte:window
bind:innerWidth={$deviceWidth}
use:shortcut={{
trigger: [
// easily hide tanstack devtools with ctrl + h
Expand Down
46 changes: 46 additions & 0 deletions app/src/routes/explorer/(components)/pixel-graph.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<script lang="ts">
import * as Tooltip from "$lib/components/ui/tooltip"

export let data: Array<{ count: number; day: Date }>

const minValue = Math.min(...data.map(d => d.count))
const maxValue = Math.max(...data.map(d => d.count))

function normalize(
value: number,
min: number,
max: number,
newMin: number,
newMax: number
): number {
return ((value - min) / (max - min)) * (newMax - newMin) + newMin
}

const normalizedData = data.map(d => ({
...d,
normalizedValue: Math.floor(normalize(d.count, minValue, maxValue, 0, 9))
}))
</script>

<div class="flex flex-row-reverse items-end gap-[2.5px]">
{#each normalizedData as data}
<Tooltip.Root>
<Tooltip.Trigger>
<div class="bar flex flex-col-reverse gap-[1px] group cursor-crosshair">
<div class="half-square bg-primary group-hover:bg-accent h-[2.5px] w-[5px] transition"></div>
{#each Array(data.normalizedValue) as _}
<div class="square bg-primary group-hover:bg-accent h-[5px] w-[5px] transition"></div>
{/each}
</div>
</Tooltip.Trigger>
<Tooltip.Content>
{#if data.day && data.count}
{new Date(data.day).toISOString().slice(0, 10)}
<br/>
{data.count}
{/if}
</Tooltip.Content>
</Tooltip.Root>
{/each}
</div>

50 changes: 50 additions & 0 deletions app/src/routes/explorer/(components)/stats-bar-mobile.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script lang="ts">
import StatsBarStat from "$lib/components/stats-bar-stat.svelte"
import { packetCountQuery, transferCountQuery, transfersPerDayQuery } from "$lib/queries/stats.ts"
import PixelGraph from "../(components)/pixel-graph.svelte"
import { userTime } from "$lib/utilities/user-time.ts"
import SpinningOutlineLogo from "$lib/components/spinning-outline-logo.svelte"
import { onMount } from "svelte"
import { fade } from "svelte/transition"
import { Separator } from "$lib/components/ui/separator"

// 30 days
$: transfersPerDayData = transfersPerDayQuery(30)

$: packetCountData = packetCountQuery()
$: transferCountData = transferCountQuery()

let show = 1
let interval: any

onMount(() => {
interval = setInterval(() => {
show = show === 1 ? 2 : 1
}, 5000)
return () => {
clearInterval(interval)
}
})
</script>

<div class="bg-muted border-b flex">
<div class="w-full">
{#if show === 1}
<div class="w-full flex h-full" in:fade>
<StatsBarStat label={"Total Transfers"} value={$transferCountData?.data?.aggregate?.count || 0}/>
<Separator orientation="vertical"/>
<StatsBarStat label="Total Packets" value={$packetCountData?.data?.aggregate?.count || 0}/>
</div>
{:else if show === 2}
<div class="w-full flex" in:fade>
<StatsBarStat label="Metrics" value={$userTime} on:click={() => show--}>
{#if $transfersPerDayData.data}
<div class="ml-6 flex items-end">
<PixelGraph data={$transfersPerDayData.data}/>
</div>
{/if}
</StatsBarStat>
</div>
{/if}
</div>
</div>
35 changes: 35 additions & 0 deletions app/src/routes/explorer/(components)/stats-bar.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script lang="ts">
import StatsBarStat from "$lib/components/stats-bar-stat.svelte"
import { packetCountQuery, transferCountQuery, transfersPerDayQuery } from "$lib/queries/stats.ts"
import PixelGraph from "../(components)/pixel-graph.svelte"
import { userTime } from "$lib/utilities/user-time.ts"
import SpinningOutlineLogo from "$lib/components/spinning-outline-logo.svelte"
import { Separator } from "$lib/components/ui/separator"

// 30 days
$: transfersPerDayData = transfersPerDayQuery(30)

$: packetCountData = packetCountQuery()
$: transferCountData = transferCountQuery()

$: console.log($packetCountData)
$: console.log($transferCountData)
</script>

<div class="bg-muted border-b flex">
<div class="w-full flex flex-1">
<StatsBarStat label={"Total Transfers"} value={$transferCountData?.data?.aggregate?.count || 0}/>
<Separator orientation="vertical"/>
<StatsBarStat label="Total Packets" value={$packetCountData?.data?.aggregate?.count || 0}/>
<Separator orientation="vertical"/>
<StatsBarStat label="Metrics" value={$userTime}>
{#if $transfersPerDayData.data}
<div class="ml-6 flex items-end">
<PixelGraph data={$transfersPerDayData.data}/>
</div>
{/if}
</StatsBarStat>
<Separator orientation="vertical"/>
<!--<SpinningOutlineLogo/>!-->
</div>
</div>
Loading
Loading