Skip to content

Commit e3f9fe8

Browse files
authored
App2 header and error center (#3980)
- **feat(app2): begin build of header** - **feat(app2): better error center** - **feat(app2): show page title** - **refactor(app2): use Option for pageName** - **fix(app2): cleanup legacy titles**
2 parents 12b4a15 + d71ca99 commit e3f9fe8

File tree

18 files changed

+114
-99
lines changed

18 files changed

+114
-99
lines changed
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<script lang="ts">
2+
import Modal from "./ui/Modal.svelte"
3+
import { settingsStore } from "$lib/stores/settings.svelte"
4+
import Button from "./ui/Button.svelte"
5+
import AppErrors from "$lib/components/layout/AppErrors/index.svelte"
6+
7+
type Props = {
8+
isOpen: boolean
9+
onClose: () => void
10+
}
11+
12+
const { isOpen, onClose }: Props = $props()
13+
</script>
14+
15+
<Modal {isOpen} {onClose} class="w-full max-w-4xl">
16+
<h2 class="text-xl font-bold mb-4">Errors</h2>
17+
<AppErrors/>
18+
19+
</Modal>

app2/src/lib/components/layout/AppErrors/index.svelte

+32-44
Original file line numberDiff line numberDiff line change
@@ -7,53 +7,41 @@ import Card from "$lib/components/ui/Card.svelte"
77
import Label from "$lib/components/ui/Label.svelte"
88
import { cn } from "$lib/utils"
99
10-
// Get all token errors from the store
11-
const tokenErrors = $derived(
12-
Array.from(tokensStore.error.entries())
13-
.filter(([_, error]) => Option.isSome(error))
14-
.map(([chainId, error]) => ({
15-
chainId,
16-
error: error.value
17-
}))
18-
)
19-
20-
const totalErrors = $derived((Option.isSome(chains.error) ? 1 : 0) + tokenErrors.length)
10+
import { totalErrorCount, tokenErrors } from "$lib/stores/app-errors.svelte"
2111
2212
let isExpanded = $state(false)
2313
</script>
2414

25-
{#if totalErrors > 0}
26-
<Card divided class="m-6 mb-0">
27-
<button
28-
class="w-full px-4 py-2 flex items-center justify-between"
29-
onclick={() => isExpanded = !isExpanded}
30-
>
31-
<span class="font-semibold text-red-500">
32-
{totalErrors} Error{totalErrors > 1 ? "s" : ""}
33-
</span>
34-
<span class={cn(
35-
"transition-transform text-red-500",
36-
isExpanded ? "rotate-180" : ""
37-
)}>
38-
39-
</span>
40-
</button>
15+
{#if totalErrorCount() > 0}
16+
<button
17+
class="w-full px-4 py-2 flex items-center justify-between"
18+
onclick={() => isExpanded = !isExpanded}
19+
>
20+
<span class="font-semibold text-red-500">
21+
{totalErrorCount()} Error{totalErrorCount() > 1 ? "s" : ""}
22+
</span>
23+
<span class={cn(
24+
"transition-transform text-red-500",
25+
isExpanded ? "rotate-180" : ""
26+
)}>
27+
28+
</span>
29+
</button>
4130

42-
{#if isExpanded}
43-
<div class="max-h-96 overflow-y-auto p-4 flex flex-col gap-4">
44-
{#if Option.isSome(chains.error)}
45-
<div>
46-
<Label>Chain Info Service</Label>
47-
<ErrorComponent error={chains.error.value}/>
48-
</div>
49-
{/if}
50-
{#each tokenErrors as { chainId, error }}
51-
<div>
52-
<Label class="mb-2">Token Info Fetcher for Chain {chainId}</Label>
53-
<ErrorComponent error={error}/>
54-
</div>
55-
{/each}
56-
</div>
57-
{/if}
58-
</Card>
31+
{#if isExpanded}
32+
<div class="max-h-96 overflow-y-auto p-4 flex flex-col gap-4">
33+
{#if Option.isSome(chains.error)}
34+
<div>
35+
<Label>Chain Info Service</Label>
36+
<ErrorComponent error={chains.error.value}/>
37+
</div>
38+
{/if}
39+
{#each tokenErrors as { chainId, error }}
40+
<div>
41+
<Label class="mb-2">Token Info Fetcher for Chain {chainId}</Label>
42+
<ErrorComponent error={error}/>
43+
</div>
44+
{/each}
45+
</div>
46+
{/if}
5947
{/if}

app2/src/lib/components/layout/Sidebar/index.svelte

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ onMount(() => {
5353

5454

5555
<div class="min-h-full flex flex-col overflow-y-auto">
56-
<div class="px-6 py-3 flex items-center">
56+
<div class="px-6 flex items-center border-b-1 h-16 border-zinc-900">
5757
<img class="h-10" src="/images/union-logo.svg" alt="Union" />
5858
</div>
5959
<div class="flex flex-col justify-between flex-1">
6060
{#each navigation as section}
61-
<section class="border-t-1 border-zinc-900 p-6">
61+
<section class="border-zinc-900 p-6">
6262
{#if section.title}
6363
<h2 class="font-bold text-sm -mt-8.5 mb-2.5 text-center uppercase text-zinc-600">{section.title}</h2>
6464
{/if}

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ const classes = cn(
3636
"focus-visible:ring-zinc-400"
3737
],
3838
variant === "danger" && [
39-
"bg-red-600 border-red-500 border text-white hover:bg-red-700",
40-
"dark:bg-red-600 dark:hover:bg-red-700",
39+
"bg-red-500 border-red-400 border text-white hover:bg-red-700",
4140
"focus-visible:ring-red-500"
4241
],
4342
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Option } from "effect"
2+
import { chains } from "$lib/stores/chains.svelte"
3+
import { tokensStore } from "$lib/stores/tokens.svelte"
4+
5+
// Get all token errors from the store
6+
const _tokenErrors = $derived(
7+
Array.from(tokensStore.error.entries())
8+
.filter(([_, error]) => Option.isSome(error))
9+
.map(([chainId, error]) => ({
10+
chainId,
11+
error: error.value // valid given prior filter
12+
}))
13+
)
14+
export const tokenErrors = () => _tokenErrors
15+
16+
const _totalErrorCount = $derived((Option.isSome(chains.error) ? 1 : 0) + _tokenErrors.length)
17+
18+
export const totalErrorCount = () => _totalErrorCount

app2/src/lib/stores/ui.svelte.ts

+12
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
class UiStore {
2+
// TODO: make Option<"wallet"|"settings"|"errors">
23
walletModalOpen: boolean = $state(false)
34
settingsModalOpen: boolean = $state(false)
5+
errorsModalOpen: boolean = $state(false)
46

57
private closeAllModals() {
68
this.walletModalOpen = false
79
this.settingsModalOpen = false
10+
this.errorsModalOpen = false
811
}
912

1013
openWalletModal() {
@@ -24,6 +27,15 @@ class UiStore {
2427
closeSettingsModal() {
2528
this.settingsModalOpen = false
2629
}
30+
31+
openErrorsModal() {
32+
this.errorsModalOpen = true
33+
}
34+
35+
closeErrorsModal() {
36+
this.closeAllModals()
37+
this.errorsModalOpen = false
38+
}
2739
}
2840

2941
export const uiStore = new UiStore()

app2/src/routes/+layout.svelte

+27-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ import { onMount } from "svelte"
44
import { Effect, Fiber, Option } from "effect"
55
import { chainsQuery } from "$lib/queries/chains.svelte"
66
import Sidebar from "$lib/components/layout/Sidebar/index.svelte"
7-
import AppErrors from "$lib/components/layout/AppErrors/index.svelte"
87
import { ENV } from "$lib/constants"
98
import { wallets } from "$lib/stores/wallets.svelte"
109
import Wallet from "$lib/components/ui/Wallet/index.svelte"
1110
import SettingsModal from "$lib/components/SettingsModal.svelte"
1211
import { uiStore } from "$lib/stores/ui.svelte"
12+
import ErrorsModal from "$lib/components/ErrorsModal.svelte"
13+
import Button from "$lib/components/ui/Button.svelte"
14+
import { totalErrorCount } from "$lib/stores/app-errors.svelte"
15+
import { page } from "$app/state"
16+
import { navigation } from "$lib/components/layout/Sidebar/navigation.ts"
1317
1418
let { children } = $props()
1519
@@ -37,6 +41,16 @@ $effect(() => {
3741
)
3842
)
3943
})
44+
45+
const pageName = $derived(
46+
Option.fromNullable(
47+
navigation.find(section => section.items.find(s => s.path === page.url.pathname))
48+
).pipe(
49+
Option.flatMap(s => Option.fromNullable(s.items.find(i => i.path === page.url.pathname))),
50+
Option.map(s => s.title),
51+
Option.getOrElse(() => page.url.pathname)
52+
)
53+
)
4054
</script>
4155

4256
<div class="grid grid-cols-[auto_1fr] min-h-[100svh] w-screen">
@@ -46,7 +60,14 @@ $effect(() => {
4660

4761
<!-- Main content area: Has margin to clear fixed sidebar -->
4862
<main class="col-start-2 ml-64 max-w-[calc(100vw-calc(var(--spacing)*64))]">
49-
<AppErrors/>
63+
<header class="flex justify-between items-center h-16 px-8 border-b-1 border-zinc-900">
64+
<h1 class="text-xl font-bold">{pageName}</h1>
65+
{#if totalErrorCount() > 0}
66+
<Button variant="danger" onclick={() => uiStore.openErrorsModal()}>
67+
{totalErrorCount()} Error{totalErrorCount() > 1 ? "s" : ""}
68+
</Button>
69+
{/if}
70+
</header>
5071
{@render children()}
5172
</main>
5273
</div>
@@ -55,3 +76,7 @@ $effect(() => {
5576
isOpen={uiStore.settingsModalOpen}
5677
onClose={() => uiStore.closeSettingsModal()}
5778
/>
79+
<ErrorsModal
80+
isOpen={uiStore.errorsModalOpen}
81+
onClose={() => uiStore.closeErrorsModal()}
82+
/>

app2/src/routes/balances/+page.svelte

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { RpcType, UniversalChainId } from "$lib/schema/chain"
1010
import TokenComponent from "$lib/components/model/TokenComponent.svelte"
1111
import { AddressEvmCanonical } from "$lib/schema/address"
1212
import ErrorComponent from "$lib/components/model/ErrorComponent.svelte"
13+
import Sections from "$lib/components/ui/Sections.svelte"
1314
1415
// Example wallet address - this would come from wallet connection in real app
1516
const testAddress = AddressEvmCanonical.make("0xe6831e169d77a861a0e71326afa6d80bcc8bc6aa")
@@ -50,9 +51,8 @@ $effect(() => {
5051
})
5152
</script>
5253

53-
<div class="flex flex-col gap-4 p-4">
54+
<Sections>
5455
<div class="flex justify-between items-center">
55-
<SectionTitle>Balances</SectionTitle>
5656
<Button onclick={fetchAllBalances}>Fetch All Balances</Button>
5757
</div>
5858

@@ -107,5 +107,5 @@ $effect(() => {
107107
</Card>
108108
{/each}
109109
{/if}
110-
</div>
110+
</Sections>
111111

-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
<script lang="ts">
2-
import SectionTitle from "$lib/components/ui/SectionTitle.svelte"
3-
import Sections from "$lib/components/ui/Sections.svelte"
4-
</script>
51

6-
<Sections>
7-
<SectionTitle>Dashboard</SectionTitle>
8-
</Sections>
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
<script lang="ts">
2-
import SectionTitle from "$lib/components/ui/SectionTitle.svelte"
3-
import Sections from "$lib/components/ui/Sections.svelte"
4-
</script>
51

6-
<Sections>
7-
<SectionTitle>Channels</SectionTitle>
8-
</Sections>
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
<script lang="ts">
2-
import SectionTitle from "$lib/components/ui/SectionTitle.svelte"
3-
import Sections from "$lib/components/ui/Sections.svelte"
4-
</script>
51

6-
<Sections>
7-
<SectionTitle>Clients</SectionTitle>
8-
</Sections>
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
<script lang="ts">
2-
import SectionTitle from "$lib/components/ui/SectionTitle.svelte"
3-
import Sections from "$lib/components/ui/Sections.svelte"
4-
</script>
51

6-
<Sections>
7-
<SectionTitle>Connections</SectionTitle>
8-
</Sections>
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
<script lang="ts">
2-
import SectionTitle from "$lib/components/ui/SectionTitle.svelte"
3-
import Sections from "$lib/components/ui/Sections.svelte"
4-
</script>
51

6-
<Sections>
7-
<SectionTitle>Packets</SectionTitle>
8-
</Sections>

app2/src/routes/explorer/transfers/+page.svelte

-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ const onNextPage = async () => {
6262
</script>
6363

6464
<Sections>
65-
<SectionTitle>Transfers</SectionTitle>
6665
<Card class="overflow-auto" divided>
6766
{#if Option.isSome(transferList.data) && Option.isSome(chains.data)}
6867
{@const chainss = chains.data.value}

app2/src/routes/stake/+page.svelte

-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
<script lang="ts">
2-
import SectionTitle from "$lib/components/ui/SectionTitle.svelte"
3-
import Sections from "$lib/components/ui/Sections.svelte"
4-
</script>
51

6-
<Sections>
7-
<SectionTitle>Stake with Escher</SectionTitle>
8-
</Sections>

app2/src/routes/transfer/+page.svelte

-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ async function submit() {
6262
</script>
6363

6464
<Sections>
65-
<SectionTitle>Transfer</SectionTitle>
6665
<Card>
6766
<pre class="text-sm text-zinc-300 whitespace-pre-wrap break-all">{JSON.stringify({
6867
source: rawIntents.source,

app2/src/routes/transfer/ucs03/+page.svelte

-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ const submit = async () => {
5454
</script>
5555

5656
<Sections>
57-
<SectionTitle>Transfer ucs03 evm</SectionTitle>
5857
<div class="flex flex-col gap-4">
5958
<div class="flex gap-4">
6059
<Button

app2/src/routes/transfers/+page.svelte

-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ const onNextPage = async () => {
101101

102102
<Sections>
103103
<section>
104-
<SectionTitle>Your Transfers</SectionTitle>
105104
<p class="flex gap-1 text-zinc-200">
106105
{#if Option.isSome(transferCount.data)}
107106
You made <span class="text-sky-400 font-bold">{transferCount.data.value.aggregate.count}</span> transfers so far.

0 commit comments

Comments
 (0)