Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@primer/octicons": "^17.11.1",
"axios": "^0.24.0",
"axios-retry": "^3.2.5",
"buffer": "^6.0.3",
"chart.js": "^4.0.1",
"chartjs-adapter-date-fns": "^2.0.1",
"chartjs-plugin-gradient": "^0.5.1",
Expand All @@ -28,6 +29,9 @@
"highlightjs-func": "^0.3.1",
"qrcode.vue": "^1.7.0",
"timeago.js": "^4.0.2",
"ton": "^13.6.1",
"ton-core": "^0.52.0",
"ton-crypto": "^3.2.0",
"vue": "^2.6.14",
"vue-clipboard2": "^0.3.3",
"vue-i18n": "^8.26.8",
Expand Down
16 changes: 9 additions & 7 deletions src/js/api/tonapi.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TONAPI_ENDPOINT, TONAPI_KEY } from '~/config.js';
import { TONAPI_ENDPOINT } from '~/config.js';
import { canonizeAddress } from '~/tonweb.js';
import axios from 'axios';

Expand All @@ -11,11 +11,9 @@ const http = axios.create({
* @return {Promise<Array>}
*/
export const getJettonBalances = async function(address) {
const response = await http.get('jetton/getBalances', { params: {
account: address,
}});
const response = await http.get(`accounts/${address}/jettons`);

const balances = (response.data.balances || []).map((balance) => Object.freeze({
return (response.data.balances || []).map(( balance ) => Object.freeze({
address: canonizeAddress(balance.wallet_address.address),
balance: balance.balance,
jetton_address: canonizeAddress(balance.jetton_address),
Expand All @@ -32,6 +30,10 @@ export const getJettonBalances = async function(address) {
}),
}),
}));

return balances;
};

export const getAccount = async function(address) {
const response = await http.get(`accounts/${address}`);

return response.data;
}
195 changes: 195 additions & 0 deletions src/js/components/UiSelect.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
<template>
<div class="ui-select input-material" @click="toggle" v-outside-click="onClickOutside">
<div class="ui-select__label_container">
<div class="ui-select__placeholder" v-bind:class="{
'ui-select__placeholder--active': selected !== undefined,
}">
{{ placeholder }}
</div>
<div class="ui-select__label">
{{ label }}
</div>
<icon-down v-if="!active" class="ui-select__icon" />
<icon-up v-else class="ui-select__icon" />
</div>
<div class="ui-select__options"
v-bind:class="{
'ui-select__options--active': active,
}"
ref="options"
>
<div class="ui-select__option"
v-for="option in options"
v-bind:key="option.value"
v-bind:class="{
'ui-select__option--active': option.value === selected,
}"
@click="select(option.value)"
>
{{ option.label }}
<icon-check v-if="option.value === selected" />
</div>
</div>
</div>
</template>

<script>
import outsideClick from '~/directives/outsideClick';
import IconDown from '@primer/octicons/build/svg/chevron-down-16.svg?inline';
import IconUp from '@primer/octicons/build/svg/chevron-up-16.svg?inline';
import IconCheck from '@primer/octicons/build/svg/check-16.svg?inline';

export default {
model: {
prop: 'modelValue',
event: 'input'
},

props: {
modelValue: {
type: String,
default: ''
},
placeholder: {
type: String,
default: ''
},
options: {
type: Array,
required: true,
default: () => []
}
},

created () {
this.selected = this.modelValue;
},

computed: {
label () {
if (this.selected === undefined) {
return this.placeholder;
}

const option = this.options.find(option => option.value === this.selected);
if (option === undefined) {
return this.placeholder;
}

return option.label;
}
},

data () {
return {
selected: undefined,
active: false
}
},

methods: {
toggle () {
this.active = !this.active;

// move options to the end of the body
// so they are not affected by overflow: hidden
if (this.active) {
document.body.appendChild(this.$refs.options);

// set position
const rect = this.$el.getBoundingClientRect();
this.$refs.options.style.top = `${rect.bottom + window.scrollY}px`;
this.$refs.options.style.left = `${rect.left + window.scrollX}px`;

// set width
this.$refs.options.style.width = `${rect.width}px`;
}
},

select ( value ) {
this.active = false;

this.selected = value;
this.$emit('input', value);
},

onClickOutside () {
if (! this.active) {
return;
}

this.active = false;
}
},

directives: { outsideClick },

components: { IconDown, IconUp, IconCheck }
}
</script>

<style scoped lang="scss">
.ui-select {
position: relative;
min-height: 18px;
min-width: 80px;
cursor: pointer;
}

.ui-select__options {
display: none;
position: absolute;
background: var(--input-bg);
border-radius: 12px;
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, .2), 0 6px 10px 0 rgba(0, 0, 0, .14), 0 1px 18px 0 rgba(0, 0, 0, .12);
margin-top: 2px;
z-index: 20;

&.ui-select__options--active {
display: block;
}
.ui-select__option {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 8px;
cursor: pointer;
border-radius: 8px;
margin: 0 5px;
font-size: 14px;
transition: .15s background ease;
&:first-child {
margin-top: 5px;
}
&:last-child {
margin-bottom: 5px;
}
&:hover {
background: var(--body-light-muted-color);
}
svg {
fill: var(--body-muted-text-color);
width: 16px;
height: 16px;
margin-left: auto;
}
}
}
.ui-select__label_container {
display: flex;
align-items: center;
}
.ui-select__placeholder {
display: none;
&--active {
display: block;
}
}
.ui-select__icon {
fill: var(--body-muted-text-color);
margin-left: auto;
width: 16px;
height: 16px;
}
</style>
20 changes: 18 additions & 2 deletions src/js/components/UiTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
</nav>

<div class="tab-pane" role="tabpanel"
v-for="tab in tabs"
v-for="tab in tabs"
v-bind:aria-labelledby="`tab_switcher_${tab.key}`"
v-bind:id="`tab_pane_${tab.key}`"
v-show="activeTab === tab.key">
Expand Down Expand Up @@ -59,7 +59,11 @@ export default {
$route: {
immediate: true,
handler({ hash }) {
this.activeTab = (hash || this.tabs[0].key).replace('#', '');
const cleanedHash = hash?.replace('#', '');

const tab = this.findTabByKey(cleanedHash);

this.activeTab = (tab?.key || this.tabs[0].key);
},
},

Expand All @@ -69,6 +73,18 @@ export default {
}
},
},

methods: {
findTabByKey ( key ) {
return this.tabs.find(tab => {
if (tab?.subtabKey && key.startsWith(tab?.subtabKey)) {
return true;
}

return tab.key === key;
});
}
}
};
</script>

Expand Down
8 changes: 4 additions & 4 deletions src/js/components/address/AddressTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import IconNft from '@img/icons/material-duotone/view-in-ar.svg?inline';
import IconToken from '@img/icons/material-duotone/toll.svg?inline';
import TabUserNfts from './TabUserNfts.vue';
import TabUserTokens from './TabUserTokens.vue';
import TabContractSources from './Verifier/Verifier.vue';
import ContractInfo from './ContractInfo.vue';
import TabContractTabs from './Verifier/VerifierTabs.vue';
import TxHistory from './TxHistory.vue';
import UiTabs from '~/components/UiTabs.vue';

Expand Down Expand Up @@ -57,12 +56,13 @@ export default {
icon: IconToken,
content: { key, props, component: TabUserTokens },
}, {
key: 'source',
key: 'contract_source',
subtabKey: 'contract_',
text: this.$t('address.tab_contract'),
icon: IconContract,
content: {
key,
component: TabContractSources,
component: TabContractTabs,
props: {
address: this.address,
isActive: this.isActive,
Expand Down
Loading