feature: governance list

This commit is contained in:
alisa 2023-04-25 00:37:16 +08:00
parent dec4b82f75
commit 581a3b0e33
4 changed files with 109 additions and 116 deletions

View File

@ -6,57 +6,56 @@ import ProposalProcess from './ProposalProcess.vue';
import type { PropType } from 'vue';
const props = defineProps({
proposals: { type: Object as PropType<PaginatedProposals>},
})
proposals: { type: Object as PropType<PaginatedProposals> },
});
// const list = computed(()=> proposl)
const format = useFormatter()
const staking = useStakingStore()
const chain = useBlockchain()
function showType(v: string){
if(v) {
return v.substring(v.lastIndexOf('.')+1)
}
return v
const format = useFormatter();
const staking = useStakingStore();
const chain = useBlockchain();
function showType(v: string) {
if (v) {
return v.substring(v.lastIndexOf('.') + 1);
}
return v;
}
const statusMap: Record<string, string> = {
PROPOSAL_STATUS_VOTING_PERIOD: 'VOTING',
PROPOSAL_STATUS_PASSED: 'PASSED',
PROPOSAL_STATUS_REJECTED: 'REJECTED',
};
</script>
<template>
<VExpansionPanels variant="accordion">
<VExpansionPanel v-for="(x, i) in proposals?.proposals">
<VExpansionPanelTitle disable-icon-rotate>
<VChip label color="primary" class="mr-2">{{x.proposal_id}}</VChip>
<div class="w-100"><VChip label>{{ showType(x.content['@type']) }}</VChip> {{ x.content?.title }}
<div class="d-flex mt-1">
<small class="text-secondary me-auto"> {{ format.toDay(x.voting_end_time, 'from') }}</small>
<ProposalProcess style="width:300px;" :pool="staking.pool" :tally="x.final_tally_result"></ProposalProcess>
<span></span>
</div>
</div>
<template #actions>
<VIcon
v-if="x.status === 'PROPOSAL_STATUS_PASSED'"
icon="mdi-check"
color="success"
class="ml-2"
/>
<VIcon
v-if="x.status === 'PROPOSAL_STATUS_REJECTED'"
icon="mdi-multiply"
color="error"
class="ml-2"
/>
</template>
</VExpansionPanelTitle>
<VExpansionPanelText>
<VCard class="card-box">
<VCardText>
<MdEditor :model-value="format.multiLine(x.content?.description)" previewOnly></MdEditor>
</VCardText>
<div class="text-center w-100 my-2">
<VBtn :to="`/${chain.chainName}/gov/${x.proposal_id}`" color="primary" variant="flat" size="small">Detail</VBtn>
<VBtn color="primary" variant="flat" class="ml-2" size="small">Vote</VBtn>
</div>
</VCard>
</VExpansionPanelText>
</VExpansionPanel>
</VExpansionPanels>
</template>
<div class="bg-[#28334e] rounded text-sm">
<RouterLink
:to="`/${chain.chainName}/gov/${item?.proposal_id}`"
v-for="(item, index) in proposals?.proposals"
:key="index"
class="py-4 px-4 hover:bg-[#353f5a] block rounded cursor-pointer"
>
<div class="grid grid-cols-6 md:grid-cols-11 flex-1">
<div class="text-white mb-3">#{{ item?.proposal_id }}</div>
<div class="col-span-5 md:pr-10 text-white truncate">
{{ item?.content?.title }}
</div>
<div class="col-span-3 mb-3 truncate">
<div class="bg-gray-600 text-gray-300 inline-block rounded-full px-2 py-[1px] text-xs">
{{ showType(item.content['@type']) }}
</div>
</div>
<div class="text-yes flex items-center mb-3">
<div class="w-1 h-1 bg-yes rounded-full mr-2"></div>
<div class="text-xs">{{ statusMap?.[item?.status] || item?.status }}</div>
</div>
<div class="truncate mb-3 col-span-2 md:col-span-1 text-right md:flex md:justify-start">
{{ format.toDay(item.voting_end_time, 'from') }}
</div>
</div>
<ProposalProcess :pool="staking.pool" :tally="item.final_tally_result"></ProposalProcess>
</RouterLink>
</div>
</template>

View File

@ -2,52 +2,36 @@
import { useFormatter } from '@/stores';
import type { Tally } from '@/types';
import { computed } from '@vue/reactivity';
import { ref, type PropType } from 'vue';
import type { PropType } from 'vue';
const props = defineProps({
tally: { type: Object as PropType<Tally>},
tally: { type: Object as PropType<Tally> },
pool: {
type: Object as PropType<{
not_bonded_tokens: string;
bonded_tokens: string;
not_bonded_tokens: string;
bonded_tokens: string;
}>,
},
})
const total = computed(() => props.pool?.bonded_tokens)
const format = useFormatter()
const yes = computed(() => (format.calculatePercent(props.tally?.yes, total.value)))
const no = computed(() => ref(format.calculatePercent(props.tally?.no, total.value)))
const abstain = computed(() => (format.calculatePercent(props.tally?.abstain, total.value)))
const veto = computed(() => (format.calculatePercent(props.tally?.no_with_veto, total.value)))
});
const total = computed(() => props.pool?.bonded_tokens);
const format = useFormatter();
const yes = computed(() => format.calculatePercent(props.tally?.yes, total.value));
const no = computed(() => format.calculatePercent(props.tally?.no, total.value));
const abstain = computed(() => format.calculatePercent(props.tally?.abstain, total.value));
const veto = computed(() => format.calculatePercent(props.tally?.no_with_veto, total.value));
</script>
<template>
<div class="progress">
<div class="progress-bar bg-success" :style="`width: ${yes}`"> {{ yes }}</div>
<div class="progress-bar bg-error" :style="`width: ${no}`">{{ no }} </div>
<div class="progress-bar " :style="`width: ${veto}; background-color: #B71C1C;`"> {{ veto }} </div>
<div class="progress-bar bg-secondary" :style="`width: ${abstain}`"> </div>
</div>
<div class="progress rounded-full h-1 text-xs">
<div class="h-1 bg-yes" :style="`width: ${yes}`"></div>
<div class="h-1 bg-no" :style="`width: ${no}`"></div>
<div class="h-1" :style="`width: ${veto}; background-color: #B71C1C;`"></div>
<div class="h-1 bg-secondary" :style="`width: ${abstain}`"></div>
</div>
</template>
<style scoped>
.progress {
height: 0.8rem;
overflow: hidden;
background-color: rgba(128, 128, 128, 0.178);
overflow: hidden;
background-color: rgba(128, 128, 128, 0.178);
}
.progress-bar {
display: inline-block;
height: 100%;
}
.progress :first-child {
border-radius: 0px !important;
border-top-right-radius: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-top-left-radius: 0;
}
.progress :last-child {
border-radius: 0px !important;
}
</style>
</style>

View File

@ -1,41 +1,42 @@
<script lang="ts" setup>
import { useThemeConfig } from '@/plugins/vuetify/@core/composable/useThemeConfig'
import { useThemeConfig } from '@/plugins/vuetify/@core/composable/useThemeConfig';
// Components
import Footer from '@/layouts/components/Footer.vue'
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue'
import UserProfile from '@/layouts/components/ChainProfile.vue'
import Footer from '@/layouts/components/Footer.vue';
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue';
import UserProfile from '@/layouts/components/ChainProfile.vue';
import { useDashboard } from '@/stores/useDashboard'
import { useDashboard } from '@/stores/useDashboard';
// @layouts plugin
import { VerticalNavLayout } from '@layouts'
import NavBarI18n from './NavBarI18n.vue'
import NavSearchBar from './NavSearchBar.vue'
import NavBarNotifications from './NavBarNotifications.vue'
import TheCustomizer from '@/plugins/vuetify/@core/components/TheCustomizer.vue'
import Breadcrumbs from './Breadcrumbs.vue'
import { useBlockchain } from '@/stores'
import { VerticalNavLayout } from '@layouts';
import NavBarI18n from './NavBarI18n.vue';
import NavSearchBar from './NavSearchBar.vue';
import NavBarNotifications from './NavBarNotifications.vue';
import TheCustomizer from '@/plugins/vuetify/@core/components/TheCustomizer.vue';
import Breadcrumbs from './Breadcrumbs.vue';
import { useBlockchain } from '@/stores';
const { appRouteTransition, isLessThanOverlayNavBreakpoint, isVerticalNavCollapsed } = useThemeConfig()
const { width: windowWidth } = useWindowSize()
const { appRouteTransition, isLessThanOverlayNavBreakpoint, isVerticalNavCollapsed } =
useThemeConfig();
const { width: windowWidth } = useWindowSize();
// Provide animation name for vertical nav collapse icon.
const verticalNavHeaderActionAnimationName = ref<null | 'rotate-180' | 'rotate-back-180'>(null)
const verticalNavHeaderActionAnimationName = ref<null | 'rotate-180' | 'rotate-back-180'>(null);
watch(isVerticalNavCollapsed, val => {
verticalNavHeaderActionAnimationName.value = val ? 'rotate-180' : 'rotate-back-180'
})
verticalNavHeaderActionAnimationName.value = val ? 'rotate-180' : 'rotate-back-180';
});
const dashboard = useDashboard()
dashboard.initial()
const blockchain = useBlockchain()
const dashboard = useDashboard();
dashboard.initial();
const blockchain = useBlockchain();
// blockchain.initial()
blockchain.$subscribe((m, s) => {
if(!Array.isArray(m.events) && m.events.key === 'chainName') {
blockchain.initial()
if (!Array.isArray(m.events) && m.events.key === 'chainName') {
blockchain.initial();
}
})
});
</script>
<template>
@ -43,8 +44,11 @@ blockchain.$subscribe((m, s) => {
<!-- 👉 navbar -->
<template #navbar="{ toggleVerticalOverlayNavActive }">
<div class="d-flex h-100 align-center">
<IconBtn v-if="isLessThanOverlayNavBreakpoint(windowWidth)" class="ms-n3"
@click="toggleVerticalOverlayNavActive(true)">
<IconBtn
v-if="isLessThanOverlayNavBreakpoint(windowWidth)"
class="ms-n3"
@click="toggleVerticalOverlayNavActive(true)"
>
<VIcon icon="mdi-menu" />
</IconBtn>
@ -52,9 +56,9 @@ blockchain.$subscribe((m, s) => {
<VSpacer />
<!-- <NavSearchBar />-->
<NavBarNotifications />
<NavBarI18n />
<NavbarThemeSwitcher />
<NavBarNotifications class="hidden md:inline-block" />
<NavBarI18n class="hidden md:inline-block" />
<NavbarThemeSwitcher class="hidden md:inline-block" />
</div>
</template>

View File

@ -5,7 +5,13 @@ module.exports = {
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {},
extend: {
colors: {
main: '#5973fe',
yes: '#3fb68b',
no: '#ff5353',
},
},
},
plugins: [],
}