Skip to content

Commit 63065bf

Browse files
authored
Better explorer, better tooltips (#4031)
All tooltips now link to external explorers, long mono data is shown in a better way. - **feat(app2): better conn/chann layout** - **fix(app2): packet sections** - **feat(app2): longmonoword** - **fix(app2): longmonoword** - **fix(app2): show raw packet data** - **feat(app): add transactioncomponent** - **feat(app2): show explorer urls in address popups** - **feat(app2): heightcomponent** - **fix(app2): use heightcomponent for timeoutheight** - **chore: fmt** - **fix(app2): better blockhash component** - **chore: fmt**
2 parents 343d41e + 7776294 commit 63065bf

File tree

11 files changed

+979
-42262
lines changed

11 files changed

+979
-42262
lines changed

app2/src/generated/graphql-env.d.ts

+524-42,150
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app2/src/lib/components/model/AddressComponent.svelte

+44-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Chain } from "$lib/schema/chain"
44
import type { AddressCanonicalBytes } from "$lib/schema/address"
55
import { cn } from "$lib/utils"
66
import Tooltip from "$lib/components/ui/Tooltip.svelte"
7-
import Truncate from "$lib/components/ui/Truncate.svelte"
7+
import LongMonoWord from "$lib/components/ui/LongMonoWord.svelte"
88
import { Effect, Option } from "effect"
99
1010
type Props = HTMLAttributes<HTMLDivElement> & {
@@ -16,13 +16,31 @@ type Props = HTMLAttributes<HTMLDivElement> & {
1616
const { address, chain, class: className = "", ...rest }: Props = $props()
1717
1818
const displayAddress = $derived(Effect.runSync(chain.getDisplayAddress(address)))
19+
20+
// Find the explorer URL for this address
21+
const getExplorerUrl = () => {
22+
if (chain.explorers.length === 0) {
23+
return null
24+
}
25+
26+
// Use the first explorer by default
27+
const explorer = chain.explorers[0]
28+
// Replace {address} placeholder if it exists, otherwise append the address
29+
const addressUrl = explorer.address_url.toString()
30+
return addressUrl.includes("{address}")
31+
? addressUrl.replace("{address}", displayAddress)
32+
: `${addressUrl}${displayAddress}`
33+
}
34+
35+
const explorerUrl = $derived(getExplorerUrl())
36+
const explorerName = $derived(chain.explorers.length > 0 ? chain.explorers[0].display_name : null)
1937
</script>
2038

2139
<Tooltip>
2240
{#snippet trigger()}
23-
<div class={cn("font-mono", className)} {...rest}>
24-
<Truncate value={displayAddress} maxLength={12} showCopy={false}/>
25-
</div>
41+
<LongMonoWord class={className} {...rest}>
42+
{displayAddress}
43+
</LongMonoWord>
2644
{/snippet}
2745

2846
{#snippet content()}
@@ -44,13 +62,33 @@ const displayAddress = $derived(Effect.runSync(chain.getDisplayAddress(address))
4462
<h3 class="text-white">Formats</h3>
4563
<div>
4664
<span class="text-white">Display:</span>
47-
<span class="font-mono">{displayAddress}</span>
65+
<LongMonoWord class="inline">
66+
{displayAddress}
67+
</LongMonoWord>
4868
</div>
4969
<div>
5070
<span class="text-white">Canonical:</span>
51-
<span class="font-mono">{address}</span>
71+
<LongMonoWord class="inline">
72+
{address}
73+
</LongMonoWord>
5274
</div>
5375
</section>
76+
77+
{#if explorerUrl}
78+
<section>
79+
<h3 class="text-white">Explorer</h3>
80+
<div>
81+
<a
82+
href={explorerUrl}
83+
class="text-sky-400 hover:text-sky-300 underline"
84+
target="_blank"
85+
rel="noopener noreferrer"
86+
>
87+
View on {explorerName || "Explorer"}
88+
</a>
89+
</div>
90+
</section>
91+
{/if}
5492
</div>
5593
{/snippet}
5694
</Tooltip>
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,80 @@
11
<script lang="ts">
2-
import Truncate from "$lib/components/ui/Truncate.svelte"
2+
import type { HTMLAttributes } from "svelte/elements"
3+
import type { Chain } from "$lib/schema/chain"
4+
import { cn } from "$lib/utils"
5+
import Tooltip from "$lib/components/ui/Tooltip.svelte"
6+
import LongMonoWord from "$lib/components/ui/LongMonoWord.svelte"
7+
import { Option } from "effect"
38
4-
interface Props {
9+
type Props = HTMLAttributes<HTMLDivElement> & {
510
hash: string
11+
chain: Chain
12+
class?: string
613
}
714
8-
const { hash }: Props = $props()
15+
const { hash, chain, class: className = "", ...rest }: Props = $props()
16+
17+
// Find the explorer URL for this block hash
18+
const getExplorerUrl = () => {
19+
if (chain.explorers.length === 0) {
20+
return null
21+
}
22+
23+
// Use the first explorer by default
24+
const explorer = chain.explorers[0]
25+
// Replace {hash} placeholder if it exists, otherwise append the hash
26+
const blockUrl = explorer.block_url.toString()
27+
return blockUrl.includes("{hash}") ? blockUrl.replace("{hash}", hash) : `${blockUrl}${hash}`
28+
}
29+
30+
const explorerUrl = $derived(getExplorerUrl())
31+
const explorerName = $derived(chain.explorers.length > 0 ? chain.explorers[0].display_name : null)
932
</script>
1033

11-
<div class="font-mono text-sm break-all rounded">
12-
<Truncate value={hash} maxLength={12} />
13-
</div>
34+
<Tooltip>
35+
{#snippet trigger()}
36+
<LongMonoWord class={className} {...rest}>
37+
{hash}
38+
</LongMonoWord>
39+
{/snippet}
40+
41+
{#snippet content()}
42+
<div class="text-sm flex flex-col gap-4 text-neutral-400">
43+
<section class="flex justify-between items-center">
44+
<h2 class="text-white font-bold text-lg">Block Details</h2>
45+
<div class="bg-sky-400 text-black font-bold rounded px-1">
46+
{chain.rpc_type.toUpperCase()}
47+
</div>
48+
</section>
49+
50+
<section>
51+
<h3 class="text-white">Chain</h3>
52+
<div>{chain.display_name}</div>
53+
<div class="text-xs">{chain.universal_chain_id}</div>
54+
</section>
55+
56+
<section>
57+
<h3 class="text-white">Block Hash</h3>
58+
<LongMonoWord>
59+
{hash}
60+
</LongMonoWord>
61+
</section>
62+
63+
{#if explorerUrl}
64+
<section>
65+
<h3 class="text-white">Explorer</h3>
66+
<div>
67+
<a
68+
href={explorerUrl}
69+
class="text-sky-400 hover:text-sky-300 underline"
70+
target="_blank"
71+
rel="noopener noreferrer"
72+
>
73+
View on {explorerName || "Explorer"}
74+
</a>
75+
</div>
76+
</section>
77+
{/if}
78+
</div>
79+
{/snippet}
80+
</Tooltip>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<script lang="ts">
2+
import type { HTMLAttributes } from "svelte/elements"
3+
import type { Chain } from "$lib/schema/chain"
4+
import type { Height } from "$lib/schema/height"
5+
import { cn } from "$lib/utils"
6+
import Tooltip from "$lib/components/ui/Tooltip.svelte"
7+
import LongMonoWord from "$lib/components/ui/LongMonoWord.svelte"
8+
import { Option } from "effect"
9+
10+
type Props = HTMLAttributes<HTMLDivElement> & {
11+
height: Height
12+
chain: Chain
13+
class?: string
14+
}
15+
16+
const { height, chain, class: className = "", ...rest }: Props = $props()
17+
18+
// Find the explorer URL for this block height
19+
const getExplorerUrl = () => {
20+
if (chain.explorers.length === 0) {
21+
return null
22+
}
23+
24+
// Use the first explorer by default
25+
const explorer = chain.explorers[0]
26+
// Replace {block} placeholder if it exists, otherwise append the height
27+
const blockUrl = explorer.block_url.toString()
28+
return blockUrl.includes("{block}")
29+
? blockUrl.replace("{block}", height.toString())
30+
: `${blockUrl}${height}`
31+
}
32+
33+
const explorerUrl = $derived(getExplorerUrl())
34+
const explorerName = $derived(chain.explorers.length > 0 ? chain.explorers[0].display_name : null)
35+
</script>
36+
37+
<Tooltip>
38+
{#snippet trigger()}
39+
<LongMonoWord class={className} {...rest}>
40+
{height}
41+
</LongMonoWord>
42+
{/snippet}
43+
44+
{#snippet content()}
45+
<div class="text-sm flex flex-col gap-4 text-neutral-400">
46+
<section class="flex justify-between items-center">
47+
<h2 class="text-white font-bold text-lg">Block Details</h2>
48+
<div class="bg-sky-400 text-black font-bold rounded px-1">
49+
{chain.rpc_type.toUpperCase()}
50+
</div>
51+
</section>
52+
53+
<section>
54+
<h3 class="text-white">Chain</h3>
55+
<div>{chain.display_name}</div>
56+
<div class="text-xs">{chain.universal_chain_id}</div>
57+
</section>
58+
59+
<section>
60+
<h3 class="text-white">Block Height</h3>
61+
<LongMonoWord>
62+
{height}
63+
</LongMonoWord>
64+
</section>
65+
66+
{#if explorerUrl}
67+
<section>
68+
<h3 class="text-white">Explorer</h3>
69+
<div>
70+
<a
71+
href={explorerUrl}
72+
class="text-sky-400 hover:text-sky-300 underline"
73+
target="_blank"
74+
rel="noopener noreferrer"
75+
>
76+
View on {explorerName || "Explorer"}
77+
</a>
78+
</div>
79+
</section>
80+
{/if}
81+
</div>
82+
{/snippet}
83+
</Tooltip>

app2/src/lib/components/model/PacketListItemComponent.svelte

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import ChainComponent from "./ChainComponent.svelte"
77
import DateTimeComponent from "$lib/components/ui/DateTimeComponent.svelte"
88
import { goto } from "$app/navigation"
99
import SharpRightArrowIcon from "../icons/SharpRightArrowIcon.svelte"
10+
import LongMonoWord from "../ui/LongMonoWord.svelte"
1011
1112
type Props = {
1213
packet: PacketListItem
@@ -36,9 +37,9 @@ const handleClick = () => {
3637
onclick={handleClick}
3738
>
3839
<div>
39-
<div class="font-mono">
40+
<LongMonoWord>
4041
{packet.packet_hash}
41-
</div>
42+
</LongMonoWord>
4243
<div class="flex items-center gap-1 text-zinc-400 text-sm">
4344
{#if Option.isSome(sourceChain)}
4445
<ChainComponent chain={sourceChain.value} />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<script lang="ts">
2+
import type { HTMLAttributes } from "svelte/elements"
3+
import type { Chain } from "$lib/schema/chain"
4+
import type { TransactionHash } from "$lib/schema/transaction"
5+
import Tooltip from "$lib/components/ui/Tooltip.svelte"
6+
import LongMonoWord from "$lib/components/ui/LongMonoWord.svelte"
7+
8+
type Props = HTMLAttributes<HTMLDivElement> & {
9+
hash: TransactionHash
10+
chain: Chain
11+
class?: string
12+
}
13+
14+
const { hash, chain, class: className = "", ...rest }: Props = $props()
15+
16+
// Find the explorer URL for this transaction
17+
const getExplorerUrl = () => {
18+
if (chain.explorers.length === 0) {
19+
return null
20+
}
21+
22+
// Use the first explorer by default
23+
const explorer = chain.explorers[0]
24+
// Replace {txHash} placeholder if it exists, otherwise append the hash
25+
const txUrl = explorer.tx_url.toString()
26+
return txUrl.includes("{txHash}") ? txUrl.replace("{txHash}", hash) : `${txUrl}${hash}`
27+
}
28+
29+
const explorerUrl = $derived(getExplorerUrl())
30+
const explorerName = $derived(chain.explorers.length > 0 ? chain.explorers[0].display_name : null)
31+
</script>
32+
33+
<Tooltip>
34+
{#snippet trigger()}
35+
<LongMonoWord class={className} {...rest}>
36+
{hash}
37+
</LongMonoWord>
38+
{/snippet}
39+
40+
{#snippet content()}
41+
<div class="text-sm flex flex-col gap-4 text-neutral-400">
42+
<section class="flex justify-between items-center">
43+
<h2 class="text-white font-bold text-lg">Transaction Details</h2>
44+
<div class="bg-sky-400 text-black font-bold rounded px-1">
45+
{chain.rpc_type.toUpperCase()}
46+
</div>
47+
</section>
48+
49+
<section>
50+
<h3 class="text-white">Chain</h3>
51+
<div>{chain.display_name}</div>
52+
<div class="text-xs">{chain.universal_chain_id}</div>
53+
</section>
54+
55+
<section>
56+
<h3 class="text-white">Transaction Hash</h3>
57+
<LongMonoWord>
58+
{hash}
59+
</LongMonoWord>
60+
</section>
61+
62+
{#if explorerUrl}
63+
<section>
64+
<h3 class="text-white">Explorer</h3>
65+
<div>
66+
<a
67+
href={explorerUrl}
68+
class="text-sky-400 hover:text-sky-300 underline"
69+
target="_blank"
70+
rel="noopener noreferrer"
71+
>
72+
View on {explorerName || "Explorer"}
73+
</a>
74+
</div>
75+
</section>
76+
{/if}
77+
</div>
78+
{/snippet}
79+
</Tooltip>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script lang="ts">
2+
import type { HTMLAttributes } from "svelte/elements"
3+
import type { Snippet } from "svelte"
4+
import { cn } from "$lib/utils"
5+
6+
type Props = HTMLAttributes<HTMLDivElement> & {
7+
children: Snippet
8+
class?: string
9+
}
10+
11+
const { children, class: className = "", ...rest }: Props = $props()
12+
</script>
13+
14+
<div class={cn("text-sm font-mono break-all", className)} {...rest}>
15+
{@render children()}
16+
</div>

app2/src/lib/components/ui/Tooltip.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ function onTriggerEnter(e: MouseEvent) {
5858
if (isHoveringTrigger) {
5959
isVisible = true
6060
}
61-
}, 1000)
61+
}, 750)
6262
}
6363
6464
function onTriggerLeave() {

0 commit comments

Comments
 (0)