Skip to content

Commit e21e137

Browse files
committed
feat: enhance network activity and account info components with token price, price change percentage, and sparkline data
1 parent 637ea11 commit e21e137

File tree

4 files changed

+266
-41
lines changed

4 files changed

+266
-41
lines changed

packages/extension/src/ui/action/composables/account-info.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export default (
1010
) => {
1111
const marketData = new MarketData();
1212
const fiatAmount = ref<string>(defaultFiatVal);
13+
const tokenPrice = ref<string>(defaultFiatVal);
14+
const priceChangePercentage = ref<number>(0);
15+
const sparkline = ref<string>('');
1316

1417
const cryptoAmountRaw = computed(() => {
1518
const selectedAccountIdx = accountInfo.value.activeAccounts.findIndex(
@@ -30,12 +33,21 @@ export default (
3033

3134
const updateFiatValues = async () => {
3235
fiatAmount.value = defaultFiatVal;
36+
tokenPrice.value = defaultFiatVal;
37+
priceChangePercentage.value = 0;
38+
sparkline.value = '';
3339
if (network.value.coingeckoID && cryptoAmountRaw.value != '~') {
40+
const market = await marketData.getMarketData([network.value.coingeckoID]);
3441
fiatAmount.value = `${await marketData.getTokenValue(
3542
cryptoAmountRaw.value,
3643
network.value.coingeckoID,
3744
'USD',
3845
)}`;
46+
if (market && market[0]) {
47+
tokenPrice.value = market[0].current_price?.toString() || defaultFiatVal;
48+
priceChangePercentage.value = market[0].price_change_percentage_24h || 0;
49+
sparkline.value = JSON.stringify(market[0].sparkline_in_24h.price);
50+
}
3951
}
4052
};
4153
watch(cryptoAmount, updateFiatValues);
@@ -45,5 +57,8 @@ export default (
4557
return {
4658
cryptoAmount,
4759
fiatAmount,
60+
tokenPrice,
61+
priceChangePercentage,
62+
sparkline,
4863
};
4964
};

packages/extension/src/ui/action/views/network-activity/components/network-activity-total.vue

Lines changed: 231 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,60 @@
33
v-if="cryptoAmount == '~' && !assumedError"
44
class="network-activity__total"
55
>
6-
<balance-loader class="network-activity__loader-one" />
7-
<balance-loader class="network-activity__loader-two" />
6+
<div>
7+
<balance-loader class="network-activity__loader-one" />
8+
<balance-loader class="network-activity__loader-two" />
9+
</div>
810
</div>
911
<div v-else-if="assumedError" class="network-activity__total-error">
1012
<h3>
1113
<span>Loading balance error. Please try again later</span>
1214
</h3>
1315
</div>
1416
<div v-else class="network-activity__total">
15-
<h3>
16-
{{ cryptoAmount }} <span>{{ symbol }}</span>
17-
</h3>
18-
<p>
19-
<span v-if="subnetwork !== ''">Chain {{ subnetwork }} &middot;</span>
20-
{{ $filters.parseCurrency(fiatAmount) }}
21-
</p>
17+
<div class="network-activity__total-info">
18+
<h3>
19+
{{ cryptoAmount }} <span>{{ symbol }}</span>
20+
</h3>
21+
<p>
22+
<span v-if="subnetwork !== ''">Chain {{ subnetwork }} &middot;</span>
23+
{{ $filters.parseCurrency(fiatAmount) }}
24+
</p>
25+
</div>
26+
27+
<div v-if="tokenPrice !== '0.00'" class="network-activity__total-market">
28+
<div class="network-activity__total-market-header">
29+
<p>Price</p>
30+
<span
31+
v-if="priceChangePercentage !== 0"
32+
:class="{
33+
'network-activity__total-price-change': true,
34+
'is-positive': priceChangePercentage > 0,
35+
'is-negative': priceChangePercentage < 0,
36+
}"
37+
>
38+
{{ priceChangePercentage > 0 ? '+' : ''
39+
}}{{ priceChangePercentage.toFixed(2) }}%
40+
</span>
41+
</div>
42+
<h4>{{ $filters.parseCurrency(tokenPrice) }}</h4>
43+
<div v-if="sparkline !== ''" class="network-activity__total-chart">
44+
<v-chart :option="chartOption" />
45+
</div>
46+
</div>
2247
</div>
2348
</template>
2449

2550
<script setup lang="ts">
2651
import BalanceLoader from '@action/icons/common/balance-loader.vue';
27-
import { onBeforeMount, ref, watchEffect } from 'vue';
52+
import { onBeforeMount, ref, watchEffect, computed } from 'vue';
53+
import { use } from 'echarts/core';
54+
import { SVGRenderer } from 'echarts/renderers';
55+
import { LineChart } from 'echarts/charts';
56+
import { GridComponent } from 'echarts/components';
57+
import VChart from 'vue-echarts';
58+
59+
use([SVGRenderer, LineChart, GridComponent]);
2860
2961
const props = defineProps({
3062
cryptoAmount: {
@@ -43,11 +75,61 @@ const props = defineProps({
4375
type: String,
4476
default: '',
4577
},
78+
tokenPrice: {
79+
type: String,
80+
default: '0',
81+
},
82+
priceChangePercentage: {
83+
type: Number,
84+
default: 0,
85+
},
86+
sparkline: {
87+
type: String,
88+
default: '',
89+
},
4690
});
4791
4892
let timer: NodeJS.Timeout | null = null;
4993
const assumedError = ref(false);
5094
95+
const chartOption = computed(() => ({
96+
width: 90,
97+
height: 32,
98+
color: [props.priceChangePercentage >= 0 ? '#16a34a' : '#dc2626'],
99+
grid: { show: false, left: 0, top: 0, right: 0, bottom: 0 },
100+
xAxis: [
101+
{
102+
show: false,
103+
type: 'category',
104+
boundaryGap: false,
105+
},
106+
],
107+
yAxis: [
108+
{
109+
show: false,
110+
type: 'value',
111+
min: 'dataMin',
112+
max: 'dataMax',
113+
},
114+
],
115+
series: [
116+
{
117+
type: 'line',
118+
smooth: true,
119+
lineStyle: {
120+
width: 1.5,
121+
cap: 'round',
122+
},
123+
areaStyle: {
124+
opacity: 0.12,
125+
color: props.priceChangePercentage >= 0 ? '#16a34a' : '#dc2626',
126+
},
127+
showSymbol: false,
128+
data: props.sparkline !== '' ? JSON.parse(props.sparkline) : [],
129+
},
130+
],
131+
}));
132+
51133
watchEffect(() => {
52134
if (timer) {
53135
clearTimeout(timer);
@@ -70,54 +152,91 @@ onBeforeMount(() => {
70152
<style lang="less" scoped>
71153
@import '@action/styles/theme.less';
72154
73-
@keyframes fadeIn {
155+
@keyframes fadeInUp {
74156
from {
75157
opacity: 0;
158+
transform: translateY(8px);
76159
}
77160
to {
78161
opacity: 1;
162+
transform: translateY(0);
79163
}
80164
}
81165
82166
.network-activity {
83167
&__total-error {
84-
padding: 0 24px 12px 24px;
85-
animation: fadeIn 0.3s ease-out;
168+
padding: 16px 24px;
169+
margin: 0 24px 16px 24px;
170+
background: rgba(239, 68, 68, 0.08);
171+
border: 1.5px solid rgba(239, 68, 68, 0.2);
172+
border-radius: 16px;
173+
animation: fadeInUp 300ms ease-out;
86174
87175
h3 {
88176
margin: 0;
89177
font-size: 14px;
90178
line-height: 20px;
179+
font-weight: 500;
91180
92181
span {
93-
color: @error;
94-
font-weight: 500;
182+
color: #dc2626;
183+
font-weight: 600;
95184
}
96185
}
97186
}
98187
99188
&__total {
100-
padding: 0 24px 12px 24px;
101-
animation: fadeIn 0.3s ease-out;
189+
padding: 20px;
190+
margin: 0 24px 16px 24px;
191+
background: linear-gradient(180deg, #ffffff 0%, #fafbfc 100%);
192+
border-radius: 16px;
193+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
194+
border: 1.5px solid rgba(0, 0, 0, 0.06);
195+
animation: fadeInUp 300ms ease-out;
196+
display: flex;
197+
flex-direction: row;
198+
justify-content: space-between;
199+
align-items: center;
200+
position: relative;
201+
overflow: hidden;
202+
203+
&::before {
204+
content: '';
205+
position: absolute;
206+
top: 0;
207+
left: 0;
208+
right: 0;
209+
bottom: 0;
210+
background: linear-gradient(
211+
135deg,
212+
rgba(98, 126, 234, 0.03) 0%,
213+
rgba(138, 100, 220, 0.02) 100%
214+
);
215+
pointer-events: none;
216+
}
102217
103218
h3 {
104219
font-style: normal;
105220
font-weight: 700;
106-
font-size: 28px;
107-
line-height: 36px;
221+
font-size: 26px;
222+
line-height: 32px;
223+
letter-spacing: -0.3px;
108224
background: linear-gradient(135deg, #627eea 0%, #8a64dc 100%);
109225
-webkit-background-clip: text;
110226
-webkit-text-fill-color: transparent;
111227
background-clip: text;
112228
margin: 0;
229+
position: relative;
230+
z-index: 1;
113231
114232
span {
115-
font-size: 18px;
233+
font-size: 15px;
116234
font-weight: 600;
235+
margin-left: 4px;
117236
background: linear-gradient(
118237
135deg,
119-
rgba(98, 126, 234, 0.7) 0%,
120-
rgba(138, 100, 220, 0.7) 100%
238+
rgba(98, 126, 234, 0.65) 0%,
239+
rgba(138, 100, 220, 0.65) 100%
121240
);
122241
-webkit-background-clip: text;
123242
background-clip: text;
@@ -127,28 +246,107 @@ onBeforeMount(() => {
127246
p {
128247
font-style: normal;
129248
font-weight: 500;
130-
font-size: 15px;
131-
line-height: 22px;
249+
font-size: 14px;
250+
line-height: 20px;
132251
color: @secondaryLabel;
133-
margin: 4px 0 0 0;
252+
margin: 6px 0 0 0;
253+
position: relative;
254+
z-index: 1;
134255
}
135256
}
136257
258+
&__total-info {
259+
position: relative;
260+
z-index: 1;
261+
animation: fadeInUp 300ms ease-out;
262+
animation-delay: 30ms;
263+
animation-fill-mode: both;
264+
}
265+
266+
&__total-market {
267+
display: flex;
268+
flex-direction: column;
269+
align-items: flex-end;
270+
gap: 6px;
271+
min-width: 110px;
272+
position: relative;
273+
z-index: 1;
274+
animation: fadeInUp 300ms ease-out;
275+
animation-delay: 60ms;
276+
animation-fill-mode: both;
277+
278+
&-header {
279+
display: flex;
280+
align-items: center;
281+
gap: 8px;
282+
283+
p {
284+
font-size: 11px;
285+
line-height: 14px;
286+
font-weight: 600;
287+
color: @tertiaryLabel;
288+
text-transform: uppercase;
289+
letter-spacing: 0.5px;
290+
margin: 0;
291+
}
292+
}
293+
294+
h4 {
295+
font-size: 17px;
296+
line-height: 22px;
297+
font-weight: 700;
298+
color: @primaryLabel;
299+
margin: 0;
300+
}
301+
}
302+
303+
&__total-price-change {
304+
display: inline-flex;
305+
align-items: center;
306+
font-size: 11px;
307+
font-weight: 600;
308+
padding: 3px 8px;
309+
border-radius: 10px;
310+
letter-spacing: 0.02em;
311+
transition: all 200ms ease-in-out;
312+
313+
&.is-positive {
314+
color: #16a34a;
315+
background: rgba(34, 197, 94, 0.1);
316+
}
317+
318+
&.is-negative {
319+
color: #dc2626;
320+
background: rgba(239, 68, 68, 0.08);
321+
}
322+
}
323+
324+
&__total-chart {
325+
width: 90px;
326+
height: 32px;
327+
margin-top: 2px;
328+
animation: fadeInUp 300ms ease-out;
329+
animation-delay: 90ms;
330+
animation-fill-mode: both;
331+
}
332+
137333
&__loader-one {
138-
width: 120px;
139-
height: 20px;
334+
width: 150px;
335+
height: 28px;
140336
margin-bottom: 12px;
141-
margin-top: 4px;
142337
display: block !important;
143-
border-radius: 6px;
338+
border-radius: 10px;
339+
animation: fadeInUp 300ms ease-out;
144340
}
145341
146342
&__loader-two {
147-
width: 80px;
148-
height: 14px;
343+
width: 100px;
344+
height: 18px;
149345
display: block !important;
150-
margin-bottom: 6px;
151-
border-radius: 4px;
346+
border-radius: 8px;
347+
animation: fadeInUp 300ms ease-out;
348+
animation-delay: 30ms;
349+
animation-fill-mode: both;
152350
}
153351
}
154352
</style>

0 commit comments

Comments
 (0)