Skip to content

Commit ddd40e6

Browse files
authored
dashboard (#4558)
2 parents 05b5016 + f2dba8c commit ddd40e6

File tree

93 files changed

+11083
-52
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+11083
-52
lines changed

app2/app2.nix

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ _: {
2525
PUBLIC_GIT_REV = gitShortRev;
2626
PUBLIC_LAST_MODIFIED_DATE = lastModifiedDate;
2727
PUBLIC_LAST_MODIFIED_EPOCH = lastModified;
28+
VITE_SUPABASE_URL = "https://api.dashboard.union.build";
29+
VITE_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVvcnF6cHVyeXJnZm5lY2FkYWpvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzQzNzM0NDAsImV4cCI6MjA0OTk0OTQ0MH0.4xkWpfMkYgBz4nqUGkZVjQNP7NxLa4filDoJRCI3yWo";
2830
in
2931
{
3032
packages = {
@@ -35,7 +37,7 @@ _: {
3537
../typescript-sdk
3638
../ts-sdk
3739
];
38-
hash = "sha256-/yUTYjfNJ2FQPTXC52zu9oK+R4ooWSonGOUEnhxkbEI=";
40+
hash = "sha256-X2AOEDq4wK51jPuKYqOSmrDAsGY1Dc+MQZvaEnCkiZk=";
3941
buildInputs = deps;
4042
nativeBuildInputs = buildInputs;
4143
pnpmWorkspaces = [
@@ -45,10 +47,13 @@ _: {
4547
];
4648
buildPhase = ''
4749
runHook preBuild
50+
4851
export PUBLIC_DATADOG_CLIENT_TOKEN="${PUBLIC_DATADOG_CLIENT_TOKEN}"
4952
export PUBLIC_GIT_REV="${PUBLIC_GIT_REV}"
5053
export PUBLIC_LAST_MODIFIED_DATE="${PUBLIC_LAST_MODIFIED_DATE}"
5154
export PUBLIC_LAST_MODIFIED_EPOCH="${PUBLIC_LAST_MODIFIED_EPOCH}"
55+
export VITE_SUPABASE_URL="${VITE_SUPABASE_URL}"
56+
export VITE_SUPABASE_ANON_KEY="${VITE_SUPABASE_ANON_KEY}"
5257
pnpm --filter=app2 prepare
5358
pnpm --filter=app2 build
5459
runHook postBuild
@@ -78,6 +83,8 @@ _: {
7883
export PUBLIC_GIT_REV="${PUBLIC_GIT_REV}"
7984
export PUBLIC_LAST_MODIFIED_DATE="${PUBLIC_LAST_MODIFIED_DATE}"
8085
export PUBLIC_LAST_MODIFIED_EPOCH="${PUBLIC_LAST_MODIFIED_EPOCH}"
86+
export VITE_SUPABASE_URL="${VITE_SUPABASE_URL}"
87+
export VITE_SUPABASE_ANON_KEY="${VITE_SUPABASE_ANON_KEY}"
8188
pnpm install
8289
pnpm run dev -- --host
8390
'';

app2/package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
1313
"lint": "eslint .",
1414
"test:watch": "vitest",
15-
"test": "vitest --run"
15+
"test": "vitest --run",
16+
"supabase:generate": "supabase gen types --lang='typescript' --project-id='uorqzpuryrgfnecadajo' > './src/lib/dashboard/database.types.ts'"
1617
},
1718
"devDependencies": {
1819
"@aptos-labs/ts-sdk": "1.38.0",
@@ -31,6 +32,7 @@
3132
"@safe-global/safe-apps-sdk": "^9.1.0",
3233
"@safe-global/safe-gateway-typescript-sdk": "^3.23.1",
3334
"@scure/base": "^1.2.4",
35+
"@supabase/supabase-js": "^2.49.4",
3436
"@sveltejs/adapter-static": "^3.0.8",
3537
"@sveltejs/kit": "^2.20.7",
3638
"@sveltejs/vite-plugin-svelte": "^5.0.3",
@@ -51,11 +53,18 @@
5153
"graphql": "^16.10.0",
5254
"graphql-request": "^7.1.2",
5355
"happy-dom": "^17.4.4",
56+
"ox": "^0.6.9",
57+
"rehype-rewrite": "^4.0.2",
58+
"rehype-stringify": "^10.0.1",
59+
"remark-parse": "^11.0.0",
60+
"remark-rehype": "^11.1.2",
5461
"svelte": "^5.27.1",
5562
"svelte-check": "^4.1.6",
5663
"tailwind-merge": "^3.2.0",
5764
"tailwindcss": "^4.1.4",
5865
"typescript-eslint": "^8.30.1",
66+
"unified": "^11.0.5",
67+
"vfile": "^6.0.3",
5968
"viem": "^2.27.2",
6069
"vite": "^6.3.1"
6170
}

app2/src/app.d.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ interface AptosWindow {
1616

1717
declare global {
1818
namespace App {
19-
// If we use +page/layout.ts for data
20-
// interface PageData {}
19+
// interface Locals {
20+
// session: Option.Option<Session>
21+
// }
22+
// interface PageData {
23+
// session: Option.Option<Session>
24+
// }
2125
}
2226

2327
interface Window extends AptosWindow, KeplrWindow, LeapWindow, Browser {

app2/src/app.html

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,49 @@
1-
<!doctype html>
2-
<html lang="en" class="dark dark:bg-zinc-950 dark:text-white">
1+
<!DOCTYPE html>
2+
<html
3+
lang="en"
4+
class="dark dark:bg-zinc-950 dark:text-white"
5+
>
6+
<head>
7+
<meta charset="utf-8" />
38

4-
<head>
5-
<meta charset="utf-8" />
9+
<link
10+
rel="icon"
11+
type="image/png"
12+
href="%sveltekit.assets%/favicon-96x96.png"
13+
sizes="96x96"
14+
/>
15+
<link
16+
rel="icon"
17+
type="image/svg+xml"
18+
href="%sveltekit.assets%/favicon.svg"
19+
/>
20+
<link
21+
rel="shortcut icon"
22+
href="%sveltekit.assets%/favicon.ico"
23+
/>
24+
<link
25+
rel="apple-touch-icon"
26+
sizes="180x180"
27+
href="%sveltekit.assets%/apple-touch-icon.png"
28+
/>
29+
<meta
30+
name="apple-mobile-web-app-title"
31+
content="Union"
32+
/>
33+
<link
34+
rel="manifest"
35+
href="%sveltekit.assets%/manifest.json"
36+
/>
637

7-
<link rel="icon" type="image/png" href="%sveltekit.assets%/favicon-96x96.png" sizes="96x96" />
8-
<link rel="icon" type="image/svg+xml" href="%sveltekit.assets%/favicon.svg" />
9-
<link rel="shortcut icon" href="%sveltekit.assets%/favicon.ico" />
10-
<link rel="apple-touch-icon" sizes="180x180" href="%sveltekit.assets%/apple-touch-icon.png" />
11-
<meta name="apple-mobile-web-app-title" content="Union" />
12-
<link rel="manifest" href="%sveltekit.assets%/manifest.json" />
13-
14-
<meta name="viewport" content="width=device-width, initial-scale=1" />
15-
%sveltekit.head%
16-
</head>
17-
18-
<body data-sveltekit-preload-data="hover">
19-
<div style="display: contents">%sveltekit.body%</div>
20-
</body>
21-
<div id="modal-container"></div>
38+
<meta
39+
name="viewport"
40+
content="width=device-width, initial-scale=1"
41+
/>
42+
%sveltekit.head%
43+
</head>
2244

45+
<body data-sveltekit-preload-data="hover">
46+
<div style="display: contents">%sveltekit.body%</div>
47+
</body>
48+
<div id="modal-container"></div>
2349
</html>

app2/src/hooks.client.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { browser } from "$app/environment"
12
import { runSync } from "$lib/runtime.js"
23
import { type ClientInit } from "@sveltejs/kit"
3-
import { Data, Effect, identity, Match } from "effect"
4+
import type { Handle } from "@sveltejs/kit"
5+
import { Data, Effect, identity, Match, Option, pipe } from "effect"
46
import { isString } from "effect/Predicate"
57

68
class UncaughtError extends Data.TaggedError("UncaughtError")<{
@@ -49,3 +51,28 @@ export const init: ClientInit = async () => {
4951
event.preventDefault()
5052
}
5153
}
54+
55+
const PROTECTED_PATHS = ["/dashboard"]
56+
57+
export const handle: Handle = async ({ event, resolve }) => {
58+
const dashboard = await import("$lib/dashboard/stores/user.svelte").then(x => x.dashboard)
59+
if (browser && PROTECTED_PATHS.some(path => event.url.pathname.startsWith(path))) {
60+
return Effect.runPromise(
61+
pipe(
62+
Effect.succeed(dashboard.session),
63+
Effect.flatMap(session =>
64+
Option.isNone(session)
65+
? Effect.succeed(
66+
new Response("Redirect", {
67+
status: 302,
68+
headers: { Location: "/" },
69+
}),
70+
)
71+
: Effect.succeed(resolve(event))
72+
),
73+
),
74+
)
75+
}
76+
77+
return resolve(event)
78+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<svg
2+
xmlns="http://www.w3.org/2000/svg"
3+
width="1em"
4+
height="1em"
5+
viewBox="0 0 24 24"
6+
{...$$props}
7+
>
8+
<path
9+
fill="currentColor"
10+
d="M3 21V3h18v18zm2-2h14V5H5z"
11+
/>
12+
</svg>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<svg
2+
xmlns="http://www.w3.org/2000/svg"
3+
width="1em"
4+
height="1em"
5+
viewBox="0 0 24 24"
6+
{...$$props}
7+
>
8+
<path
9+
fill="currentColor"
10+
d="m10.6 16.2l7.05-7.05l-1.4-1.4l-5.65 5.65l-2.85-2.85l-1.4 1.4zM3 21V3h18v18z"
11+
/>
12+
</svg>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!-- material-symbols:upcoming !-->
2+
<svg
3+
xmlns="http://www.w3.org/2000/svg"
4+
width="1em"
5+
height="1em"
6+
viewBox="0 0 24 24"
7+
{...$$props}
8+
>
9+
<path
10+
fill="currentColor"
11+
d="M17.6 10.81L16.19 9.4l3.56-3.55l1.41 1.41c-.11.03-3.56 3.55-3.56 3.55M13 3h-2v5h2zm6.28 2.11l-1.41-1.41l-3.56 3.55l1.41 1.41zM4.5 11.5h15v2h-15zM11 16.46v-3.96h2v3.96z"
12+
/>
13+
</svg>

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { page } from "$app/state"
33
import ExternalLinkIcon from "$lib/components/icons/ExternalLinkIcon.svelte"
44
import ConnectWalletButton from "$lib/components/ui/ConnectWalletButton.svelte"
5+
import ProfileCard from "$lib/dashboard/components/SideCard.svelte"
56
import { uiStore } from "$lib/stores/ui.svelte"
67
import { cn } from "$lib/utils"
78
import { onMount } from "svelte"
@@ -12,7 +13,6 @@ const isCurrentPath = (path: string) => {
1213
if (page.url.pathname === path) {
1314
return true
1415
}
15-
1616
// Check if current path is a subroute of the navigation item
1717
// For example, /explorer/packets/123 should highlight /explorer/packets
1818
if (path !== "/" && page.url.pathname.startsWith(`${path}/`)) {
@@ -32,12 +32,13 @@ const updateHighlightPosition = () => {
3232
3333
// Check all navigation items to find the best match
3434
const allNavItems = document.querySelectorAll("[data-path]")
35-
allNavItems.forEach(item => {
35+
allNavItems.forEach((item) => {
3636
const itemPath = item.getAttribute("data-path")
3737
if (
3838
itemPath
3939
&& (page.url.pathname === itemPath
40-
|| (page.url.pathname.startsWith(`${itemPath}/`) && itemPath.length > bestMatchLength))
40+
|| (page.url.pathname.startsWith(`${itemPath}/`)
41+
&& itemPath.length > bestMatchLength))
4142
) {
4243
bestMatch = item as HTMLElement
4344
bestMatchLength = itemPath.length
@@ -100,6 +101,7 @@ onMount(() => {
100101
{/key}
101102
</a>
102103
<div class="flex flex-col flex-1">
104+
<ProfileCard />
103105
{#each navigation as section}
104106
{#if section.title !== "Developer" || uiStore.showDeveloperPages}
105107
<section class="border-zinc-900 p-6 last:flex-1 flex flex-col justify-end">
@@ -145,7 +147,9 @@ onMount(() => {
145147
data-path={subroute.path}
146148
class={cn(
147149
"relative flex items-center gap-2 px-3 py-1 rounded-lg transition-colors",
148-
isCurrentPath(subroute.path) ? "" : "dark:hover:bg-zinc-900",
150+
isCurrentPath(subroute.path)
151+
? ""
152+
: "dark:hover:bg-zinc-900",
149153
)}
150154
>
151155
{subroute.title}

app2/src/lib/components/layout/Sidebar/navigation.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,6 @@ export const navigation: Array<NavSection> = [
119119
{
120120
title: "More Union",
121121
items: [
122-
{
123-
path: "https://dashboard.union.build",
124-
title: "Dashboard",
125-
icon: SharpDashboardIcon,
126-
external: true,
127-
},
128122
{
129123
path: "https://discord.union.build",
130124
title: "Discord",

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Button from "./Button.svelte"
1212
onclick={() => uiStore.openWalletModal()}
1313
>
1414
<SharpWalletIcon class="size-5" />
15-
My Wallets
15+
Connections
1616
<div class="flex items-center gap-1 ml-1 -mr-1">
1717
<div
1818
class="{Option.isSome(wallets.evmAddress) ? 'pulse-1 bg-green-500 shadow-[0_0_2px_1px_rgba(34,197,94,0.6)]' : 'bg-zinc-800'} w-2 h-2 rounded-full transition-colors duration-200"

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ const internalOnClose = () => {
8787
>
8888
{#if showCloseButton}
8989
<button
90-
class="cursor-pointer border-0 absolute top-2 right-4 text-white text-lg"
90+
class="cursor-pointer border-0 absolute top-2 right-4 text-white text-lg z-50"
9191
onclick={internalOnClose}
9292
>
9393
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<script lang="ts">
2+
import { onMount } from "svelte"
3+
4+
type Props = {
5+
progress: number
6+
}
7+
8+
let { progress = 0 }: Props = $props()
9+
10+
let isVisible = $state(false)
11+
12+
let progressBar: HTMLElement
13+
14+
$effect(() => {
15+
const observer = new IntersectionObserver(
16+
([entry]) => {
17+
if (entry.isIntersecting) {
18+
isVisible = true
19+
observer.unobserve(progressBar)
20+
}
21+
},
22+
{
23+
threshold: 0.1,
24+
rootMargin: "50px",
25+
},
26+
)
27+
28+
if (progressBar) {
29+
observer.observe(progressBar)
30+
}
31+
32+
return () => observer.disconnect()
33+
})
34+
</script>
35+
36+
<div
37+
class="w-full h-1 bg-zinc-800 overflow-hidden rounded-full"
38+
bind:this={progressBar}
39+
>
40+
<div
41+
class="h-full bg-accent transition-all duration-1000"
42+
class:opacity-0={!isVisible}
43+
class:opacity-100={isVisible}
44+
style="width: {isVisible ? progress + '%' : '0%'}"
45+
>
46+
</div>
47+
</div>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ type Props = {
1111
const { children, class: className = "" }: Props = $props()
1212
</script>
1313

14-
<div class="flex flex-col gap-4 p-4 md:gap-6 md:p-8 lg:px-16 xl:px-32 {className}">
14+
<div class="flex relative flex-col gap-4 p-4 md:gap-6 md:p-8 lg:px-16 xl:px-32 {className}">
1515
{@render children()}
1616
</div>

0 commit comments

Comments
 (0)