-
- All the best for your new project.
-
- Please make sure to read our
- Template Documentation
- to understand where to go from here and how to use our template.
-
-
+
+
+
+
+
+
+ Ping DashboardBeta
+
+
+
+
+ Ping Dashboard is not just an explorer but also a wallet and more ... đ
+
+
+ Cosmos Ecosystem Blockchains đ
+
+
+
+
+
+
+
+
+
diff --git a/packages/dashboard/src/plugins/vuetify/@core/scss/template/_variables.scss b/packages/dashboard/src/plugins/vuetify/@core/scss/template/_variables.scss
index 169b71c8..89c02888 100644
--- a/packages/dashboard/src/plugins/vuetify/@core/scss/template/_variables.scss
+++ b/packages/dashboard/src/plugins/vuetify/@core/scss/template/_variables.scss
@@ -22,11 +22,14 @@ $vertical-nav-horizontal-padding-start: utils.get-first-value($vertical-nav-hori
"default": (
"--v-theme-background": (
"light": (247,247,249),
- "dark": (40,42,66),
+ // "dark": (40,42,66),
+ "dark": (22, 29, 49)
),
"--v-theme-surface": (
"light": (255, 255, 255),
- "dark": (48,51,78),
+ "dark": (40,51,78),
+ // "dark": (48,51,78),
+ // "dark": #283046
),
),
"bordered": (
diff --git a/packages/dashboard/src/plugins/vuetify/@layouts/components/VerticalNav.vue b/packages/dashboard/src/plugins/vuetify/@layouts/components/VerticalNav.vue
index e0a3dff5..1b17aa06 100644
--- a/packages/dashboard/src/plugins/vuetify/@layouts/components/VerticalNav.vue
+++ b/packages/dashboard/src/plugins/vuetify/@layouts/components/VerticalNav.vue
@@ -41,6 +41,8 @@ const resolveNavItemComponent = (item: NavLink | NavSectionTitle | NavGroup) =>
return VerticalNavLink
}
+
+
/*
âšī¸ Close overlay side when route is changed
Close overlay vertical nav when link is clicked
diff --git a/packages/dashboard/src/plugins/vuetify/@layouts/components/VerticalNavGroup.vue b/packages/dashboard/src/plugins/vuetify/@layouts/components/VerticalNavGroup.vue
index a69c7d8b..8d9a42bb 100644
--- a/packages/dashboard/src/plugins/vuetify/@layouts/components/VerticalNavGroup.vue
+++ b/packages/dashboard/src/plugins/vuetify/@layouts/components/VerticalNavGroup.vue
@@ -39,7 +39,7 @@ const isVerticalNavHovered = inject(injectionKeyIsVerticalNavHovered, ref(false)
// })
const isGroupActive = ref(false)
-const isGroupOpen = ref(false)
+const isGroupOpen = ref(true)
/**
* Checks if any of children group is open or not.
@@ -77,7 +77,9 @@ watch(() => route.path, () => {
const isActive = isNavGroupActive(props.item.children, router)
// Don't open group if vertical nav is collapsed and window size is more than overlay nav breakpoint
- isGroupOpen.value = isActive && !isVerticalNavMini(windowWidth, isVerticalNavHovered).value
+ if(props.item.badgeContent) {
+ isGroupOpen.value = isActive && !isVerticalNavMini(windowWidth, isVerticalNavHovered).value
+ }
isGroupActive.value = isActive
}, { immediate: true })
@@ -135,7 +137,7 @@ watch(openGroups, val => {
if (isAnyChildOpen(props.item.children))
return
- isGroupOpen.value = isActive
+ // isGroupOpen.value = isActive
isGroupActive.value = isActive
}, { deep: true })
diff --git a/packages/dashboard/src/plugins/vuetify/@layouts/utils.ts b/packages/dashboard/src/plugins/vuetify/@layouts/utils.ts
index 35062785..c96d1e57 100644
--- a/packages/dashboard/src/plugins/vuetify/@layouts/utils.ts
+++ b/packages/dashboard/src/plugins/vuetify/@layouts/utils.ts
@@ -52,9 +52,10 @@ export const isNavLinkActive = (link: NavLink, router: Router) => {
if (!resolveRoutedName)
return false
- return matchedRoutes.some(route => {
- return route.name === resolveRoutedName || route.meta.navActiveLink === resolveRoutedName
- })
+ return false
+ // return matchedRoutes.some(route => {
+ // return route.name === resolveRoutedName || route.meta.navActiveLink === resolveRoutedName
+ // })
}
/**
diff --git a/packages/dashboard/src/router/index.ts b/packages/dashboard/src/router/index.ts
index 8f09a5d0..f8e75086 100644
--- a/packages/dashboard/src/router/index.ts
+++ b/packages/dashboard/src/router/index.ts
@@ -1,12 +1,25 @@
import { setupLayouts } from "virtual:generated-layouts";
import { createRouter, createWebHistory } from "vue-router";
+import { useDashboard } from "@/stores/useDashboard";
import routes from "~pages";
+// import { useDashboard } from "@/stores/useDashboard";
+// const dashboard = useDashboard()
+
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [...setupLayouts(routes)],
});
+//update current blockchain
+router.beforeEach((to) => {
+ const { chain } = to.params
+ if(chain){
+ const dashboard = useDashboard()
+ dashboard.setCurrentChain(chain.toString())
+ }
+})
+
// Docs: https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards
export default router;
\ No newline at end of file
diff --git a/packages/dashboard/src/stores/option.ts b/packages/dashboard/src/stores/option.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/dashboard/src/stores/useBlockchain.ts b/packages/dashboard/src/stores/useBlockchain.ts
new file mode 100644
index 00000000..c07bd0a4
--- /dev/null
+++ b/packages/dashboard/src/stores/useBlockchain.ts
@@ -0,0 +1,12 @@
+import { ref, computed } from "vue";
+import { defineStore } from "pinia";
+
+const route = useRoute()
+console.log('route', route)
+
+export const useBlockchain = defineStore("blockchain", () => {
+ const current = ref('');
+
+
+ return { current };
+});
diff --git a/packages/dashboard/src/stores/useDashboard.ts b/packages/dashboard/src/stores/useDashboard.ts
new file mode 100644
index 00000000..967c1e77
--- /dev/null
+++ b/packages/dashboard/src/stores/useDashboard.ts
@@ -0,0 +1,191 @@
+import { ref, computed } from "vue";
+import { defineStore } from "pinia";
+import { get } from '../libs/http'
+import type { Chain, Asset } from '@ping-pub/chain-registry-client/dist/types'
+import type { VerticalNavItems } from '@/@layouts/types'
+import ChainRegistryClient from '@ping-pub/chain-registry-client'
+
+export interface DirectoryChain {
+ assets: Asset[],
+ bech32_prefix: string,
+ best_apis: {
+ rest: {address: string, provider: string}[]
+ rpc: {address: string, provider: string}[]
+ },
+ chain_id: string,
+ chain_name: string,
+ pretty_name: string,
+ coingecko_id: string,
+ cosmwasm_enabled: boolean,
+ decimals: number,
+ denom: string,
+ display: string,
+ explorers: {
+ name?: string | undefined;
+ kind?: string | undefined;
+ url?: string | undefined;
+ tx_page?: string | undefined;
+ account_page?: string | undefined;
+ }[] | undefined,
+ height: number,
+ image: string,
+ name: string,
+ network_type: string,
+ symbol: string,
+ versions: {
+ application_version: string,
+ cosmos_sdk_version: string,
+ tendermint_version: string,
+ }
+}
+
+function pathConvert(path: string | undefined) {
+ if(path) {
+ path = path.replace('https://raw.githubusercontent.com/cosmos/chain-registry/master', 'https://registry.ping.pub')
+ }
+ return path
+}
+
+export function getLogo(conf: {
+ svg?: string,
+ png?: string,
+ jpeg?: string,
+} | undefined) {
+ if(conf) {
+ return pathConvert(conf.svg || conf.png || conf.jpeg)
+ }
+ return undefined
+}
+
+function createChainFromDirectory(source: DirectoryChain) : Chain {
+ const conf: Chain = {} as Chain;
+ conf.apis = source.best_apis
+ conf.bech32_prefix = source.bech32_prefix
+ conf.chain_id = source.chain_id
+ conf.chain_name = source.chain_name
+ conf.explorers = source.explorers
+ conf.pretty_name = source.pretty_name
+ if(source.versions) {
+ conf.codebase = {
+ recommended_version: source.versions.application_version,
+ cosmos_sdk_version: source.versions.cosmos_sdk_version,
+ tendermint_version: source.versions.tendermint_version,
+ }
+ }
+ if(source.image) {
+ conf.logo_URIs = {
+ svg: source.image
+ }
+ }
+
+ return conf
+}
+
+export enum LoadingStatus {
+ Empty,
+ Loading,
+ Loaded,
+}
+export enum ConfigSource {
+ MainnetCosmosDirectory = "https://chains.cosmos.directory",
+ TestnetCosmosDirectory = "https://chains.testcosmos.directory",
+ Local = './src/blockchain',
+}
+
+export const useDashboard = defineStore("dashboard", () => {
+ const status = ref(LoadingStatus.Empty)
+ // current blockchain for display
+ const source = ref(ConfigSource.MainnetCosmosDirectory)
+ const favorite = ref(JSON.parse(localStorage.getItem('favorite') || '["cosmoshub", "osmosis"]') as string[])
+ const current = ref(favorite.value[0])
+ const chains = ref({} as Record
);
+
+ const findChainByName = computed((name) => chains.value[name]);
+
+ const computeChainNav = computed(() => {
+ const currChain = chains.value[current.value]
+ let currNavItem: VerticalNavItems = []
+ if(currChain) {
+ currNavItem = [{
+ title: currChain.pretty_name || currChain.chain_name || current.value,
+ icon: {image: getLogo(currChain.logo_URIs), size: '22'},
+ children: [
+ {
+ title: 'Dashboard',
+ to: { path: `/${current.value}`},
+ icon: { icon: 'mdi-chevron-right', size: '22'}
+ }
+ ]
+ }]
+ }
+ const favNavItems: VerticalNavItems = []
+ favorite.value.forEach(name => {
+ const ch = chains.value[name]
+ if(ch) {
+ favNavItems.push({
+ title: ch.pretty_name || ch.chain_name || name,
+ to: { path: `/${ch.chain_name || name}`},
+ icon: {image: getLogo(ch.logo_URIs), size: '22'}
+ } )
+ }
+ })
+
+ return [...currNavItem,
+ { heading: 'Ecosystem' },
+ {
+ title: 'Favorite',
+ children: favNavItems,
+ badgeContent: favorite.value.length,
+ badgeClass: 'bg-success',
+ icon: { icon: 'mdi-star', size: '22'}
+ },
+ {
+ title: 'All Blockchains',
+ to: { path : '/'},
+ badgeContent: length.value,
+ badgeClass: 'bg-success',
+ icon: { icon: 'mdi-grid', size: '22'}
+ }
+ ]
+ })
+
+ const length = computed(()=> {
+ return Object.keys(chains.value).length
+ })
+ async function initial() {
+ await loadingFromRegistry()
+ }
+
+ async function loadingChainByName(name: string) {
+ // const chain = await client.fetchChainInfo(name)
+ // chains.value[name] = chain
+ }
+ function loadingFromRegistry() {
+ if(status.value === LoadingStatus.Empty) {
+ status.value = LoadingStatus.Loading
+ get(source.value).then((res)=> {
+ res.chains.forEach(( x: DirectoryChain ) => {
+ chains.value[x.chain_name] = createChainFromDirectory(x)
+ });
+ status.value = LoadingStatus.Loaded
+ })
+ }
+ }
+ function setCurrentChain(name: string) {
+ if(name && name !== current.value) {
+ current.value = name
+ }
+ }
+ function setConfigSource(newSource: ConfigSource) {
+ source.value = newSource
+ initial()
+ }
+ return {
+ // states
+ status, favorite, current, chains, length,
+ // getters
+ computeChainNav, findChainByName,
+ // actions
+ initial, loadingFromRegistry, loadingChainByName, setCurrentChain, setConfigSource
+ };
+});
diff --git a/packages/dashboard/themeConfig.ts b/packages/dashboard/themeConfig.ts
index 77437766..7b27eea7 100644
--- a/packages/dashboard/themeConfig.ts
+++ b/packages/dashboard/themeConfig.ts
@@ -1,6 +1,6 @@
import { breakpointsVuetify } from '@vueuse/core'
-import { VIcon } from 'vuetify/components'
+import { VAvatar } from 'vuetify/components'
// â Logo SVG must be imported with ?raw suffix
// import logo from '@/assets/logo.svg?raw'
@@ -24,7 +24,7 @@ export const { themeConfig, layoutConfig } = defineThemeConfig({
isRtl: false,
skin: Skins.Default,
routeTransition: RouteTransitions.Fade,
- iconRenderer: VIcon,
+ iconRenderer: VAvatar,
},
navbar: {
type: NavbarType.Sticky,
diff --git a/yarn.lock b/yarn.lock
index 3f224ef9..db32b879 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -243,6 +243,13 @@
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/plugin-syntax-typescript" "^7.20.0"
+"@babel/runtime@^7.19.4":
+ version "7.20.13"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.13.tgz#7055ab8a7cff2b8f6058bf6ae45ff84ad2aded4b"
+ integrity sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==
+ dependencies:
+ regenerator-runtime "^0.13.11"
+
"@babel/standalone@^7.20.12":
version "7.20.15"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.20.15.tgz#ef82f1a9789d21d8b23f74d9fa8acecbe6ced02c"
@@ -294,6 +301,13 @@
resolved "https://registry.yarnpkg.com/@casl/vue/-/vue-2.2.1.tgz#decb6966a982dabd41c26379692dfde2bf67793a"
integrity sha512-1OeGhT4A7VBkEACacF2ZlHkPiFJvyFy9h2PhBnMoetFDojMHbrn3ZjKgL5zQ4wSIrTQo9KbbzG3f0uAei2GKCQ==
+"@chain-registry/types@^0.14.0":
+ version "0.14.0"
+ resolved "https://registry.yarnpkg.com/@chain-registry/types/-/types-0.14.0.tgz#43ea04992adabdee2a0f03f8a519b01722ab354b"
+ integrity sha512-TlIqc3CijT734no7RiYBfUvCG2fory0blwrBcK4XTYOCi2vANsxfDdiPLFQcaSETYDd14DdjhrdXwMocEeOnLQ==
+ dependencies:
+ "@babel/runtime" "^7.19.4"
+
"@esbuild/android-arm64@0.16.17":
version "0.16.17"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23"
@@ -1546,6 +1560,14 @@
dependencies:
esquery "^1.0.1"
+"@ping-pub/chain-registry-client@^0.0.25":
+ version "0.0.25"
+ resolved "https://registry.yarnpkg.com/@ping-pub/chain-registry-client/-/chain-registry-client-0.0.25.tgz#fcb974bdc0ef40db26425d8bf5c382aafb884f44"
+ integrity sha512-33foemlTE5pDMhmRN2MhtIjW0/6f4x0kR5nNneocP1ycsTwv9RgEbsjq30TFmOTW8UC1AgoQupe+LKVYHYbyBA==
+ dependencies:
+ "@chain-registry/types" "^0.14.0"
+ cross-fetch "^3.1.5"
+
"@rollup/pluginutils@^5.0.2":
version "5.0.2"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33"
@@ -6238,6 +6260,11 @@ redent@^3.0.0:
indent-string "^4.0.0"
strip-indent "^3.0.0"
+regenerator-runtime@^0.13.11:
+ version "0.13.11"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
+ integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
+
regexp.prototype.flags@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"