diff --git a/public/brand-assets/telos-zero/telos-zero-dark-gradient-o.png b/public/brand-assets/telos-zero/telos-zero-dark-gradient-o.png
new file mode 100644
index 00000000..eadb1863
Binary files /dev/null and b/public/brand-assets/telos-zero/telos-zero-dark-gradient-o.png differ
diff --git a/public/brand-assets/telos-zero/telos-zero-dark-gradient.png b/public/brand-assets/telos-zero/telos-zero-dark-gradient.png
new file mode 100644
index 00000000..c7e416ca
Binary files /dev/null and b/public/brand-assets/telos-zero/telos-zero-dark-gradient.png differ
diff --git a/public/brand-assets/telos-zero/telos-zero-light-gradient.png b/public/brand-assets/telos-zero/telos-zero-light-gradient.png
new file mode 100644
index 00000000..1d03205f
Binary files /dev/null and b/public/brand-assets/telos-zero/telos-zero-light-gradient.png differ
diff --git a/public/brand-assets/telos-zero/telos-zero-light.png b/public/brand-assets/telos-zero/telos-zero-light.png
new file mode 100644
index 00000000..83b387d2
Binary files /dev/null and b/public/brand-assets/telos-zero/telos-zero-light.png differ
diff --git a/public/brand-assets/telos/telos-dark-gradient.svg b/public/brand-assets/telos/telos-dark-gradient.svg
new file mode 100644
index 00000000..009f71a7
--- /dev/null
+++ b/public/brand-assets/telos/telos-dark-gradient.svg
@@ -0,0 +1,16 @@
+
diff --git a/public/brand-assets/telos/telos-icon-256.png b/public/brand-assets/telos/telos-icon-256.png
new file mode 100644
index 00000000..c9021a28
Binary files /dev/null and b/public/brand-assets/telos/telos-icon-256.png differ
diff --git a/public/brand-assets/telos/telos-icon.svg b/public/brand-assets/telos/telos-icon.svg
new file mode 100644
index 00000000..0a37cea2
--- /dev/null
+++ b/public/brand-assets/telos/telos-icon.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/brand-assets/telos/telos-light-gradient.svg b/public/brand-assets/telos/telos-light-gradient.svg
new file mode 100644
index 00000000..aced79b5
--- /dev/null
+++ b/public/brand-assets/telos/telos-light-gradient.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/brand-assets/telos/telos-light.svg b/public/brand-assets/telos/telos-light.svg
new file mode 100644
index 00000000..35f06b3c
--- /dev/null
+++ b/public/brand-assets/telos/telos-light.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/chains/telos-testnet/favicon.png b/public/chains/telos-testnet/favicon.png
index 2be9c2c7..c9021a28 100644
Binary files a/public/chains/telos-testnet/favicon.png and b/public/chains/telos-testnet/favicon.png differ
diff --git a/public/chains/telos/favicon.png b/public/chains/telos/favicon.png
index 2be9c2c7..c9021a28 100644
Binary files a/public/chains/telos/favicon.png and b/public/chains/telos/favicon.png differ
diff --git a/public/fonts/silka-bold-webfont.woff2 b/public/fonts/silka-bold-webfont.woff2
new file mode 100644
index 00000000..471efcd7
Binary files /dev/null and b/public/fonts/silka-bold-webfont.woff2 differ
diff --git a/public/fonts/silka-light-webfont.ttf b/public/fonts/silka-light-webfont.ttf
new file mode 100644
index 00000000..facaa55a
Binary files /dev/null and b/public/fonts/silka-light-webfont.ttf differ
diff --git a/public/fonts/silka-medium-webfont.woff2 b/public/fonts/silka-medium-webfont.woff2
new file mode 100644
index 00000000..c1501348
Binary files /dev/null and b/public/fonts/silka-medium-webfont.woff2 differ
diff --git a/public/fonts/silka-regular-webfont.woff2 b/public/fonts/silka-regular-webfont.woff2
new file mode 100644
index 00000000..6fa50eb4
Binary files /dev/null and b/public/fonts/silka-regular-webfont.woff2 differ
diff --git a/public/fonts/silka-semibold-webfont.ttf b/public/fonts/silka-semibold-webfont.ttf
new file mode 100644
index 00000000..bd8169ec
Binary files /dev/null and b/public/fonts/silka-semibold-webfont.ttf differ
diff --git a/public/icons/android-chrome-192x192.png b/public/icons/android-chrome-192x192.png
index c3e56c4f..aa325e64 100644
Binary files a/public/icons/android-chrome-192x192.png and b/public/icons/android-chrome-192x192.png differ
diff --git a/public/icons/android-chrome-512x512.png b/public/icons/android-chrome-512x512.png
index 57d67062..11671ab8 100644
Binary files a/public/icons/android-chrome-512x512.png and b/public/icons/android-chrome-512x512.png differ
diff --git a/public/icons/apple-touch-icon.png b/public/icons/apple-touch-icon.png
index 9fe69f6f..9b1ae548 100644
Binary files a/public/icons/apple-touch-icon.png and b/public/icons/apple-touch-icon.png differ
diff --git a/public/icons/favicon-16x16.png b/public/icons/favicon-16x16.png
index 2ba6897c..9551e584 100644
Binary files a/public/icons/favicon-16x16.png and b/public/icons/favicon-16x16.png differ
diff --git a/public/icons/favicon-32x32.png b/public/icons/favicon-32x32.png
index 210d27a7..f852a81a 100644
Binary files a/public/icons/favicon-32x32.png and b/public/icons/favicon-32x32.png differ
diff --git a/public/icons/site.webmanifest b/public/icons/site.webmanifest
index 45dc8a20..2b948973 100644
--- a/public/icons/site.webmanifest
+++ b/public/icons/site.webmanifest
@@ -1 +1 @@
-{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
\ No newline at end of file
+{"name":"Telos Block Explorer","short_name":"Telos Explorer","icons":[{"src":"/icons/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/icons/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#2C2B2F","background_color":"#FFFFFF","display":"standalone"}
diff --git a/quasar.conf.js b/quasar.conf.js
index a22292dd..e6525cf7 100644
--- a/quasar.conf.js
+++ b/quasar.conf.js
@@ -164,36 +164,21 @@ module.exports = configure(function (ctx) {
},
manifest: {
- name: '\'OBE\'',
- short_name: '\'OBE\'',
- description: '..',
+ name: 'Telos Block Explorer',
+ short_name: 'Telos Explorer',
+ description: 'Open block explorer for Telos and AntelopeIO networks.',
display: 'standalone',
orientation: 'portrait',
- background_color: '#ffffff',
- theme_color: '#027be3',
+ background_color: '#FFFFFF',
+ theme_color: '#2C2B2F',
icons: [
{
- src: 'icons/icon-128x128.png',
- sizes: '128x128',
- type: 'image/png'
- },
- {
- src: 'icons/icon-192x192.png',
+ src: 'icons/android-chrome-192x192.png',
sizes: '192x192',
type: 'image/png'
},
{
- src: 'icons/icon-256x256.png',
- sizes: '256x256',
- type: 'image/png'
- },
- {
- src: 'icons/icon-384x384.png',
- sizes: '384x384',
- type: 'image/png'
- },
- {
- src: 'icons/icon-512x512.png',
+ src: 'icons/android-chrome-512x512.png',
sizes: '512x512',
type: 'image/png'
}
diff --git a/src/api/price.ts b/src/api/price.ts
index 997929fd..e452f0b8 100644
--- a/src/api/price.ts
+++ b/src/api/price.ts
@@ -1,37 +1,78 @@
import axios from 'axios';
-import { PriceStats, PriceHistory } from 'src/types';
+import { DateTuple, PriceStats, PriceHistory } from 'src/types';
import { PriceChartData } from 'src/types/PriceChartData';
+const HOURS_23_MS = 23 * 60 * 60 * 1000;
+const DAY_MS = 24 * 60 * 60 * 1000;
+
+interface CoinPaprikaTicker {
+ last_updated: string;
+ quotes: {
+ USD: {
+ price: number;
+ volume_24h: number;
+ market_cap: number;
+ percent_change_24h: number;
+ };
+ };
+}
+
+interface CoinPaprikaHistoryPoint {
+ timestamp: string;
+ price: number;
+}
+
+interface TelosMarketData {
+ collected: number;
+ price: number;
+ market_cap: string;
+ volume: string;
+}
+
export const getCoingeckoUsdPrice = async (
tokenId: string,
): Promise => {
- const stats: PriceStats = await axios.get(
- getCoingeckoExchangeStatsUrl(tokenId),
- );
+ try {
+ const stats: PriceStats = await axios.get(
+ getCoingeckoExchangeStatsUrl(tokenId),
+ );
- return stats.data[tokenId].usd;
+ return stats.data[tokenId].usd;
+ } catch (error) {
+ if (tokenId === 'telos') {
+ return getTelosFallbackUsdPrice();
+ }
+ throw error;
+ }
};
export const getCoingeckoPriceChartData = async (
tokenId: string,
): Promise => {
- const exchangeStatsUrl = getCoingeckoExchangeStatsUrl(tokenId);
- const priceHistoryUrl = `https://api.coingecko.com/api/v3/coins/${tokenId}/market_chart?vs_currency=USD&days=1`; // &interval=hourly` - restore if when enterprise plan enabled;
+ try {
+ const exchangeStatsUrl = getCoingeckoExchangeStatsUrl(tokenId);
+ const priceHistoryUrl = `https://api.coingecko.com/api/v3/coins/${tokenId}/market_chart?vs_currency=USD&days=1`; // &interval=hourly` - restore if when enterprise plan enabled;
- const [priceStats, priceHistory]: [PriceStats, PriceHistory] =
- await Promise.all([
- axios.get(exchangeStatsUrl),
- axios.get(priceHistoryUrl),
- ]);
+ const [priceStats, priceHistory]: [PriceStats, PriceHistory] =
+ await Promise.all([
+ axios.get(exchangeStatsUrl),
+ axios.get(priceHistoryUrl),
+ ]);
- return {
- lastUpdated: priceStats.data[tokenId].last_updated_at,
- tokenPrice: priceStats.data[tokenId].usd,
- dayChange: priceStats.data[tokenId].usd_24h_change,
- dayVolume: priceStats.data[tokenId].usd_24h_vol,
- marketCap: priceStats.data[tokenId].usd_market_cap,
- prices: priceHistory.data.prices,
- };
+ return {
+ lastUpdated: priceStats.data[tokenId].last_updated_at,
+ tokenPrice: priceStats.data[tokenId].usd,
+ dayChange: priceStats.data[tokenId].usd_24h_change,
+ dayVolume: priceStats.data[tokenId].usd_24h_vol,
+ marketCap: priceStats.data[tokenId].usd_market_cap,
+ prices: normalizePriceSeries(priceHistory.data.prices, priceStats.data[tokenId].usd),
+ };
+ } catch (error) {
+ if (tokenId === 'telos') {
+ return getCoinPaprikaTelosPriceChartData();
+ }
+ throw error;
+ }
};
// eslint-disable-next-line @typescript-eslint/require-await
@@ -45,3 +86,77 @@ export const getEmptyPriceChartData = async (): Promise => ({
});
const getCoingeckoExchangeStatsUrl = (tokenId: string): string => `https://api.coingecko.com/api/v3/simple/price?ids=${tokenId}&vs_currencies=USD&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true&include_last_updated_at=true`;
+
+const getCoinPaprikaTelosPriceChartData = async (): Promise => {
+ try {
+ const start = new Date(Date.now() - HOURS_23_MS).toISOString();
+ const [ticker, history] = await Promise.all([
+ axios.get('https://api.coinpaprika.com/v1/tickers/tlos-telos'),
+ axios.get(
+ `https://api.coinpaprika.com/v1/tickers/tlos-telos/historical?start=${encodeURIComponent(start)}&interval=1h`,
+ ),
+ ]);
+ const usd = ticker.data.quotes.USD;
+ const prices = history.data
+ .map(point => [Date.parse(point.timestamp), point.price] as DateTuple)
+ .filter(([timestamp, price]) => Number.isFinite(Number(timestamp)) && Number.isFinite(price));
+
+ return {
+ lastUpdated: Date.parse(ticker.data.last_updated) / 1000,
+ tokenPrice: usd.price,
+ dayChange: usd.percent_change_24h,
+ dayVolume: usd.volume_24h,
+ marketCap: usd.market_cap,
+ prices: normalizePriceSeries(prices, usd.price),
+ };
+ } catch (error) {
+ return getTelosMarketDataFallback();
+ }
+};
+
+const getTelosMarketDataFallback = async (): Promise => {
+ const marketData = await getTelosMarketData();
+
+ return {
+ lastUpdated: marketData.collected / 1000,
+ tokenPrice: marketData.price,
+ dayChange: 0,
+ dayVolume: Number(marketData.volume),
+ marketCap: Number(marketData.market_cap),
+ prices: normalizePriceSeries([], marketData.price),
+ };
+};
+
+const getTelosFallbackUsdPrice = async (): Promise => {
+ try {
+ const marketData = await getTelosMarketData();
+ return marketData.price;
+ } catch (error) {
+ const ticker = await axios.get('https://api.coinpaprika.com/v1/tickers/tlos-telos');
+ return ticker.data.quotes.USD.price;
+ }
+};
+
+const getTelosMarketData = async (): Promise => {
+ const response = await axios.get(
+ 'https://api.telos.net/v1/evm/tokens/marketdata?symbols=TLOS',
+ );
+
+ return response.data[0];
+};
+
+const normalizePriceSeries = (prices: DateTuple[], currentPrice: number): DateTuple[] => {
+ if (prices.length >= 2) {
+ return prices;
+ }
+
+ if (!Number.isFinite(currentPrice) || currentPrice <= 0) {
+ return [];
+ }
+
+ const now = Date.now();
+ return [
+ [now - DAY_MS, currentPrice],
+ [now, currentPrice],
+ ];
+};
diff --git a/src/assets/obe_worldmap_telos.svg b/src/assets/obe_worldmap_telos.svg
index 464aaa9c..17754fe5 100644
--- a/src/assets/obe_worldmap_telos.svg
+++ b/src/assets/obe_worldmap_telos.svg
@@ -6,24 +6,24 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/AccountCard.vue b/src/components/AccountCard.vue
index d5bb35dd..d1e10ab4 100644
--- a/src/components/AccountCard.vue
+++ b/src/components/AccountCard.vue
@@ -549,7 +549,7 @@ export default defineComponent({
:disable="tokensLoading || isLoading"
:label="tokensLoading ? 'Loading...' : 'Send'"
color="primary"
- class="full-width"
+ class="full-width account-action-button"
@click="openSendDialog = true"
/>
@@ -557,7 +557,7 @@ export default defineComponent({
@@ -566,7 +566,7 @@ export default defineComponent({
@@ -718,6 +718,21 @@ $medium:750px
.resource
margin-right: 2rem
+.account-action-button
+ background-color: rgba(255, 255, 255, 0.1) !important
+ background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0.08) 100%) !important
+ border: 1px solid rgba(0, 242, 254, 0.38)
+ box-shadow: 0 8px 18px rgba(0, 0, 0, 0.2), inset 0 0 0 1px rgba(255, 255, 255, 0.04)
+ color: #FFFFFF !important
+ font-weight: 600
+ min-height: 44px
+ &::before
+ border-color: transparent !important
+ &:hover, &:focus
+ background-color: rgba(0, 242, 254, 0.12) !important
+ border-color: rgba(196, 113, 245, 0.5)
+ box-shadow: 0 10px 22px rgba(0, 0, 0, 0.22), 0 0 18px rgba(0, 242, 254, 0.1)
+
.text-right
font-weight: bold
&.total-loading-spinner
@@ -737,6 +752,10 @@ $medium:750px
a
cursor: pointer
text-decoration: underline
+ color: var(--q-info, #00F2FE)
+ text-underline-offset: 2px
+ &:hover, &:focus
+ color: var(--q-accent, #C471F5)
.total-amount
color: white
@@ -776,10 +795,16 @@ $medium:750px
a
cursor: pointer
text-decoration: underline
- color: white
+ color: var(--q-info, #00F2FE)
font-size: 16px
font-weight: normal
+ text-underline-offset: 2px
+ &:hover, &:focus
+ color: var(--q-accent, #C471F5)
.tx-link
text-decoration: none !important
+ color: var(--q-info, #00F2FE)
+ &:hover, &:focus
+ color: var(--q-accent, #C471F5)
diff --git a/src/components/CoinSelectorDialog.vue b/src/components/CoinSelectorDialog.vue
index 5fe1cbc9..7cf31b2c 100644
--- a/src/components/CoinSelectorDialog.vue
+++ b/src/components/CoinSelectorDialog.vue
@@ -116,14 +116,14 @@ export default defineComponent({
cursor: pointer
.addBtn
- color: white
- background-image: linear-gradient(to right, $deep-purple-2 20%, $light-blue-6 80% )
+ color: var(--q-dark)
+ background: var(--q-color-primary-gradient)
&:hover
- background-image: linear-gradient(to left, $deep-purple-2 20%, $light-blue-6 80%)
+ box-shadow: 0 8px 20px rgba(79, 172, 254, 0.22)
.dialogCard
- background: radial-gradient(circle at 48% 100%, rgba(108, 35, 255, 1) 0%, rgba(84, 0, 253, 1) 20%, rgba(2, 27, 100, 1) 92%)
+ background: var(--q-color-secondary-gradient)
color: white
// Hide scrollbar for Chrome, Safari and Opera
diff --git a/src/components/Footer.vue b/src/components/Footer.vue
index 224523c2..31714c2f 100644
--- a/src/components/Footer.vue
+++ b/src/components/Footer.vue
@@ -31,7 +31,11 @@ export default {
.footer-background
background: var(--q-color-footer-background)
backdrop-filter: blur(14px)
+ border-top: 1px solid var(--q-color-header-border)
.no-dec
text-decoration: none
color: white
+ font-size: 12px
+ font-weight: 600
+ letter-spacing: 0
diff --git a/src/components/Header.vue b/src/components/Header.vue
index 703a55dc..b58fd1df 100644
--- a/src/components/Header.vue
+++ b/src/components/Header.vue
@@ -22,7 +22,7 @@ export default defineComponent({
const headerSettings = computed((): HeaderSettings => ConfigManager.get().getCurrentChain().getUiCustomization().headerSettings);
const account = computed(() => accountStore.accountName);
- const isLarge = computed((): boolean => $q.screen.gt.md);
+ const isLarge = computed((): boolean => $q.screen.gt.xs);
const showMultichainSelector = computed(() => process.env.SHOW_MULTICHAIN_SELECTOR === 'true');
const isTestnet = ref(getChain().isTestnet());
@@ -53,7 +53,7 @@ export default defineComponent({