+37
-8
src/App.svelte
+37
-8
src/App.svelte
···
1
1
<script lang="ts">
2
2
import { onMount } from 'svelte';
3
-
import { Progress } from '@skeletonlabs/skeleton-svelte';
3
+
import { formatDistanceToNow, addSeconds, formatDate, formatISO9075 } from 'date-fns';
4
+
import { Progress, Switch } from '@skeletonlabs/skeleton-svelte';
4
5
import instancesData from './instances.json';
5
-
import { formatDistanceToNow, addSeconds } from 'date-fns';
6
6
import numeral from 'numeral';
7
7
8
+
const AUTO_REFRESH_INTERVAL = 15 // in seconds
9
+
const BUNDLE_OPS = 10_000
8
10
9
11
type Instance = {
10
12
url: string,
···
20
22
mempoolPercent: 0,
21
23
})
22
24
25
+
let isUpdating = $state(false)
26
+
let canRefresh = $state(true)
27
+
let lastUpdated = $state(new Date())
28
+
let autoRefreshEnabled = $state(true)
23
29
let instances = $state(instancesData)
24
30
let instancesSorted = $derived(instances.sort((a, b) => a.status?.responseTime > b.status?.responseTime ? 1 : -1))
25
31
···
56
62
}
57
63
58
64
async function doCheck() {
65
+
isUpdating = true
66
+
canRefresh = false
59
67
for (const i of instances) {
60
68
i.status = undefined
61
69
}
···
75
83
}
76
84
}
77
85
instance.status = status
86
+
lastUpdated = new Date()
78
87
}))
88
+
isUpdating = false
89
+
setTimeout(() => (canRefresh = false), 1000)
79
90
}
80
91
81
92
onMount(() => {
82
93
doCheck()
94
+
95
+
setTimeout(() => {
96
+
if (autoRefreshEnabled) {
97
+
doCheck()
98
+
}
99
+
}, AUTO_REFRESH_INTERVAL * 1000)
83
100
})
84
101
</script>
85
102
86
103
<main class="w-full mt-10">
87
104
<div class="max-w-4xl mx-auto px-3">
88
105
89
-
<header class="flex items-center gap-2 flex-wrap">
106
+
<header class="flex items-center gap-10 flex-wrap">
90
107
<div class="grow">
91
-
<h1 class="text-3xl ">plcbundle instances</h1>
108
+
<h1 class="text-3xl linear-text-gradient">plcbundle instances</h1>
92
109
</div>
93
-
<div class="">
94
-
<button type="button" class="btn btn-sm preset-tonal-primary" onclick={() => doCheck()}>Refresh</button>
110
+
<div class="flex items-center gap-6">
111
+
<Switch class="opacity-75" checked={autoRefreshEnabled} onCheckedChange={(x) => autoRefreshEnabled = x.checked} disabled={isUpdating}>
112
+
<Switch.Control className="data-[state=checked]:preset-filled-success-500">
113
+
<Switch.Thumb />
114
+
</Switch.Control>
115
+
<Switch.Label>Auto-refresh ({AUTO_REFRESH_INTERVAL}s)</Switch.Label>
116
+
<Switch.HiddenInput />
117
+
</Switch>
118
+
<button type="button" class="btn btn-sm preset-tonal-primary" onclick={() => doCheck()} disabled={canRefresh}>Refresh</button>
95
119
</div>
96
120
</header>
97
121
···
125
149
{#if lastKnownBundle.number > 0}
126
150
<div>
127
151
<div class="font-semibold text-2xl animate-pulse">{lastKnownBundle.number + 1}</div>
128
-
<div>{formatNumber(lastKnownBundle.mempool)} / 10,000 <span class="opacity-50">({lastKnownBundle.mempoolPercent}%)</span></div>
152
+
<div>{formatNumber(lastKnownBundle.mempool)} / {formatNumber(BUNDLE_OPS)} <span class="opacity-50">({lastKnownBundle.mempoolPercent}%)</span></div>
129
153
{#if lastKnownBundle.etaNext}
130
154
<div class="mt-2 opacity-50">ETA: {formatDistanceToNow(lastKnownBundle.etaNext)}</div>
131
155
{/if}
···
165
189
</table>
166
190
167
191
<div class="mt-12 opacity-50">
168
-
Source: <a href="https://tangled.org/@tree.fail/plcbundle-watch">https://tangled.org/@tree.fail/plcbundle-watch</a>
192
+
<div>
193
+
Last updated: {formatISO9075(lastUpdated)}
194
+
</div>
195
+
<div class="mt-4">
196
+
Source: <a href="https://tangled.org/@tree.fail/plcbundle-watch">https://tangled.org/@tree.fail/plcbundle-watch</a>
197
+
</div>
169
198
</div>
170
199
</div>
171
200
</main>
+7
src/app.css
+7
src/app.css