383 lines
12 KiB
Vue
383 lines
12 KiB
Vue
<script lang="ts" setup>
|
|
import MdEditor from 'md-editor-v3';
|
|
import PriceMarketChart from '@/components/charts/PriceMarketChart.vue';
|
|
|
|
import { Icon } from '@iconify/vue';
|
|
import {
|
|
useBlockchain,
|
|
useFormatter,
|
|
useTxDialog,
|
|
useWalletStore,
|
|
useStakingStore,
|
|
} from '@/stores';
|
|
import { onMounted, ref } from 'vue';
|
|
import { useIndexModule } from './indexStore';
|
|
import { computed } from '@vue/reactivity';
|
|
|
|
import CardStatisticsVertical from '@/components/CardStatisticsVertical.vue';
|
|
import ProposalListItem from '@/components/ProposalListItem.vue';
|
|
|
|
const blockchain = useBlockchain();
|
|
const store = useIndexModule();
|
|
const walletStore = useWalletStore();
|
|
const format = useFormatter();
|
|
const dialog = useTxDialog();
|
|
const stakingStore = useStakingStore();
|
|
|
|
const coinInfo = computed(() => {
|
|
return store.coinInfo;
|
|
});
|
|
|
|
onMounted(() => {
|
|
store.loadDashboard();
|
|
walletStore.loadMyAsset();
|
|
});
|
|
|
|
const ticker = computed(() => store.coinInfo.tickers[store.tickerIndex]);
|
|
|
|
blockchain.$subscribe((m, s) => {
|
|
if (
|
|
!Array.isArray(m.events) &&
|
|
['chainName', 'endpoint'].includes(m.events.key)
|
|
) {
|
|
store.loadDashboard();
|
|
walletStore.loadMyAsset();
|
|
}
|
|
});
|
|
function shortName(name: string, id: string) {
|
|
return name.toLowerCase().startsWith('ibc/') ||
|
|
name.toLowerCase().startsWith('0x')
|
|
? id
|
|
: name;
|
|
}
|
|
|
|
const comLinks = [
|
|
{
|
|
name: 'Website',
|
|
icon: 'mdi-web',
|
|
href: store.homepage,
|
|
},
|
|
{
|
|
name: 'Twitter',
|
|
icon: 'mdi-twitter',
|
|
href: store.twitter,
|
|
},
|
|
{
|
|
name: 'Telegram',
|
|
icon: 'mdi-telegram',
|
|
href: store.telegram,
|
|
},
|
|
{
|
|
name: 'Github',
|
|
icon: 'mdi-github',
|
|
href: store.github,
|
|
},
|
|
];
|
|
|
|
// wallet box
|
|
const change = computed(() => {
|
|
const token = walletStore.balanceOfStakingToken;
|
|
return token ? format.priceChanges(token.denom) : 0;
|
|
});
|
|
const color = computed(() => {
|
|
switch (true) {
|
|
case change.value > 0:
|
|
return 'text-green-600';
|
|
case change.value === 0:
|
|
return 'text-grey-500';
|
|
case change.value < 0:
|
|
return 'text-red-600';
|
|
}
|
|
});
|
|
const endpoint = 'https://juno-api.polkachu.com';
|
|
const params = JSON.stringify({
|
|
proposal_id: '1',
|
|
validator_address: 'junovaloper1jxv0u20scum4trha72c7ltfgfqef6nscm9pmg2',
|
|
chain_name: 'juno',
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<div
|
|
v-if="coinInfo && coinInfo.name"
|
|
class="bg-base-100 rounded shadow mb-4"
|
|
>
|
|
<div class="flex p-4">
|
|
<div class="">
|
|
<div class="text-xl font-semibold text-main">
|
|
{{ coinInfo.name }} (<span class="uppercase">{{
|
|
coinInfo.symbol
|
|
}}</span
|
|
>)
|
|
</div>
|
|
<div class="text-xs mt-2">
|
|
Rank:
|
|
<div
|
|
class="badge text-xs badge-error bg-[#fcebea] dark:bg-[#41384d] text-red-400"
|
|
>
|
|
#{{ coinInfo.market_cap_rank }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 flex items-center">
|
|
<a
|
|
v-for="(item, index) of comLinks"
|
|
:key="index"
|
|
:href="item.href"
|
|
class="link link-primary px-2 py-1 rounded-sm no-underline hover:text-primary hover:bg-gray-100 dark:hover:bg-slate-800 flex items-center"
|
|
>
|
|
<Icon :icon="item?.icon" />
|
|
<span class="ml-1 text-sm uppercase">{{ item?.name }}</span>
|
|
</a>
|
|
</div>
|
|
|
|
<div>
|
|
<div
|
|
class="dropdown dropdown-hover w-full md:w-[400px] mt-[16px] md:mt-[36px]"
|
|
>
|
|
<label>
|
|
<div
|
|
class="bg-gray-100 dark:bg-[#384059] flex items-center justify-between px-4 py-2 cursor-pointer rounded"
|
|
>
|
|
<div>
|
|
<div
|
|
class="font-semibold text-xl text-[#666] dark:text-white"
|
|
>
|
|
{{ ticker?.market?.name || '' }}
|
|
</div>
|
|
<div class="text-info text-sm">
|
|
{{ shortName(ticker?.base, ticker.coin_id) }}/{{
|
|
shortName(ticker?.target, ticker.target_coin_id)
|
|
}}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-right">
|
|
<div
|
|
class="text-xl font-semibold text-[#666] dark:text-white"
|
|
>
|
|
${{ ticker.converted_last.usd }}
|
|
</div>
|
|
<div class="text-sm" :class="store.priceColor">
|
|
{{ store.priceChange }}%
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
<div class="dropdown-content pt-1">
|
|
<div
|
|
class="h-64 overflow-auto w-full md:w-[400px] shadow rounded"
|
|
>
|
|
<ul class="menu w-full bg-gray-100 rounded dark:bg-[#384059]">
|
|
<li
|
|
v-for="(item, index) in store.coinInfo.tickers"
|
|
:key="index"
|
|
@click="store.selectTicker(index)"
|
|
>
|
|
<div
|
|
class="flex items-center justify-between hover:bg-base-100"
|
|
>
|
|
<div class="flex-1">
|
|
<div class="text-main text-sm">
|
|
{{ item?.market?.name }}
|
|
</div>
|
|
<div class="text-sm text-gray-500 dark:text-gray-400">
|
|
{{ shortName(item?.base, item.coin_id) }}/{{
|
|
shortName(item?.target, item.target_coin_id)
|
|
}}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-base text-main">
|
|
${{ item.converted_last.usd }}
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<a
|
|
:color="store.trustColor"
|
|
class="mt-5 text-white btn btn-success w-full md:w-[400px] flex items-center"
|
|
:href="ticker.trade_url"
|
|
target="_blank"
|
|
>
|
|
Buy {{ coinInfo.symbol || '' }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex-1 hidden md:block">
|
|
<PriceMarketChart />
|
|
</div>
|
|
</div>
|
|
<div class="h-[1px] w-full bg-gray-100 dark:bg-[#384059]"></div>
|
|
<div class="max-h-[250px] overflow-auto p-4 text-sm">
|
|
<MdEditor
|
|
:model-value="coinInfo.description?.en"
|
|
previewOnly
|
|
></MdEditor>
|
|
</div>
|
|
<div class="mx-4 flex flex-wrap items-center">
|
|
<div
|
|
v-for="tag in coinInfo.categories"
|
|
class="mr-2 mb-4 text-xs bg-gray-100 dark:bg-[#384059] px-3 rounded-full py-1"
|
|
>
|
|
{{ tag }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-6">
|
|
<div v-for="item in store.stats">
|
|
<CardStatisticsVertical v-bind="item" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-base-100 rounded mt-4 shadow">
|
|
<div class="px-4 pt-4 pb-2 text-lg font-semibold text-main">
|
|
Active Proposals
|
|
</div>
|
|
<div class="px-4 pb-4">
|
|
<ProposalListItem :proposals="store?.proposals" />
|
|
</div>
|
|
<div class="pl-4 pb-8 py-4" v-if="store.proposals?.length === 0">
|
|
No active proposals
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-base-100 rounded mt-4 shadow">
|
|
<div class="px-4 pt-4 pb-2 text-lg font-semibold text-main">
|
|
{{ walletStore.currentAddress || 'Not Connected' }}
|
|
<RouterLink
|
|
v-if="walletStore.currentAddress"
|
|
class="float-right font-light text-sm cursor-pointert link link-primary no-underline font-medium"
|
|
to="/wallet/portfolio"
|
|
>More</RouterLink
|
|
>
|
|
</div>
|
|
<div
|
|
class="grid grid-cols-1 md:grid-cols-4 auto-cols-auto gap-4 px-4 pb-6"
|
|
>
|
|
<div class="bg-gray-100 dark:bg-[#373f59] rounded-sm px-4 py-3">
|
|
<div class="text-sm mb-1">Balance</div>
|
|
<div class="text-lg font-semibold text-main">
|
|
{{ format.formatToken(walletStore.balanceOfStakingToken) }}
|
|
</div>
|
|
<div class="text-sm" :class="color">
|
|
<span class="ml-1">
|
|
${{ format.tokenValue(walletStore.balanceOfStakingToken) }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="bg-gray-100 dark:bg-[#373f59] rounded-sm px-4 py-3">
|
|
<div class="text-sm mb-1">Staking</div>
|
|
<div class="text-lg font-semibold text-main">
|
|
{{ format.formatToken(walletStore.stakingAmount) }}
|
|
</div>
|
|
<div class="text-sm" :class="color">
|
|
${{ format.tokenValue(walletStore.stakingAmount) }}
|
|
</div>
|
|
</div>
|
|
<div class="bg-gray-100 dark:bg-[#373f59] rounded-sm px-4 py-3">
|
|
<div class="text-sm mb-1">Reward</div>
|
|
<div class="text-lg font-semibold text-main">
|
|
{{ format.formatToken(walletStore.rewardAmount) }}
|
|
</div>
|
|
<div class="text-sm" :class="color">
|
|
${{ format.tokenValue(walletStore.rewardAmount) }}
|
|
</div>
|
|
</div>
|
|
<div class="bg-gray-100 dark:bg-[#373f59] rounded-sm px-4 py-3">
|
|
<div class="text-sm mb-1">Unbonding</div>
|
|
<div class="text-lg font-semibold text-main">
|
|
{{ format.formatToken(walletStore.unbondingAmount) }}
|
|
</div>
|
|
<div class="text-sm" :class="color">
|
|
${{ format.tokenValue(walletStore.unbondingAmount) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="px-4 pb-4">
|
|
<table class="table table-compact w-full table-zebra">
|
|
<thead>
|
|
<tr>
|
|
<th>Validator</th>
|
|
<th>Delegations</th>
|
|
<th>Rewards</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="(item, index) in walletStore.delegations" :key="index">
|
|
<td>
|
|
{{
|
|
format.validatorFromBech32(
|
|
item?.delegation?.validator_address
|
|
)
|
|
}}
|
|
</td>
|
|
<td>{{ format.formatToken(item?.balance) }}</td>
|
|
<td>
|
|
{{
|
|
format.formatToken(
|
|
walletStore?.rewards?.rewards?.find(
|
|
(el) =>
|
|
el?.validator_address ===
|
|
item?.delegation?.validator_address
|
|
)?.reward?.[0]
|
|
)
|
|
}}
|
|
</td>
|
|
<td>
|
|
<div>
|
|
<button
|
|
class="btn btn-xs btn-primary btn-ghost text-primary rounded-sm mr-2"
|
|
>
|
|
Delegate
|
|
</button>
|
|
<button
|
|
class="btn btn-xs btn-primary btn-ghost text-primary rounded-sm"
|
|
>
|
|
Withdraw Rewards
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-3 gap-4 px-4 pb-6 mt-4">
|
|
<label for="send" class="btn btn-success text-white">Send</label>
|
|
<RouterLink to="/wallet/receive" class="btn btn-info text-white"
|
|
>Receive</RouterLink
|
|
>
|
|
<label for="PingTokenConvert" class="btn btn-primary text-white"
|
|
>Convert</label
|
|
>
|
|
</div>
|
|
<Teleport to="body">
|
|
<ping-token-convert
|
|
chain-name="juno"
|
|
:endpoint="endpoint"
|
|
:params="params"
|
|
></ping-token-convert>
|
|
</Teleport>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<route>
|
|
{
|
|
meta: {
|
|
i18n: 'dashboard',
|
|
order: 1,
|
|
}
|
|
}
|
|
</route>
|