diff --git a/.gitignore b/.gitignore index f2edcdce9..e26d0db58 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,4 @@ polkadot astar-collator # Chopstick binaries -db.sqlite +db.sqlite* \ No newline at end of file diff --git a/package.json b/package.json index 962fe8f1b..8daeafd4a 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,12 @@ "heroku-postbuild": "yarn install && yarn build", "heroku-deploy": "git push heroku main", "playwright:codegen": "npx playwright codegen http://localhost:8080", - "playwright": "BASE_URL='http://localhost:8080' ENDPOINT='ws://127.0.0.1:9944' npx playwright test --project=chromium --debug", + "playwright": "BASE_URL='http://localhost:8080' ENDPOINT='ws://127.0.0.1:9944' npx playwright test --project=chromium", "playwright:ci": "node ./tests/chopsticks/start-chopsticks.js" }, "dependencies": { "@astar-network/astar-sdk-core": "^0.2.5", - "@astar-network/astar-ui": "^0.0.104", + "@astar-network/astar-ui": "^0.0.136", "@astar-network/metamask-astar-adapter": "^0.5.4", "@astar-network/metamask-astar-types": "^0.6.1", "@ethersproject/bignumber": "^5.5.0", diff --git a/src/assets/img/account_bg_native.webp b/src/assets/img/account_bg_native.webp new file mode 100644 index 000000000..4f71b8673 Binary files /dev/null and b/src/assets/img/account_bg_native.webp differ diff --git a/src/assets/img/account_bg_shiden.webp b/src/assets/img/account_bg_shiden.webp new file mode 100644 index 000000000..410036d4b Binary files /dev/null and b/src/assets/img/account_bg_shiden.webp differ diff --git a/src/assets/img/account_bg_testnet.webp b/src/assets/img/account_bg_testnet.webp new file mode 100644 index 000000000..e5619777b Binary files /dev/null and b/src/assets/img/account_bg_testnet.webp differ diff --git a/src/assets/img/account_bg_testnet_zk.webp b/src/assets/img/account_bg_testnet_zk.webp new file mode 100644 index 000000000..9c64aa1ef Binary files /dev/null and b/src/assets/img/account_bg_testnet_zk.webp differ diff --git a/src/assets/img/account_bg_zk.webp b/src/assets/img/account_bg_zk.webp new file mode 100644 index 000000000..56323e849 Binary files /dev/null and b/src/assets/img/account_bg_zk.webp differ diff --git a/src/assets/img/assets_bg_dark.webp b/src/assets/img/assets_bg_dark.webp new file mode 100644 index 000000000..25dec5768 Binary files /dev/null and b/src/assets/img/assets_bg_dark.webp differ diff --git a/src/assets/img/assets_bg_dark_A.webp b/src/assets/img/assets_bg_dark_A.webp new file mode 100644 index 000000000..45f458228 Binary files /dev/null and b/src/assets/img/assets_bg_dark_A.webp differ diff --git a/src/assets/img/assets_bg_light.webp b/src/assets/img/assets_bg_light.webp new file mode 100644 index 000000000..8989f5ffa Binary files /dev/null and b/src/assets/img/assets_bg_light.webp differ diff --git a/src/assets/img/assets_icon_dark.svg b/src/assets/img/assets_icon_dark.svg new file mode 100644 index 000000000..2358c09dc --- /dev/null +++ b/src/assets/img/assets_icon_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/img/assets_icon_light.svg b/src/assets/img/assets_icon_light.svg new file mode 100644 index 000000000..367c6f385 --- /dev/null +++ b/src/assets/img/assets_icon_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/img/bg_common.webp b/src/assets/img/bg_common.webp new file mode 100644 index 000000000..d8bb1bf87 Binary files /dev/null and b/src/assets/img/bg_common.webp differ diff --git a/src/assets/img/icon_astar2.svg b/src/assets/img/icon_astar2.svg new file mode 100644 index 000000000..4fa2bac20 --- /dev/null +++ b/src/assets/img/icon_astar2.svg @@ -0,0 +1,1152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/icon_docs.svg b/src/assets/img/icon_docs.svg new file mode 100644 index 000000000..a43bdabe7 --- /dev/null +++ b/src/assets/img/icon_docs.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/icon_forum.svg b/src/assets/img/icon_forum.svg new file mode 100644 index 000000000..9c51bd95b --- /dev/null +++ b/src/assets/img/icon_forum.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/icon_home.svg b/src/assets/img/icon_home.svg new file mode 100644 index 000000000..3ae0d3471 --- /dev/null +++ b/src/assets/img/icon_home.svg @@ -0,0 +1,1409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/icon_startale.svg b/src/assets/img/icon_startale.svg new file mode 100644 index 000000000..c23f5bef9 --- /dev/null +++ b/src/assets/img/icon_startale.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/icon_tech_stack.svg b/src/assets/img/icon_tech_stack.svg new file mode 100644 index 000000000..89e235e1a --- /dev/null +++ b/src/assets/img/icon_tech_stack.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/zkevm_text_bg.webp b/src/assets/img/zkevm_text_bg.webp new file mode 100644 index 000000000..069cb868f Binary files /dev/null and b/src/assets/img/zkevm_text_bg.webp differ diff --git a/src/components/assets/Account.vue b/src/components/assets/Account.vue index e5329cab2..74152287f 100644 --- a/src/components/assets/Account.vue +++ b/src/components/assets/Account.vue @@ -1,87 +1,118 @@ - - - - - - {{ currentAccount ? currentAccountName : 'My Wallet' }} - - - - {{ getShortenAddress(currentAccount) }} + + + + + + + + + + + Shibuya EVM (L1) + Astar zKatana + + + + + + {{ currentNetworkName.replace('Network', '') }} + EVM (L1) + + + Astar zKatana + + Astar zkEVM + + + + + + {{ currentNetworkIdx === 4 ? 'Astar' : currentNetworkName.replace('Network', '') }} + {{ $t('native') }} + - - - {{ $n(totalBal) }} USD + + + + + + + - - - - - - - - - - Unify accounts - + + + + {{ getShortenAddress(currentAccount) }} - - - - - - {{ $t('copy') }} - + + {{ $n(totalBal) }} + {{ $t('usd') }} - - - - + + - - {{ $t(isH160 ? 'blockscout' : 'subscan') }} - - + + + + + + + {{ $t('assets.unifyAccounts') }} + + + + + + + + {{ $t('copy') }} + + + + + + + + + {{ $t(isH160 ? 'blockscout' : 'subscan') }} + + - - - - - - - - {{ - $t('assets.theSignatory', { account: multisig.signatory.name }) - }} - - - - {{ $t('assets.totalBalance') }} - - ${{ $n(totalBal) }} + + + + + + + + + + + + + {{ + $t('assets.theSignatory', { account: multisig.signatory.name }) + }} - + + + + @@ -111,6 +142,7 @@ import { getEvmMappedSs58Address, setAddressMapping } from 'src/hooks/helper/add import { useStore } from 'src/store'; import { computed, defineComponent, ref, watch, watchEffect } from 'vue'; import { useI18n } from 'vue-i18n'; +import Rewards from 'src/components/assets/Rewards.vue'; export default defineComponent({ components: { @@ -118,6 +150,7 @@ export default defineComponent({ EvmNativeToken, ZkAstr, AuIcon, + Rewards, }, props: { ttlErc20Amount: { @@ -240,6 +273,27 @@ export default defineComponent({ { immediate: false } ); + const bg_img = { + native: require('/src/assets/img/account_bg_native.webp'), + shiden: require('/src/assets/img/account_bg_shiden.webp'), + testnet: require('/src/assets/img/account_bg_testnet.webp'), + zk: require('/src/assets/img/account_bg_zk.webp'), + testnet_zk: require('/src/assets/img/account_bg_testnet_zk.webp'), + }; + + const bg = computed(() => { + if (currentNetworkIdx.value === endpointKey.ASTAR) { + return bg_img.native; + } else if (currentNetworkIdx.value === endpointKey.SHIDEN) { + return bg_img.shiden; + } else if (currentNetworkIdx.value === endpointKey.ZKATANA) { + return bg_img.testnet_zk; + } + return bg_img.testnet; + }); + + const currentNetworkName = ref(providerEndpoints[currentNetworkIdx.value].displayName); + return { iconWallet, currentAccountName, @@ -260,6 +314,9 @@ export default defineComponent({ unifiedAccount, isAccountUnified, isZkEvm, + bg, + currentNetworkIdx, + currentNetworkName, getShortenAddress, copyAddress, showAccountUnificationModal, diff --git a/src/components/assets/AssetSearchOption.vue b/src/components/assets/AssetSearchOption.vue index b42d8aa9b..6e1312886 100644 --- a/src/components/assets/AssetSearchOption.vue +++ b/src/components/assets/AssetSearchOption.vue @@ -1,27 +1,14 @@ - - - - - - - - - - - - - - - + + - - - - + + - - - - {{ $t(isH160 ? 'assets.astarEvmAccount' : 'assets.astarNativeAccount') }} - - + - - - - - - - + + + + + + + + + + - {{ $t('assets.assets') }} - - - - - - - - - + + + + - - - diff --git a/src/components/assets/EvmAssetList.vue b/src/components/assets/EvmAssetList.vue index 10a83d8fd..cd4d86c94 100644 --- a/src/components/assets/EvmAssetList.vue +++ b/src/components/assets/EvmAssetList.vue @@ -1,36 +1,44 @@ - - - - + + + + + {{ $t('assets.assets') }} - - - - - - - - - - - - {{ $t('assets.noResults') }} - - - {{ $t('assets.letsImportToken') }} - + + + + + + + + + + + + + + + + {{ $t('assets.noResults') }} + + + {{ $t('assets.letsImportToken') }} @@ -42,6 +50,7 @@ import EvmCbridgeToken from 'src/components/assets/EvmCbridgeToken.vue'; import { useNetworkInfo } from 'src/hooks'; import { Erc20Token } from 'src/modules/token'; import { PropType, computed, defineComponent, ref } from 'vue'; +import { useStore } from 'src/store'; export default defineComponent({ components: { @@ -97,6 +106,13 @@ export default defineComponent({ search.value = event.target.value; }; + const store = useStore(); + const isDarkTheme = computed(() => store.getters['general/theme'] === 'DARK'); + const icon_img = { + light: require('/src/assets/img/assets_icon_light.svg'), + dark: require('/src/assets/img/assets_icon_dark.svg'), + }; + return { symbol, token, @@ -106,6 +122,8 @@ export default defineComponent({ filteredTokens, cbridgeAppLink, isHideSmallBalances, + isDarkTheme, + icon_img, setIsSearch, checkIsCbridgeToken, toggleIsHideSmallBalances, diff --git a/src/components/assets/EvmCbridgeToken.vue b/src/components/assets/EvmCbridgeToken.vue index a42b28c6b..b280a184a 100644 --- a/src/components/assets/EvmCbridgeToken.vue +++ b/src/components/assets/EvmCbridgeToken.vue @@ -1,87 +1,110 @@ - - - - - + + + + - - {{ token.symbol }} - {{ formatTokenName(token.name) }} - + + + {{ token.symbol }} + {{ formatTokenName(token.name) }} - - - - - - - - {{ $n(Number(token.userBalanceUsd)) }} {{ $t('usd') }} - + + + + + {{ isTruncate ? $n(truncate(token.userBalance, 3)) : Number(token.userBalance) }} + + + {{ token.symbol }} - - - - {{ $t('assets.transfer') }} - - - - - {{ $t('assets.bridge') }} - - - - - - - - - - - - - {{ $t('blockscout') }} - + + + {{ $n(Number(token.userBalanceUsd)) }} - - - - - + - - - {{ $t('assets.addToWallet') }} - - + + {{ $t('usd') }} + + + + + + + + {{ $t('assets.send') }} + + {{ $t('assets.send') }} + + + + + + + + {{ $t('assets.bridge') }} + + {{ $t('assets.bridge') }} + + + + + + + + {{ $t('blockscout') }} + + {{ $t('blockscout') }} + + + + + + + + + + {{ $t('add') }} + + {{ $t('assets.addToWallet') }} + + + + + + @@ -91,16 +114,16 @@ import { SupportWallet } from 'src/config/wallets'; import { addToEvmProvider, getEvmProvider } from 'src/hooks/helper/wallet'; import { Erc20Token, getErc20Explorer, getTokenImage } from 'src/modules/token'; import { useStore } from 'src/store'; -import { computed, defineComponent, PropType } from 'vue'; +import { computed, defineComponent, PropType, ref } from 'vue'; import { buildTransferPageLink } from 'src/router/routes'; -import { useNetworkInfo } from 'src/hooks'; +import { useNetworkInfo, useBreakpoints } from 'src/hooks'; import Jazzicon from 'vue3-jazzicon/src/components'; import TokenBalance from 'src/components/common/TokenBalance.vue'; +import { truncate } from '@astar-network/astar-sdk-core'; export default defineComponent({ components: { [Jazzicon.name]: Jazzicon, - TokenBalance, }, props: { token: { @@ -109,6 +132,8 @@ export default defineComponent({ }, }, setup({ token }) { + const isExpand = ref(false); + const tokenImg = computed(() => getTokenImage({ isNativeToken: false, symbol: token.symbol, iconUrl: token.image }) ); @@ -134,12 +159,24 @@ export default defineComponent({ const currentWallet = computed(() => store.getters['general/currentWallet']); const provider = getEvmProvider(currentWallet.value); + const { width, screenSize } = useBreakpoints(); + + const isTruncate = !token.symbol.toUpperCase().includes('BTC'); + + const isFavorite = ref(false); + return { tokenImg, nativeTokenSymbol, explorerLink, cbridgeAppLink, provider, + width, + screenSize, + isExpand, + isTruncate, + isFavorite, + truncate, buildTransferPageLink, formatTokenName, addToEvmProvider, @@ -149,5 +186,5 @@ export default defineComponent({ diff --git a/src/components/assets/EvmNativeToken.vue b/src/components/assets/EvmNativeToken.vue index fcadbc7f2..3a4243881 100644 --- a/src/components/assets/EvmNativeToken.vue +++ b/src/components/assets/EvmNativeToken.vue @@ -1,69 +1,83 @@ - - - - - - - - {{ nativeTokenSymbol }} - {{ currentNetworkName }} - - - - - + + + + + + {{ nativeTokenSymbol }} + + + + - - - - - - - - {{ $n(balUsd) }} {{ $t('usd') }} - - - - - - - {{ $t('assets.bridge') }} - - - - - {{ $t('assets.transfer') }} - - - - - - {{ $t('assets.bridge') }} - - - - - {{ $t('assets.faucet') }} - - - - {{ $t('assets.faucet') }} - - + + + {{ isTruncate ? $n(truncate(bal, 3)) : Number(bal) }} + + {{ nativeTokenSymbol }} + + + + + + + + + {{ $t('assets.bridge') }} + + {{ $t('assets.bridge') }} + + + + + + + + {{ $t('assets.send') }} + + {{ $t('assets.send') }} + + + + + + + + + {{ $t('assets.bridge') }} + + {{ $t('assets.bridge') }} + + + + + + + + {{ $t('assets.faucet') }} + + {{ $t('assets.faucet') }} + + + + + + + + {{ $t('assets.faucet') }} + + {{ $t('assets.faucet') }} + + @@ -74,15 +88,16 @@ import { cbridgeAppLink } from 'src/c-bridge'; import ModalFaucet from 'src/components/assets/modals/ModalFaucet.vue'; import TokenBalance from 'src/components/common/TokenBalance.vue'; import { faucetBalRequirement } from 'src/config/wallets'; -import { useAccount, useNetworkInfo, usePrice } from 'src/hooks'; +import { useAccount, useNetworkInfo, usePrice, useBreakpoints } from 'src/hooks'; import { getTokenImage } from 'src/modules/token'; import { buildTransferPageLink, buildEthereumBridgePageLink } from 'src/router/routes'; import { useStore } from 'src/store'; import { computed, defineComponent, ref, watchEffect } from 'vue'; import { faucetSethLink } from 'src/links'; +import { truncate } from '@astar-network/astar-sdk-core'; export default defineComponent({ - components: { ModalFaucet, TokenBalance }, + components: { ModalFaucet }, setup() { const bal = ref(0); const balUsd = ref(0); @@ -132,6 +147,10 @@ export default defineComponent({ isModalFaucet.value = isOpen; }; + const { width, screenSize } = useBreakpoints(); + + const isTruncate = !nativeTokenSymbol.value.toUpperCase().includes('BTC'); + return { nativeTokenImg, nativeTokenSymbol, @@ -144,6 +163,10 @@ export default defineComponent({ isZkEvm, isZkatana, faucetSethLink, + width, + screenSize, + isTruncate, + truncate, handleModalFaucet, buildTransferPageLink, buildEthereumBridgePageLink, diff --git a/src/components/assets/NativeAssetList.vue b/src/components/assets/NativeAssetList.vue index 8cd2ae86a..8b66c910e 100644 --- a/src/components/assets/NativeAssetList.vue +++ b/src/components/assets/NativeAssetList.vue @@ -1,223 +1,219 @@ - - - - - - - - - {{ nativeTokenSymbol }} - {{ currentNetworkName }} - - - - + + + + + + + {{ nativeTokenSymbol }} + + + + + + + + + {{ isTruncate ? $n(truncate(bal, 3)) : Number(bal) }} + {{ nativeTokenSymbol }} - - - - - - - - - - - - {{ $t('assets.transferableBalance') }} - - - {{ $t('assets.transferable') }} - - - - - - - - - + + + + + + + + + + + + + {{ $t('assets.transferable') }} + + + + {{ isTruncate ? $n(truncate(transferableBalance, 3)) : Number(transferableBalance) }} + + {{ nativeTokenSymbol }} + + + + + + + + + + + + + + {{ $t('assets.send') }} + + {{ $t('assets.send') }} + + + - - - {{ $t('assets.faucet') }} + + + + + {{ $t('assets.faucet') }} + + {{ $t('assets.faucet') }} + + + + + + + {{ $t('assets.send') }} + + {{ $t('assets.send') }} + + + + + + + + + + + + {{ $t('assets.evmDeposit') }} - - - - {{ $t('assets.transfer') }} - - + + + {{ isTruncate ? $n(truncate(numEvmDeposit, 3)) : Number(numEvmDeposit) }} + + {{ nativeTokenSymbol }} - - - - - - - {{ $t(isExpand ? 'assets.collapse' : 'assets.expand') }} - - - - - + + + + + + {{ $t('assets.withdraw') }} + + + - - - {{ $t('assets.yourEvmDeposit') }} - - - - - - - + + + + + + {{ $t('assets.lockedTokens') }} + + + + {{ $n(truncate(lockInDappStaking + vestingTtl, 3)) }} - - - - + + {{ nativeTokenSymbol }} - - - {{ $t('assets.withdraw') }} - + + + + + + + + + + + + + {{ $t(isExpand ? 'assets.collapse' : 'assets.expand') }} + + + + - - - - {{ $t('assets.transferableBalance') }} - - + + + + + {{ $t('assets.vesting') }} - - - - - - - - + + + {{ isTruncate ? $n(truncate(vestingTtl, 3)) : Number(vestingTtl) }} - - - - - - {{ $t('assets.transfer') }} - - - - - - - - {{ $t('assets.yourVestingInfo') }} - - - - - - - - - + + {{ nativeTokenSymbol }} + + + - - - - - {{ $t('assets.view') }} - + + + + {{ $t('assets.view') }} + + - - - {{ $t('assets.yourStaking') }} - - + + + + {{ $t('common.staking') }} - - - - - - + + + {{ + isTruncate ? $n(truncate(lockInDappStaking, 3)) : Number(lockInDappStaking) + }} + + + {{ nativeTokenSymbol }} + + + - - - - - {{ $t('manage') }} - + + + + {{ $t('manage') }} + + - - - - - - + import { u8aToString } from '@polkadot/util'; import { ethers } from 'ethers'; -import { useBalance, useBalloons, useEvmDeposit, useNetworkInfo, usePrice } from 'src/hooks'; -import { checkIsNullOrUndefined } from '@astar-network/astar-sdk-core'; +import { + useBalance, + useBalloons, + useEvmDeposit, + useNetworkInfo, + usePrice, + useBreakpoints, +} from 'src/hooks'; +import { checkIsNullOrUndefined, truncate } from '@astar-network/astar-sdk-core'; import { getTokenImage } from 'src/modules/token'; import { generateAstarNativeTokenObject } from 'src/modules/xcm/tokens'; import { useStore } from 'src/store'; @@ -255,8 +258,6 @@ export default defineComponent({ ModalFaucet, ModalEvmWithdraw, ModalVesting, - TokenBalance, - Balloon, }, setup() { const isModalTransfer = ref(false); @@ -358,6 +359,10 @@ export default defineComponent({ el && el.classList.toggle('asset-collapsed'); }; + const { width, screenSize } = useBreakpoints(); + + const isTruncate = !nativeTokenSymbol.value.toUpperCase().includes('BTC'); + return { bal, nativeTokenSymbol, @@ -383,6 +388,11 @@ export default defineComponent({ isExpand, isBalloonNativeToken, isBalloonNativeTokenClosing, + + width, + screenSize, + isTruncate, + truncate, buildTransferPageLink, handleModalVesting, handleModalFaucet, diff --git a/src/components/assets/Rewards.vue b/src/components/assets/Rewards.vue new file mode 100644 index 000000000..ec220985a --- /dev/null +++ b/src/components/assets/Rewards.vue @@ -0,0 +1,122 @@ + + + + + + {{ $t('assets.yourEstimatedRewards') }} + + + + + {{ $n(pendingRewards || 0) }} + {{ nativeTokenSymbol }} + + + + + + + + + + + diff --git a/src/components/assets/SideAds.vue b/src/components/assets/SideAds.vue new file mode 100644 index 000000000..bc4a4c35e --- /dev/null +++ b/src/components/assets/SideAds.vue @@ -0,0 +1,92 @@ + + + + + + + + + + {{ item.link !== undefined ? 'FEATURED' : 'NEW LISTING' }} + + {{ item.name }} + + {{ item.shortDescription }} + + + + + + + + diff --git a/src/components/assets/XcmCurrency.vue b/src/components/assets/XcmCurrency.vue index b0acdba7e..b7d671718 100644 --- a/src/components/assets/XcmCurrency.vue +++ b/src/components/assets/XcmCurrency.vue @@ -1,80 +1,80 @@ - - - - - - - - - - - {{ token.metadata.symbol }} - {{ token.metadata.name }} - + + + + + + + + + {{ token.metadata.symbol }} + {{ token.metadata.name }} - - - - - - - - - - {{ $n(Number(token.userBalanceUsd)) }} {{ $t('usd') }} - + + + + + {{ isTruncate ? $n(truncate(token.userBalance, 3)) : Number(token.userBalance) }} + + + {{ token.metadata.symbol }} - - - - {{ $t('assets.transfer') }} - - - - - - - - - - - - {{ $t('subscan') }} - + + + {{ $n(Number(token.userBalanceUsd)) }} + + + {{ $t('usd') }} + + + + + + + + {{ $t('assets.send') }} + + {{ $t('assets.send') }} + + + + + + + + {{ $t('subscan') }} + + {{ $t('subscan') }} + + + + + diff --git a/src/components/header/mobile/BlogPosts.vue b/src/components/header/mobile/BlogPosts.vue new file mode 100644 index 000000000..708f51c3c --- /dev/null +++ b/src/components/header/mobile/BlogPosts.vue @@ -0,0 +1,89 @@ + + + + + + + + + + + diff --git a/src/components/header/mobile/CommunityLinks.vue b/src/components/header/mobile/CommunityLinks.vue new file mode 100644 index 000000000..d5db92697 --- /dev/null +++ b/src/components/header/mobile/CommunityLinks.vue @@ -0,0 +1,112 @@ + + + Astar Network is owned by the community + + + + + + + + + {{ $t('sidenavi.discord') }} + + + + + + + + {{ $t('sidenavi.twitter') }} + + + + + + + + {{ $t('sidenavi.telegram') }} + + + + + + + + {{ $t('sidenavi.reddit') }} + + + + + + + + {{ $t('sidenavi.youtube') }} + + + + + + + + {{ $t('sidenavi.github') }} + + + + + + diff --git a/src/components/header/mobile/LightDarkMode.vue b/src/components/header/mobile/LightDarkMode.vue new file mode 100644 index 000000000..7ec20c212 --- /dev/null +++ b/src/components/header/mobile/LightDarkMode.vue @@ -0,0 +1,74 @@ + + + + + + + {{ $t('common.lightTheme') }} + + + + + + + {{ $t('common.darkTheme') }} + + + + + + + diff --git a/src/components/header/mobile/LocaleChanger.vue b/src/components/header/mobile/LocaleChanger.vue new file mode 100644 index 000000000..cd73a3237 --- /dev/null +++ b/src/components/header/mobile/LocaleChanger.vue @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + diff --git a/src/components/header/mobile/MobileNav.vue b/src/components/header/mobile/MobileNav.vue new file mode 100644 index 000000000..a915e4e47 --- /dev/null +++ b/src/components/header/mobile/MobileNav.vue @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + {{ $t('sidenavi.myAssets') }} + + + + + + + {{ $t('common.staking') }} + + + + + + + Data + + + + + + {{ $t('sidenavi.data') }} + + + + + + + + + + + + {{ $t('sidenavi.settings') }} + + + + + + + + + + + + + + + diff --git a/src/components/header/modals/ModalNetwork.vue b/src/components/header/modals/ModalNetwork.vue index 0f7ccbed6..a7bb0d329 100644 --- a/src/components/header/modals/ModalNetwork.vue +++ b/src/components/header/modals/ModalNetwork.vue @@ -188,7 +188,7 @@ export default defineComponent({ const isH160 = computed(() => store.getters['general/isH160Formatted']); const checkIsDisabledZkOption = (provider: ChainProvider): boolean => { - return !isH160.value && provider.displayName.includes('zk'); + return !isH160.value && provider.displayName.toLowerCase().includes('zk'); }; const setInitialNewEndpoint = (): string => { diff --git a/src/components/sidenav/SidebarMobile.vue b/src/components/sidenav/SidebarMobile.vue deleted file mode 100644 index 563f751b5..000000000 --- a/src/components/sidenav/SidebarMobile.vue +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - {{ $t('dashboard.dashboard') }} - - - - - - - {{ $t('dashboard.dashboard') }} - - - - - - - {{ $t('assets.assets') }} - - - - - - - {{ $t('common.staking') }} - - - - - - - {{ $t('assets.bridge') }} - - - - - - - {{ $t('common.ecosystem') }} - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/components/sidenav/styles/sidebar-desktop.scss b/src/components/sidenav/styles/sidebar-desktop.scss index d36832d29..7e1657121 100644 --- a/src/components/sidenav/styles/sidebar-desktop.scss +++ b/src/components/sidenav/styles/sidebar-desktop.scss @@ -24,6 +24,8 @@ } .sidebar { + position: relative; + z-index: 1; width: 224px; padding-top: 24px; background: #081029; diff --git a/src/css/quasar.variables.scss b/src/css/quasar.variables.scss index 0293a68fd..b4195a231 100644 --- a/src/css/quasar.variables.scss +++ b/src/css/quasar.variables.scss @@ -11,13 +11,15 @@ $gray-7: #222829; $navy-1: #080f2e; $navy-2: #060b23; $navy-3: #1f2f5f; +$navy-4: #141E3E; $object-light: #e6e9ee; $modal-item-bg-dark: #141c34; $astar-blue: #0085ff; $astar-blue-dark: #05b6fd; -$astar-pink: #E6007A; +$astar-pink: #E0338F; +$astar-purple: #703AC2; $shiden-purple: #770cff; $shiden-purple-dark: #a67cff; $warning-red: #ff5621; diff --git a/src/hooks/useClaimAll.ts b/src/hooks/useClaimAll.ts index a1a42e45b..8486919fb 100644 --- a/src/hooks/useClaimAll.ts +++ b/src/hooks/useClaimAll.ts @@ -105,7 +105,7 @@ export function useClaimAll() { } }; - watch([isSendingTx, senderSs58Account, era], updateClaimEras); + watch([isSendingTx, senderSs58Account, era, dapps], updateClaimEras); const claimAll = async (): Promise => { const dappStakingServiceFactory = container.get<() => IDappStakingService>( diff --git a/src/i18n/en-US/index.ts b/src/i18n/en-US/index.ts index 81c9b460c..a13b5e74f 100644 --- a/src/i18n/en-US/index.ts +++ b/src/i18n/en-US/index.ts @@ -89,8 +89,8 @@ export default { common: { updateMetadata: 'Update Metadata', metadataAlreadyInstalled: 'Metadata Already Installed', - lightMode: 'Light mode', - darkMode: 'Dark mode', + lightTheme: 'Light theme', + darkTheme: 'Dark theme', dApps: 'dApps', dappStaking: 'dApp Staking', staking: 'Staking', @@ -129,6 +129,8 @@ export default { }, sidenavi: { community: 'Community', + myAssets: 'My Assets', + data: 'Data', discord: 'Discord', twitter: 'Twitter', telegram: 'Telegram', @@ -452,6 +454,7 @@ export default { switchToEvm: 'Switch to EVM', totalBalance: 'Total Balance', transfer: 'Transfer', + send: 'Send', syncing: 'Syncing...', faucet: 'Faucet', bridge: 'Bridge', @@ -464,7 +467,8 @@ export default { expand: 'Expand', collapse: 'Collapse', transferableBalance: 'Transferable Balance', - transferable: '(Transferable)', + transferable: 'Transferable', + evmDeposit: 'EVM deposit', yourEvmDeposit: 'Your EVM deposit', yourVestingInfo: 'Your Vesting Info', yourStaking: 'Your Staking', @@ -484,6 +488,15 @@ export default { tokenHasBeenAdded: 'The token has been added already', assetsAreNowFolded: 'All utilities for {token} token are now folded - open up here!', theSignatory: '{account} is the signatory', + myWallet: 'My Wallet', + reward: 'Reward', + lockedTokens: 'Locked tokens', + vesting: 'Vesting', + favorite: 'Favorite', + addToFavorite: 'Add to favorite', + removeFromFavorite: 'Remove from favorite', + unifyAccounts: 'Unify accounts', + yourEstimatedRewards: 'Your estimated Rewards', toast: { completedMessage: 'You have sent {transferAmt} {symbol} to {toAddress}', completedBridgeMessage: 'You have sent {transferAmt} {symbol} from {fromChain} to {toChain}', diff --git a/src/layouts/DashboardLayout.vue b/src/layouts/DashboardLayout.vue index 67580fe29..51ee344b5 100644 --- a/src/layouts/DashboardLayout.vue +++ b/src/layouts/DashboardLayout.vue @@ -5,9 +5,6 @@ - - - - + @@ -52,9 +52,13 @@ export default defineComponent({ diff --git a/src/router/utils/index.ts b/src/router/utils/index.ts index b1adf107c..af5b969aa 100644 --- a/src/router/utils/index.ts +++ b/src/router/utils/index.ts @@ -8,7 +8,7 @@ export const getHeaderName = (path: string): string => { } else if (path.includes('transfer')) { return 'Transfer Assets'; } else if (path.includes('assets')) { - return 'Assets'; + return 'Your Assets'; } else if (path.includes('stake')) { return 'Stake'; } else if (path.includes('dapp-staking')) { diff --git a/tests/assets-transactions-evm.spec.ts b/tests/assets-transactions-evm.spec.ts index a5bbd4917..816bb2fad 100644 --- a/tests/assets-transactions-evm.spec.ts +++ b/tests/assets-transactions-evm.spec.ts @@ -60,8 +60,7 @@ test.describe('account panel', () => { context: BrowserContext; }) => { // transfer test (from native to evm) :: need to testing - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); + page.getByTestId('transfer-link-button').click(); const faucetAmount = BigInt(200); await page.getByPlaceholder('Destination Address').fill(ALICE_EVM_ADDRESS); await page.getByPlaceholder('0.0').fill(faucetAmount.toString()); diff --git a/tests/test_specs/assets-transactions.spec.ts b/tests/test_specs/assets-transactions.spec.ts index 02ca7a890..38cd4e7eb 100644 --- a/tests/test_specs/assets-transactions.spec.ts +++ b/tests/test_specs/assets-transactions.spec.ts @@ -48,9 +48,7 @@ test.describe('account panel', () => { // Test case: AS001 test('should transfer tokens from Alice to Bob', async ({ page, context }) => { const transferAmount = BigInt(1000); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); - + page.getByTestId('transfer-link-button').click(); await page.getByPlaceholder('Destination Address').fill(BOB_ADDRESS); await page.getByPlaceholder('0.0').fill(transferAmount.toString()); await page.getByRole('button', { name: 'Confirm' }).click(); @@ -70,9 +68,7 @@ test.describe('account panel', () => { await selectMultisigAccount(page, context, false); // Memo: PolkaSafe SDK will check the balance of the Multisig account on mainnet before sending the transaction (the SDK through an error if the balance is not enough) const transferAmount = BigInt(1); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); - + page.getByTestId('transfer-link-button').click(); await page.getByPlaceholder('Destination Address').fill(BOB_ADDRESS); await page.getByPlaceholder('0.0').fill(transferAmount.toString()); await page.getByRole('button', { name: 'Confirm' }).click(); @@ -84,9 +80,7 @@ test.describe('account panel', () => { await selectMultisigAccount(page, context, true); // Memo: PolkaSafe SDK will check the balance of the Multisig account on mainnet before sending the transaction (the SDK through an error if the balance is not enough) const transferAmount = BigInt(1); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); - + page.getByTestId('transfer-link-button').click(); await page.getByPlaceholder('Destination Address').fill(BOB_ADDRESS); await page.getByPlaceholder('0.0').fill(transferAmount.toString()); await page.getByRole('button', { name: 'Confirm' }).click(); @@ -101,9 +95,7 @@ test.describe('account panel', () => { page: Page; }) => { const baseTransferAmount = BigInt(1000); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); - + page.getByTestId('transfer-link-button').click(); const aliceBalanceBeforeTransaction = await getBalance(ALICE_ADDRESS); await page.getByPlaceholder('Destination Address').fill(BOB_ADDRESS); @@ -132,8 +124,7 @@ test.describe('account panel', () => { page: Page; context: BrowserContext; }) => { - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); + page.getByTestId('transfer-link-button').click(); const faucetAmount = BigInt(200); await page.getByPlaceholder('Destination Address').fill(ALICE_EVM_ADDRESS); await page.getByPlaceholder('0.0').fill(faucetAmount.toString()); diff --git a/tests/test_specs/assets.spec.ts b/tests/test_specs/assets.spec.ts index 04d197a17..d09e05147 100644 --- a/tests/test_specs/assets.spec.ts +++ b/tests/test_specs/assets.spec.ts @@ -58,11 +58,9 @@ test.describe('account panel', () => { }); test('account expander works', async ({ page }) => { - await page.locator('.icon--expand').first().click(); - const transferButton = page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }); + const transferButton = page.getByTestId('transfer-link-button'); await expect(transferButton).toBeVisible(); - await page.locator('.icon--expand').first().click(); - await expect(transferButton).not.toBeVisible(); + await expect(page.getByText('Vesting')).toBeVisible(); }); }); diff --git a/tests/test_specs/reserve-transfer-asset-xcm.spec.ts b/tests/test_specs/reserve-transfer-asset-xcm.spec.ts index 884fad211..4ad81ca22 100644 --- a/tests/test_specs/reserve-transfer-asset-xcm.spec.ts +++ b/tests/test_specs/reserve-transfer-asset-xcm.spec.ts @@ -40,8 +40,7 @@ test.beforeEach(async ({ page, context }) => { test.describe('Test case: XCM006', () => { test('should transfer Alice ASTR tokens from Astar to Acala', async ({ page, context }) => { const transferAmount = BigInt(1000); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); + page.getByTestId('transfer-link-button').click(); await page.getByText('Cross-chain Transfer').click(); await page.getByRole('main').getByRole('button').first().click(); await page.locator('#amount').fill(transferAmount.toString()); @@ -64,8 +63,7 @@ test.describe('Test case: XCM006', () => { test.describe('Test case: XCM003', () => { test('should transfer Alice ASTR tokens from Acala to Astar', async ({ page, context }) => { const transferAmount = BigInt(900); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); + page.getByTestId('transfer-link-button').click(); await page.getByText('Cross-chain Transfer').click(); // memo wait for from/to values to switch on UI, because if switch happens after amount is entered, the amount would be cleared @@ -92,8 +90,7 @@ test.describe('Test case: XCM004', () => { test('should transfer Alice ACA tokens from Astar to Acala', async ({ page, context }) => { const assetId = '18446744073709551616'; const transferAmount = BigInt(1000); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); + page.getByTestId('transfer-link-button').click(); await page.getByText('Cross-chain Transfer').click(); await page.getByRole('main').getByRole('button').first().click(); @@ -124,8 +121,7 @@ test.describe('Test case: XCM001', () => { test('should transfer Alice ACA tokens from Acala to Astar', async ({ page, context }) => { const assetId = '18446744073709551616'; const transferAmount = BigInt(900); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); + page.getByTestId('transfer-link-button').click(); await page.getByText('Cross-chain Transfer').click(); await page @@ -155,8 +151,7 @@ test.describe('Test case: XCM001-1', () => { test('should transfer Alice DOT tokens from Polkadot to Astar', async ({ page, context }) => { const assetId = '340282366920938463463374607431768211455'; const transferAmount = BigInt(100); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); + page.getByTestId('transfer-link-button').click(); await page.getByText('Cross-chain Transfer').click(); await page.locator('div:nth-child(3) > .wrapper--select-chain').click(); @@ -186,8 +181,7 @@ test.describe('Test case: XCM004-1', () => { test('should transfer Alice DOT tokens from Astar to Polkadot', async ({ page, context }) => { const assetId = '340282366920938463463374607431768211455'; const transferAmount = BigInt(100); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); + page.getByTestId('transfer-link-button').click(); await page.getByText('Cross-chain Transfer').click(); await page.getByRole('main').getByRole('button').first().click(); @@ -218,8 +212,7 @@ test.describe('Test case: XCM001-2', () => { test('should transfer Alice USDT tokens from Statemint to Astar', async ({ page, context }) => { const assetId = '4294969280'; const transferAmount = BigInt(10000); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); + page.getByTestId('transfer-link-button').click(); await page.getByText('Cross-chain Transfer').click(); await page.locator('div:nth-child(3) > .wrapper--select-chain').click(); @@ -249,8 +242,7 @@ test.describe('Test case: XCM004-2', () => { test('should transfer Alice USDT tokens from Astar to Statemint', async ({ page, context }) => { const assetId = '4294969280'; const transferAmount = BigInt(10000); - await page.locator('.icon--expand').first().click(); - await page.locator('#asset-expand').getByRole('button', { name: 'Transfer' }).click(); + page.getByTestId('transfer-link-button').click(); await page.getByText('Cross-chain Transfer').click(); await page.getByRole('main').getByRole('button').first().click(); diff --git a/yarn.lock b/yarn.lock index 66a4178d5..9746a8f62 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,10 +42,10 @@ ethers "^5.6.9" web3 "^1.7.3" -"@astar-network/astar-ui@^0.0.104": - version "0.0.104" - resolved "https://registry.yarnpkg.com/@astar-network/astar-ui/-/astar-ui-0.0.104.tgz#daa860f3db4a9771c0c05def14ecd86ee652ba2a" - integrity sha512-8/2sQfHPoRnGQKshNRd7WuWOytah7AX1oV2JT8VCICsNPJO7Idm4KhvrZjP29BhdHC6eYc3/MBD/QWacAVCuRA== +"@astar-network/astar-ui@^0.0.136": + version "0.0.136" + resolved "https://registry.yarnpkg.com/@astar-network/astar-ui/-/astar-ui-0.0.136.tgz#cbf468d5d099ced53ed6d5a4cab23af5390315d9" + integrity sha512-Kuizskf6J738hejB7Y7Az6n2PSUVSbpjwrWQ0m9Uh0Rtpmj5eb/MVXT9vyl5zZP3jxOchZcrbjhsMW8VrzARwA== dependencies: "@iconify-prerendered/vue-ic" "^0.21.1672653513" vue "^3.2.23"