Skip to content

Commit 039800e

Browse files
committed
Add proposal metadata
1 parent 99a460a commit 039800e

File tree

1 file changed

+87
-19
lines changed

1 file changed

+87
-19
lines changed

components/modules/proposal/ProposalDescription.vue

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,107 @@
22
/** Shared Components */
33
import TablePlaceholderView from "@/components/shared/TablePlaceholderView.vue"
44
5+
/** Store */
6+
import { useNotificationsStore } from "@/store/notifications.store"
7+
const notificationsStore = useNotificationsStore()
8+
59
const props = defineProps({
610
proposal: {
711
type: Object,
812
required: true,
913
},
1014
})
15+
16+
const metadata = computed(() => {
17+
const m = props.proposal?.metadata
18+
if (typeof m !== 'string') return m
19+
20+
try {
21+
new URL(m)
22+
return m
23+
} catch (_) {}
24+
25+
const base64Pattern = /^[A-Za-z0-9+/=]+$/
26+
if (!base64Pattern.test(m)) {
27+
return m
28+
}
29+
30+
try {
31+
const decoded = atob(m)
32+
const parsed = JSON.parse(decoded)
33+
return JSON.stringify(parsed, null, 2)
34+
} catch {
35+
return m
36+
}
37+
})
38+
39+
const isCopied = ref(false)
40+
const handleCopy = (text) => {
41+
if (!text) return
42+
43+
window.navigator.clipboard.writeText(text)
44+
45+
notificationsStore.create({
46+
notification: {
47+
type: "info",
48+
icon: "check",
49+
title: "Successfully copied to clipboard",
50+
autoDestroy: true,
51+
},
52+
})
53+
54+
isCopied.value = true
55+
setTimeout(() => {
56+
isCopied.value = false
57+
}, 2_000)
58+
}
1159
</script>
1260
1361
<template>
14-
<Flex direction="column" gap="4">
15-
<Flex align="center" :class="$style.header">
16-
<Flex align="center" gap="8">
17-
<Icon name="menu" size="14" color="primary" />
18-
<Text size="13" weight="600" color="primary">Description</Text>
62+
<Flex direction="column" gap="40">
63+
<Flex v-if="metadata" direction="column" gap="4">
64+
<Flex align="center" :class="$style.header">
65+
<Flex align="center" gap="8">
66+
<Icon name="code" size="14" color="primary" />
67+
<Text size="13" weight="600" color="primary">Metadata</Text>
68+
<Icon @click="handleCopy(metadata)" :name="isCopied ? 'check' : 'copy'" size="12" :color="isCopied ? 'green' : 'secondary'" style="cursor: pointer;" />
69+
</Flex>
1970
</Flex>
71+
72+
<div :class="$style.content">
73+
<Flex direction="column" gap="16">
74+
<Text as="pre" size="14" height="160" weight="500" color="body">
75+
{{ metadata }}
76+
</Text>
77+
</Flex>
78+
</div>
2079
</Flex>
2180
22-
<div :class="$style.content">
23-
<Flex v-if="proposal.description" direction="column" gap="16">
24-
<Text as="pre" size="14" height="160" weight="500" color="body" :class="[$style.description]">
25-
{{ proposal.description }}
26-
</Text>
81+
<Flex direction="column" gap="4">
82+
<Flex align="center" :class="$style.header">
83+
<Flex align="center" gap="8">
84+
<Icon name="menu" size="14" color="primary" />
85+
<Text size="13" weight="600" color="primary">Description</Text>
86+
</Flex>
2787
</Flex>
2888
29-
<TablePlaceholderView
30-
v-else
31-
title="There's no description"
32-
description="This proposal does not contain any description."
33-
icon="menu"
34-
subIcon="search"
35-
:descriptionWidth="260"
36-
/>
37-
</div>
89+
<div :class="$style.content">
90+
<Flex v-if="proposal.description" direction="column" gap="16">
91+
<Text as="pre" size="14" height="160" weight="500" color="body" :class="[$style.description]">
92+
{{ proposal.description }}
93+
</Text>
94+
</Flex>
95+
96+
<TablePlaceholderView
97+
v-else
98+
title="There's no description"
99+
description="This proposal does not contain any description."
100+
icon="menu"
101+
subIcon="search"
102+
:descriptionWidth="260"
103+
/>
104+
</div>
105+
</Flex>
38106
</Flex>
39107
</template>
40108

0 commit comments

Comments
 (0)