Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
4eca9c8
wip: Governance Init && Proposals Page
xdeq May 26, 2025
296d26a
feat: Proposal page
xdeq May 28, 2025
969ccac
fix(proposal): link to proposer
xdeq May 28, 2025
d53c9ef
feat(address): Add governance votes
xdeq May 28, 2025
5bdb75d
fix(ProposalOverview): link to voter page
xdeq May 28, 2025
4cba218
fix(gov): min width for vote bar
xdeq May 28, 2025
80e2d82
fix voting wwrapper min height
xdeq May 28, 2025
4c882ab
feat(ProposalChanges): empty state for changes
xdeq May 28, 2025
75f2c6d
fix(ProposalOverview): minor fixes
xdeq May 28, 2025
182d535
fix(proposals): removed status color
xdeq May 28, 2025
f13856f
feat(ProposalOverview): tooltip for full desc
xdeq May 28, 2025
f56021e
feat(ProposalOverview): comma for votes && min width for vote bar
xdeq May 28, 2025
2b9dc16
fix(Tooltip): min-width for trigger
xdeq May 28, 2025
324abbb
fix(proposals): hide removed proposals
xdeq May 28, 2025
7455b77
feat: Add VotesAllocation
xdeq Jun 1, 2025
76a8c60
fix(VotesTable): pagination
xdeq Jun 1, 2025
1380866
feat(proposal): filter votes by option
xdeq Jun 3, 2025
66120fa
feat: Add useFilters
xdeq Jun 3, 2025
881f980
fix(proposal): correct link on vote
xdeq Jun 3, 2025
1f5f1f0
fix(AddressOverview): Add text-overflow for address hash
xdeq Jun 3, 2025
ab91289
feat(proposal): Check gov.threshold for Yes votes
xdeq Jun 3, 2025
38bc26c
feat(proposal): Check gov.veto_threshold for no_with_veto votes
xdeq Jun 3, 2025
da6f709
fix(proposal): votes nav
xdeq Jun 5, 2025
bb32266
fix(proposal): Add a separate card for proposal description
xdeq Jun 5, 2025
4c929fb
feat(proposal): Add an amount badge for community_pool_spend
xdeq Jun 5, 2025
9835ecb
feat(TablePlaceholderView): Add callback button
xdeq Jun 5, 2025
0ccbfd2
minor fixes for Radio & VotesTable
xdeq Jun 5, 2025
b560213
feat: Add ProposalTimeline
xdeq Jun 5, 2025
29d929d
feat(proposal): desc for rejected&removed type
xdeq Jun 5, 2025
5428766
fix(ProposalTimeline): revert
xdeq Jun 5, 2025
83b69d2
fix(VotesAllocation): left pos based on const.gov.threshold
xdeq Jun 7, 2025
14a9b67
ref(VotesAllocation): auto expand for inactive&active proposal status
xdeq Jun 7, 2025
e4ef112
ref(ProposalTimeline): auto expand for inactive&active proposal status
xdeq Jun 7, 2025
85ca00a
ref(proposal): rejected & removed status
xdeq Jun 7, 2025
da4f738
ref(proposal): show ProposalChanges only for param_changed
xdeq Jun 7, 2025
117f743
ref(proposal): separate Votes tab into Validators&Addresses Votes
xdeq Jun 7, 2025
e04bbba
revert filter icon
xdeq Jun 7, 2025
69fa2c7
fix(LatestPFBTable&RecentNamespacesTable): rm CopyButton
xdeq Jun 7, 2025
3d3c69e
ref filters
xdeq Jun 7, 2025
e45ef22
fix(NavLink): rm default Icon name
xdeq Jun 7, 2025
09db11f
fix(gov): switch from constants.gov
xdeq Jun 11, 2025
6937c82
ref(gov): multi-select for option filter
xdeq Jun 11, 2025
de572a6
feat(gov): Add VotingPower bar
xdeq Jun 11, 2025
7dd2ab8
ref(ProposalTimeline): dynamic start/end
xdeq Jun 11, 2025
cdccc7f
fix(VotesAllocation&VotingPower): zero votes
xdeq Jun 11, 2025
c0f1784
gov: minor fixes & imp
xdeq Jun 14, 2025
df088af
Merge branch 'dev' into gov
GusevPM Jun 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ activityStore.$subscribe((mutation, state) => {
localStorage.setItem("rollups_ranking", JSON.stringify(state.rollups_ranking))
})

appStore.initConstants()

let watchInterval = null

onMounted(async () => {
Expand Down
6 changes: 6 additions & 0 deletions assets/icons.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions assets/styles/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ $grayscale: (

/* General */
--brand: #18d2a5;
--brand-rgb: 24, 210, 165;
--blue: #379bff;
--blue-rgb: 55, 155, 255;
--red: #eb5757;
--red-rgb: 235, 87, 87;
--dark-red: #592121;
--orange: #ff5a17;
--light-orange: #ff8351;
Expand Down
7 changes: 3 additions & 4 deletions components/AddressBadge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ const props = defineProps({
},
color: {
type: String,
default: "primary"
default: "primary",
},
})

const alias = computed(() => {
const { $getDisplayName } = useNuxtApp()

return $getDisplayName('addresses', "", props.account)
return $getDisplayName("addresses", "", props.account)
})
</script>

Expand All @@ -23,4 +22,4 @@ const alias = computed(() => {
<Text size="13" weight="600" :color="color"> {{ alias }} </Text>
</Flex>
</NuxtLink>
</template>
</template>
12 changes: 2 additions & 10 deletions components/DatePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,11 @@ watch(
<template>
<Popover :open="isOpen" @on-close="handleClose" :width="popoverStyles.width" :side="popoverStyles.side">
<Button v-if="showTitle" @click="handleOpen" type="secondary" size="mini">
<Icon name="plus-circle" size="12" color="tertiary" />
<Icon name="plus-circle" size="12" :color="selectedRange ? 'brand' : 'tertiary'" />

<Text color="secondary">Date Range</Text>
<Text color="secondary">Date Range<template v-if="selectedRange">:</template></Text>

<template v-if="selectedRange">
<div :class="$style.vertical_divider" />

<Text size="12" weight="600" color="primary">
{{ selectedRange }}
</Text>
Expand Down Expand Up @@ -445,12 +443,6 @@ watch(
height: 100%;
}

.vertical_divider {
min-width: 2px;
height: 50%;
background: var(--op-10);
}

.period {
cursor: pointer;
}
Expand Down
32 changes: 26 additions & 6 deletions components/Icon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { computed } from "vue"
import icons from "@/assets/icons.json"

const props = defineProps({
name: { type: String, required: true, default: "warning" },
name: { type: String, required: true, default: "" },
size: { type: [String, Number], default: "16" },
color: { type: String, default: null },
hoverColor: { type: String, required: false },
rotate: { type: [String, Number], default: 0 },
fill: { type: Boolean, default: false },
scale: { type: [String, Number], default: 1 },
Expand All @@ -15,8 +16,8 @@ const props = defineProps({

const styles = computed(() => {
const s = {
minWidth: `${props.size}px`,
minHeight: `${props.size}px`,
minWidth: `${props.size}px`,
minHeight: `${props.size}px`,
transformBox: "view-box",
transformOrigin: "center center",
transform: "",
Expand All @@ -25,7 +26,7 @@ const styles = computed(() => {
const ops = []
if (props.rotate) ops.push(`rotate(${props.rotate}deg)`)
if (props.scale != 1) ops.push(`scale(${props.scale})`)
if (ops.length) s.transform = ops.join(" ")
if (ops.length) s.transform = ops.join(" ")

return s
})
Expand All @@ -38,6 +39,10 @@ const classes = computed(() => {
return iconClasses
})

const hoverColorVar = computed(() => {
return `var(--txt-${props.hoverColor})`
})

const getIcon = () => {
return icons[props.name.charAt(0).toLowerCase() + props.name.slice(1)]
}
Expand All @@ -48,7 +53,14 @@ const isSplitted = () => {
</script>

<template>
<svg viewBox="0 0 24 24" :width="size" :height="size" :style="styles" :class="[classes, loading && $style.loading]" role="img">
<svg
viewBox="0 0 24 24"
:width="size"
:height="size"
:style="styles"
:class="[classes, hoverColor && $style.hovered, loading && $style.loading]"
role="img"
>
<path v-if="!isSplitted(name)" :d="getIcon(name)" />
<template v-else>
<path v-if="!Array.isArray(getIcon(name))" :d="getIcon(name)" :style="{ opacity: path.opacity }" />
Expand All @@ -66,6 +78,14 @@ const isSplitted = () => {
</template>

<style module>
.hovered {
transition: all 0.3s var(--bezier);

&:hover {
fill: v-bind(hoverColorVar);
}
}

.loading {
animation: skeleton 1s ease-in-out infinite;
}
Expand All @@ -83,4 +103,4 @@ const isSplitted = () => {
opacity: 1;
}
}
</style>
</style>
7 changes: 6 additions & 1 deletion components/LeftSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,16 @@ const mainLinks = reactive([
{
name: "Ecosystem",
path: "/stats?tab=ecosystem",
queryParam: {tab: "ecosystem"},
queryParam: { tab: "ecosystem" },
show: isMainnet(),
},
],
},
{
icon: "governance",
name: "Governance",
path: "/proposals",
},
])

const isModularLinksCollapsed = ref(false)
Expand Down
57 changes: 57 additions & 0 deletions components/OgImage/ProposalImage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<script setup>
/** Vendor */
import { DateTime } from "luxon"

/** Services */
import { comma, formatBytes } from "@/services/utils"

defineOptions({
inheritAttrs: false,
})

const props = defineProps({
title: String,
proposal: Object,
})

const bgStyles = computed(() => {
return {
style: {
filter: "grayscale(1)",
opacity: "0.05",
},
}
})
</script>

<template>
<div class="w-full h-full" :style="{ background: '#111111', padding: '100px', fontFamily: 'IBM+Plex+Mono', overflow: 'hidden' }">
<img src="/img/bg.png" width="1200" height="600" class="absolute" v-bind="bgStyles" />

<div :style="{ height: '100%', display: 'flex', flexDirection: 'column', gap: '32px' }">
<div :style="{ display: 'flex', alignItems: 'center' }">
<span :style="{ fontSize: '40px', color: 'rgba(255,255,255, 0.6)', textTransform: 'capitalize', marginRight: '24px;' }">
{{ proposal.status }}
</span>

<span :style="{ fontSize: '40px', color: 'rgba(255,255,255, 0.3)' }">
- {{ DateTime.fromISO(proposal.deposit_time).toFormat("ff") }}
</span>
</div>

<span :style="{ fontSize: '50px', color: 'rgba(255,255,255, 0.9)' }"> {{ proposal.title }} </span>
<span :style="{ fontSize: '50px', color: 'rgba(255,255,255, 0.3)' }"> {{ proposal.description }} </span>

<div>
<span :style="{ fontSize: '32px', color: 'rgba(255,255,255, 0.3)' }">Yes: </span>
<span :style="{ fontSize: '32px', color: 'rgba(255,255,255, 0.6)' }">{{ proposal.yes }}</span>
<span :style="{ fontSize: '32px', color: 'rgba(255,255,255, 0.3)' }">, No: </span>
<span :style="{ fontSize: '32px', color: 'rgba(255,255,255, 0.6)' }">{{ proposal.no }}</span>
<span :style="{ fontSize: '32px', color: 'rgba(255,255,255, 0.3)' }">, No with veto: </span>
<span :style="{ fontSize: '32px', color: 'rgba(255,255,255, 0.6)' }">{{ proposal.no_with_veto }}</span>
<span :style="{ fontSize: '32px', color: 'rgba(255,255,255, 0.3)' }">, Abstain: </span>
<span :style="{ fontSize: '32px', color: 'rgba(255,255,255, 0.6)' }">{{ proposal.abstain }}</span>
</div>
</div>
</div>
</template>
2 changes: 0 additions & 2 deletions components/data/LatestPFBTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ isLoading.value = false
<Text size="13" weight="600" color="primary" mono>
{{ pfb.hash.slice(pfb.hash.length - 4, pfb.hash.length).toUpperCase() }}
</Text>

<CopyButton :text="pfb.hash.toUpperCase()" />
</Flex>

<template #content>
Expand Down
12 changes: 4 additions & 8 deletions components/data/RecentNamespacesTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,14 @@ const handleSort = async (by) => {

<tbody>
<tr v-for="ns in namespaces">
<td style="width: 1px">
<td>
<NuxtLink :to="`/namespace/${ns.namespace_id}`">
<Flex align="center">
<Tooltip position="start">
<Flex direction="column" gap="4">
<Flex align="center" gap="8">
<Text size="12" weight="600" color="primary" mono class="table_column_alias">
{{ $getDisplayName("namespaces", ns.namespace_id) }}
</Text>

<CopyButton :text="getNamespaceID(ns.namespace_id)" />
</Flex>
<Text size="13" weight="600" color="primary" mono class="table_column_alias">
{{ $getDisplayName("namespaces", ns.namespace_id) }}
</Text>

<Text
v-if="ns.name !== getNamespaceID(ns.namespace_id)"
Expand Down
4 changes: 2 additions & 2 deletions components/modals/ConstantsModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ const searchTerm = ref("")
const rawModules = ref({})

onMounted(async () => {
const data = await fetchConstants()
rawModules.value = data.module
const { data } = await fetchConstants()
rawModules.value = data.value.module
})

const modules = computed(() => {
Expand Down
6 changes: 3 additions & 3 deletions components/modules/address/AddressCharts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ const updateUserSettings = () => {
}

/** Charts */
const chartWrapperEl = ref()
const txSeriesChartEl = ref()
const feeSeriesChartEl = ref()
const chartWrapperEl = useTemplateRef("chartWrapperEl")
const txSeriesChartEl = useTemplateRef("txSeriesChartEl")
const feeSeriesChartEl = useTemplateRef("feeSeriesChartEl")

/** Data */
const isLoading = ref(false)
Expand Down
32 changes: 21 additions & 11 deletions components/modules/address/AddressOverview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ const handleOpenQRModal = () => {
<Flex v-else direction="column" gap="8" :class="$style.key_value">
<Text size="12" weight="600" color="secondary">Address</Text>

<Text size="13" weight="600" color="primary"> {{ address.hash }} </Text>
<Text size="13" weight="600" color="primary" class="overflow_ellipsis"> {{ address.hash }} </Text>
</Flex>

<Flex direction="column" gap="16" :class="$style.key_value">
Expand Down Expand Up @@ -854,12 +854,16 @@ const handleOpenQRModal = () => {
size="mini"
:disabled="!transactions.length && !hasActiveFilters"
>
<Icon name="plus-circle" size="12" color="tertiary" />
<Text color="secondary">Status</Text>
<Icon
name="plus-circle"
size="12"
:color="Object.keys(filters.status).find((f) => filters.status[f]) ? 'brand' : 'tertiary'"
/>
<Text color="secondary"
>Status<template v-if="Object.keys(filters.status).find((f) => filters.status[f])">:</template></Text
>

<template v-if="Object.keys(filters.status).find((f) => filters.status[f])">
<div :class="$style.vertical_divider" />

<Text size="12" weight="600" color="primary" style="text-transform: capitalize">
{{
Object.keys(filters.status)
Expand All @@ -874,7 +878,7 @@ const handleOpenQRModal = () => {

<template #content>
<Flex direction="column" gap="12">
<Text size="12" weight="500" color="secondary">Filter by Status</Text>
<Text size="12" weight="600" color="secondary">Filter by Status</Text>

<Flex direction="column" gap="8">
<Checkbox v-model="filters.status.success">
Expand All @@ -897,12 +901,18 @@ const handleOpenQRModal = () => {
size="mini"
:disabled="!transactions.length && !hasActiveFilters"
>
<Icon name="plus-circle" size="12" color="tertiary" />
<Text color="secondary">Message Type</Text>
<Icon
name="plus-circle"
size="12"
:color="Object.keys(filters.message_type).find((f) => filters.message_type[f]) ? 'brand' : 'tertiary'"
/>
<Text color="secondary"
>Message Type<template v-if="Object.keys(filters.message_type).find((f) => filters.message_type[f])"
>:</template
></Text
>

<template v-if="Object.keys(filters.message_type).find((f) => filters.message_type[f])">
<div :class="$style.vertical_divider" />

<Text size="12" weight="600" color="primary">
{{
Object.keys(filters.message_type).filter((f) => filters.message_type[f]).length < 3
Expand All @@ -929,7 +939,7 @@ const handleOpenQRModal = () => {

<template #content>
<Flex direction="column" gap="12">
<Text size="12" weight="500" color="secondary">Filter by Message Type</Text>
<Text size="12" weight="600" color="secondary">Filter by Message Type</Text>

<Input v-model="searchTerm" size="small" placeholder="Search" autofocus />

Expand Down
Loading