WiP
This commit is contained in:
20
components.json
Normal file
20
components.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "default",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": false,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
}
|
||||
}
|
||||
@@ -24,10 +24,14 @@
|
||||
"@polkadot-api/substrate-bindings": "^0.9.3",
|
||||
"@polkadot-api/substrate-client": "^0.3.0",
|
||||
"@polkadot-api/utils": "^0.1.2",
|
||||
"@radix-ui/react-accordion": "^1.2.1",
|
||||
"@radix-ui/react-dialog": "^1.1.2",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-popover": "^1.1.2",
|
||||
"@radix-ui/react-radio-group": "^1.2.1",
|
||||
"@radix-ui/react-scroll-area": "^1.2.0",
|
||||
"@radix-ui/react-select": "^2.1.2",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@radix-ui/react-tabs": "^1.1.1",
|
||||
"@radix-ui/react-toggle": "^1.1.0",
|
||||
"@radix-ui/react-toggle-group": "^1.1.0",
|
||||
@@ -40,6 +44,7 @@
|
||||
"buffer": "^6.0.3",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "1.0.0",
|
||||
"lucide-react": "^0.454.0",
|
||||
"polkadot-api": "^1.7.0",
|
||||
"react": "^18.3.1",
|
||||
@@ -52,6 +57,7 @@
|
||||
"rxjs": "^7.8.1",
|
||||
"save-as": "^0.1.8",
|
||||
"tailwind-merge": "^2.5.4",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"uuid": "^11.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -12,11 +12,10 @@ import { createClient as createSubstrateClient } from "@polkadot-api/substrate-c
|
||||
import { toHex } from "@polkadot-api/utils"
|
||||
import { state } from "@react-rxjs/core"
|
||||
import { createClient, PolkadotClient } from "polkadot-api"
|
||||
import { chainSpec } from "polkadot-api/chains/westend2"
|
||||
import { withLogsRecorder } from "polkadot-api/logs-provider"
|
||||
import { withPolkadotSdkCompat } from "polkadot-api/polkadot-sdk-compat"
|
||||
import { getSmProvider } from "polkadot-api/sm-provider"
|
||||
import { Client } from "polkadot-api/smoldot"
|
||||
import { Chain, Client } from "polkadot-api/smoldot"
|
||||
import { startFromWorker } from "polkadot-api/smoldot/from-worker"
|
||||
import SmWorker from "polkadot-api/smoldot/worker?worker"
|
||||
import { getWsProvider } from "polkadot-api/ws-provider/web"
|
||||
@@ -26,11 +25,18 @@ import {
|
||||
from,
|
||||
map,
|
||||
NEVER,
|
||||
Observable,
|
||||
of,
|
||||
startWith,
|
||||
switchMap,
|
||||
tap,
|
||||
} from "rxjs"
|
||||
import polkadotRawNetworks from "./pages/Network/polkadot.json"
|
||||
import { createSignal } from "@react-rxjs/utils"
|
||||
import { chainSpec } from "polkadot-api/chains/polkadot"
|
||||
import { chainSpec as ksmChainSpec } from "polkadot-api/chains/ksmcc3"
|
||||
import { chainSpec as westendChainSpec } from "polkadot-api/chains/westend2"
|
||||
import { chainSpec as paseoChainSpec } from "polkadot-api/chains/paseo"
|
||||
|
||||
export type ChainSource = { id: string } & (
|
||||
| {
|
||||
@@ -46,11 +52,75 @@ export type ChainSource = { id: string } & (
|
||||
}
|
||||
)
|
||||
|
||||
const selectedSource$ = of<ChainSource>({
|
||||
id: "polkadot",
|
||||
type: "chainSpec",
|
||||
value: { chainSpec },
|
||||
export type Network = {
|
||||
id: string
|
||||
display: string
|
||||
endpoints: Record<string, string>
|
||||
lightclient: boolean
|
||||
}
|
||||
|
||||
export type NetworkCategory = {
|
||||
name: string
|
||||
networks: Network[]
|
||||
}
|
||||
export type SelectedChain = {
|
||||
network: Network
|
||||
endpoint: string
|
||||
}
|
||||
|
||||
const polkadot = polkadotRawNetworks.map(
|
||||
(x): Network => ({
|
||||
endpoints: x.rpcs as any,
|
||||
lightclient: x.hasChainSpecs,
|
||||
id: x.id,
|
||||
display: x.display,
|
||||
}),
|
||||
)
|
||||
|
||||
export const networkCategories: NetworkCategory[] = [
|
||||
{
|
||||
name: "Polkadot",
|
||||
networks: polkadot,
|
||||
},
|
||||
]
|
||||
|
||||
export const [selectedChainChanged$, onChangeChain] =
|
||||
createSignal<SelectedChain>()
|
||||
export const selectedChain$ = state<SelectedChain>(selectedChainChanged$, {
|
||||
network: polkadot[0],
|
||||
endpoint: "light-client",
|
||||
})
|
||||
selectedChain$.subscribe()
|
||||
|
||||
const relayChains = new Set(["polkadot", "kusama", "westend", "paseo"])
|
||||
const selectedSource$ = selectedChain$.pipe(
|
||||
switchMap(
|
||||
({ endpoint, network }): Observable<ChainSource> | Promise<ChainSource> => {
|
||||
if (endpoint !== "light-client")
|
||||
return of({
|
||||
type: "websocket",
|
||||
value: endpoint,
|
||||
} as ChainSource)
|
||||
const { id } = network
|
||||
if (relayChains.has(id)) {
|
||||
return of({
|
||||
type: "chainSpec",
|
||||
value: { chainSpec: id },
|
||||
} as ChainSource)
|
||||
}
|
||||
return import(`./chainspecs/${id}.ts`).then(({ chainSpec }) => {
|
||||
const parsed = JSON.parse(chainSpec)
|
||||
return {
|
||||
type: "chainSpec",
|
||||
value: {
|
||||
chainSpec,
|
||||
relayChain: parsed.relayChain || parsed.relay_chain,
|
||||
},
|
||||
} as ChainSource
|
||||
})
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
type AnyMetadata = CodecType<typeof metadataCodec>
|
||||
|
||||
@@ -119,31 +189,48 @@ async function getMetadata(client: PolkadotClient): Promise<AnyMetadata> {
|
||||
return decAnyMetadata(metadataResponse.asBytes())
|
||||
}
|
||||
|
||||
let smoldot: Client | null = null
|
||||
export function getProvider(source: ChainSource) {
|
||||
let smoldot: {
|
||||
client: Client
|
||||
relayChains: Record<string, Promise<Chain>>
|
||||
} | null = null
|
||||
function getProvider(source: ChainSource) {
|
||||
if (source.type === "websocket") {
|
||||
return withPolkadotSdkCompat(getWsProvider(source.value))
|
||||
}
|
||||
|
||||
if (!smoldot) {
|
||||
smoldot = startFromWorker(new SmWorker(), {
|
||||
const client = startFromWorker(new SmWorker(), {
|
||||
logCallback: (level, target, message) => {
|
||||
console.debug("[%s(%s)] %s", target, level, message)
|
||||
},
|
||||
})
|
||||
smoldot = {
|
||||
client,
|
||||
relayChains: {
|
||||
polkadot: client.addChain({
|
||||
chainSpec: chainSpec,
|
||||
}),
|
||||
kusama: client.addChain({
|
||||
chainSpec: ksmChainSpec,
|
||||
}),
|
||||
westend: client.addChain({
|
||||
chainSpec: westendChainSpec,
|
||||
}),
|
||||
paseo: client.addChain({
|
||||
chainSpec: paseoChainSpec,
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
const chain = source.value.relayChain
|
||||
? smoldot
|
||||
.addChain({
|
||||
chainSpec: source.value.relayChain,
|
||||
? smoldot.relayChains[source.value.relayChain].then((chain) => {
|
||||
return smoldot!.client.addChain({
|
||||
chainSpec: source.value.chainSpec,
|
||||
potentialRelayChains: [chain],
|
||||
})
|
||||
.then((chain) =>
|
||||
smoldot!.addChain({
|
||||
chainSpec: source.value.chainSpec,
|
||||
potentialRelayChains: [chain],
|
||||
}),
|
||||
)
|
||||
: smoldot.addChain({
|
||||
})
|
||||
: smoldot.relayChains[source.value.chainSpec] ||
|
||||
smoldot.client.addChain({
|
||||
chainSpec: source.value.chainSpec,
|
||||
})
|
||||
|
||||
|
||||
30
src/chainspecs/acala.ts
Normal file
30
src/chainspecs/acala.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
export const chainSpec = JSON.stringify({
|
||||
name: "Acala",
|
||||
id: "acala",
|
||||
chainType: "Live",
|
||||
bootNodes: [
|
||||
"/dns/acala-bootnode-4.aca-api.network/tcp/30333/p2p/12D3KooWBLwm4oKY5fsbkdSdipHzYJJHSHhuoyb1eTrH31cidrnY",
|
||||
"/dns/acala-bootnode-4.aca-api.network/tcp/30334/ws/p2p/12D3KooWBLwm4oKY5fsbkdSdipHzYJJHSHhuoyb1eTrH31cidrnY",
|
||||
"/dns/acala-bootnode-5.aca-api.network/tcp/80/ws/p2p/12D3KooWN6ZZ2LFSJo2vDci3hqmmcvqMcKJAbREvuYCdvoBvV2D4",
|
||||
"/dns/acala-bootnode-5.aca-api.network/tcp/443/wss/p2p/12D3KooWN6ZZ2LFSJo2vDci3hqmmcvqMcKJAbREvuYCdvoBvV2D4",
|
||||
"/dns/acala-bootnode-6.aca-api.network/tcp/80/ws/p2p/12D3KooWEBniruZHpoVj8RUtAFPahaN8UaGP6UtQb5Bdp4MVYbLc",
|
||||
"/dns/acala-bootnode-6.aca-api.network/tcp/443/wss/p2p/12D3KooWEBniruZHpoVj8RUtAFPahaN8UaGP6UtQb5Bdp4MVYbLc",
|
||||
"/dns/acala-bootnode-7.aca-api.network/tcp/80/ws/p2p/12D3KooWMq7AtHFx3ZboMT92HQw8BvhZFzJh8UrPCZeMB3yFLe1V",
|
||||
],
|
||||
properties: {
|
||||
ss58Format: 10,
|
||||
tokenDecimals: [12, 12, 10, 10],
|
||||
tokenSymbol: ["ACA", "AUSD", "DOT", "LDOT"],
|
||||
},
|
||||
relayChain: "polkadot",
|
||||
paraId: 2000,
|
||||
consensusEngine: null,
|
||||
codeSubstitutes: {},
|
||||
badBlocks: [
|
||||
"0xa820d0e6b3babb3a7023a229cfe61c32ceb68602f5339e2d416d7fbca5e82aa7",
|
||||
],
|
||||
genesis: {
|
||||
stateRootHash:
|
||||
"0x010c5745a5d42bcfbe0a644d5a2a4e22e2ff0fd378d48208ecfacea5b7e05a74",
|
||||
},
|
||||
})
|
||||
28
src/chainspecs/ajuna.ts
Normal file
28
src/chainspecs/ajuna.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
export const chainSpec = JSON.stringify({
|
||||
name: "Ajuna Polkadot",
|
||||
id: "ajuna_polkadot",
|
||||
chainType: "Live",
|
||||
bootNodes: [
|
||||
"/dns4/boot-node.helikon.io/tcp/8510/p2p/12D3KooWA1zjoSfN1CWRMY4nRxD94sSnNAj8UkhD7tsh4K6rwYSX",
|
||||
"/dns4/boot-node.helikon.io/tcp/8512/wss/p2p/12D3KooWA1zjoSfN1CWRMY4nRxD94sSnNAj8UkhD7tsh4K6rwYSX",
|
||||
"/dns4/node-7135141363928633344-0.p2p.onfinality.io/tcp/20256/ws/p2p/12D3KooWS8wVu6hmDwZvqDXJWnBX5sKb9edR1HWv5hYKD1Ysc2ud",
|
||||
"/dns4/node-7163299142418038784-0.p2p.onfinality.io/tcp/20806/ws/p2p/12D3KooWKNTJ5zQr3SK2DphVxEzbBWW9wSqd64ruad1uiiZd6E1Y",
|
||||
"/dns/ajuna.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWRyAHbMPNL7CuQtm987a6iLKftME3eQpVqBC6fUsjWuof",
|
||||
"/dns/ajuna.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWLXSQdRNS5EXuhpFYiRKHufRsQtb64t4CYj2ah7zx86jA",
|
||||
"/dns/rpc-para.ajuna.network/tcp/30332/p2p/12D3KooWLFfa4J2T3JGZft74q3Wu6kSYHPJHNzLsVhdLPGbAZ9Wf",
|
||||
"/dns/rpc-para.ajuna.network/tcp/30333/ws/p2p/12D3KooWLFfa4J2T3JGZft74q3Wu6kSYHPJHNzLsVhdLPGbAZ9Wf",
|
||||
"/dns/ajuna-polkadot-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWAPXggzmvxX8pefwGMNXDzUwigHEKCmrwZzMpySJbYwUK",
|
||||
"/dns/ajuna-polkadot-boot-ng.dwellir.com/tcp/30363/p2p/12D3KooWAPXggzmvxX8pefwGMNXDzUwigHEKCmrwZzMpySJbYwUK",
|
||||
"/dns/ajuna-polkadot-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWAPXggzmvxX8pefwGMNXDzUwigHEKCmrwZzMpySJbYwUK",
|
||||
"/dns/ajuna-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWCfjWNEmYcGJwF8S1xizhSHyFHwwDLmQxQCr2Wu9JUTYw",
|
||||
"/dns/ajuna-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWCfjWNEmYcGJwF8S1xizhSHyFHwwDLmQxQCr2Wu9JUTYw",
|
||||
],
|
||||
properties: { ss58Format: 1328, tokenDecimals: 12, tokenSymbol: "AJUN" },
|
||||
relay_chain: "polkadot",
|
||||
para_id: 2051,
|
||||
codeSubstitutes: {},
|
||||
genesis: {
|
||||
stateRootHash:
|
||||
"0x6e666a1df855628a99876f9f876b94d6d20a397fb1b5d92a3747df75e29c61b1",
|
||||
},
|
||||
})
|
||||
24
src/chainspecs/astar.ts
Normal file
24
src/chainspecs/astar.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
export const chainSpec = JSON.stringify({
|
||||
name: "Astar",
|
||||
id: "astar",
|
||||
chainType: "Live",
|
||||
bootNodes: [
|
||||
"/ip4/109.238.14.102/tcp/30333/ws/p2p/12D3KooWPH9bkXRkPcHGKd7DSgYfLLVE1Cw7QNr2M4kKwdVwGZXN",
|
||||
"/ip4/199.85.208.179/tcp/30333/ws/p2p/12D3KooWMwrAXhSuzCrtiwfVQuB4oLAZj3CLxVzMrqBJB4GKjnQa",
|
||||
"/ip4/131.153.79.50/tcp/30333/ws/p2p/12D3KooWB2XY9Uw1ZR8qtD5DQ4TKivJkQdqM5c6hyY9ixSDAASBa",
|
||||
"/dns/bootnode-01.astar.network/tcp/443/wss/p2p/12D3KooWPH9bkXRkPcHGKd7DSgYfLLVE1Cw7QNr2M4kKwdVwGZXN",
|
||||
"/dns/bootnode-02.astar.network/tcp/443/wss/p2p/12D3KooWMwrAXhSuzCrtiwfVQuB4oLAZj3CLxVzMrqBJB4GKjnQa",
|
||||
"/dns/bootnode-03.astar.network/tcp/443/wss/p2p/12D3KooWB2XY9Uw1ZR8qtD5DQ4TKivJkQdqM5c6hyY9ixSDAASBa",
|
||||
"/dns4/astar-bootnode-1-tls.p2p.onfinality.io/tcp/443/wss/p2p/12D3KooWERrQFE8ss7zYfcHp8ULVCc1N7gur7GqZ8ESuZB1Nmioh",
|
||||
],
|
||||
properties: { ss58Format: 5, tokenDecimals: 18, tokenSymbol: "ASTR" },
|
||||
relayChain: "polkadot",
|
||||
paraId: 2006,
|
||||
consensusEngine: null,
|
||||
codeSubstitutes: {},
|
||||
badBlocks: [],
|
||||
genesis: {
|
||||
stateRootHash:
|
||||
"0xc9451593261d67c47e14c5cbefeeffff5b5a1707cf81800becfc79e6df354da9",
|
||||
},
|
||||
})
|
||||
25
src/chainspecs/hydradx.ts
Normal file
25
src/chainspecs/hydradx.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export const chainSpec = JSON.stringify({
|
||||
name: "Hydration",
|
||||
id: "hydra",
|
||||
chainType: "Live",
|
||||
bootNodes: [
|
||||
"/dns/p2p-01.hydra.hydradx.io/tcp/30333/p2p/12D3KooWHzv7XVVBwY4EX1aKJBU6qzEjqGk6XtoFagr5wEXx6MsH",
|
||||
"/dns/p2p-02.hydra.hydradx.io/tcp/30333/p2p/12D3KooWR72FwHrkGNTNes6U5UHQezWLmrKu6b45MvcnRGK8J3S6",
|
||||
"/dns/p2p-03.hydra.hydradx.io/tcp/30333/p2p/12D3KooWFDwxZinAjgmLVgsideCmdB2bz911YgiQdLEiwKovezUz",
|
||||
"/dns4/boot.helikon.io/tcp/15120/p2p/12D3KooWDcQY1L2ny3F7YPyP4snCZZYc4eKWgPLEzdBvWBUjH5Yt",
|
||||
"/dns4/boot.helikon.io/tcp/15125/wss/p2p/12D3KooWDcQY1L2ny3F7YPyP4snCZZYc4eKWgPLEzdBvWBUjH5Yt",
|
||||
"/dns/hydration.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWGZaDfqPyzVxhA3k1qv72P7xqYTJS8W9U7GWUEdXYhtUU",
|
||||
"/dns/hydration.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWBJMG8LCh6pLYbGapA3SNzjhQWE87ieGux41jKQrrf5js",
|
||||
"/dns/hydration-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWCtrMH4H2p5XkGHkU7K4CcbSmErouNuN3j7Bysj4a8hJX",
|
||||
"/dns/hydration-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWCtrMH4H2p5XkGHkU7K4CcbSmErouNuN3j7Bysj4a8hJX",
|
||||
],
|
||||
properties: { tokenDecimals: 12, tokenSymbol: "HDX" },
|
||||
relay_chain: "polkadot",
|
||||
para_id: 2034,
|
||||
consensusEngine: null,
|
||||
codeSubstitutes: {},
|
||||
genesis: {
|
||||
stateRootHash:
|
||||
"0x33a542156b00e7dd467e2b7704563abd84f888ccbc6afd6f1a1802a55db1d4de",
|
||||
},
|
||||
})
|
||||
1
src/chainspecs/kusama.ts
Normal file
1
src/chainspecs/kusama.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { chainSpec } from "polkadot-api/chains/ksmcc3"
|
||||
1
src/chainspecs/polkadot.ts
Normal file
1
src/chainspecs/polkadot.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { chainSpec } from "polkadot-api/chains/polkadot"
|
||||
1
src/chainspecs/polkadot_asset_hub.ts
Normal file
1
src/chainspecs/polkadot_asset_hub.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { chainSpec } from "polkadot-api/chains/polkadot_asset_hub"
|
||||
1
src/chainspecs/polkadot_bridge_hub.ts
Normal file
1
src/chainspecs/polkadot_bridge_hub.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { chainSpec } from "polkadot-api/chains/polkadot_bridge_hub"
|
||||
1
src/chainspecs/polkadot_collectives.ts
Normal file
1
src/chainspecs/polkadot_collectives.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { chainSpec } from "polkadot-api/chains/polkadot_collectives"
|
||||
1
src/chainspecs/polkadot_people.ts
Normal file
1
src/chainspecs/polkadot_people.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { chainSpec } from "polkadot-api/chains/polkadot_people"
|
||||
56
src/components/ui/accordion.tsx
Normal file
56
src/components/ui/accordion.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import * as React from "react"
|
||||
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
||||
import { ChevronDown } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Accordion = AccordionPrimitive.Root
|
||||
|
||||
const AccordionItem = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AccordionPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn("border-b", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AccordionItem.displayName = "AccordionItem"
|
||||
|
||||
const AccordionTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<AccordionPrimitive.Header className="flex">
|
||||
<AccordionPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200" />
|
||||
</AccordionPrimitive.Trigger>
|
||||
</AccordionPrimitive.Header>
|
||||
))
|
||||
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
|
||||
|
||||
const AccordionContent = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<AccordionPrimitive.Content
|
||||
ref={ref}
|
||||
className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
||||
{...props}
|
||||
>
|
||||
<div className={cn("pb-4 pt-0", className)}>{children}</div>
|
||||
</AccordionPrimitive.Content>
|
||||
))
|
||||
|
||||
AccordionContent.displayName = AccordionPrimitive.Content.displayName
|
||||
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
||||
56
src/components/ui/button.tsx
Normal file
56
src/components/ui/button.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
icon: "h-10 w-10",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
|
||||
export { Button, buttonVariants }
|
||||
153
src/components/ui/command.tsx
Normal file
153
src/components/ui/command.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
import * as React from "react"
|
||||
import { type DialogProps } from "@radix-ui/react-dialog"
|
||||
import { Command as CommandPrimitive } from "cmdk"
|
||||
import { Search } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Command.displayName = CommandPrimitive.displayName
|
||||
|
||||
interface CommandDialogProps extends DialogProps {}
|
||||
|
||||
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0 shadow-lg">
|
||||
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
{children}
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||
|
||||
const CommandList = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandList.displayName = CommandPrimitive.List.displayName
|
||||
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||
>((props, ref) => (
|
||||
<CommandPrimitive.Empty
|
||||
ref={ref}
|
||||
className="py-6 text-center text-sm"
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||
|
||||
const CommandGroup = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||
|
||||
const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 h-px bg-border", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||
|
||||
const CommandItem = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||
|
||||
const CommandShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
CommandShortcut.displayName = "CommandShortcut"
|
||||
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as React from "react"
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||
import { cn } from "@/utils"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Dialog = DialogPrimitive.Root
|
||||
|
||||
@@ -18,7 +20,7 @@ const DialogOverlay = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -34,12 +36,16 @@ const DialogContent = React.forwardRef<
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background bg-polkadot-900 p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className,
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
))
|
||||
@@ -52,7 +58,7 @@ const DialogHeader = ({
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -66,7 +72,7 @@ const DialogFooter = ({
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -81,7 +87,7 @@ const DialogTitle = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
42
src/components/ui/radio-group.tsx
Normal file
42
src/components/ui/radio-group.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import * as React from "react"
|
||||
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
||||
import { Circle } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const RadioGroup = React.forwardRef<
|
||||
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<RadioGroupPrimitive.Root
|
||||
className={cn("grid gap-2", className)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
|
||||
|
||||
const RadioGroupItem = React.forwardRef<
|
||||
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<RadioGroupPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
|
||||
<Circle className="h-2.5 w-2.5 fill-current text-current" />
|
||||
</RadioGroupPrimitive.Indicator>
|
||||
</RadioGroupPrimitive.Item>
|
||||
)
|
||||
})
|
||||
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
|
||||
|
||||
export { RadioGroup, RadioGroupItem }
|
||||
46
src/components/ui/scroll-area.tsx
Normal file
46
src/components/ui/scroll-area.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import * as React from "react"
|
||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const ScrollArea = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("relative overflow-hidden", className)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
))
|
||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
||||
|
||||
const ScrollBar = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
>(({ className, orientation = "vertical", ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
ref={ref}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"flex touch-none select-none transition-colors",
|
||||
orientation === "vertical" &&
|
||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
))
|
||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
||||
|
||||
export { ScrollArea, ScrollBar }
|
||||
@@ -2,8 +2,9 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
input, dialog {
|
||||
@apply bg-black
|
||||
input,
|
||||
dialog {
|
||||
@apply bg-black;
|
||||
}
|
||||
|
||||
:root {
|
||||
@@ -38,3 +39,66 @@ input, dialog {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 0% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 0 0% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 0 0% 3.9%;
|
||||
--primary: 0 0% 9%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 0 0% 96.1%;
|
||||
--secondary-foreground: 0 0% 9%;
|
||||
--muted: 0 0% 96.1%;
|
||||
--muted-foreground: 0 0% 45.1%;
|
||||
--accent: 0 0% 96.1%;
|
||||
--accent-foreground: 0 0% 9%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 89.8%;
|
||||
--input: 0 0% 89.8%;
|
||||
--ring: 0 0% 3.9%;
|
||||
--chart-1: 12 76% 61%;
|
||||
--chart-2: 173 58% 39%;
|
||||
--chart-3: 197 37% 24%;
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
.dark {
|
||||
--background: 0 0% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 0 0% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 0 0% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 0 0% 9%;
|
||||
--secondary: 0 0% 14.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 14.9%;
|
||||
--muted-foreground: 0 0% 63.9%;
|
||||
--accent: 0 0% 14.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 14.9%;
|
||||
--input: 0 0% 14.9%;
|
||||
--ring: 0 0% 83.1%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
}
|
||||
}
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
6
src/lib/utils.ts
Normal file
6
src/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
@@ -1,47 +1,55 @@
|
||||
import { Link } from "react-router-dom"
|
||||
import { NetworkSwitcher } from "./Network/Network"
|
||||
|
||||
export const Header = () => (
|
||||
<div className="flex p-4 pb-2 items-center flex-shrink-0">
|
||||
<div className="flex flex-1 items-center flex-row gap-2">
|
||||
<img className="w-14 min-w-14" src="/papi_logo-dark.svg" alt="papi-logo" />
|
||||
<h1 className="hidden lg:block poppins-regular text-xl">papi <span className="poppins-extralight">console</span></h1>
|
||||
<img
|
||||
className="w-14 min-w-14"
|
||||
src="/papi_logo-dark.svg"
|
||||
alt="papi-logo"
|
||||
/>
|
||||
<h1 className="hidden lg:block poppins-regular text-xl">
|
||||
papi <span className="poppins-extralight">console</span>
|
||||
</h1>
|
||||
</div>
|
||||
<NetworkSwitcher />
|
||||
<div className="flex flex-row items-center justify-end bg-polkadot-800 px-1 py-1 rounded-full">
|
||||
<Link
|
||||
to="/explorer"
|
||||
className="text-polkadot-300 cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
>
|
||||
Explorer
|
||||
</Link>
|
||||
<Link
|
||||
to="/metadata"
|
||||
className="text-polkadot-300 cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
>
|
||||
Metadata
|
||||
</Link>
|
||||
<Link
|
||||
to="/storage"
|
||||
className="text-polkadot-300 cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
>
|
||||
Storage
|
||||
</Link>
|
||||
<Link
|
||||
to="/extrinsics"
|
||||
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
>
|
||||
Extrinsics
|
||||
</Link>
|
||||
<Link
|
||||
to="/constants"
|
||||
className="text-polkadot-300 cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
>
|
||||
Constants
|
||||
</Link>
|
||||
<Link
|
||||
to="/runtimeCalls"
|
||||
className="text-polkadot-300 cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
>
|
||||
Runtime Calls
|
||||
</Link>
|
||||
<Link
|
||||
to="/extrinsics"
|
||||
className="text-polkadot-300 cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
to="/metadata"
|
||||
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
|
||||
>
|
||||
Extrinsics
|
||||
Metadata
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
151
src/pages/Network/Network.tsx
Normal file
151
src/pages/Network/Network.tsx
Normal file
@@ -0,0 +1,151 @@
|
||||
import { useState } from "react"
|
||||
import { Check, ChevronDown } from "lucide-react"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "@/components/ui/command"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog"
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
||||
import { ScrollArea } from "@/components/ui/scroll-area"
|
||||
import { useStateObservable } from "@react-rxjs/core"
|
||||
import {
|
||||
Network,
|
||||
networkCategories,
|
||||
onChangeChain,
|
||||
selectedChain$,
|
||||
} from "@/chain.state"
|
||||
|
||||
export function NetworkSwitcher() {
|
||||
const [open, setOpen] = useState(false)
|
||||
const selectedChain = useStateObservable(selectedChain$)
|
||||
const [selectedNetwork, setSelectedNetwork] = useState<Network>(
|
||||
selectedChain.network,
|
||||
)
|
||||
const [selectedRpc, setSelecteRpc] = useState<string>(
|
||||
selectedChain.endpoint ?? "light-client",
|
||||
)
|
||||
|
||||
const handleNetworkSelect = (network: Network) => {
|
||||
setSelectedNetwork(network)
|
||||
setSelecteRpc(
|
||||
network.lightclient
|
||||
? "light-client"
|
||||
: Object.values(network.endpoints)[0],
|
||||
)
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
setOpen(false)
|
||||
onChangeChain({
|
||||
network: selectedNetwork,
|
||||
endpoint: selectedRpc,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" className="w-[200px] justify-between">
|
||||
{selectedNetwork.display}
|
||||
<ChevronDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Switch Network</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Command className="rounded-lg border shadow-md">
|
||||
<CommandInput placeholder="Search networks..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No networks found.</CommandEmpty>
|
||||
<ScrollArea className="h-[260px]">
|
||||
{networkCategories.map((category) => (
|
||||
<CommandGroup key={category.name} heading={category.name}>
|
||||
{category.networks.map((network) => (
|
||||
<CommandItem
|
||||
key={network.id}
|
||||
onSelect={() => handleNetworkSelect(network)}
|
||||
>
|
||||
<Check
|
||||
className={`mr-2 h-4 w-4 ${
|
||||
selectedNetwork.id === network.id
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
}`}
|
||||
/>
|
||||
{network.display}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
))}
|
||||
</ScrollArea>
|
||||
</CommandList>
|
||||
</Command>
|
||||
{selectedNetwork && (
|
||||
<Accordion type="single" collapsible className="w-full -mt-3">
|
||||
<AccordionItem value="connection-options">
|
||||
<AccordionTrigger>Connection Options</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<ScrollArea className="h-[155px] rounded-lg border p-2">
|
||||
<RadioGroup>
|
||||
{selectedNetwork.lightclient ? (
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem
|
||||
value="light-client"
|
||||
id="light-client"
|
||||
checked={selectedRpc === "light-client"}
|
||||
onClick={() => setSelecteRpc("light-client")}
|
||||
/>
|
||||
<Label htmlFor="light-client">
|
||||
Light Client (smoldot)
|
||||
</Label>
|
||||
</div>
|
||||
) : null}
|
||||
{Object.entries(selectedNetwork.endpoints).map(
|
||||
([rpcName, url]) => (
|
||||
<div key={url} className="flex items-center space-x-2">
|
||||
<RadioGroupItem
|
||||
value={url}
|
||||
id={url}
|
||||
checked={selectedRpc === url}
|
||||
onClick={() => setSelecteRpc(url)}
|
||||
/>
|
||||
<Label htmlFor={url}>{rpcName}</Label>
|
||||
</div>
|
||||
),
|
||||
)}
|
||||
</RadioGroup>
|
||||
</ScrollArea>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
)}
|
||||
<Button
|
||||
onClick={handleConfirm}
|
||||
disabled={!selectedNetwork || selectedRpc == null}
|
||||
>
|
||||
Confirm Selection
|
||||
</Button>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
1
src/pages/Network/index.ts
Normal file
1
src/pages/Network/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./Network"
|
||||
642
src/pages/Network/polkadot.json
Normal file
642
src/pages/Network/polkadot.json
Normal file
@@ -0,0 +1,642 @@
|
||||
[
|
||||
{
|
||||
"id": "polkadot",
|
||||
"display": "Polkadot Relay Chain",
|
||||
"hasChainSpecs": true,
|
||||
"rpcs": {
|
||||
"Allnodes": "wss://polkadot-rpc.publicnode.com",
|
||||
"Blockops": "wss://polkadot-public-rpc.blockops.network/ws",
|
||||
"Dwellir": "wss://polkadot-rpc.dwellir.com",
|
||||
"Dwellir Tunisia": "wss://polkadot-rpc-tn.dwellir.com",
|
||||
"IBP1": "wss://rpc.ibp.network/polkadot",
|
||||
"IBP2": "wss://polkadot.dotters.network",
|
||||
"LuckyFriday": "wss://rpc-polkadot.luckyfriday.io",
|
||||
"OnFinality": "wss://polkadot.api.onfinality.io/public-ws",
|
||||
"RadiumBlock": "wss://polkadot.public.curie.radiumblock.co/ws",
|
||||
"RockX": "wss://rockx-dot.w3node.com/polka-public-dot/ws",
|
||||
"Stakeworld": "wss://dot-rpc.stakeworld.io",
|
||||
"SubQuery": "wss://polkadot.rpc.subquery.network/public/ws"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "DOT",
|
||||
"decimals": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "polkadot_asset_hub",
|
||||
"display": "AssetHub",
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://asset-hub-polkadot-rpc.dwellir.com",
|
||||
"Dwellir Tunisia": "wss://statemint-rpc-tn.dwellir.com",
|
||||
"IBP1": "wss://sys.ibp.network/asset-hub-polkadot",
|
||||
"IBP2": "wss://asset-hub-polkadot.dotters.network",
|
||||
"LuckyFriday": "wss://rpc-asset-hub-polkadot.luckyfriday.io",
|
||||
"OnFinality": "wss://statemint.api.onfinality.io/public-ws",
|
||||
"Parity": "wss://polkadot-asset-hub-rpc.polkadot.io",
|
||||
"RadiumBlock": "wss://statemint.public.curie.radiumblock.co/ws",
|
||||
"Stakeworld": "wss://dot-rpc.stakeworld.io/assethub"
|
||||
},
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": true,
|
||||
"parachain": 1000
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "DOT",
|
||||
"decimals": 10
|
||||
},
|
||||
"hasChainSpecs": true
|
||||
},
|
||||
{
|
||||
"id": "polkadot_bridge_hub",
|
||||
"display": "BridgeHub",
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://bridge-hub-polkadot-rpc.dwellir.com",
|
||||
"Dwellir Tunisia": "wss://polkadot-bridge-hub-rpc-tn.dwellir.com",
|
||||
"IBP1": "wss://sys.ibp.network/bridgehub-polkadot",
|
||||
"IBP2": "wss://bridge-hub-polkadot.dotters.network",
|
||||
"LuckyFriday": "wss://rpc-bridge-hub-polkadot.luckyfriday.io",
|
||||
"OnFinality": "wss://bridgehub-polkadot.api.onfinality.io/public-ws",
|
||||
"Parity": "wss://polkadot-bridge-hub-rpc.polkadot.io",
|
||||
"RadiumBlock": "wss://bridgehub-polkadot.public.curie.radiumblock.co/ws",
|
||||
"Stakeworld": "wss://dot-rpc.stakeworld.io/bridgehub"
|
||||
},
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": true,
|
||||
"parachain": 1002
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "DOT",
|
||||
"decimals": 10
|
||||
},
|
||||
"hasChainSpecs": true
|
||||
},
|
||||
{
|
||||
"id": "polkadot_collectives",
|
||||
"display": "Collectives",
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://collectives-polkadot-rpc.dwellir.com",
|
||||
"Dwellir Tunisia": "wss://polkadot-collectives-rpc-tn.dwellir.com",
|
||||
"IBP1": "wss://sys.ibp.network/collectives-polkadot",
|
||||
"IBP2": "wss://collectives-polkadot.dotters.network",
|
||||
"LuckyFriday": "wss://rpc-collectives-polkadot.luckyfriday.io",
|
||||
"OnFinality": "wss://collectives.api.onfinality.io/public-ws",
|
||||
"Parity": "wss://polkadot-collectives-rpc.polkadot.io",
|
||||
"RadiumBlock": "wss://collectives.public.curie.radiumblock.co/ws",
|
||||
"Stakeworld": "wss://dot-rpc.stakeworld.io/collectives"
|
||||
},
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": true,
|
||||
"parachain": 1001
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "DOT",
|
||||
"decimals": 10
|
||||
},
|
||||
"hasChainSpecs": true
|
||||
},
|
||||
{
|
||||
"id": "polkadot_core_time",
|
||||
"display": "Coretime",
|
||||
"rpcs": {
|
||||
"IBP2": "wss://coretime-polkadot.dotters.network",
|
||||
"Parity": "wss://polkadot-coretime-rpc.polkadot.io"
|
||||
},
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": true,
|
||||
"parachain": 1005
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "DOT",
|
||||
"decimals": 10
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "polkadot_people",
|
||||
"display": "People",
|
||||
"rpcs": {
|
||||
"IBP1": "wss://sys.ibp.network/people-polkadot",
|
||||
"IBP2": "wss://people-polkadot.dotters.network",
|
||||
"LuckyFriday": "wss://rpc-people-polkadot.luckyfriday.io",
|
||||
"Parity": "wss://polkadot-people-rpc.polkadot.io",
|
||||
"RadiumBlock": "wss://people-polkadot.public.curie.radiumblock.co/ws"
|
||||
},
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": true,
|
||||
"parachain": 1004
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "DOT",
|
||||
"decimals": 10
|
||||
},
|
||||
"hasChainSpecs": true
|
||||
},
|
||||
{
|
||||
"id": "acala",
|
||||
"display": "Acala",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2000
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://acala-rpc.dwellir.com",
|
||||
"OnFinality": "wss://acala-polkadot.api.onfinality.io/public-ws"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "ACA",
|
||||
"decimals": 12
|
||||
},
|
||||
"hasChainSpecs": true
|
||||
},
|
||||
{
|
||||
"id": "ajuna",
|
||||
"display": "Ajuna Network",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2051
|
||||
},
|
||||
"rpcs": {
|
||||
"AjunaNetwork": "wss://rpc-para.ajuna.network",
|
||||
"IBP1": "wss://ajuna.ibp.network",
|
||||
"IBP2": "wss://ajuna.dotters.network",
|
||||
"OnFinality": "wss://ajuna.api.onfinality.io/public-ws",
|
||||
"RadiumBlock": "wss://ajuna.public.curie.radiumblock.co/ws"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "AJUN",
|
||||
"decimals": 12
|
||||
},
|
||||
"hasChainSpecs": true
|
||||
},
|
||||
{
|
||||
"id": "astar",
|
||||
"display": "Astar",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2006
|
||||
},
|
||||
"rpcs": {
|
||||
"Astar": "wss://rpc.astar.network",
|
||||
"Automata 1RPC": "wss://1rpc.io/astr",
|
||||
"Dwellir": "wss://astar-rpc.dwellir.com",
|
||||
"OnFinality": "wss://astar.api.onfinality.io/public-ws",
|
||||
"RadiumBlock": "wss://astar.public.curie.radiumblock.co/ws"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "ASTR",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": true
|
||||
},
|
||||
{
|
||||
"id": "bifrost",
|
||||
"display": "Bifrost",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2030
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://bifrost-polkadot-rpc.dwellir.com",
|
||||
"IBP1": "wss://bifrost-polkadot.ibp.network",
|
||||
"IBP2": "wss://bifrost-polkadot.dotters.network",
|
||||
"Liebi": "wss://hk.p.bifrost-rpc.liebi.com/ws",
|
||||
"LiebiEU": "wss://eu.bifrost-polkadot-rpc.liebi.com/ws",
|
||||
"RadiumBlock": "wss://bifrost.public.curie.radiumblock.co/ws"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "BNC",
|
||||
"decimals": 12
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "bitgreen",
|
||||
"display": "Bitgreen",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2048
|
||||
},
|
||||
"rpcs": {
|
||||
"Bitgreen": "wss://mainnet.bitgreen.org"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "BBB",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "centrifuge",
|
||||
"display": "Centrifuge",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2031
|
||||
},
|
||||
"rpcs": {
|
||||
"Centrifuge": "wss://fullnode.centrifuge.io",
|
||||
"Dwellir": "wss://centrifuge-rpc.dwellir.com",
|
||||
"LuckyFriday": "wss://rpc-centrifuge.luckyfriday.io",
|
||||
"OnFinality": "wss://centrifuge-parachain.api.onfinality.io/public-ws"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "CFG",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "crustParachain",
|
||||
"display": "Crust",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2008
|
||||
},
|
||||
"rpcs": {
|
||||
"Crust": "wss://crust-parachain.crustapps.net",
|
||||
"Crust APP": "wss://crust-parachain.crustnetwork.app",
|
||||
"Crust CC": "wss://crust-parachain.crustnetwork.cc",
|
||||
"Crust XYZ": "wss://crust-parachain.crustnetwork.xyz"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "CRU",
|
||||
"decimals": 12
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "darwinia",
|
||||
"display": "Darwinia",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2046
|
||||
},
|
||||
"rpcs": {
|
||||
"Darwinia": "wss://rpc.darwinia.network",
|
||||
"Dcdao": "wss://darwinia-rpc.dcdao.box",
|
||||
"Dwellir": "wss://darwinia-rpc.dwellir.com"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "RING",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "frequency",
|
||||
"display": "Frequency",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2091
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://frequency-rpc.dwellir.com",
|
||||
"Frequency 0": "wss://0.rpc.frequency.xyz",
|
||||
"Frequency 1": "wss://1.rpc.frequency.xyz",
|
||||
"OnFinality": "wss://frequency-polkadot.api.onfinality.io/public-ws"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "FRQCY",
|
||||
"decimals": 8
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "hydradx",
|
||||
"display": "Hydration",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2034
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://hydradx-rpc.dwellir.com",
|
||||
"Galactic Council": "wss://rpc.hydradx.cloud",
|
||||
"Helikon": "wss://rpc.helikon.io/hydradx",
|
||||
"IBP1": "wss://hydradx.paras.ibp.network",
|
||||
"IBP2": "wss://hydration.dotters.network"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "HDX",
|
||||
"decimals": 12
|
||||
},
|
||||
"hasChainSpecs": true
|
||||
},
|
||||
{
|
||||
"id": "hyperbridge",
|
||||
"display": "Hyperbridge (Nexus)",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 3367
|
||||
},
|
||||
"rpcs": {
|
||||
"BlockOps": "wss://hyperbridge-nexus-rpc.blockops.network",
|
||||
"IBP1": "wss://nexus.ibp.network",
|
||||
"IBP2": "wss://nexus.dotters.network"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "BRIDGE",
|
||||
"decimals": 12
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "integritee",
|
||||
"display": "Integritee Network",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 3359
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://integritee-rpc.dwellir.com",
|
||||
"Integritee": "wss://polkadot.api.integritee.network"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "TEER",
|
||||
"decimals": 12
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "kilt",
|
||||
"display": "KILT Spiritnet",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2086
|
||||
},
|
||||
"rpcs": {
|
||||
"BOTLabs": "wss://spiritnet.kilt.io/",
|
||||
"Dwellir": "wss://kilt-rpc.dwellir.com",
|
||||
"IBP1": "wss://kilt.ibp.network",
|
||||
"IBP2": "wss://kilt.dotters.network"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "KILT",
|
||||
"decimals": 15
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "laos",
|
||||
"display": "Laos",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 3370
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://laos-rpc.dwellir.com",
|
||||
"freeverse.io": "wss://rpc.laos.laosfoundation.io"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "LAOS",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "litentry",
|
||||
"display": "Litentry",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2013
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://litentry-rpc.dwellir.com",
|
||||
"Litentry": "wss://rpc.litentry-parachain.litentry.io"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "LIT",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "logion",
|
||||
"display": "Logion",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 3354
|
||||
},
|
||||
"rpcs": {
|
||||
"Logion 1": "wss://para-rpc01.logion.network"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "LGNT",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "manta",
|
||||
"display": "Manta",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2104
|
||||
},
|
||||
"rpcs": {
|
||||
"Manta Network": "wss://ws.manta.systems"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "MANTA",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "moonbeam",
|
||||
"display": "Moonbeam",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2004
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://moonbeam-rpc.dwellir.com",
|
||||
"IBP1": "wss://moonbeam.ibp.network",
|
||||
"IBP2": "wss://moonbeam.dotters.network",
|
||||
"Moonbeam Foundation": "wss://wss.api.moonbeam.network",
|
||||
"OnFinality": "wss://moonbeam.api.onfinality.io/public-ws",
|
||||
"RadiumBlock": "wss://moonbeam.public.curie.radiumblock.co/ws",
|
||||
"UnitedBloc": "wss://moonbeam.unitedbloc.com",
|
||||
"Allnodes": "wss://moonbeam-rpc.publicnode.com"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "GLMR",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "mythos",
|
||||
"display": "Mythos",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 3369
|
||||
},
|
||||
"rpcs": {
|
||||
"parity": "wss://polkadot-mythos-rpc.polkadot.io"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "MYTH",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "neuroweb",
|
||||
"display": "NeuroWeb",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2043
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://neuroweb-rpc.dwellir.com",
|
||||
"TraceLabs": "wss://parachain-rpc.origin-trail.network"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "NEURO",
|
||||
"decimals": 12
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "nodle",
|
||||
"display": "Nodle",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2026
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://nodle-rpc.dwellir.com",
|
||||
"OnFinality": "wss://nodle-parachain.api.onfinality.io/public-ws"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "NODL",
|
||||
"decimals": 11
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "pendulum",
|
||||
"display": "Pendulum",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2094
|
||||
},
|
||||
"rpcs": {
|
||||
"PendulumChain": "wss://rpc-pendulum.prd.pendulumchain.tech"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "PEN",
|
||||
"decimals": 12
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "phala",
|
||||
"display": "Phala Network",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2035
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://phala-rpc.dwellir.com",
|
||||
"Helikon": "wss://rpc.helikon.io/phala",
|
||||
"OnFinality": "wss://phala.api.onfinality.io/public-ws",
|
||||
"Phala": "wss://api.phala.network/ws",
|
||||
"RadiumBlock": "wss://phala.public.curie.radiumblock.co/ws"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "PHA",
|
||||
"decimals": 12
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "polimec",
|
||||
"display": "Polimec",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 3344
|
||||
},
|
||||
"rpcs": {
|
||||
"Amforc": "wss://polimec.rpc.amforc.com",
|
||||
"Helikon": "wss://rpc.helikon.io/polimec",
|
||||
"IBP1": "wss://polimec.ibp.network",
|
||||
"IBP2": "wss://polimec.dotters.network",
|
||||
"Polimec Foundation": "wss://rpc.polimec.org"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "PLMC",
|
||||
"decimals": 10
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "unique",
|
||||
"display": "Unique Network",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2037
|
||||
},
|
||||
"rpcs": {
|
||||
"Dwellir": "wss://unique-rpc.dwellir.com",
|
||||
"Geo Load Balancer": "wss://ws.unique.network",
|
||||
"IBP1": "wss://unique.ibp.network",
|
||||
"IBP2": "wss://unique.dotters.network",
|
||||
"Unique America": "wss://us-ws.unique.network",
|
||||
"Unique Asia": "wss://asia-ws.unique.network",
|
||||
"Unique Europe": "wss://eu-ws.unique.network"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "UNQ",
|
||||
"decimals": 18
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
},
|
||||
{
|
||||
"id": "zeitgeist",
|
||||
"display": "Zeitgeist",
|
||||
"relayChainInfo": {
|
||||
"id": "polkadot",
|
||||
"isSystem": false,
|
||||
"parachain": 2092
|
||||
},
|
||||
"rpcs": {
|
||||
"OnFinality": "wss://zeitgeist.api.onfinality.io/public-ws",
|
||||
"ZeitgeistPM": "wss://main.rpc.zeitgeist.pm/ws"
|
||||
},
|
||||
"nativeToken": {
|
||||
"symbol": "ZTG",
|
||||
"decimals": 10
|
||||
},
|
||||
"hasChainSpecs": false
|
||||
}
|
||||
]
|
||||
@@ -2,30 +2,99 @@
|
||||
* @type {import("tailwindcss").Config}
|
||||
*/
|
||||
export default {
|
||||
darkMode: ["class"],
|
||||
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
polkadot: {
|
||||
950: "#030110",
|
||||
900: "#0C052C",
|
||||
800: "#23126D",
|
||||
700: "#4027AE",
|
||||
650: "#6543EF",
|
||||
600: "#5E39F2",
|
||||
500: "#E6007A",
|
||||
400: "#FC76FF",
|
||||
300: "#DB9EFF",
|
||||
200: "#E4DAFF",
|
||||
100: "#F2F3FF",
|
||||
0: "#FBFCFF",
|
||||
100: "#F2F3FF",
|
||||
200: "#E4DAFF",
|
||||
300: "#DB9EFF",
|
||||
400: "#FC76FF",
|
||||
500: "#E6007A",
|
||||
600: "#5E39F2",
|
||||
650: "#6543EF",
|
||||
700: "#4027AE",
|
||||
800: "#23126D",
|
||||
900: "#0C052C",
|
||||
950: "#030110",
|
||||
},
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
card: {
|
||||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "hsl(var(--popover))",
|
||||
foreground: "hsl(var(--popover-foreground))",
|
||||
},
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive))",
|
||||
foreground: "hsl(var(--destructive-foreground))",
|
||||
},
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
chart: {
|
||||
1: "hsl(var(--chart-1))",
|
||||
2: "hsl(var(--chart-2))",
|
||||
3: "hsl(var(--chart-3))",
|
||||
4: "hsl(var(--chart-4))",
|
||||
5: "hsl(var(--chart-5))",
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
},
|
||||
keyframes: {
|
||||
"accordion-down": {
|
||||
from: {
|
||||
height: "0",
|
||||
},
|
||||
to: {
|
||||
height: "var(--radix-accordion-content-height)",
|
||||
},
|
||||
},
|
||||
"accordion-up": {
|
||||
from: {
|
||||
height: "var(--radix-accordion-content-height)",
|
||||
},
|
||||
to: {
|
||||
height: "0",
|
||||
},
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
function ({ addVariant }) {
|
||||
addVariant("group-state-open", ':merge(.group)[data-state="open"] &');
|
||||
addVariant("group-state-open", ':merge(.group)[data-state="open"] &')
|
||||
},
|
||||
require("tailwindcss-animate"),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
|
||||
@@ -3,5 +3,11 @@
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user