Merge branch 'master' into nymkappa/unix-socket
This commit is contained in:
		
						commit
						ba8cca6ba5
					
				| @ -1,12 +1,14 @@ | |||||||
| import { Application, Request, Response } from "express"; | import { Application, Request, Response } from 'express'; | ||||||
| import config from "../../config"; | import config from '../../config'; | ||||||
| import axios from "axios"; | import axios from 'axios'; | ||||||
| import logger from "../../logger"; | import logger from '../../logger'; | ||||||
|  | import mempool from '../mempool'; | ||||||
|  | import AccelerationRepository from '../../repositories/AccelerationRepository'; | ||||||
| 
 | 
 | ||||||
| class AccelerationRoutes { | class AccelerationRoutes { | ||||||
|   private tag = 'Accelerator'; |   private tag = 'Accelerator'; | ||||||
| 
 | 
 | ||||||
|   public initRoutes(app: Application) { |   public initRoutes(app: Application): void { | ||||||
|     app |     app | ||||||
|       .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations', this.$getAcceleratorAccelerations.bind(this)) |       .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations', this.$getAcceleratorAccelerations.bind(this)) | ||||||
|       .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/history', this.$getAcceleratorAccelerationsHistory.bind(this)) |       .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/history', this.$getAcceleratorAccelerationsHistory.bind(this)) | ||||||
| @ -15,35 +17,27 @@ class AccelerationRoutes { | |||||||
|     ; |     ; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async $getAcceleratorAccelerations(req: Request, res: Response) { |   private async $getAcceleratorAccelerations(req: Request, res: Response): Promise<void> { | ||||||
|     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; |     const accelerations = mempool.getAccelerations(); | ||||||
|     try { |     res.status(200).send(Object.values(accelerations)); | ||||||
|       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); |  | ||||||
|       for (const key in response.headers) { |  | ||||||
|         res.setHeader(key, response.headers[key]);  |  | ||||||
|       }       |  | ||||||
|       response.data.pipe(res); |  | ||||||
|     } catch (e) { |  | ||||||
|       logger.err(`Unable to get current accelerations from ${url} in $getAcceleratorAccelerations(), ${e}`, this.tag); |  | ||||||
|       res.status(500).end(); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async $getAcceleratorAccelerationsHistory(req: Request, res: Response) { |   private async $getAcceleratorAccelerationsHistory(req: Request, res: Response): Promise<void> { | ||||||
|     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; |     const history = await AccelerationRepository.$getAccelerationInfo(null, req.query.blockHeight ? parseInt(req.query.blockHeight as string, 10) : null); | ||||||
|     try { |     res.status(200).send(history.map(accel => ({ | ||||||
|       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); |       txid: accel.txid, | ||||||
|       for (const key in response.headers) { |       added: accel.added, | ||||||
|         res.setHeader(key, response.headers[key]);  |       status: 'completed', | ||||||
|       }       |       effectiveFee: accel.effective_fee, | ||||||
|       response.data.pipe(res); |       effectiveVsize: accel.effective_vsize, | ||||||
|     } catch (e) { |       boostRate: accel.boost_rate, | ||||||
|       logger.err(`Unable to get acceleration history from ${url} in $getAcceleratorAccelerationsHistory(), ${e}`, this.tag); |       boostCost: accel.boost_cost, | ||||||
|       res.status(500).end(); |       blockHeight: accel.height, | ||||||
|     } |       pools: [accel.pool], | ||||||
|  |     }))); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async $getAcceleratorAccelerationsHistoryAggregated(req: Request, res: Response) { |   private async $getAcceleratorAccelerationsHistoryAggregated(req: Request, res: Response): Promise<void> { | ||||||
|     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; |     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; | ||||||
|     try { |     try { | ||||||
|       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); |       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); | ||||||
| @ -57,7 +51,7 @@ class AccelerationRoutes { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async $getAcceleratorAccelerationsStats(req: Request, res: Response) { |   private async $getAcceleratorAccelerationsStats(req: Request, res: Response): Promise<void> { | ||||||
|     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; |     const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; | ||||||
|     try { |     try { | ||||||
|       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); |       const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ import websocketHandler from './websocket-handler'; | |||||||
| import redisCache from './redis-cache'; | import redisCache from './redis-cache'; | ||||||
| import rbfCache from './rbf-cache'; | import rbfCache from './rbf-cache'; | ||||||
| import { calcBitsDifference } from './difficulty-adjustment'; | import { calcBitsDifference } from './difficulty-adjustment'; | ||||||
|  | import AccelerationRepository from '../repositories/AccelerationRepository'; | ||||||
| 
 | 
 | ||||||
| class Blocks { | class Blocks { | ||||||
|   private blocks: BlockExtended[] = []; |   private blocks: BlockExtended[] = []; | ||||||
| @ -872,6 +873,7 @@ class Blocks { | |||||||
|             await BlocksRepository.$deleteBlocksFrom(lastBlock.height - 10); |             await BlocksRepository.$deleteBlocksFrom(lastBlock.height - 10); | ||||||
|             await HashratesRepository.$deleteLastEntries(); |             await HashratesRepository.$deleteLastEntries(); | ||||||
|             await cpfpRepository.$deleteClustersFrom(lastBlock.height - 10); |             await cpfpRepository.$deleteClustersFrom(lastBlock.height - 10); | ||||||
|  |             await AccelerationRepository.$deleteAccelerationsFrom(lastBlock.height - 10); | ||||||
|             this.blocks = this.blocks.slice(0, -10); |             this.blocks = this.blocks.slice(0, -10); | ||||||
|             this.updateTimerProgress(timer, `rolled back chain divergence from ${this.currentBlockHeight}`); |             this.updateTimerProgress(timer, `rolled back chain divergence from ${this.currentBlockHeight}`); | ||||||
|             for (let i = 10; i >= 0; --i) { |             for (let i = 10; i >= 0; --i) { | ||||||
| @ -974,6 +976,9 @@ class Blocks { | |||||||
|       if (this.blocks.length > config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4) { |       if (this.blocks.length > config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4) { | ||||||
|         this.blocks = this.blocks.slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4); |         this.blocks = this.blocks.slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4); | ||||||
|       } |       } | ||||||
|  |       blockSummary.transactions.forEach(tx => { | ||||||
|  |         delete tx.acc; | ||||||
|  |       }); | ||||||
|       this.blockSummaries.push(blockSummary); |       this.blockSummaries.push(blockSummary); | ||||||
|       if (this.blockSummaries.length > config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4) { |       if (this.blockSummaries.length > config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4) { | ||||||
|         this.blockSummaries = this.blockSummaries.slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4); |         this.blockSummaries = this.blockSummaries.slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4); | ||||||
| @ -1117,6 +1122,7 @@ class Blocks { | |||||||
|           } |           } | ||||||
|           return { |           return { | ||||||
|             txid: tx.txid, |             txid: tx.txid, | ||||||
|  |             time: tx.firstSeen, | ||||||
|             fee: tx.fee || 0, |             fee: tx.fee || 0, | ||||||
|             vsize: tx.vsize, |             vsize: tx.vsize, | ||||||
|             value: Math.round(tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0)), |             value: Math.round(tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0)), | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ import cpfpRepository from '../repositories/CpfpRepository'; | |||||||
| import { RowDataPacket } from 'mysql2'; | import { RowDataPacket } from 'mysql2'; | ||||||
| 
 | 
 | ||||||
| class DatabaseMigration { | class DatabaseMigration { | ||||||
|   private static currentVersion = 76; |   private static currentVersion = 77; | ||||||
|   private queryTimeout = 3600_000; |   private queryTimeout = 3600_000; | ||||||
|   private statisticsAddedIndexed = false; |   private statisticsAddedIndexed = false; | ||||||
|   private uniqueLogs: string[] = []; |   private uniqueLogs: string[] = []; | ||||||
| @ -664,6 +664,11 @@ class DatabaseMigration { | |||||||
|       await this.$executeQuery('ALTER TABLE `blocks_audits` ADD prioritized_txs JSON DEFAULT "[]"'); |       await this.$executeQuery('ALTER TABLE `blocks_audits` ADD prioritized_txs JSON DEFAULT "[]"'); | ||||||
|       await this.updateToSchemaVersion(76); |       await this.updateToSchemaVersion(76); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     if (databaseSchemaVersion < 77 && config.MEMPOOL.NETWORK === 'mainnet') { | ||||||
|  |       await this.$executeQuery('ALTER TABLE `accelerations` ADD requested datetime DEFAULT NULL'); | ||||||
|  |       await this.updateToSchemaVersion(77); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  | |||||||
| @ -5,6 +5,9 @@ import axios from 'axios'; | |||||||
| 
 | 
 | ||||||
| export interface Acceleration { | export interface Acceleration { | ||||||
|   txid: string, |   txid: string, | ||||||
|  |   added: number, | ||||||
|  |   effectiveVsize: number, | ||||||
|  |   effectiveFee: number, | ||||||
|   feeDelta: number, |   feeDelta: number, | ||||||
|   pools: number[], |   pools: number[], | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ import { IEsploraApi } from '../api/bitcoin/esplora-api.interface'; | |||||||
| import { Common } from '../api/common'; | import { Common } from '../api/common'; | ||||||
| import config from '../config'; | import config from '../config'; | ||||||
| import blocks from '../api/blocks'; | import blocks from '../api/blocks'; | ||||||
| import accelerationApi, { Acceleration } from '../api/services/acceleration'; | import accelerationApi, { Acceleration, AccelerationHistory } from '../api/services/acceleration'; | ||||||
| import accelerationCosts from '../api/acceleration/acceleration'; | import accelerationCosts from '../api/acceleration/acceleration'; | ||||||
| import bitcoinApi from '../api/bitcoin/bitcoin-api-factory'; | import bitcoinApi from '../api/bitcoin/bitcoin-api-factory'; | ||||||
| import transactionUtils from '../api/transaction-utils'; | import transactionUtils from '../api/transaction-utils'; | ||||||
| @ -15,6 +15,7 @@ import { BlockExtended, MempoolTransactionExtended } from '../mempool.interfaces | |||||||
| export interface PublicAcceleration { | export interface PublicAcceleration { | ||||||
|   txid: string, |   txid: string, | ||||||
|   height: number, |   height: number, | ||||||
|  |   added: number, | ||||||
|   pool: { |   pool: { | ||||||
|     id: number, |     id: number, | ||||||
|     slug: string, |     slug: string, | ||||||
| @ -29,15 +30,20 @@ export interface PublicAcceleration { | |||||||
| class AccelerationRepository { | class AccelerationRepository { | ||||||
|   private bidBoostV2Activated = 831580; |   private bidBoostV2Activated = 831580; | ||||||
| 
 | 
 | ||||||
|   public async $saveAcceleration(acceleration: AccelerationInfo, block: IEsploraApi.Block, pool_id: number): Promise<void> { |   public async $saveAcceleration(acceleration: AccelerationInfo, block: IEsploraApi.Block, pool_id: number, accelerationData: Acceleration[]): Promise<void> { | ||||||
|  |     const accelerationMap: { [txid: string]: Acceleration } = {}; | ||||||
|  |     for (const acc of accelerationData) { | ||||||
|  |       accelerationMap[acc.txid] = acc; | ||||||
|  |     } | ||||||
|     try { |     try { | ||||||
|       await DB.query(` |       await DB.query(` | ||||||
|         INSERT INTO accelerations(txid, added, height, pool, effective_vsize, effective_fee, boost_rate, boost_cost) |         INSERT INTO accelerations(txid, requested, added, height, pool, effective_vsize, effective_fee, boost_rate, boost_cost) | ||||||
|         VALUE (?, FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?) |         VALUE (?, FROM_UNIXTIME(?), FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?) | ||||||
|         ON DUPLICATE KEY UPDATE |         ON DUPLICATE KEY UPDATE | ||||||
|           height = ? |           height = ? | ||||||
|       `, [
 |       `, [
 | ||||||
|         acceleration.txSummary.txid, |         acceleration.txSummary.txid, | ||||||
|  |         accelerationMap[acceleration.txSummary.txid].added, | ||||||
|         block.timestamp, |         block.timestamp, | ||||||
|         block.height, |         block.height, | ||||||
|         pool_id, |         pool_id, | ||||||
| @ -64,7 +70,7 @@ class AccelerationRepository { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let query = ` |     let query = ` | ||||||
|       SELECT * FROM accelerations |       SELECT *, UNIX_TIMESTAMP(requested) as requested_timestamp, UNIX_TIMESTAMP(added) as block_timestamp FROM accelerations | ||||||
|       JOIN pools on pools.unique_id = accelerations.pool |       JOIN pools on pools.unique_id = accelerations.pool | ||||||
|     `;
 |     `;
 | ||||||
|     let params: any[] = []; |     let params: any[] = []; | ||||||
| @ -99,6 +105,7 @@ class AccelerationRepository { | |||||||
|         return rows.map(row => ({ |         return rows.map(row => ({ | ||||||
|           txid: row.txid, |           txid: row.txid, | ||||||
|           height: row.height, |           height: row.height, | ||||||
|  |           added: row.requested_timestamp || row.block_timestamp, | ||||||
|           pool: { |           pool: { | ||||||
|             id: row.id, |             id: row.id, | ||||||
|             slug: row.slug, |             slug: row.slug, | ||||||
| @ -202,7 +209,7 @@ class AccelerationRepository { | |||||||
|         const tx = blockTxs[acc.txid]; |         const tx = blockTxs[acc.txid]; | ||||||
|         const accelerationInfo = accelerationCosts.getAccelerationInfo(tx, boostRate, transactions); |         const accelerationInfo = accelerationCosts.getAccelerationInfo(tx, boostRate, transactions); | ||||||
|         accelerationInfo.cost = Math.max(0, Math.min(acc.feeDelta, accelerationInfo.cost)); |         accelerationInfo.cost = Math.max(0, Math.min(acc.feeDelta, accelerationInfo.cost)); | ||||||
|         this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id); |         this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id, successfulAccelerations); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     const lastSyncedHeight = await this.$getLastSyncedHeight(); |     const lastSyncedHeight = await this.$getLastSyncedHeight(); | ||||||
| @ -230,7 +237,7 @@ class AccelerationRepository { | |||||||
|     logger.debug(`Fetching accelerations between block ${lastSyncedHeight} and ${currentHeight}`); |     logger.debug(`Fetching accelerations between block ${lastSyncedHeight} and ${currentHeight}`); | ||||||
| 
 | 
 | ||||||
|     // Fetch accelerations from mempool.space since the last synced block;
 |     // Fetch accelerations from mempool.space since the last synced block;
 | ||||||
|     const accelerationsByBlock = {}; |     const accelerationsByBlock: {[height: number]: AccelerationHistory[]} = {}; | ||||||
|     const blockHashes = {}; |     const blockHashes = {}; | ||||||
|     let done = false; |     let done = false; | ||||||
|     let page = 1; |     let page = 1; | ||||||
| @ -297,12 +304,16 @@ class AccelerationRepository { | |||||||
|           const feeStats = Common.calcEffectiveFeeStatistics(template); |           const feeStats = Common.calcEffectiveFeeStatistics(template); | ||||||
|           boostRate = feeStats.medianFee; |           boostRate = feeStats.medianFee; | ||||||
|         } |         } | ||||||
|  |         const accelerationSummaries = accelerations.map(acc => ({ | ||||||
|  |           ...acc, | ||||||
|  |           pools: acc.pools.map(pool => pool.pool_unique_id), | ||||||
|  |         })) | ||||||
|         for (const acc of accelerations) { |         for (const acc of accelerations) { | ||||||
|           if (blockTxs[acc.txid]) { |           if (blockTxs[acc.txid]) { | ||||||
|             const tx = blockTxs[acc.txid]; |             const tx = blockTxs[acc.txid]; | ||||||
|             const accelerationInfo = accelerationCosts.getAccelerationInfo(tx, boostRate, transactions); |             const accelerationInfo = accelerationCosts.getAccelerationInfo(tx, boostRate, transactions); | ||||||
|             accelerationInfo.cost = Math.max(0, Math.min(acc.feeDelta, accelerationInfo.cost)); |             accelerationInfo.cost = Math.max(0, Math.min(acc.feeDelta, accelerationInfo.cost)); | ||||||
|             await this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id); |             await this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id, accelerationSummaries); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         await this.$setLastSyncedHeight(height); |         await this.$setLastSyncedHeight(height); | ||||||
| @ -317,6 +328,26 @@ class AccelerationRepository { | |||||||
| 
 | 
 | ||||||
|     logger.debug(`Indexing accelerations completed`); |     logger.debug(`Indexing accelerations completed`); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Delete accelerations from the database above blockHeight | ||||||
|  |    */ | ||||||
|  |   public async $deleteAccelerationsFrom(blockHeight: number): Promise<void> { | ||||||
|  |     logger.info(`Delete newer accelerations from height ${blockHeight} from the database`); | ||||||
|  |     try { | ||||||
|  |       const currentSyncedHeight = await this.$getLastSyncedHeight(); | ||||||
|  |       if (currentSyncedHeight >= blockHeight) { | ||||||
|  |         await DB.query(` | ||||||
|  |           UPDATE state | ||||||
|  |           SET number = ? | ||||||
|  |           WHERE name = 'last_acceleration_block' | ||||||
|  |         `, [blockHeight - 1]);
 | ||||||
|  |       } | ||||||
|  |       await DB.query(`DELETE FROM accelerations where height >= ${blockHeight}`); | ||||||
|  |     } catch (e) { | ||||||
|  |       logger.err('Cannot delete indexed accelerations. Reason: ' + (e instanceof Error ? e.message : e)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default new AccelerationRepository(); | export default new AccelerationRepository(); | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								contributors/daweilv.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								contributors/daweilv.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of April 7, 2024. | ||||||
|  | 
 | ||||||
|  | Signed: daweilv | ||||||
| @ -170,6 +170,11 @@ | |||||||
|             ], |             ], | ||||||
|             "styles": [ |             "styles": [ | ||||||
|               "src/styles.scss", |               "src/styles.scss", | ||||||
|  |               { | ||||||
|  |                 "input": "src/theme-contrast.scss", | ||||||
|  |                 "bundleName": "contrast", | ||||||
|  |                 "inject": false | ||||||
|  |               }, | ||||||
|               "node_modules/@fortawesome/fontawesome-svg-core/styles.css" |               "node_modules/@fortawesome/fontawesome-svg-core/styles.css" | ||||||
|             ], |             ], | ||||||
|             "vendorChunk": true, |             "vendorChunk": true, | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| export const mempoolFeeColors = [ | export const defaultMempoolFeeColors = [ | ||||||
|   '557d00', |   '557d00', | ||||||
|   '5d7d01', |   '5d7d01', | ||||||
|   '637d02', |   '637d02', | ||||||
| @ -39,6 +39,47 @@ export const mempoolFeeColors = [ | |||||||
|   'ae005b', |   'ae005b', | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
|  | export const contrastMempoolFeeColors = [ | ||||||
|  |   '0082e6', | ||||||
|  |   '0984df', | ||||||
|  |   '1285d9', | ||||||
|  |   '1a87d2', | ||||||
|  |   '2388cb', | ||||||
|  |   '2c8ac5', | ||||||
|  |   '358bbe', | ||||||
|  |   '3e8db7', | ||||||
|  |   '468eb0', | ||||||
|  |   '4f90aa', | ||||||
|  |   '5892a3', | ||||||
|  |   '61939c', | ||||||
|  |   '6a9596', | ||||||
|  |   '72968f', | ||||||
|  |   '7b9888', | ||||||
|  |   '849982', | ||||||
|  |   '8d9b7b', | ||||||
|  |   '959c74', | ||||||
|  |   '9e9e6e', | ||||||
|  |   'a79f67', | ||||||
|  |   'b0a160', | ||||||
|  |   'b9a35a', | ||||||
|  |   'c1a453', | ||||||
|  |   'caa64c', | ||||||
|  |   'd3a745', | ||||||
|  |   'dca93f', | ||||||
|  |   'e5aa38', | ||||||
|  |   'edac31', | ||||||
|  |   'f6ad2b', | ||||||
|  |   'ffaf24', | ||||||
|  |   'ffb01e', | ||||||
|  |   'ffb118', | ||||||
|  |   'ffb212', | ||||||
|  |   'ffb30c', | ||||||
|  |   'ffb406', | ||||||
|  |   'ffb500', | ||||||
|  |   'ffb600', | ||||||
|  |   'ffb700', | ||||||
|  |  ]; | ||||||
|  | 
 | ||||||
| export const chartColors = [ | export const chartColors = [ | ||||||
|   "#D81B60", |   "#D81B60", | ||||||
|   "#8E24AA", |   "#8E24AA", | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ import { SharedModule } from './shared/shared.module'; | |||||||
| import { StorageService } from './services/storage.service'; | import { StorageService } from './services/storage.service'; | ||||||
| import { HttpCacheInterceptor } from './services/http-cache.interceptor'; | import { HttpCacheInterceptor } from './services/http-cache.interceptor'; | ||||||
| import { LanguageService } from './services/language.service'; | import { LanguageService } from './services/language.service'; | ||||||
|  | import { ThemeService } from './services/theme.service'; | ||||||
| import { FiatShortenerPipe } from './shared/pipes/fiat-shortener.pipe'; | import { FiatShortenerPipe } from './shared/pipes/fiat-shortener.pipe'; | ||||||
| import { FiatCurrencyPipe } from './shared/pipes/fiat-currency.pipe'; | import { FiatCurrencyPipe } from './shared/pipes/fiat-currency.pipe'; | ||||||
| import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-string.pipe'; | import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-string.pipe'; | ||||||
| @ -38,6 +39,7 @@ const providers = [ | |||||||
|   StorageService, |   StorageService, | ||||||
|   EnterpriseService, |   EnterpriseService, | ||||||
|   LanguageService, |   LanguageService, | ||||||
|  |   ThemeService, | ||||||
|   ShortenStringPipe, |   ShortenStringPipe, | ||||||
|   FiatShortenerPipe, |   FiatShortenerPipe, | ||||||
|   FiatCurrencyPipe, |   FiatCurrencyPipe, | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .become-sponsor { | .become-sponsor { | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
|   border-radius: 16px; |   border-radius: 16px; | ||||||
|   padding: 12px 20px; |   padding: 12px 20px; | ||||||
|   width: 400px; |   width: 400px; | ||||||
|  | |||||||
| @ -92,7 +92,7 @@ | |||||||
| 
 | 
 | ||||||
|       &.target { |       &.target { | ||||||
|         .fill { |         .fill { | ||||||
|           background: #653b9c; |           background: var(--tertiary); | ||||||
|         } |         } | ||||||
|         .fee { |         .fee { | ||||||
|           position: absolute; |           position: absolute; | ||||||
| @ -114,7 +114,7 @@ | |||||||
|         } |         } | ||||||
|         &.active, &:hover { |         &.active, &:hover { | ||||||
|           .fill { |           .fill { | ||||||
|             background: #105fb0; |             background: var(--primary); | ||||||
|           } |           } | ||||||
|           .line { |           .line { | ||||||
|             .fee-rate .label { |             .fee-rate .label { | ||||||
|  | |||||||
| @ -65,6 +65,7 @@ | |||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|       <br> |       <br> | ||||||
|  |       @if (paymentType !== 'cashapp') { | ||||||
|         <h5 i18n="accelerator.pay-how-much">How much more are you willing to pay?</h5> |         <h5 i18n="accelerator.pay-how-much">How much more are you willing to pay?</h5> | ||||||
|         <div class="row"> |         <div class="row"> | ||||||
|           <div class="col"> |           <div class="col"> | ||||||
| @ -83,6 +84,7 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|  |       } | ||||||
|    |    | ||||||
|       <h5>Acceleration summary</h5> |       <h5>Acceleration summary</h5> | ||||||
|       <div class="row mb-3"> |       <div class="row mb-3"> | ||||||
| @ -90,6 +92,29 @@ | |||||||
|           <table class="table table-borderless table-border table-dark table-accelerator"> |           <table class="table table-borderless table-border table-dark table-accelerator"> | ||||||
|             <tbody> |             <tbody> | ||||||
|               <!-- ESTIMATED FEE --> |               <!-- ESTIMATED FEE --> | ||||||
|  |               @if (paymentType === 'cashapp') { | ||||||
|  |                 <ng-container> | ||||||
|  |                   <tr class="group-first"> | ||||||
|  |                     <td class="item" i18n="accelerator.boost-rate">Boost rate</td> | ||||||
|  |                     <td class="amt" style="font-size: 16px"> | ||||||
|  |                       {{ maxRateOptions[selectFeeRateIndex].rate | number : '1.0-0' }} | ||||||
|  |                     </td> | ||||||
|  |                     <td class="units"><span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td> | ||||||
|  |                   </tr> | ||||||
|  |                   <tr class="info"> | ||||||
|  |                     <td class="info"> | ||||||
|  |                       <i><small i18n="accelerator.estimated-extra-fee-required">Boost fee</small></i> | ||||||
|  |                     </td> | ||||||
|  |                     <td class="amt"> | ||||||
|  |                       {{ maxRateOptions[selectFeeRateIndex].fee | number }} | ||||||
|  |                     </td> | ||||||
|  |                     <td class="units"> | ||||||
|  |                       <span class="symbol" i18n="shared.sats">sats</span> | ||||||
|  |                       <span class="fiat ml-1"><app-fiat [value]="maxRateOptions[selectFeeRateIndex].fee"></app-fiat></span> | ||||||
|  |                     </td> | ||||||
|  |                   </tr> | ||||||
|  |                 </ng-container> | ||||||
|  |               } @else { | ||||||
|                 <ng-container> |                 <ng-container> | ||||||
|                   <tr class="group-first"> |                   <tr class="group-first"> | ||||||
|                     <td class="item" i18n="accelerator.next-block-rate">Next block market rate</td> |                     <td class="item" i18n="accelerator.next-block-rate">Next block market rate</td> | ||||||
| @ -111,6 +136,7 @@ | |||||||
|                     </td> |                     </td> | ||||||
|                   </tr> |                   </tr> | ||||||
|                 </ng-container> |                 </ng-container> | ||||||
|  |               } | ||||||
|    |    | ||||||
|               <!-- MEMPOOL BASE FEE --> |               <!-- MEMPOOL BASE FEE --> | ||||||
|               <tr> |               <tr> | ||||||
| @ -141,6 +167,28 @@ | |||||||
|                 </td> |                 </td> | ||||||
|               </tr> |               </tr> | ||||||
| 
 | 
 | ||||||
|  |                | ||||||
|  |               @if (paymentType === 'cashapp') { | ||||||
|  |                 <!-- FIXED COST --> | ||||||
|  |                 <ng-container> | ||||||
|  |                   <tr class="group-first group-last" style="border-top: 1px solid lightgrey; border-collapse: collapse;"> | ||||||
|  |                     <td class="item"> | ||||||
|  |                       <b style="background-color: #105fb0;" class="p-1 pl-0" i18n="accelerator.total-cost">Total cost</b> | ||||||
|  |                     </td> | ||||||
|  |                     <td class="amt"> | ||||||
|  |                       <span style="background-color: #105fb0" class="p-1 pl-0"> | ||||||
|  |                         {{ maxCost | number }} | ||||||
|  |                       </span> | ||||||
|  |                     </td> | ||||||
|  |                     <td class="units"> | ||||||
|  |                       <span class="symbol" i18n="shared.sats">sats</span> | ||||||
|  |                       <span class="fiat ml-1"> | ||||||
|  |                         <app-fiat [value]="maxCost" [colorClass]="'green-color'"></app-fiat> | ||||||
|  |                       </span> | ||||||
|  |                     </td> | ||||||
|  |                   </tr> | ||||||
|  |                 </ng-container> | ||||||
|  |               } @else { | ||||||
|                 <!-- NEXT BLOCK ESTIMATE --> |                 <!-- NEXT BLOCK ESTIMATE --> | ||||||
|                 <ng-container> |                 <ng-container> | ||||||
|                   <tr class="group-first" style="border-top: 1px dashed grey; border-collapse: collapse;"> |                   <tr class="group-first" style="border-top: 1px dashed grey; border-collapse: collapse;"> | ||||||
| @ -168,10 +216,10 @@ | |||||||
|                 <ng-container> |                 <ng-container> | ||||||
|                   <tr class="group-first"> |                   <tr class="group-first"> | ||||||
|                     <td class="item"> |                     <td class="item"> | ||||||
|                     <b style="background-color: #105fb0;" class="p-1 pl-0" i18n="accelerator.maximum-cost">Maximum acceleration cost</b> |                       <b style="background-color: var(--primary);" class="p-1 pl-0" i18n="accelerator.maximum-cost">Maximum acceleration cost</b> | ||||||
|                     </td> |                     </td> | ||||||
|                     <td class="amt"> |                     <td class="amt"> | ||||||
|                     <span style="background-color: #105fb0" class="p-1 pl-0"> |                       <span style="background-color: var(--primary)" class="p-1 pl-0"> | ||||||
|                         {{ maxCost | number }} |                         {{ maxCost | number }} | ||||||
|                       </span> |                       </span> | ||||||
|                     </td> |                     </td> | ||||||
| @ -188,6 +236,7 @@ | |||||||
|                     </td> |                     </td> | ||||||
|                   </tr> |                   </tr> | ||||||
|                 </ng-container> |                 </ng-container> | ||||||
|  |               } | ||||||
|    |    | ||||||
|               <!-- USER BALANCE --> |               <!-- USER BALANCE --> | ||||||
|               <ng-container *ngIf="isLoggedIn() && estimate.userBalance < maxCost"> |               <ng-container *ngIf="isLoggedIn() && estimate.userBalance < maxCost"> | ||||||
| @ -237,14 +286,17 @@ | |||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
| 
 | 
 | ||||||
|       <div class="row d-flex justify-content-end align-items-center mr-1" style="height: 48px" *ngIf="!hideCashApp && paymentType === 'cashapp'"> |       @if (!hideCashApp && paymentType === 'cashapp') { | ||||||
|         <div [style]="showSpinner ? 'opacity: 0' : 'opacity: 1'" class="p-2">Accelerate with</div> |         <div #cashappCTA class="cashapp-placeholder {{ stickyCTA }}"></div> | ||||||
|  |         <div class="d-flex justify-content-center align-items-center cashapp-cta {{ stickyCTA }}" (click)="submitCashappPay()"> | ||||||
|  |           <div [style]="showSpinner ? 'opacity: 0' : 'opacity: 1'" class="p-2">Accelerate for <app-fiat [value]="maxCost" [colorClass]="estimate.userBalance < maxCost ? 'red-color' : 'green-color'"></app-fiat> with</div> | ||||||
|           <div id="cash-app-pay" style="max-width: 320px" [style]="showSpinner ? 'opacity: 0' : 'opacity: 1'"></div> |           <div id="cash-app-pay" style="max-width: 320px" [style]="showSpinner ? 'opacity: 0' : 'opacity: 1'"></div> | ||||||
|           <div *ngIf="showSpinner" class="d-flex align-items-center"> |           <div *ngIf="showSpinner" class="d-flex align-items-center"> | ||||||
|             <span class="mr-2">Loading</span> |             <span class="mr-2">Loading</span> | ||||||
|             <div class="spinner-border text-light" style="width: 25px; height: 25px"></div> |             <div class="spinner-border text-light" style="width: 25px; height: 25px"></div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|  |       } | ||||||
|    |    | ||||||
|     </div> |     </div> | ||||||
|   </ng-container> |   </ng-container> | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| .fee-card { | .fee-card { | ||||||
|   padding: 15px; |   padding: 15px; | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
| 
 | 
 | ||||||
|   .feerate { |   .feerate { | ||||||
|     display: flex; |     display: flex; | ||||||
| @ -23,7 +23,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .feerate.active { | .feerate.active { | ||||||
|   background-color: #105fb0 !important; |   background-color: var(--primary) !important; | ||||||
|   opacity: 1; |   opacity: 1; | ||||||
|   border: 1px solid #007fff !important; |   border: 1px solid #007fff !important; | ||||||
| } | } | ||||||
| @ -110,3 +110,60 @@ | |||||||
| .item { | .item { | ||||||
|   white-space: initial; |   white-space: initial; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .cashapp-cta { | ||||||
|  |   width: 100%; | ||||||
|  |   height: 54px; | ||||||
|  |   background: #653b9c; | ||||||
|  |   position: relative; | ||||||
|  |   bottom: initial; | ||||||
|  |   top: initial; | ||||||
|  |   border-radius: 3px; | ||||||
|  |   font-size: 14px; | ||||||
|  |   line-height: 16px; | ||||||
|  |   text-align: center; | ||||||
|  |   padding: 4px 6px; | ||||||
|  |   cursor: pointer; | ||||||
|  |   box-shadow: 0px 0px 15px 0px #000; | ||||||
|  | 
 | ||||||
|  |   &.sticky-top { | ||||||
|  |     position: fixed; | ||||||
|  |     width: calc(100vw - 30px - 1.5rem); | ||||||
|  |     margin: auto; | ||||||
|  |     z-index: 50; | ||||||
|  |     left: 0; | ||||||
|  |     right: 0; | ||||||
|  |     top: 102px; | ||||||
|  |     @media (min-width: 573px) { | ||||||
|  |       top: 62px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   &.sticky-bottom { | ||||||
|  |     position: fixed; | ||||||
|  |     width: calc(100vw - 30px - 1.5rem); | ||||||
|  |     margin: auto; | ||||||
|  |     z-index: 50; | ||||||
|  |     left: 0; | ||||||
|  |     right: 0; | ||||||
|  |     bottom: 50px; | ||||||
|  |     @media (min-width: 430px) { | ||||||
|  |       bottom: 56px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @media (max-width: 400px) { | ||||||
|  |     width: calc(100% + 1.5rem); | ||||||
|  |     margin: 0 -0.75rem; | ||||||
|  |     &.sticky-top, &.sticky-bottom { | ||||||
|  |       width: calc(100vw - 30px); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .cashapp-placeholder { | ||||||
|  |   height: 54px; | ||||||
|  | 
 | ||||||
|  |   &.non-stick { | ||||||
|  |     height: 0px; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,4 +1,4 @@ | |||||||
| import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges, HostListener, ChangeDetectorRef } from '@angular/core'; | import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges, HostListener, ChangeDetectorRef, ViewChild, ElementRef } from '@angular/core'; | ||||||
| import { Subscription, catchError, of, tap } from 'rxjs'; | import { Subscription, catchError, of, tap } from 'rxjs'; | ||||||
| import { StorageService } from '../../services/storage.service'; | import { StorageService } from '../../services/storage.service'; | ||||||
| import { Transaction } from '../../interfaces/electrs.interface'; | import { Transaction } from '../../interfaces/electrs.interface'; | ||||||
| @ -43,6 +43,9 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|   @Input() tx: Transaction | undefined; |   @Input() tx: Transaction | undefined; | ||||||
|   @Input() scrollEvent: boolean; |   @Input() scrollEvent: boolean; | ||||||
| 
 | 
 | ||||||
|  |   @ViewChild('cashappCTA') | ||||||
|  |   cashappCTA: ElementRef; | ||||||
|  | 
 | ||||||
|   math = Math; |   math = Math; | ||||||
|   error = ''; |   error = ''; | ||||||
|   showSuccess = false; |   showSuccess = false; | ||||||
| @ -56,9 +59,11 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|   defaultBid = 0; |   defaultBid = 0; | ||||||
|   maxCost = 0; |   maxCost = 0; | ||||||
|   userBid = 0; |   userBid = 0; | ||||||
|  |   accelerationUUID: string; | ||||||
|   selectFeeRateIndex = 1; |   selectFeeRateIndex = 1; | ||||||
|   isMobile: boolean = window.innerWidth <= 767.98; |   isMobile: boolean = window.innerWidth <= 767.98; | ||||||
|   user: any = undefined; |   user: any = undefined; | ||||||
|  |   stickyCTA: string = 'non-stick'; | ||||||
| 
 | 
 | ||||||
|   maxRateOptions: RateOption[] = []; |   maxRateOptions: RateOption[] = []; | ||||||
| 
 | 
 | ||||||
| @ -66,6 +71,7 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|   paymentType: 'bitcoin' | 'cashapp' = 'bitcoin'; |   paymentType: 'bitcoin' | 'cashapp' = 'bitcoin'; | ||||||
|   cashAppSubscription: Subscription; |   cashAppSubscription: Subscription; | ||||||
|   conversionsSubscription: Subscription; |   conversionsSubscription: Subscription; | ||||||
|  |   cashappSubmit: any; | ||||||
|   payments: any; |   payments: any; | ||||||
|   showSpinner = false; |   showSpinner = false; | ||||||
|   square: any; |   square: any; | ||||||
| @ -80,7 +86,10 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|     private cd: ChangeDetectorRef |     private cd: ChangeDetectorRef | ||||||
|   ) { |   ) { | ||||||
|     if (this.stateService.ref === 'https://cash.app/') { |     if (this.stateService.ref === 'https://cash.app/') { | ||||||
|  |       this.paymentType = 'cashapp'; | ||||||
|       this.insertSquare(); |       this.insertSquare(); | ||||||
|  |     } else { | ||||||
|  |       this.paymentType = 'bitcoin'; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -94,21 +103,23 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ngOnInit() { |   ngOnInit() { | ||||||
|  |     this.accelerationUUID = window.crypto.randomUUID(); | ||||||
|     if (this.stateService.ref === 'https://cash.app/') { |     if (this.stateService.ref === 'https://cash.app/') { | ||||||
|       this.paymentType = 'cashapp'; |       this.paymentType = 'cashapp'; | ||||||
|       this.stateService.ref = ''; |  | ||||||
|     } else { |     } else { | ||||||
|       this.paymentType = 'bitcoin'; |       this.paymentType = 'bitcoin'; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ngOnChanges(changes: SimpleChanges): void { |   ngOnChanges(changes: SimpleChanges): void { | ||||||
|     if (changes.scrollEvent) { |     if (changes.scrollEvent && this.paymentType !== 'cashapp' && this.stateService.ref !== 'https://cash.app/') { | ||||||
|       this.scrollToPreview('acceleratePreviewAnchor', 'start'); |       this.scrollToPreview('acceleratePreviewAnchor', 'start'); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ngAfterViewInit() { |   ngAfterViewInit() { | ||||||
|  |     this.onScroll(); | ||||||
|  | 
 | ||||||
|     if (this.paymentType === 'cashapp') { |     if (this.paymentType === 'cashapp') { | ||||||
|       this.showSpinner = true; |       this.showSpinner = true; | ||||||
|     } |     } | ||||||
| @ -173,10 +184,15 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|             this.maxCost = this.userBid + this.estimate.mempoolBaseFee + this.estimate.vsizeFee; |             this.maxCost = this.userBid + this.estimate.mempoolBaseFee + this.estimate.vsizeFee; | ||||||
| 
 | 
 | ||||||
|             if (!this.error) { |             if (!this.error) { | ||||||
|               this.scrollToPreview('acceleratePreviewAnchor', 'start'); |  | ||||||
|               if (this.paymentType === 'cashapp') { |               if (this.paymentType === 'cashapp') { | ||||||
|                 this.setupSquare(); |                 this.setupSquare(); | ||||||
|  |               } else { | ||||||
|  |                 this.scrollToPreview('acceleratePreviewAnchor', 'start'); | ||||||
|               } |               } | ||||||
|  | 
 | ||||||
|  |               setTimeout(() => { | ||||||
|  |                 this.onScroll(); | ||||||
|  |               }, 100); | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         }), |         }), | ||||||
| @ -231,7 +247,8 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|     } |     } | ||||||
|     this.accelerationSubscription = this.servicesApiService.accelerate$( |     this.accelerationSubscription = this.servicesApiService.accelerate$( | ||||||
|       this.tx.txid, |       this.tx.txid, | ||||||
|       this.userBid |       this.userBid, | ||||||
|  |       this.accelerationUUID | ||||||
|     ).subscribe({ |     ).subscribe({ | ||||||
|       next: () => { |       next: () => { | ||||||
|         this.audioService.playSound('ascend-chime-cartoon'); |         this.audioService.playSound('ascend-chime-cartoon'); | ||||||
| @ -301,6 +318,10 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|      |      | ||||||
|     this.conversionsSubscription = this.stateService.conversions$.subscribe( |     this.conversionsSubscription = this.stateService.conversions$.subscribe( | ||||||
|       async (conversions) => { |       async (conversions) => { | ||||||
|  |         if (this.cashAppPay) { | ||||||
|  |           this.cashAppPay.destroy(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         const maxCostUsd = this.maxCost / 100_000_000 * conversions.USD; |         const maxCostUsd = this.maxCost / 100_000_000 * conversions.USD; | ||||||
|         const paymentRequest = this.payments.paymentRequest({ |         const paymentRequest = this.payments.paymentRequest({ | ||||||
|           countryCode: 'US', |           countryCode: 'US', | ||||||
| @ -310,13 +331,15 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|             label: 'Total', |             label: 'Total', | ||||||
|             pending: true, |             pending: true, | ||||||
|             productUrl: `https://mempool.space/tx/${this.tx.txid}`, |             productUrl: `https://mempool.space/tx/${this.tx.txid}`, | ||||||
|           } |           }, | ||||||
|  |           button: { shape: 'semiround', size: 'small', theme: 'light'} | ||||||
|         }); |         }); | ||||||
|         this.cashAppPay = await this.payments.cashAppPay(paymentRequest, { |         this.cashAppPay = await this.payments.cashAppPay(paymentRequest, { | ||||||
|           redirectURL: `https://mempool.space/tx/${this.tx.txid}`, |           redirectURL: `https://mempool.space/tx/${this.tx.txid}`, | ||||||
|           referenceId: `accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`, |           referenceId: `accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`, | ||||||
|  |           button: { shape: 'semiround', size: 'small', theme: 'light'} | ||||||
|         }); |         }); | ||||||
|         await this.cashAppPay.attach('#cash-app-pay'); |         const renderPromise = this.cashAppPay.CashAppPayInstance.render('#cash-app-pay', { button: { theme: 'light', size: 'small', shape: 'semiround' }, manage: false }); | ||||||
|         this.showSpinner = false; |         this.showSpinner = false; | ||||||
|          |          | ||||||
|         const that = this; |         const that = this; | ||||||
| @ -332,7 +355,8 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|               that.userBid, |               that.userBid, | ||||||
|               tokenResult.token, |               tokenResult.token, | ||||||
|               tokenResult.details.cashAppPay.cashtag, |               tokenResult.details.cashAppPay.cashtag, | ||||||
|               tokenResult.details.cashAppPay.referenceId |               tokenResult.details.cashAppPay.referenceId, | ||||||
|  |               that.accelerationUUID | ||||||
|             ).subscribe({ |             ).subscribe({ | ||||||
|               next: () => { |               next: () => { | ||||||
|                 that.audioService.playSound('ascend-chime-cartoon'); |                 that.audioService.playSound('ascend-chime-cartoon'); | ||||||
| @ -351,13 +375,19 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|             }); |             }); | ||||||
|           } |           } | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |         this.cashappSubmit = await renderPromise; | ||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   insertSquare(): void { |   insertSquare(): void { | ||||||
|     let statsUrl = 'https://sandbox.web.squarecdn.com/v1/square.js'; |     let statsUrl = 'https://sandbox.web.squarecdn.com/v1/square.js'; | ||||||
|     if (document.location.hostname === 'mempool-staging.tk7.mempool.space' || document.location.hostname === 'mempool.space') { |     if (document.location.hostname === 'mempool-staging.fmt.mempool.space' || | ||||||
|  |         document.location.hostname === 'mempool-staging.va1.mempool.space' || | ||||||
|  |         document.location.hostname === 'mempool-staging.fra.mempool.space' || | ||||||
|  |         document.location.hostname === 'mempool-staging.tk7.mempool.space' || | ||||||
|  |         document.location.hostname === 'mempool.space') { | ||||||
|       statsUrl = 'https://web.squarecdn.com/v1/square.js'; |       statsUrl = 'https://web.squarecdn.com/v1/square.js'; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -367,4 +397,34 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges | |||||||
|       g.type='text/javascript'; g.src=statsUrl; s.parentNode.insertBefore(g, s); |       g.type='text/javascript'; g.src=statsUrl; s.parentNode.insertBefore(g, s); | ||||||
|     })(); |     })(); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   submitCashappPay(): void { | ||||||
|  |     if (this.cashappSubmit) { | ||||||
|  |       this.cashappSubmit?.begin(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @HostListener('window:scroll', ['$event']) // for window scroll events
 | ||||||
|  |   onScroll() { | ||||||
|  |     if (this.estimate && !this.cashappCTA?.nativeElement) { | ||||||
|  |       setTimeout(() => { | ||||||
|  |         this.onScroll(); | ||||||
|  |       }, 200); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if (!this.cashappCTA?.nativeElement || this.paymentType !== 'cashapp' || !this.isMobile) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     const cta = this.cashappCTA.nativeElement; | ||||||
|  |     const rect = cta.getBoundingClientRect(); | ||||||
|  |     const topOffset = window.innerWidth <= 572 ? 102 : 62; | ||||||
|  |     const bottomOffset = window.innerWidth < 430 ? 50 : 56; | ||||||
|  |     if (rect.top < topOffset) { | ||||||
|  |       this.stickyCTA = 'sticky-top'; | ||||||
|  |     } else if (rect.top > window.innerHeight - (bottomOffset + 54)) { | ||||||
|  |       this.stickyCTA = 'sticky-bottom'; | ||||||
|  |     } else { | ||||||
|  |       this.stickyCTA = 'non-stick'; | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -45,7 +45,7 @@ | |||||||
|     </form> |     </form> | ||||||
|   </div> |   </div> | ||||||
| 
 | 
 | ||||||
|   <div [class.chart]="!widget" [class.chart-widget]="widget" *browserOnly echarts [initOpts]="chartInitOptions" [options]="chartOptions" |   <div [class.chart]="!widget" [class.chart-widget]="widget" *browserOnly [style]="{ height: widget ? ((height + 20) + 'px') : null}" echarts [initOpts]="chartInitOptions" [options]="chartOptions" | ||||||
|     (chartInit)="onChartInit($event)"> |     (chartInit)="onChartInit($event)"> | ||||||
|   </div> |   </div> | ||||||
|   <div class="text-center loadingGraphs" *ngIf="!stateService.isBrowser || isLoading"> |   <div class="text-center loadingGraphs" *ngIf="!stateService.isBrowser || isLoading"> | ||||||
|  | |||||||
| @ -62,7 +62,7 @@ h5 { | |||||||
| 
 | 
 | ||||||
| .card-title { | .card-title { | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .disabled { | .disabled { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| .card-title { | .card-title { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
|   font-size: 10px; |   font-size: 10px; | ||||||
|   margin-bottom: 4px;   |   margin-bottom: 4px;   | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
|  | |||||||
| @ -39,10 +39,10 @@ | |||||||
|             </td> |             </td> | ||||||
|           </ng-container> |           </ng-container> | ||||||
|           <ng-container *ngIf="!pending"> |           <ng-container *ngIf="!pending"> | ||||||
|             <td *ngIf="acceleration.feePaid" class="fee text-right"> |             <td *ngIf="acceleration.boost != null" class="fee text-right"> | ||||||
|               {{ (acceleration.boost) | number }} <span class="symbol" i18n="shared.sat|sat">sat</span> |               {{ acceleration.boost | number }} <span class="symbol" i18n="shared.sat|sat">sat</span> | ||||||
|             </td> |             </td> | ||||||
|             <td *ngIf="!acceleration.feePaid" class="fee text-right"> |             <td *ngIf="acceleration.boost == null" class="fee text-right"> | ||||||
|               ~ |               ~ | ||||||
|             </td> |             </td> | ||||||
|             <td class="block text-right"> |             <td class="block text-right"> | ||||||
|  | |||||||
| @ -59,7 +59,7 @@ tr, td, th { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .progress { | .progress { | ||||||
|   background-color: #2d3348; |   background-color: var(--secondary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .txid { | .txid { | ||||||
| @ -148,7 +148,7 @@ tr, td, th { | |||||||
| 
 | 
 | ||||||
| .tooltip-custom .tooltiptext { | .tooltip-custom .tooltiptext { | ||||||
|   visibility: hidden; |   visibility: hidden; | ||||||
|   color: #fff; |   color: var(--fg); | ||||||
|   text-align: center; |   text-align: center; | ||||||
|   padding: 5px 0; |   padding: 5px 0; | ||||||
|   border-radius: 6px; |   border-radius: 6px; | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ export class AccelerationsListComponent implements OnInit { | |||||||
|               } |               } | ||||||
|             } |             } | ||||||
|             for (const acc of accelerations) { |             for (const acc of accelerations) { | ||||||
|               acc.boost = acc.feePaid - acc.baseFee - acc.vsizeFee; |               acc.boost = acc.boostCost != null ? acc.boostCost : (acc.feePaid - acc.baseFee - acc.vsizeFee); | ||||||
|             } |             } | ||||||
|             if (this.widget) { |             if (this.widget) { | ||||||
|               return of(accelerations.slice(0, 6)); |               return of(accelerations.slice(0, 6)); | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ | |||||||
|           <a class="title-link" href="" [routerLink]="['/mempool-block/0' | relativeUrl]"> |           <a class="title-link" href="" [routerLink]="['/mempool-block/0' | relativeUrl]"> | ||||||
|             <h5 class="card-title d-inline">Mempool Goggles™ : <ng-container i18n="accelerator.accelerations">Accelerations</ng-container></h5> |             <h5 class="card-title d-inline">Mempool Goggles™ : <ng-container i18n="accelerator.accelerations">Accelerations</ng-container></h5> | ||||||
|             <span> </span> |             <span> </span> | ||||||
|             <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: #4a68b9"></fa-icon> |             <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: var(--title-fg)"></fa-icon> | ||||||
|           </a> |           </a> | ||||||
|           <div class="mempool-block-wrapper" *ngIf="webGlEnabled"> |           <div class="mempool-block-wrapper" *ngIf="webGlEnabled"> | ||||||
|             <app-mempool-block-overview [index]="0" [overrideColors]="getAcceleratorColor"></app-mempool-block-overview> |             <app-mempool-block-overview [index]="0" [overrideColors]="getAcceleratorColor"></app-mempool-block-overview> | ||||||
| @ -85,7 +85,7 @@ | |||||||
|           <a class="title-link" href="" [routerLink]="['/acceleration/list' | relativeUrl]"> |           <a class="title-link" href="" [routerLink]="['/acceleration/list' | relativeUrl]"> | ||||||
|             <h5 class="card-title d-inline" i18n="dashboard.recent-accelerations">Recent Accelerations</h5> |             <h5 class="card-title d-inline" i18n="dashboard.recent-accelerations">Recent Accelerations</h5> | ||||||
|             <span> </span> |             <span> </span> | ||||||
|             <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: #4a68b9"></fa-icon> |             <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: var(--title-fg)"></fa-icon> | ||||||
|           </a> |           </a> | ||||||
|           <app-accelerations-list [attr.data-cy]="'recent-accelerations'" [widget]=true [accelerations$]="minedAccelerations$"></app-accelerations-list> |           <app-accelerations-list [attr.data-cy]="'recent-accelerations'" [widget]=true [accelerations$]="minedAccelerations$"></app-accelerations-list> | ||||||
|         </div> |         </div> | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .card { | .card { | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .graph-card { | .graph-card { | ||||||
| @ -29,10 +29,10 @@ | |||||||
| 
 | 
 | ||||||
| .card-title { | .card-title { | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
| } | } | ||||||
| .card-title > a { | .card-title > a { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .card-body.pool-ranking { | .card-body.pool-ranking { | ||||||
|  | |||||||
| @ -8,13 +8,15 @@ import { Observable, catchError, combineLatest, distinctUntilChanged, interval, | |||||||
| import { Color } from '../../block-overview-graph/sprite-types'; | import { Color } from '../../block-overview-graph/sprite-types'; | ||||||
| import { hexToColor } from '../../block-overview-graph/utils'; | import { hexToColor } from '../../block-overview-graph/utils'; | ||||||
| import TxView from '../../block-overview-graph/tx-view'; | import TxView from '../../block-overview-graph/tx-view'; | ||||||
| import { feeLevels, mempoolFeeColors } from '../../../app.constants'; | import { feeLevels, defaultMempoolFeeColors, contrastMempoolFeeColors } from '../../../app.constants'; | ||||||
| import { ServicesApiServices } from '../../../services/services-api.service'; | import { ServicesApiServices } from '../../../services/services-api.service'; | ||||||
| import { detectWebGL } from '../../../shared/graphs.utils'; | import { detectWebGL } from '../../../shared/graphs.utils'; | ||||||
| import { AudioService } from '../../../services/audio.service'; | import { AudioService } from '../../../services/audio.service'; | ||||||
|  | import { ThemeService } from '../../../services/theme.service'; | ||||||
| 
 | 
 | ||||||
| const acceleratedColor: Color = hexToColor('8F5FF6'); | const acceleratedColor: Color = hexToColor('8F5FF6'); | ||||||
| const normalColors = mempoolFeeColors.map(hex => hexToColor(hex.slice(0,6) + '5F')); | const normalColors = defaultMempoolFeeColors.map(hex => hexToColor(hex + '5F')); | ||||||
|  | const contrastColors = contrastMempoolFeeColors.map(hex => hexToColor(hex.slice(0,6) + '5F')); | ||||||
| 
 | 
 | ||||||
| interface AccelerationBlock extends BlockExtended { | interface AccelerationBlock extends BlockExtended { | ||||||
|   accelerationCount: number, |   accelerationCount: number, | ||||||
| @ -37,6 +39,7 @@ export class AcceleratorDashboardComponent implements OnInit { | |||||||
|   firstLoad = true; |   firstLoad = true; | ||||||
| 
 | 
 | ||||||
|   graphHeight: number = 300; |   graphHeight: number = 300; | ||||||
|  |   theme: ThemeService; | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     private seoService: SeoService, |     private seoService: SeoService, | ||||||
| @ -116,15 +119,15 @@ export class AcceleratorDashboardComponent implements OnInit { | |||||||
|       switchMap(([accelerations, blocks]) => { |       switchMap(([accelerations, blocks]) => { | ||||||
|         const blockMap = {}; |         const blockMap = {}; | ||||||
|         for (const block of blocks) { |         for (const block of blocks) { | ||||||
|           blockMap[block.id] = block; |           blockMap[block.height] = block; | ||||||
|         } |         } | ||||||
|         const accelerationsByBlock: { [ hash: string ]: Acceleration[] } = {}; |         const accelerationsByBlock: { [ height: number ]: Acceleration[] } = {}; | ||||||
|         for (const acceleration of accelerations) { |         for (const acceleration of accelerations) { | ||||||
|           if (['completed_provisional', 'failed_provisional', 'completed'].includes(acceleration.status) && acceleration.pools.includes(blockMap[acceleration.blockHash]?.extras.pool.id)) { |           if (['completed_provisional', 'failed_provisional', 'completed'].includes(acceleration.status) && acceleration.pools.includes(blockMap[acceleration.blockHeight]?.extras.pool.id)) { | ||||||
|             if (!accelerationsByBlock[acceleration.blockHash]) { |             if (!accelerationsByBlock[acceleration.blockHeight]) { | ||||||
|               accelerationsByBlock[acceleration.blockHash] = []; |               accelerationsByBlock[acceleration.blockHeight] = []; | ||||||
|             } |             } | ||||||
|             accelerationsByBlock[acceleration.blockHash].push(acceleration); |             accelerationsByBlock[acceleration.blockHeight].push(acceleration); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         return of(blocks.slice(0, 6).map(block => { |         return of(blocks.slice(0, 6).map(block => { | ||||||
| @ -141,7 +144,7 @@ export class AcceleratorDashboardComponent implements OnInit { | |||||||
|     } else { |     } else { | ||||||
|       const rate = tx.fee / tx.vsize; // color by simple single-tx fee rate
 |       const rate = tx.fee / tx.vsize; // color by simple single-tx fee rate
 | ||||||
|       const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1; |       const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1; | ||||||
|       return normalColors[feeLevelIndex] || normalColors[mempoolFeeColors.length - 1]; |       return this.theme.theme === 'contrast' ? contrastColors[feeLevelIndex] || contrastColors[contrastColors.length - 1] : normalColors[feeLevelIndex] || normalColors[normalColors.length - 1]; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| .card-title { | .card-title { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
|   font-size: 10px; |   font-size: 10px; | ||||||
|   margin-bottom: 4px;   |   margin-bottom: 4px;   | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import { ChainStats } from '../../interfaces/electrs.interface'; | |||||||
| import { ElectrsApiService } from '../../services/electrs-api.service'; | import { ElectrsApiService } from '../../services/electrs-api.service'; | ||||||
| import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe'; | import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe'; | ||||||
| import { Router } from '@angular/router'; | import { Router } from '@angular/router'; | ||||||
|  | import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-address-graph', |   selector: 'app-address-graph', | ||||||
| @ -46,6 +47,7 @@ export class AddressGraphComponent implements OnChanges { | |||||||
|     private router: Router, |     private router: Router, | ||||||
|     private amountShortenerPipe: AmountShortenerPipe, |     private amountShortenerPipe: AmountShortenerPipe, | ||||||
|     private cd: ChangeDetectorRef, |     private cd: ChangeDetectorRef, | ||||||
|  |     private relativeUrlPipe: RelativeUrlPipe, | ||||||
|   ) {} |   ) {} | ||||||
| 
 | 
 | ||||||
|   ngOnChanges(changes: SimpleChanges): void { |   ngOnChanges(changes: SimpleChanges): void { | ||||||
| @ -159,7 +161,7 @@ export class AddressGraphComponent implements OnChanges { | |||||||
|       ], |       ], | ||||||
|       series: [ |       series: [ | ||||||
|         { |         { | ||||||
|           name: $localize`Balance:Balance`, |           name: $localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`, | ||||||
|           showSymbol: false, |           showSymbol: false, | ||||||
|           symbol: 'circle', |           symbol: 'circle', | ||||||
|           symbolSize: 8, |           symbolSize: 8, | ||||||
| @ -178,7 +180,7 @@ export class AddressGraphComponent implements OnChanges { | |||||||
| 
 | 
 | ||||||
|   onChartClick(e) { |   onChartClick(e) { | ||||||
|     if (this.hoverData?.length && this.hoverData[0]?.[2]?.txid) { |     if (this.hoverData?.length && this.hoverData[0]?.[2]?.txid) { | ||||||
|       this.router.navigate(['/tx/', this.hoverData[0][2].txid]); |       this.router.navigate([this.relativeUrlPipe.transform('/tx/'), this.hoverData[0][2].txid]); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .qr-wrapper { | .qr-wrapper { | ||||||
|   background-color: #FFF; |   background-color: var(--fg); | ||||||
|   padding: 10px; |   padding: 10px; | ||||||
|   padding-bottom: 5px; |   padding-bottom: 5px; | ||||||
|   display: inline-block; |   display: inline-block; | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| .qr-wrapper { | .qr-wrapper { | ||||||
|   background-color: #FFF; |   background-color: var(--fg); | ||||||
|   padding: 10px; |   padding: 10px; | ||||||
|   padding-bottom: 5px; |   padding-bottom: 5px; | ||||||
|   display: inline-block; |   display: inline-block; | ||||||
|  | |||||||
| @ -1,3 +1,3 @@ | |||||||
| .green-color { | .green-color { | ||||||
|   color: #3bcc49; |   color: var(--green); | ||||||
| } | } | ||||||
| @ -1,5 +1,5 @@ | |||||||
| .qr-wrapper { | .qr-wrapper { | ||||||
|   background-color: #FFF; |   background-color: var(--fg); | ||||||
|   padding: 10px; |   padding: 10px; | ||||||
|   padding-bottom: 5px; |   padding-bottom: 5px; | ||||||
|   display: inline-block; |   display: inline-block; | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .card { | .card { | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
|   width: 200px; |   width: 200px; | ||||||
|   height: 200px; |   height: 200px; | ||||||
|   align-items: center; |   align-items: center; | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .card { | .card { | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
|   width: 200px; |   width: 200px; | ||||||
|   height: 200px; |   height: 200px; | ||||||
|   align-items: center; |   align-items: center; | ||||||
|  | |||||||
| @ -95,7 +95,7 @@ | |||||||
|     } |     } | ||||||
|     .card-title { |     .card-title { | ||||||
|       font-size: 1rem; |       font-size: 1rem; | ||||||
|       color: #4a68b9; |       color: var(--title-fg); | ||||||
|     } |     } | ||||||
|     .card-text { |     .card-text { | ||||||
|       font-size: 18px; |       font-size: 18px; | ||||||
|  | |||||||
| @ -233,7 +233,7 @@ export class BlockFeeRatesGraphComponent implements OnInit { | |||||||
|         borderRadius: 4, |         borderRadius: 4, | ||||||
|         shadowColor: 'rgba(0, 0, 0, 0.5)', |         shadowColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|         textStyle: { |         textStyle: { | ||||||
|           color: '#b1b1b1', |           color: 'var(--tooltip-grey)', | ||||||
|           align: 'left', |           align: 'left', | ||||||
|         }, |         }, | ||||||
|         borderColor: '#000', |         borderColor: '#000', | ||||||
| @ -309,7 +309,7 @@ export class BlockFeeRatesGraphComponent implements OnInit { | |||||||
|         splitLine: { |         splitLine: { | ||||||
|           lineStyle: { |           lineStyle: { | ||||||
|             type: 'dotted', |             type: 'dotted', | ||||||
|             color: '#ffffff66', |             color: 'var(--transparent-fg)', | ||||||
|             opacity: 0.25, |             opacity: 0.25, | ||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
| @ -376,7 +376,7 @@ export class BlockFeeRatesGraphComponent implements OnInit { | |||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     this.chartOptions.grid.bottom = 40; |     this.chartOptions.grid.bottom = 40; | ||||||
|     this.chartOptions.backgroundColor = '#11131f'; |     this.chartOptions.backgroundColor = 'var(--active-bg)'; | ||||||
|     this.chartInstance.setOption(this.chartOptions); |     this.chartInstance.setOption(this.chartOptions); | ||||||
|     download(this.chartInstance.getDataURL({ |     download(this.chartInstance.getDataURL({ | ||||||
|       pixelRatio: 2, |       pixelRatio: 2, | ||||||
|  | |||||||
| @ -151,7 +151,7 @@ export class BlockFeesGraphComponent implements OnInit { | |||||||
|         borderRadius: 4, |         borderRadius: 4, | ||||||
|         shadowColor: 'rgba(0, 0, 0, 0.5)', |         shadowColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|         textStyle: { |         textStyle: { | ||||||
|           color: '#b1b1b1', |           color: 'var(--tooltip-grey)', | ||||||
|           align: 'left', |           align: 'left', | ||||||
|         }, |         }, | ||||||
|         borderColor: '#000', |         borderColor: '#000', | ||||||
| @ -214,7 +214,7 @@ export class BlockFeesGraphComponent implements OnInit { | |||||||
|           splitLine: { |           splitLine: { | ||||||
|             lineStyle: { |             lineStyle: { | ||||||
|               type: 'dotted', |               type: 'dotted', | ||||||
|               color: '#ffffff66', |               color: 'var(--transparent-fg)', | ||||||
|               opacity: 0.25, |               opacity: 0.25, | ||||||
|             } |             } | ||||||
|           }, |           }, | ||||||
| @ -305,7 +305,7 @@ export class BlockFeesGraphComponent implements OnInit { | |||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     this.chartOptions.grid.bottom = 40; |     this.chartOptions.grid.bottom = 40; | ||||||
|     this.chartOptions.backgroundColor = '#11131f'; |     this.chartOptions.backgroundColor = 'var(--active-bg)'; | ||||||
|     this.chartInstance.setOption(this.chartOptions); |     this.chartInstance.setOption(this.chartOptions); | ||||||
|     download(this.chartInstance.getDataURL({ |     download(this.chartInstance.getDataURL({ | ||||||
|       pixelRatio: 2, |       pixelRatio: 2, | ||||||
|  | |||||||
| @ -71,7 +71,7 @@ | |||||||
|   .filter-tag { |   .filter-tag { | ||||||
|     font-size: 0.9em; |     font-size: 0.9em; | ||||||
|     background: #181b2daf; |     background: #181b2daf; | ||||||
|     border: solid 1px #105fb0; |     border: solid 1px var(--primary); | ||||||
|     color: white; |     color: white; | ||||||
|     border-radius: 0.2rem; |     border-radius: 0.2rem; | ||||||
|     padding: 0.2em 0.5em; |     padding: 0.2em 0.5em; | ||||||
| @ -80,15 +80,15 @@ | |||||||
|     pointer-events: all; |     pointer-events: all; | ||||||
| 
 | 
 | ||||||
|     &.selected { |     &.selected { | ||||||
|       background-color: #105fb0; |       background-color: var(--primary); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &.any-mode { |   &.any-mode { | ||||||
|     .filter-tag { |     .filter-tag { | ||||||
|       border: solid 1px #1a9436; |       border: solid 1px var(--success); | ||||||
|       &.selected { |       &.selected { | ||||||
|         background-color: #1a9436; |         background-color: var(--success); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -114,15 +114,15 @@ | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &.blue { |     &.blue { | ||||||
|       border: solid 1px #105fb0; |       border: solid 1px var(--primary); | ||||||
|       &.active { |       &.active { | ||||||
|         background: #105fb0; |         background: var(--primary); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     &.green { |     &.green { | ||||||
|       border: solid 1px #1a9436; |       border: solid 1px var(--success); | ||||||
|       &.active { |       &.active { | ||||||
|         background: #1a9436; |         background: var(--success); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     &.yellow { |     &.yellow { | ||||||
|  | |||||||
| @ -131,7 +131,7 @@ export class BlockHealthGraphComponent implements OnInit { | |||||||
|         borderRadius: 4, |         borderRadius: 4, | ||||||
|         shadowColor: 'rgba(0, 0, 0, 0.5)', |         shadowColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|         textStyle: { |         textStyle: { | ||||||
|           color: '#b1b1b1', |           color: 'var(--tooltip-grey)', | ||||||
|           align: 'left', |           align: 'left', | ||||||
|         }, |         }, | ||||||
|         borderColor: '#000', |         borderColor: '#000', | ||||||
| @ -178,7 +178,7 @@ export class BlockHealthGraphComponent implements OnInit { | |||||||
|           splitLine: { |           splitLine: { | ||||||
|             lineStyle: { |             lineStyle: { | ||||||
|               type: 'dotted', |               type: 'dotted', | ||||||
|               color: '#ffffff66', |               color: 'var(--transparent-fg)', | ||||||
|               opacity: 0.25, |               opacity: 0.25, | ||||||
|             } |             } | ||||||
|           }, |           }, | ||||||
| @ -290,7 +290,7 @@ export class BlockHealthGraphComponent implements OnInit { | |||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     this.chartOptions.grid.bottom = 40; |     this.chartOptions.grid.bottom = 40; | ||||||
|     this.chartOptions.backgroundColor = '#11131f'; |     this.chartOptions.backgroundColor = 'var(--active-bg)'; | ||||||
|     this.chartInstance.setOption(this.chartOptions); |     this.chartInstance.setOption(this.chartOptions); | ||||||
|     download(this.chartInstance.getDataURL({ |     download(this.chartInstance.getDataURL({ | ||||||
|       pixelRatio: 2, |       pixelRatio: 2, | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
|   position: relative; |   position: relative; | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   padding-bottom: 100%; |   padding-bottom: 100%; | ||||||
|   background: #181b2d; |   background: var(--stat-box-bg); | ||||||
|   display: flex; |   display: flex; | ||||||
|   justify-content: center; |   justify-content: center; | ||||||
|   align-items: center; |   align-items: center; | ||||||
|  | |||||||
| @ -7,8 +7,9 @@ import TxView from './tx-view'; | |||||||
| import { Color, Position } from './sprite-types'; | import { Color, Position } from './sprite-types'; | ||||||
| import { Price } from '../../services/price.service'; | import { Price } from '../../services/price.service'; | ||||||
| import { StateService } from '../../services/state.service'; | import { StateService } from '../../services/state.service'; | ||||||
|  | import { ThemeService } from '../../services/theme.service'; | ||||||
| import { Subscription } from 'rxjs'; | import { Subscription } from 'rxjs'; | ||||||
| import { defaultColorFunction, setOpacity, defaultAuditColors, defaultColors, ageColorFunction } from './utils'; | import { defaultColorFunction, setOpacity, defaultAuditColors, defaultColors, ageColorFunction, contrastColorFunction, contrastAuditColors, contrastColors } from './utils'; | ||||||
| import { ActiveFilter, FilterMode, toFlags } from '../../shared/filters.utils'; | import { ActiveFilter, FilterMode, toFlags } from '../../shared/filters.utils'; | ||||||
| import { detectWebGL } from '../../shared/graphs.utils'; | import { detectWebGL } from '../../shared/graphs.utils'; | ||||||
| 
 | 
 | ||||||
| @ -20,6 +21,13 @@ const unmatchedAuditColors = { | |||||||
|   prioritized: setOpacity(defaultAuditColors.prioritized, unmatchedOpacity), |   prioritized: setOpacity(defaultAuditColors.prioritized, unmatchedOpacity), | ||||||
|   accelerated: setOpacity(defaultAuditColors.accelerated, unmatchedOpacity), |   accelerated: setOpacity(defaultAuditColors.accelerated, unmatchedOpacity), | ||||||
| }; | }; | ||||||
|  | const unmatchedContrastAuditColors = { | ||||||
|  |   censored: setOpacity(contrastAuditColors.censored, unmatchedOpacity), | ||||||
|  |   missing: setOpacity(contrastAuditColors.missing, unmatchedOpacity), | ||||||
|  |   added: setOpacity(contrastAuditColors.added, unmatchedOpacity), | ||||||
|  |   prioritized: setOpacity(contrastAuditColors.prioritized, unmatchedOpacity), | ||||||
|  |   accelerated: setOpacity(contrastAuditColors.accelerated, unmatchedOpacity), | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-block-overview-graph', |   selector: 'app-block-overview-graph', | ||||||
| @ -53,6 +61,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On | |||||||
| 
 | 
 | ||||||
|   @ViewChild('blockCanvas') |   @ViewChild('blockCanvas') | ||||||
|   canvas: ElementRef<HTMLCanvasElement>; |   canvas: ElementRef<HTMLCanvasElement>; | ||||||
|  |   themeChangedSubscription: Subscription; | ||||||
| 
 | 
 | ||||||
|   gl: WebGLRenderingContext; |   gl: WebGLRenderingContext; | ||||||
|   animationFrameRequest: number; |   animationFrameRequest: number; | ||||||
| @ -84,6 +93,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On | |||||||
|     readonly ngZone: NgZone, |     readonly ngZone: NgZone, | ||||||
|     readonly elRef: ElementRef, |     readonly elRef: ElementRef, | ||||||
|     public stateService: StateService, |     public stateService: StateService, | ||||||
|  |     private themeService: ThemeService, | ||||||
|   ) { |   ) { | ||||||
|     this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); |     this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); | ||||||
|     this.vertexArray = new FastVertexArray(512, TxSprite.dataSize); |     this.vertexArray = new FastVertexArray(512, TxSprite.dataSize); | ||||||
| @ -102,6 +112,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On | |||||||
|       if (this.gl) { |       if (this.gl) { | ||||||
|         this.initCanvas(); |         this.initCanvas(); | ||||||
|         this.resizeCanvas(); |         this.resizeCanvas(); | ||||||
|  |         this.themeChangedSubscription = this.themeService.themeChanged$.subscribe(() => { | ||||||
|  |           this.scene.setColorFunction(this.getColorFunction()); | ||||||
|  |         }); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -148,6 +161,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On | |||||||
|     if (this.canvas) { |     if (this.canvas) { | ||||||
|       this.canvas.nativeElement.removeEventListener('webglcontextlost', this.handleContextLost); |       this.canvas.nativeElement.removeEventListener('webglcontextlost', this.handleContextLost); | ||||||
|       this.canvas.nativeElement.removeEventListener('webglcontextrestored', this.handleContextRestored); |       this.canvas.nativeElement.removeEventListener('webglcontextrestored', this.handleContextRestored); | ||||||
|  |       this.themeChangedSubscription?.unsubscribe(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -293,7 +307,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On | |||||||
|         this.start(); |         this.start(); | ||||||
|       } else { |       } else { | ||||||
|         this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution, |         this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution, | ||||||
|           blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray, |           blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray, theme: this.themeService, | ||||||
|           highlighting: this.auditHighlighting, animationDuration: this.animationDuration, animationOffset: this.animationOffset, |           highlighting: this.auditHighlighting, animationDuration: this.animationDuration, animationOffset: this.animationOffset, | ||||||
|         colorFunction: this.getColorFunction() }); |         colorFunction: this.getColorFunction() }); | ||||||
|         this.start(); |         this.start(); | ||||||
| @ -563,14 +577,27 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On | |||||||
|   getFilterColorFunction(flags: bigint, gradient: 'fee' | 'age'): ((tx: TxView) => Color) { |   getFilterColorFunction(flags: bigint, gradient: 'fee' | 'age'): ((tx: TxView) => Color) { | ||||||
|     return (tx: TxView) => { |     return (tx: TxView) => { | ||||||
|       if ((this.filterMode === 'and' && (tx.bigintFlags & flags) === flags) || (this.filterMode === 'or' && (flags === 0n || (tx.bigintFlags & flags) > 0n))) { |       if ((this.filterMode === 'and' && (tx.bigintFlags & flags) === flags) || (this.filterMode === 'or' && (flags === 0n || (tx.bigintFlags & flags) > 0n))) { | ||||||
|  |         if (this.themeService.theme !== 'contrast') { | ||||||
|           return (gradient === 'age') ? ageColorFunction(tx, defaultColors.fee, defaultAuditColors, this.relativeTime || (Date.now() / 1000)) : defaultColorFunction(tx, defaultColors.fee, defaultAuditColors, this.relativeTime || (Date.now() / 1000)); |           return (gradient === 'age') ? ageColorFunction(tx, defaultColors.fee, defaultAuditColors, this.relativeTime || (Date.now() / 1000)) : defaultColorFunction(tx, defaultColors.fee, defaultAuditColors, this.relativeTime || (Date.now() / 1000)); | ||||||
|         } else { |         } else { | ||||||
|  |           return (gradient === 'age') ? ageColorFunction(tx, contrastColors.fee, contrastAuditColors, this.relativeTime || (Date.now() / 1000)) : contrastColorFunction(tx, contrastColors.fee, contrastAuditColors, this.relativeTime || (Date.now() / 1000)); | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         if (this.themeService.theme !== 'contrast') { | ||||||
|           return (gradient === 'age') ? { r: 1, g: 1, b: 1, a: 0.05 } : defaultColorFunction( |           return (gradient === 'age') ? { r: 1, g: 1, b: 1, a: 0.05 } : defaultColorFunction( | ||||||
|             tx, |             tx, | ||||||
|             defaultColors.unmatchedfee, |             defaultColors.unmatchedfee, | ||||||
|             unmatchedAuditColors, |             unmatchedAuditColors, | ||||||
|             this.relativeTime || (Date.now() / 1000) |             this.relativeTime || (Date.now() / 1000) | ||||||
|           ); |           ); | ||||||
|  |         } else { | ||||||
|  |           return (gradient === 'age') ? { r: 1, g: 1, b: 1, a: 0.05 } : contrastColorFunction( | ||||||
|  |             tx, | ||||||
|  |             contrastColors.unmatchedfee, | ||||||
|  |             unmatchedContrastAuditColors, | ||||||
|  |             this.relativeTime || (Date.now() / 1000) | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -2,13 +2,15 @@ import { FastVertexArray } from './fast-vertex-array'; | |||||||
| import TxView from './tx-view'; | import TxView from './tx-view'; | ||||||
| import { TransactionStripped } from '../../interfaces/node-api.interface'; | import { TransactionStripped } from '../../interfaces/node-api.interface'; | ||||||
| import { Color, Position, Square, ViewUpdateParams } from './sprite-types'; | import { Color, Position, Square, ViewUpdateParams } from './sprite-types'; | ||||||
| import { defaultColorFunction } from './utils'; | import { defaultColorFunction, contrastColorFunction } from './utils'; | ||||||
|  | import { ThemeService } from '../../services/theme.service'; | ||||||
| 
 | 
 | ||||||
| export default class BlockScene { | export default class BlockScene { | ||||||
|   scene: { count: number, offset: { x: number, y: number}}; |   scene: { count: number, offset: { x: number, y: number}}; | ||||||
|   vertexArray: FastVertexArray; |   vertexArray: FastVertexArray; | ||||||
|   txs: { [key: string]: TxView }; |   txs: { [key: string]: TxView }; | ||||||
|   getColor: ((tx: TxView) => Color) = defaultColorFunction; |   getColor: ((tx: TxView) => Color) = defaultColorFunction; | ||||||
|  |   theme: ThemeService; | ||||||
|   orientation: string; |   orientation: string; | ||||||
|   flip: boolean; |   flip: boolean; | ||||||
|   animationDuration: number = 900; |   animationDuration: number = 900; | ||||||
| @ -29,11 +31,11 @@ export default class BlockScene { | |||||||
|   animateUntil = 0; |   animateUntil = 0; | ||||||
|   dirty: boolean; |   dirty: boolean; | ||||||
| 
 | 
 | ||||||
|   constructor({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting, colorFunction }: |   constructor({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, theme, highlighting, colorFunction }: | ||||||
|       { width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number, |       { width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number, | ||||||
|         orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean, colorFunction: ((tx: TxView) => Color) | null } |         orientation: string, flip: boolean, vertexArray: FastVertexArray, theme: ThemeService, highlighting: boolean, colorFunction: ((tx: TxView) => Color) | null } | ||||||
|   ) { |   ) { | ||||||
|     this.init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting, colorFunction }); |     this.init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, theme, highlighting, colorFunction }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   resize({ width = this.width, height = this.height, animate = true }: { width?: number, height?: number, animate: boolean }): void { |   resize({ width = this.width, height = this.height, animate = true }: { width?: number, height?: number, animate: boolean }): void { | ||||||
| @ -67,7 +69,7 @@ export default class BlockScene { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   setColorFunction(colorFunction: ((tx: TxView) => Color) | null): void { |   setColorFunction(colorFunction: ((tx: TxView) => Color) | null): void { | ||||||
|     this.getColor = colorFunction || defaultColorFunction; |     this.theme.theme !== 'default' ? this.getColor = colorFunction || contrastColorFunction : this.getColor = colorFunction || defaultColorFunction; | ||||||
|     this.updateAllColors(); |     this.updateAllColors(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -197,6 +199,7 @@ export default class BlockScene { | |||||||
|           this.txs[tx.txid].feerate = tx.rate || (this.txs[tx.txid].fee / this.txs[tx.txid].vsize); |           this.txs[tx.txid].feerate = tx.rate || (this.txs[tx.txid].fee / this.txs[tx.txid].vsize); | ||||||
|           this.txs[tx.txid].rate = tx.rate; |           this.txs[tx.txid].rate = tx.rate; | ||||||
|           this.txs[tx.txid].dirty = true; |           this.txs[tx.txid].dirty = true; | ||||||
|  |           this.updateColor(this.txs[tx.txid], startTime, 50, true); | ||||||
|         } |         } | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
| @ -232,9 +235,9 @@ export default class BlockScene { | |||||||
|     this.animateUntil = Math.max(this.animateUntil, tx.setHighlight(value)); |     this.animateUntil = Math.max(this.animateUntil, tx.setHighlight(value)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting, colorFunction }: |   private init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, theme, highlighting, colorFunction }: | ||||||
|       { width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number, |       { width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number, | ||||||
|         orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean, colorFunction: ((tx: TxView) => Color) | null } |         orientation: string, flip: boolean, vertexArray: FastVertexArray, theme: ThemeService, highlighting: boolean, colorFunction: ((tx: TxView) => Color) | null } | ||||||
|   ): void { |   ): void { | ||||||
|     this.animationDuration = animationDuration || 1000; |     this.animationDuration = animationDuration || 1000; | ||||||
|     this.configAnimationOffset = animationOffset; |     this.configAnimationOffset = animationOffset; | ||||||
| @ -243,7 +246,8 @@ export default class BlockScene { | |||||||
|     this.flip = flip; |     this.flip = flip; | ||||||
|     this.vertexArray = vertexArray; |     this.vertexArray = vertexArray; | ||||||
|     this.highlightingEnabled = highlighting; |     this.highlightingEnabled = highlighting; | ||||||
|     this.getColor = colorFunction || defaultColorFunction; |     theme.theme !== 'default' ? this.getColor = colorFunction || contrastColorFunction : this.getColor = colorFunction || defaultColorFunction; | ||||||
|  |     this.theme = theme; | ||||||
| 
 | 
 | ||||||
|     this.scene = { |     this.scene = { | ||||||
|       count: 0, |       count: 0, | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import { feeLevels, mempoolFeeColors } from '../../app.constants'; | import { feeLevels, defaultMempoolFeeColors, contrastMempoolFeeColors } from '../../app.constants'; | ||||||
| import { Color } from './sprite-types'; | import { Color } from './sprite-types'; | ||||||
| import TxView from './tx-view'; | import TxView from './tx-view'; | ||||||
| 
 | 
 | ||||||
| @ -47,7 +47,7 @@ interface ColorPalette { | |||||||
| // precomputed colors
 | // precomputed colors
 | ||||||
| const defaultColors: { [key: string]: ColorPalette } = { | const defaultColors: { [key: string]: ColorPalette } = { | ||||||
|   fee: { |   fee: { | ||||||
|     base: mempoolFeeColors.map(hexToColor), |     base: defaultMempoolFeeColors.map(hexToColor), | ||||||
|     audit: [], |     audit: [], | ||||||
|     marginal: [], |     marginal: [], | ||||||
|     baseLevel: (tx: TxView, rate: number) => feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1 |     baseLevel: (tx: TxView, rate: number) => feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1 | ||||||
| @ -72,7 +72,37 @@ export const defaultAuditColors = { | |||||||
|   missing: darken(desaturate(hexToColor('f344df'), 0.3), 0.7), |   missing: darken(desaturate(hexToColor('f344df'), 0.3), 0.7), | ||||||
|   added: hexToColor('0099ff'), |   added: hexToColor('0099ff'), | ||||||
|   prioritized: darken(desaturate(hexToColor('0099ff'), 0.3), 0.7), |   prioritized: darken(desaturate(hexToColor('0099ff'), 0.3), 0.7), | ||||||
|   accelerated: hexToColor('8F5FF6'), |   accelerated: hexToColor('8f5ff6'), | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const contrastColors: { [key: string]: ColorPalette } = { | ||||||
|  |   fee: { | ||||||
|  |     base: contrastMempoolFeeColors.map(hexToColor), | ||||||
|  |     audit: [], | ||||||
|  |     marginal: [], | ||||||
|  |     baseLevel: (tx: TxView, rate: number) => feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1 | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  | for (const key in contrastColors) { | ||||||
|  |   const base = contrastColors[key].base; | ||||||
|  |   contrastColors[key].audit = base.map((color) => darken(desaturate(color, 0.3), 0.9)); | ||||||
|  |   contrastColors[key].marginal = base.map((color) => darken(desaturate(color, 0.8), 1.1)); | ||||||
|  |   contrastColors['unmatched' + key] = { | ||||||
|  |     base: contrastColors[key].base.map(c => setOpacity(c, 0.2)), | ||||||
|  |     audit: contrastColors[key].audit.map(c => setOpacity(c, 0.2)), | ||||||
|  |     marginal: contrastColors[key].marginal.map(c => setOpacity(c, 0.2)), | ||||||
|  |     baseLevel: contrastColors[key].baseLevel, | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export { contrastColors as contrastColors }; | ||||||
|  | 
 | ||||||
|  | export const contrastAuditColors = { | ||||||
|  |   censored: hexToColor('ffa8ff'), | ||||||
|  |   missing: darken(desaturate(hexToColor('ffa8ff'), 0.3), 0.7), | ||||||
|  |   added: hexToColor('00bb98'), | ||||||
|  |   prioritized: darken(desaturate(hexToColor('00bb98'), 0.3), 0.7), | ||||||
|  |   accelerated: hexToColor('8f5ff6'), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export function defaultColorFunction( | export function defaultColorFunction( | ||||||
| @ -83,7 +113,7 @@ export function defaultColorFunction( | |||||||
| ): Color { | ): Color { | ||||||
|   const rate = tx.fee / tx.vsize; // color by simple single-tx fee rate
 |   const rate = tx.fee / tx.vsize; // color by simple single-tx fee rate
 | ||||||
|   const levelIndex = colors.baseLevel(tx, rate, relativeTime || (Date.now() / 1000)); |   const levelIndex = colors.baseLevel(tx, rate, relativeTime || (Date.now() / 1000)); | ||||||
|   const levelColor = colors.base[levelIndex] || colors.base[mempoolFeeColors.length - 1]; |   const levelColor = colors.base[levelIndex] || colors.base[defaultMempoolFeeColors.length - 1]; | ||||||
|   // Normal mode
 |   // Normal mode
 | ||||||
|   if (!tx.scene?.highlightingEnabled) { |   if (!tx.scene?.highlightingEnabled) { | ||||||
|     if (tx.acc) { |     if (tx.acc) { | ||||||
| @ -100,7 +130,7 @@ export function defaultColorFunction( | |||||||
|     case 'missing': |     case 'missing': | ||||||
|     case 'sigop': |     case 'sigop': | ||||||
|     case 'rbf': |     case 'rbf': | ||||||
|       return colors.marginal[levelIndex] || colors.marginal[mempoolFeeColors.length - 1]; |       return colors.marginal[levelIndex] || colors.marginal[defaultMempoolFeeColors.length - 1]; | ||||||
|     case 'fresh': |     case 'fresh': | ||||||
|     case 'freshcpfp': |     case 'freshcpfp': | ||||||
|       return auditColors.missing; |       return auditColors.missing; | ||||||
| @ -109,12 +139,12 @@ export function defaultColorFunction( | |||||||
|     case 'prioritized': |     case 'prioritized': | ||||||
|       return auditColors.prioritized; |       return auditColors.prioritized; | ||||||
|     case 'selected': |     case 'selected': | ||||||
|       return colors.marginal[levelIndex] || colors.marginal[mempoolFeeColors.length - 1]; |       return colors.marginal[levelIndex] || colors.marginal[defaultMempoolFeeColors.length - 1]; | ||||||
|     case 'accelerated': |     case 'accelerated': | ||||||
|       return auditColors.accelerated; |       return auditColors.accelerated; | ||||||
|     case 'found': |     case 'found': | ||||||
|       if (tx.context === 'projected') { |       if (tx.context === 'projected') { | ||||||
|         return colors.audit[levelIndex] || colors.audit[mempoolFeeColors.length - 1]; |         return colors.audit[levelIndex] || colors.audit[defaultMempoolFeeColors.length - 1]; | ||||||
|       } else { |       } else { | ||||||
|         return levelColor; |         return levelColor; | ||||||
|       } |       } | ||||||
| @ -127,17 +157,27 @@ export function defaultColorFunction( | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export function contrastColorFunction( | ||||||
|  |   tx: TxView, | ||||||
|  |   colors: { base: Color[], audit: Color[], marginal: Color[], baseLevel: (tx: TxView, rate: number, time: number) => number } = contrastColors.fee, | ||||||
|  |   auditColors: { [status: string]: Color } = contrastAuditColors, | ||||||
|  |   relativeTime?: number, | ||||||
|  | ): Color { | ||||||
|  |   return defaultColorFunction(tx, colors, auditColors, relativeTime); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export function ageColorFunction( | export function ageColorFunction( | ||||||
|   tx: TxView, |   tx: TxView, | ||||||
|   colors: { base: Color[], audit: Color[], marginal: Color[], baseLevel: (tx: TxView, rate: number, time: number) => number } = defaultColors.fee, |   colors: { base: Color[], audit: Color[], marginal: Color[], baseLevel: (tx: TxView, rate: number, time: number) => number } = defaultColors.fee, | ||||||
|   auditColors: { [status: string]: Color } = defaultAuditColors, |   auditColors: { [status: string]: Color } = defaultAuditColors, | ||||||
|   relativeTime?: number, |   relativeTime?: number, | ||||||
|  |   theme?: string, | ||||||
| ): Color { | ): Color { | ||||||
|   if (tx.acc || tx.status === 'accelerated') { |   if (tx.acc || tx.status === 'accelerated') { | ||||||
|     return auditColors.accelerated; |     return auditColors.accelerated; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const color = defaultColorFunction(tx, colors, auditColors, relativeTime);  |   const color = theme !== 'contrast' ? defaultColorFunction(tx, colors, auditColors, relativeTime) : contrastColorFunction(tx, colors, auditColors, relativeTime); | ||||||
| 
 | 
 | ||||||
|   const ageLevel = (!tx.time ? 0 : (0.8 * Math.tanh((1 / 15) * Math.log2((Math.max(1, 0.6 * ((relativeTime - tx.time) - 60))))))); |   const ageLevel = (!tx.time ? 0 : (0.8 * Math.tanh((1 / 15) * Math.log2((Math.max(1, 0.6 * ((relativeTime - tx.time) - 60))))))); | ||||||
|   return { |   return { | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
|   background: rgba(#11131f, 0.95); |   background: rgba(#11131f, 0.95); | ||||||
|   border-radius: 4px; |   border-radius: 4px; | ||||||
|   box-shadow: 1px 1px 10px rgba(0,0,0,0.5); |   box-shadow: 1px 1px 10px rgba(0,0,0,0.5); | ||||||
|   color: #b1b1b1; |   color: var(--tooltip-grey); | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: column; |   flex-direction: column; | ||||||
|   justify-content: space-between; |   justify-content: space-between; | ||||||
| @ -30,7 +30,7 @@ th, td { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .badge.badge-accelerated { | .badge.badge-accelerated { | ||||||
|   background-color: #653b9c; |   background-color: var(--tertiary); | ||||||
|   box-shadow: #ad7de57f 0px 0px 12px -2px; |   box-shadow: #ad7de57f 0px 0px 12px -2px; | ||||||
|   color: white; |   color: white; | ||||||
|   animation: acceleratePulse 1s infinite; |   animation: acceleratePulse 1s infinite; | ||||||
| @ -51,27 +51,27 @@ th, td { | |||||||
| 
 | 
 | ||||||
|   .filter-tag { |   .filter-tag { | ||||||
|     background: #181b2daf; |     background: #181b2daf; | ||||||
|     border: solid 1px #105fb0; |     border: solid 1px var(--primary); | ||||||
|     color: white; |     color: white; | ||||||
|     transition: background-color 300ms; |     transition: background-color 300ms; | ||||||
| 
 | 
 | ||||||
|     &.matching { |     &.matching { | ||||||
|       background-color: #105fb0; |       background-color: var(--primary); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &.any-mode { |   &.any-mode { | ||||||
|     .filter-tag { |     .filter-tag { | ||||||
|       border: solid 1px #1a9436; |       border: solid 1px var(--success); | ||||||
|       &.matching { |       &.matching { | ||||||
|         background-color: #1a9436; |         background-color: var(--success); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @keyframes acceleratePulse { | @keyframes acceleratePulse { | ||||||
|   0% { background-color: #653b9c; box-shadow: #ad7de57f 0px 0px 12px -2px; } |   0% { background-color: var(--tertiary); box-shadow: #ad7de57f 0px 0px 12px -2px; } | ||||||
|   50% { background-color: #8457bb; box-shadow: #ad7de5 0px 0px 18px -2px;} |   50% { background-color: #8457bb; box-shadow: #ad7de5 0px 0px 18px -2px;} | ||||||
|   100% { background-color: #653b9c; box-shadow: #ad7de57f 0px 0px 12px -2px; } |   100% { background-color: var(--tertiary); box-shadow: #ad7de57f 0px 0px 12px -2px; } | ||||||
| } | } | ||||||
| @ -150,7 +150,7 @@ export class BlockRewardsGraphComponent implements OnInit { | |||||||
|         borderRadius: 4, |         borderRadius: 4, | ||||||
|         shadowColor: 'rgba(0, 0, 0, 0.5)', |         shadowColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|         textStyle: { |         textStyle: { | ||||||
|           color: '#b1b1b1', |           color: 'var(--tooltip-grey)', | ||||||
|           align: 'left', |           align: 'left', | ||||||
|         }, |         }, | ||||||
|         borderColor: '#000', |         borderColor: '#000', | ||||||
| @ -219,7 +219,7 @@ export class BlockRewardsGraphComponent implements OnInit { | |||||||
|           splitLine: { |           splitLine: { | ||||||
|             lineStyle: { |             lineStyle: { | ||||||
|               type: 'dotted', |               type: 'dotted', | ||||||
|               color: '#ffffff66', |               color: 'var(--transparent-fg)', | ||||||
|               opacity: 0.25, |               opacity: 0.25, | ||||||
|             } |             } | ||||||
|           }, |           }, | ||||||
| @ -315,7 +315,7 @@ export class BlockRewardsGraphComponent implements OnInit { | |||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     this.chartOptions.grid.bottom = 40; |     this.chartOptions.grid.bottom = 40; | ||||||
|     this.chartOptions.backgroundColor = '#11131f'; |     this.chartOptions.backgroundColor = 'var(--active-bg)'; | ||||||
|     this.chartInstance.setOption(this.chartOptions); |     this.chartInstance.setOption(this.chartOptions); | ||||||
|     download(this.chartInstance.getDataURL({ |     download(this.chartInstance.getDataURL({ | ||||||
|       pixelRatio: 2, |       pixelRatio: 2, | ||||||
|  | |||||||
| @ -146,7 +146,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit { | |||||||
|         borderRadius: 4, |         borderRadius: 4, | ||||||
|         shadowColor: 'rgba(0, 0, 0, 0.5)', |         shadowColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|         textStyle: { |         textStyle: { | ||||||
|           color: '#b1b1b1', |           color: 'var(--tooltip-grey)', | ||||||
|           align: 'left', |           align: 'left', | ||||||
|         }, |         }, | ||||||
|         borderColor: '#000', |         borderColor: '#000', | ||||||
| @ -230,7 +230,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit { | |||||||
|           splitLine: { |           splitLine: { | ||||||
|             lineStyle: { |             lineStyle: { | ||||||
|               type: 'dotted', |               type: 'dotted', | ||||||
|               color: '#ffffff66', |               color: 'var(--transparent-fg)', | ||||||
|               opacity: 0.25, |               opacity: 0.25, | ||||||
|             } |             } | ||||||
|           }, |           }, | ||||||
| @ -252,7 +252,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit { | |||||||
|             symbol: 'none', |             symbol: 'none', | ||||||
|             lineStyle: { |             lineStyle: { | ||||||
|               type: 'solid', |               type: 'solid', | ||||||
|               color: '#ffffff66', |               color: 'var(--transparent-fg)', | ||||||
|               opacity: 1, |               opacity: 1, | ||||||
|               width: 1, |               width: 1, | ||||||
|             }, |             }, | ||||||
| @ -342,7 +342,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit { | |||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     this.chartOptions.grid.bottom = 40; |     this.chartOptions.grid.bottom = 40; | ||||||
|     this.chartOptions.backgroundColor = '#11131f'; |     this.chartOptions.backgroundColor = 'var(--active-bg)'; | ||||||
|     this.chartInstance.setOption(this.chartOptions); |     this.chartInstance.setOption(this.chartOptions); | ||||||
|     download(this.chartInstance.getDataURL({ |     download(this.chartInstance.getDataURL({ | ||||||
|       pixelRatio: 2, |       pixelRatio: 2, | ||||||
|  | |||||||
| @ -136,7 +136,7 @@ export class BlockPreviewComponent implements OnInit, OnDestroy { | |||||||
|                   return of(transactions); |                   return of(transactions); | ||||||
|                 }) |                 }) | ||||||
|               ), |               ), | ||||||
|             this.stateService.env.ACCELERATOR === true && block.height > 819500 ? this.servicesApiService.getAccelerationHistory$({ blockHash: block.id }) : of([]) |             this.stateService.env.ACCELERATOR === true && block.height > 819500 ? this.servicesApiService.getAccelerationHistory$({ blockHeight: block.height }) : of([]) | ||||||
|           ]); |           ]); | ||||||
|         } |         } | ||||||
|       ), |       ), | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .qr-wrapper { | .qr-wrapper { | ||||||
|   background-color: #FFF; |   background-color: var(--fg); | ||||||
|   padding: 10px; |   padding: 10px; | ||||||
|   padding-bottom: 5px; |   padding-bottom: 5px; | ||||||
|   display: inline-block; |   display: inline-block; | ||||||
| @ -175,9 +175,7 @@ h1 { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   a { |   a { | ||||||
|     color: #1ad8f4; |  | ||||||
|     &:hover, &:focus { |     &:hover, &:focus { | ||||||
|       color: #09a3ba; |  | ||||||
|       display: inline-block; |       display: inline-block; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -254,7 +252,7 @@ h1 { | |||||||
|   cursor: pointer; |   cursor: pointer; | ||||||
| 
 | 
 | ||||||
|   &.active { |   &.active { | ||||||
|     background: #24273e; |     background: var(--box-bg); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &.active, &:hover { |   &.active, &:hover { | ||||||
|  | |||||||
| @ -345,7 +345,7 @@ export class BlockComponent implements OnInit, OnDestroy { | |||||||
|                 return of(null); |                 return of(null); | ||||||
|               }) |               }) | ||||||
|             ), |             ), | ||||||
|           this.stateService.env.ACCELERATOR === true && block.height > 819500 ? this.servicesApiService.getAccelerationHistory$({ blockHash: block.id }) : of([]) |           this.stateService.env.ACCELERATOR === true && block.height > 819500 ? this.servicesApiService.getAccelerationHistory$({ blockHeight: block.height }) : of([]) | ||||||
|         ]); |         ]); | ||||||
|       }) |       }) | ||||||
|     ) |     ) | ||||||
| @ -358,11 +358,15 @@ export class BlockComponent implements OnInit, OnDestroy { | |||||||
| 
 | 
 | ||||||
|       const acceleratedInBlock = {}; |       const acceleratedInBlock = {}; | ||||||
|       for (const acc of accelerations) { |       for (const acc of accelerations) { | ||||||
|  |         if (acc.pools?.some(pool => pool === this.block?.extras?.pool.id || pool?.['pool_unique_id'] === this.block?.extras?.pool.id)) { | ||||||
|           acceleratedInBlock[acc.txid] = acc; |           acceleratedInBlock[acc.txid] = acc; | ||||||
|         } |         } | ||||||
|  |       } | ||||||
|       for (const tx of transactions) { |       for (const tx of transactions) { | ||||||
|         if (acceleratedInBlock[tx.txid]) { |         if (acceleratedInBlock[tx.txid]) { | ||||||
|           tx.acc = true; |           tx.acc = true; | ||||||
|  |         } else { | ||||||
|  |           tx.acc = false; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -117,7 +117,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .black-background { | .black-background { | ||||||
|   background-color: #11131f; |   background-color: var(--active-bg); | ||||||
|   z-index: 100; |   z-index: 100; | ||||||
|   position: relative; |   position: relative; | ||||||
| } | } | ||||||
| @ -144,7 +144,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .loading .bitcoin-block.mined-block { | .loading .bitcoin-block.mined-block { | ||||||
|   background: #2d3348; |   background: var(--secondary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @keyframes opacityPulse { | @keyframes opacityPulse { | ||||||
|  | |||||||
| @ -63,11 +63,11 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|   blockPadding: number = 30; |   blockPadding: number = 30; | ||||||
| 
 | 
 | ||||||
|   gradientColors = { |   gradientColors = { | ||||||
|     '': ['#9339f4', '#105fb0'], |     '': ['var(--mainnet-alt)', 'var(--primary)'], | ||||||
|     liquid: ['#116761', '#183550'], |     liquid: ['var(--liquid)', 'var(--testnet-alt)'], | ||||||
|     'liquidtestnet': ['#494a4a', '#272e46'], |     'liquidtestnet': ['var(--liquidtestnet)', 'var(--liquidtestnet-alt)'], | ||||||
|     testnet: ['#1d486f', '#183550'], |     testnet: ['var(--testnet)', 'var(--testnet-alt)'], | ||||||
|     signet: ['#6f1d5d', '#471850'], |     signet: ['var(--signet)', 'var(--signet-alt)'], | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
| @ -330,7 +330,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|       left: addLeft + this.blockOffset * index + 'px', |       left: addLeft + this.blockOffset * index + 'px', | ||||||
|       background: `repeating-linear-gradient(
 |       background: `repeating-linear-gradient(
 | ||||||
|         #2d3348, |         #2d3348, | ||||||
|         #2d3348 ${greenBackgroundHeight}%, |         var(--secondary) ${greenBackgroundHeight}%, | ||||||
|         ${this.gradientColors[this.network][0]} ${Math.max(greenBackgroundHeight, 0)}%, |         ${this.gradientColors[this.network][0]} ${Math.max(greenBackgroundHeight, 0)}%, | ||||||
|         ${this.gradientColors[this.network][1]} 100% |         ${this.gradientColors[this.network][1]} 100% | ||||||
|       )`,
 |       )`,
 | ||||||
| @ -366,7 +366,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
| 
 | 
 | ||||||
|     return { |     return { | ||||||
|       left: addLeft + this.blockOffset * this.emptyBlocks.indexOf(block) + 'px', |       left: addLeft + this.blockOffset * this.emptyBlocks.indexOf(block) + 'px', | ||||||
|       background: "#2d3348", |       background: "var(--secondary)", | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .black-background { | .black-background { | ||||||
|   background-color: #11131f; |   background-color: var(--active-bg); | ||||||
|   z-index: 100; |   z-index: 100; | ||||||
|   position: relative; |   position: relative; | ||||||
| } | } | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ tr, td, th { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .progress { | .progress { | ||||||
|   background-color: #2d3348; |   background-color: var(--secondary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .pool { | .pool { | ||||||
| @ -266,7 +266,7 @@ tr, td, th { | |||||||
| 
 | 
 | ||||||
| .tooltip-custom .tooltiptext { | .tooltip-custom .tooltiptext { | ||||||
|   visibility: hidden; |   visibility: hidden; | ||||||
|   color: #fff; |   color: var(--fg); | ||||||
|   text-align: center; |   text-align: center; | ||||||
|   padding: 5px 0; |   padding: 5px 0; | ||||||
|   border-radius: 6px; |   border-radius: 6px; | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
|     height: 100%; |     height: 100%; | ||||||
| 
 | 
 | ||||||
|     .face { |     .face { | ||||||
|       fill: #11131f; |       fill: var(--active-bg); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -29,8 +29,8 @@ | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &.hour { |     &.hour { | ||||||
|       fill: #105fb0; |       fill: var(--primary); | ||||||
|       stroke: #105fb0; |       stroke: var(--primary); | ||||||
|       stroke-width: 6px; |       stroke-width: 6px; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -161,7 +161,7 @@ | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .side.bottom { |     .side.bottom { | ||||||
|       background: #105fb0; |       background: var(--primary); | ||||||
|       transform: rotateX(-90deg);  |       transform: rotateX(-90deg);  | ||||||
|       margin-top: var(--half-side); |       margin-top: var(--half-side); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ | |||||||
|           <h5 class="card-title" i18n="difficulty-box.current-period">Current Period</h5> |           <h5 class="card-title" i18n="difficulty-box.current-period">Current Period</h5> | ||||||
|           <div class="card-text">{{ epochData.progress | number: '1.2-2' }} <span class="symbol">%</span></div> |           <div class="card-text">{{ epochData.progress | number: '1.2-2' }} <span class="symbol">%</span></div> | ||||||
|           <div class="progress small-bar"> |           <div class="progress small-bar"> | ||||||
|             <div class="progress-bar" role="progressbar" style="width: 15%; background-color: #105fb0" [ngStyle]="{'width': epochData.base}"> </div> |             <div class="progress-bar" role="progressbar" style="width: 15%; background-color: var(--primary)" [ngStyle]="{'width': epochData.base}"> </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="item" *ngIf="showHalving"> |         <div class="item" *ngIf="showHalving"> | ||||||
|  | |||||||
| @ -79,12 +79,12 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .card { | .card { | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
|   height: 100%; |   height: 100%; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .card-title { | .card-title { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
|   overflow: hidden; |   overflow: hidden; | ||||||
|   text-overflow: ellipsis; |   text-overflow: ellipsis; | ||||||
| @ -94,7 +94,7 @@ | |||||||
| .progress { | .progress { | ||||||
|   display: inline-flex; |   display: inline-flex; | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   background-color: #2d3348; |   background-color: var(--secondary); | ||||||
|   height: 1.1rem; |   height: 1.1rem; | ||||||
|   max-width: 180px; |   max-width: 180px; | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ | |||||||
|   justify-content: space-around; |   justify-content: space-around; | ||||||
|   height: 50.5px; |   height: 50.5px; | ||||||
|   .shared-block { |   .shared-block { | ||||||
|     color: #ffffff66; |     color: var(--transparent-fg); | ||||||
|     font-size: 12px; |     font-size: 12px; | ||||||
|   } |   } | ||||||
|   .item { |   .item { | ||||||
| @ -91,19 +91,19 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .card { | .card { | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
|   height: 100%; |   height: 100%; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .card-title { | .card-title { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .progress { | .progress { | ||||||
|   display: inline-flex; |   display: inline-flex; | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   background-color: #2d3348; |   background-color: var(--secondary); | ||||||
|   height: 1.1rem; |   height: 1.1rem; | ||||||
|   max-width: 180px; |   max-width: 180px; | ||||||
| } | } | ||||||
| @ -177,10 +177,10 @@ | |||||||
| .epoch-blocks { | .epoch-blocks { | ||||||
|   display: block; |   display: block; | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   background: #2d3348; |   background: var(--secondary); | ||||||
| 
 | 
 | ||||||
|   .rect { |   .rect { | ||||||
|     fill: #2d3348; |     fill: var(--secondary); | ||||||
| 
 | 
 | ||||||
|     &.behind { |     &.behind { | ||||||
|       fill: #D81B60; |       fill: #D81B60; | ||||||
| @ -189,7 +189,7 @@ | |||||||
|       fill: url(#diff-gradient); |       fill: url(#diff-gradient); | ||||||
|     } |     } | ||||||
|     &.ahead { |     &.ahead { | ||||||
|       fill: #1a9436; |       fill: var(--success); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &.hover { |     &.hover { | ||||||
| @ -223,12 +223,12 @@ | |||||||
|     height: 100%; |     height: 100%; | ||||||
|   } |   } | ||||||
|   .background { |   .background { | ||||||
|     background: linear-gradient(to right, #105fb0, #9339f4); |     background: linear-gradient(to right, var(--primary), #9339f4); | ||||||
|     left: 0; |     left: 0; | ||||||
|     right: 0; |     right: 0; | ||||||
|   } |   } | ||||||
|   .remaining { |   .remaining { | ||||||
|     background: #2d3348; |     background: var(--secondary); | ||||||
|     right: 0; |     right: 0; | ||||||
|   } |   } | ||||||
|   .label { |   .label { | ||||||
|  | |||||||
| @ -82,24 +82,24 @@ export class DifficultyComponent implements OnInit { | |||||||
|     .pipe( |     .pipe( | ||||||
|       map(([blocks, da]) => { |       map(([blocks, da]) => { | ||||||
|         const maxHeight = blocks.reduce((max, block) => Math.max(max, block.height), 0); |         const maxHeight = blocks.reduce((max, block) => Math.max(max, block.height), 0); | ||||||
|         let colorAdjustments = '#ffffff66'; |         let colorAdjustments = 'var(--transparent-fg)'; | ||||||
|         if (da.difficultyChange > 0) { |         if (da.difficultyChange > 0) { | ||||||
|           colorAdjustments = '#3bcc49'; |           colorAdjustments = 'var(--green)'; | ||||||
|         } |         } | ||||||
|         if (da.difficultyChange < 0) { |         if (da.difficultyChange < 0) { | ||||||
|           colorAdjustments = '#dc3545'; |           colorAdjustments = 'var(--red)'; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let colorPreviousAdjustments = '#dc3545'; |         let colorPreviousAdjustments = 'var(--red)'; | ||||||
|         if (da.previousRetarget) { |         if (da.previousRetarget) { | ||||||
|           if (da.previousRetarget >= 0) { |           if (da.previousRetarget >= 0) { | ||||||
|             colorPreviousAdjustments = '#3bcc49'; |             colorPreviousAdjustments = 'var(--green)'; | ||||||
|           } |           } | ||||||
|           if (da.previousRetarget === 0) { |           if (da.previousRetarget === 0) { | ||||||
|             colorPreviousAdjustments = '#ffffff66'; |             colorPreviousAdjustments = 'var(--transparent-fg)'; | ||||||
|           } |           } | ||||||
|         } else { |         } else { | ||||||
|           colorPreviousAdjustments = '#ffffff66'; |           colorPreviousAdjustments = 'var(--transparent-fg)'; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const blocksUntilHalving = 210000 - (maxHeight % 210000); |         const blocksUntilHalving = 210000 - (maxHeight % 210000); | ||||||
|  | |||||||
| @ -128,7 +128,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr | |||||||
|         splitLine: { |         splitLine: { | ||||||
|           lineStyle: { |           lineStyle: { | ||||||
|             type: 'dotted', |             type: 'dotted', | ||||||
|             color: '#ffffff66', |             color: 'var(--transparent-fg)', | ||||||
|             opacity: 0.25, |             opacity: 0.25, | ||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| .card-title { | .card-title { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
|   font-size: 10px; |   font-size: 10px; | ||||||
|   margin-bottom: 4px; |   margin-bottom: 4px; | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
| @ -36,7 +36,7 @@ | |||||||
|       margin-bottom: 0; |       margin-bottom: 0; | ||||||
|     } |     } | ||||||
|     .card-text span { |     .card-text span { | ||||||
|       color: #ffffff66; |       color: var(--transparent-fg); | ||||||
|       font-size: 12px; |       font-size: 12px; | ||||||
|       top: 0px; |       top: 0px; | ||||||
|     } |     } | ||||||
| @ -79,6 +79,7 @@ | |||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: row; |   flex-direction: row; | ||||||
|   transition: background-color 1s; |   transition: background-color 1s; | ||||||
|  |   color: var(--color-fg); | ||||||
|   &.priority { |   &.priority { | ||||||
|     @media (767px < width < 992px), (width < 576px) { |     @media (767px < width < 992px), (width < 576px) { | ||||||
|       width: 100%; |       width: 100%; | ||||||
|  | |||||||
| @ -1,9 +1,10 @@ | |||||||
| import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; | import { Component, OnInit, ChangeDetectionStrategy, OnDestroy, ChangeDetectorRef } from '@angular/core'; | ||||||
| import { StateService } from '../../services/state.service'; | import { StateService } from '../../services/state.service'; | ||||||
| import { Observable, combineLatest } from 'rxjs'; | import { Observable, combineLatest, Subscription } from 'rxjs'; | ||||||
| import { Recommendedfees } from '../../interfaces/websocket.interface'; | import { Recommendedfees } from '../../interfaces/websocket.interface'; | ||||||
| import { feeLevels, mempoolFeeColors } from '../../app.constants'; | import { feeLevels } from '../../app.constants'; | ||||||
| import { map, startWith, tap } from 'rxjs/operators'; | import { map, startWith, tap } from 'rxjs/operators'; | ||||||
|  | import { ThemeService } from '../../services/theme.service'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-fees-box', |   selector: 'app-fees-box', | ||||||
| @ -11,14 +12,18 @@ import { map, startWith, tap } from 'rxjs/operators'; | |||||||
|   styleUrls: ['./fees-box.component.scss'], |   styleUrls: ['./fees-box.component.scss'], | ||||||
|   changeDetection: ChangeDetectionStrategy.OnPush, |   changeDetection: ChangeDetectionStrategy.OnPush, | ||||||
| }) | }) | ||||||
| export class FeesBoxComponent implements OnInit { | export class FeesBoxComponent implements OnInit, OnDestroy { | ||||||
|   isLoading$: Observable<boolean>; |   isLoading$: Observable<boolean>; | ||||||
|   recommendedFees$: Observable<Recommendedfees>; |   recommendedFees$: Observable<Recommendedfees>; | ||||||
|  |   themeSubscription: Subscription; | ||||||
|   gradient = 'linear-gradient(to right, #2e324e, #2e324e)'; |   gradient = 'linear-gradient(to right, #2e324e, #2e324e)'; | ||||||
|   noPriority = '#2e324e'; |   noPriority = '#2e324e'; | ||||||
|  |   fees: Recommendedfees; | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     private stateService: StateService |     private stateService: StateService, | ||||||
|  |     private themeService: ThemeService, | ||||||
|  |     private cd: ChangeDetectorRef, | ||||||
|   ) { } |   ) { } | ||||||
| 
 | 
 | ||||||
|   ngOnInit(): void { |   ngOnInit(): void { | ||||||
| @ -31,18 +36,32 @@ export class FeesBoxComponent implements OnInit { | |||||||
|     this.recommendedFees$ = this.stateService.recommendedFees$ |     this.recommendedFees$ = this.stateService.recommendedFees$ | ||||||
|       .pipe( |       .pipe( | ||||||
|         tap((fees) => { |         tap((fees) => { | ||||||
|           let feeLevelIndex = feeLevels.slice().reverse().findIndex((feeLvl) => fees.minimumFee >= feeLvl); |           this.fees = fees; | ||||||
|           feeLevelIndex = feeLevelIndex >= 0 ? feeLevels.length - feeLevelIndex : feeLevelIndex; |           this.setFeeGradient(); | ||||||
|           const startColor = '#' + (mempoolFeeColors[feeLevelIndex - 1] || mempoolFeeColors[mempoolFeeColors.length - 1]); |  | ||||||
| 
 |  | ||||||
|           feeLevelIndex = feeLevels.slice().reverse().findIndex((feeLvl) => fees.fastestFee >= feeLvl); |  | ||||||
|           feeLevelIndex = feeLevelIndex >= 0 ? feeLevels.length - feeLevelIndex : feeLevelIndex; |  | ||||||
|           const endColor = '#' + (mempoolFeeColors[feeLevelIndex - 1] || mempoolFeeColors[mempoolFeeColors.length - 1]); |  | ||||||
| 
 |  | ||||||
|           this.gradient = `linear-gradient(to right, ${startColor}, ${endColor})`; |  | ||||||
|           this.noPriority = startColor; |  | ||||||
|         } |         } | ||||||
|       ) |       ) | ||||||
|     ); |     ); | ||||||
|  |     this.themeSubscription = this.themeService.themeChanged$.subscribe(() => { | ||||||
|  |       this.setFeeGradient(); | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setFeeGradient() { | ||||||
|  |     let feeLevelIndex = feeLevels.slice().reverse().findIndex((feeLvl) => this.fees.minimumFee >= feeLvl); | ||||||
|  |     feeLevelIndex = feeLevelIndex >= 0 ? feeLevels.length - feeLevelIndex : feeLevelIndex; | ||||||
|  |     const startColor = '#' + (this.themeService.mempoolFeeColors[feeLevelIndex - 1] || this.themeService.mempoolFeeColors[this.themeService.mempoolFeeColors.length - 1]); | ||||||
|  | 
 | ||||||
|  |     feeLevelIndex = feeLevels.slice().reverse().findIndex((feeLvl) => this.fees.fastestFee >= feeLvl); | ||||||
|  |     feeLevelIndex = feeLevelIndex >= 0 ? feeLevels.length - feeLevelIndex : feeLevelIndex; | ||||||
|  |     const endColor = '#' + (this.themeService.mempoolFeeColors[feeLevelIndex - 1] || this.themeService.mempoolFeeColors[this.themeService.mempoolFeeColors.length - 1]); | ||||||
|  | 
 | ||||||
|  |     this.gradient = `linear-gradient(to right, ${startColor}, ${endColor})`; | ||||||
|  |     this.noPriority = startColor; | ||||||
|  | 
 | ||||||
|  |     this.cd.markForCheck(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   ngOnDestroy(): void { | ||||||
|  |     this.themeSubscription.unsubscribe(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
|   bottom: 0; |   bottom: 0; | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   height: 60px; |   height: 60px; | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
|   box-shadow: 15px 15px 15px 15px #000; |   box-shadow: 15px 15px 15px 15px #000; | ||||||
|   z-index: 10; |   z-index: 10; | ||||||
| 
 | 
 | ||||||
| @ -40,16 +40,8 @@ | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .txPerSecond { |  | ||||||
|   color: #4a9ff4; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .mempoolSize { | .mempoolSize { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .unconfirmedTx { |  | ||||||
|   color: #f14d80; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .info-block { | .info-block { | ||||||
| @ -61,7 +53,7 @@ | |||||||
| .progress { | .progress { | ||||||
|   display: inline-flex; |   display: inline-flex; | ||||||
|   width: 160px; |   width: 160px; | ||||||
|   background-color: #2d3348; |   background-color: var(--secondary); | ||||||
|   height: 1.1rem; |   height: 1.1rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -94,12 +94,12 @@ | |||||||
|     } |     } | ||||||
|     .card-title { |     .card-title { | ||||||
|       font-size: 1rem; |       font-size: 1rem; | ||||||
|       color: #4a68b9; |       color: var(--title-fg); | ||||||
|     } |     } | ||||||
|     .card-text { |     .card-text { | ||||||
|       font-size: 18px; |       font-size: 18px; | ||||||
|       span { |       span { | ||||||
|         color: #ffffff66; |         color: var(--transparent-fg); | ||||||
|         font-size: 12px; |         font-size: 12px; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -242,7 +242,7 @@ export class HashrateChartComponent implements OnInit { | |||||||
|         borderRadius: 4, |         borderRadius: 4, | ||||||
|         shadowColor: 'rgba(0, 0, 0, 0.5)', |         shadowColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|         textStyle: { |         textStyle: { | ||||||
|           color: '#b1b1b1', |           color: 'var(--tooltip-grey)', | ||||||
|           align: 'left', |           align: 'left', | ||||||
|         }, |         }, | ||||||
|         borderColor: '#000', |         borderColor: '#000', | ||||||
| @ -354,7 +354,7 @@ export class HashrateChartComponent implements OnInit { | |||||||
|           splitLine: { |           splitLine: { | ||||||
|             lineStyle: { |             lineStyle: { | ||||||
|               type: 'dotted', |               type: 'dotted', | ||||||
|               color: '#ffffff66', |               color: 'var(--transparent-fg)', | ||||||
|               opacity: 0.25, |               opacity: 0.25, | ||||||
|             } |             } | ||||||
|           }, |           }, | ||||||
| @ -472,7 +472,7 @@ export class HashrateChartComponent implements OnInit { | |||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     this.chartOptions.grid.bottom = 30; |     this.chartOptions.grid.bottom = 30; | ||||||
|     this.chartOptions.backgroundColor = '#11131f'; |     this.chartOptions.backgroundColor = 'var(--active-bg)'; | ||||||
|     this.chartInstance.setOption(this.chartOptions); |     this.chartInstance.setOption(this.chartOptions); | ||||||
|     download(this.chartInstance.getDataURL({ |     download(this.chartInstance.getDataURL({ | ||||||
|       pixelRatio: 2, |       pixelRatio: 2, | ||||||
|  | |||||||
| @ -225,7 +225,7 @@ export class HashrateChartPoolsComponent implements OnInit { | |||||||
|         borderRadius: 4, |         borderRadius: 4, | ||||||
|         shadowColor: 'rgba(0, 0, 0, 0.5)', |         shadowColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|         textStyle: { |         textStyle: { | ||||||
|           color: '#b1b1b1', |           color: 'var(--tooltip-grey)', | ||||||
|           align: 'left', |           align: 'left', | ||||||
|         }, |         }, | ||||||
|         borderColor: '#000', |         borderColor: '#000', | ||||||
| @ -308,7 +308,7 @@ export class HashrateChartPoolsComponent implements OnInit { | |||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     this.chartOptions.grid.bottom = 30; |     this.chartOptions.grid.bottom = 30; | ||||||
|     this.chartOptions.backgroundColor = '#11131f'; |     this.chartOptions.backgroundColor = 'var(--active-bg)'; | ||||||
|     this.chartInstance.setOption(this.chartOptions); |     this.chartInstance.setOption(this.chartOptions); | ||||||
|     download(this.chartInstance.getDataURL({ |     download(this.chartInstance.getDataURL({ | ||||||
|       pixelRatio: 2, |       pixelRatio: 2, | ||||||
|  | |||||||
| @ -272,7 +272,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On | |||||||
|         splitLine: { |         splitLine: { | ||||||
|           lineStyle: { |           lineStyle: { | ||||||
|             type: 'dotted', |             type: 'dotted', | ||||||
|             color: '#ffffff66', |             color: 'var(--transparent-fg)', | ||||||
|             opacity: 0.25, |             opacity: 0.25, | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
| @ -332,7 +332,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On | |||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     this.mempoolStatsChartOption.grid.height = prevHeight + 20; |     this.mempoolStatsChartOption.grid.height = prevHeight + 20; | ||||||
|     this.mempoolStatsChartOption.backgroundColor = '#11131f'; |     this.mempoolStatsChartOption.backgroundColor = 'var(--active-bg)'; | ||||||
|     this.chartInstance.setOption(this.mempoolStatsChartOption); |     this.chartInstance.setOption(this.mempoolStatsChartOption); | ||||||
|     download(this.chartInstance.getDataURL({ |     download(this.chartInstance.getDataURL({ | ||||||
|       pixelRatio: 2, |       pixelRatio: 2, | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| li.nav-item.active { | li.nav-item.active { | ||||||
|   background-color: #653b9c; |   background-color: var(--tertiary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fa-icon { | fa-icon { | ||||||
| @ -47,7 +47,7 @@ li.nav-item { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .navbar-nav { | .navbar-nav { | ||||||
|   background: #212121; |   background: var(--navbar-bg); | ||||||
|   bottom: 0; |   bottom: 0; | ||||||
|   box-shadow: 0px 0px 15px 0px #000; |   box-shadow: 0px 0px 15px 0px #000; | ||||||
|   flex-direction: row; |   flex-direction: row; | ||||||
| @ -91,6 +91,10 @@ li.nav-item { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .dropdown-container { | ||||||
|  |   margin-top: 5px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| nav { | nav { | ||||||
|   box-shadow: 0px 0px 15px 0px #000; |   box-shadow: 0px 0px 15px 0px #000; | ||||||
| } | } | ||||||
| @ -108,23 +112,23 @@ nav { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .mainnet.active { | .mainnet.active { | ||||||
|   background-color: #653b9c; |   background-color: var(--tertiary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .liquid.active { | .liquid.active { | ||||||
|   background-color: #116761; |   background-color: var(--liquid); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .liquidtestnet.active { | .liquidtestnet.active { | ||||||
|   background-color: #494a4a; |   background-color: var(--liquidtestnet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .testnet.active { | .testnet.active { | ||||||
|   background-color: #1d486f; |   background-color: var(--testnet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .signet.active { | .signet.active { | ||||||
|   background-color: #6f1d5d; |   background-color: var(--signet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .dropdown-divider { | .dropdown-divider { | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ | |||||||
| 
 | 
 | ||||||
|   <div class="item"> |   <div class="item"> | ||||||
|     <a class="title-link" [routerLink]="['/audit/wallet/utxos' | relativeUrl]" [fragment]="'expired'"> |     <a class="title-link" [routerLink]="['/audit/wallet/utxos' | relativeUrl]" [fragment]="'expired'"> | ||||||
|       <h5 class="card-title"><ng-container i18n="liquid.total-expired">Total Expired</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5> |       <h5 class="card-title"><ng-container i18n="liquid.total-expired">Total Expired</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: var(--title-fg)"></fa-icon></h5> | ||||||
|     </a> |     </a> | ||||||
|     <div *ngIf="(stats$ | async) as expiredStats; else loadingData" class="card-text"> |     <div *ngIf="(stats$ | async) as expiredStats; else loadingData" class="card-text"> | ||||||
|       <div class="fee-text" i18n-ngbTooltip="liquid.expired-utxos" ngbTooltip="Total amount of BTC held in Federation UTXOs that have expired timelocks" placement="top">{{ (+expiredStats.all.total) / 100000000 | number: '1.5-5' }} <span style="color: #b86d12;">BTC</span></div> |       <div class="fee-text" i18n-ngbTooltip="liquid.expired-utxos" ngbTooltip="Total amount of BTC held in Federation UTXOs that have expired timelocks" placement="top">{{ (+expiredStats.all.total) / 100000000 | number: '1.5-5' }} <span style="color: #b86d12;">BTC</span></div> | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .card-title { |     .card-title { | ||||||
|       color: #4a68b9; |       color: var(--title-fg); | ||||||
|       font-size: 10px; |       font-size: 10px; | ||||||
|       margin-bottom: 4px;   |       margin-bottom: 4px;   | ||||||
|       font-size: 1rem; |       font-size: 1rem; | ||||||
|  | |||||||
| @ -33,7 +33,7 @@ tr, td, th { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .progress { | .progress { | ||||||
|   background-color: #2d3348; |   background-color: var(--secondary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .address { | .address { | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
|   <div class="fee-estimation-container"> |   <div class="fee-estimation-container"> | ||||||
|     <div class="item"> |     <div class="item"> | ||||||
|       <a class="title-link" [routerLink]="['/audit/wallet/addresses' | relativeUrl]"> |       <a class="title-link" [routerLink]="['/audit/wallet/addresses' | relativeUrl]"> | ||||||
|         <h5 class="card-title"><ng-container i18n="liquid.federation-wallet">Liquid Federation Wallet</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5> |         <h5 class="card-title"><ng-container i18n="liquid.federation-wallet">Liquid Federation Wallet</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: var(--title-fg)"></fa-icon></h5> | ||||||
|       </a> |       </a> | ||||||
|       <div class="card-text"> |       <div class="card-text"> | ||||||
|         <div class="fee-text">{{ federationWalletStats.address_count }} <span i18n="shared.addresses">addresses</span></div> |         <div class="fee-text">{{ federationWalletStats.address_count }} <span i18n="shared.addresses">addresses</span></div> | ||||||
| @ -16,7 +16,7 @@ | |||||||
|   <div class="fee-estimation-container loading-container"> |   <div class="fee-estimation-container loading-container"> | ||||||
|     <div class="item"> |     <div class="item"> | ||||||
|       <a class="title-link" [routerLink]="['/audit/wallet/addresses' | relativeUrl]"> |       <a class="title-link" [routerLink]="['/audit/wallet/addresses' | relativeUrl]"> | ||||||
|         <h5 class="card-title"><ng-container i18n="liquid.federation-wallet">Liquid Federation Wallet</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5> |         <h5 class="card-title"><ng-container i18n="liquid.federation-wallet">Liquid Federation Wallet</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: var(--title-fg)"></fa-icon></h5> | ||||||
|       </a> |       </a> | ||||||
|       <div class="card-text"> |       <div class="card-text"> | ||||||
|         <div class="skeleton-loader"></div> |         <div class="skeleton-loader"></div> | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ | |||||||
| 
 | 
 | ||||||
|     .card-title { |     .card-title { | ||||||
|       margin: 0; |       margin: 0; | ||||||
|       color: #4a68b9; |       color: var(--title-fg); | ||||||
|       font-size: 10px; |       font-size: 10px; | ||||||
|       font-size: 1rem; |       font-size: 1rem; | ||||||
|       white-space: nowrap; |       white-space: nowrap; | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ tr, td, th { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .progress { | .progress { | ||||||
|   background-color: #2d3348; |   background-color: var(--secondary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .txid { | .txid { | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ tr, td, th { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .progress { | .progress { | ||||||
|   background-color: #2d3348; |   background-color: var(--secondary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .transaction { | .transaction { | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
|   <div class="fee-estimation-container"> |   <div class="fee-estimation-container"> | ||||||
|     <div class="item"> |     <div class="item"> | ||||||
|       <a class="title-link" [routerLink]="['/audit/pegs' | relativeUrl]"> |       <a class="title-link" [routerLink]="['/audit/pegs' | relativeUrl]"> | ||||||
|         <h5 class="card-title"><ng-container i18n="liquid.recent-pegs">Recent Peg-In / Out's</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5> |         <h5 class="card-title"><ng-container i18n="liquid.recent-pegs">Recent Peg-In / Out's</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: var(--title-fg)"></fa-icon></h5> | ||||||
|       </a> |       </a> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
| @ -26,7 +26,7 @@ | |||||||
|   <div class="fee-estimation-container loading-container"> |   <div class="fee-estimation-container loading-container"> | ||||||
|     <div class="item"> |     <div class="item"> | ||||||
|       <a class="title-link" [routerLink]="['/audit/pegs' | relativeUrl]"> |       <a class="title-link" [routerLink]="['/audit/pegs' | relativeUrl]"> | ||||||
|         <h5 class="card-title"><ng-container i18n="liquid.recent-pegs">Recent Peg-In / Out's</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5> |         <h5 class="card-title"><ng-container i18n="liquid.recent-pegs">Recent Peg-In / Out's</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: var(--title-fg)"></fa-icon></h5> | ||||||
|       </a> |       </a> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ | |||||||
| 
 | 
 | ||||||
|     .card-title { |     .card-title { | ||||||
|       margin: 0; |       margin: 0; | ||||||
|       color: #4a68b9; |       color: var(--title-fg); | ||||||
|       font-size: 10px; |       font-size: 10px; | ||||||
|       font-size: 1rem; |       font-size: 1rem; | ||||||
|       white-space: nowrap; |       white-space: nowrap; | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ | |||||||
| 
 | 
 | ||||||
|   <div class="item"> |   <div class="item"> | ||||||
|     <!-- <a class="title-link" [routerLink]="['/audit/emergency-spends' | relativeUrl]"> |     <!-- <a class="title-link" [routerLink]="['/audit/emergency-spends' | relativeUrl]"> | ||||||
|       <h5 class="card-title"><ng-container i18n="liquid.forfeited-utxos">Forfeited UTXOs</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5> |       <h5 class="card-title"><ng-container i18n="liquid.forfeited-utxos">Forfeited UTXOs</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: var(--title-fg)"></fa-icon></h5> | ||||||
|     </a> --> |     </a> --> | ||||||
|     <h5 class="card-title" i18n="liquid.emergency-keys">Emergency Keys</h5> |     <h5 class="card-title" i18n="liquid.emergency-keys">Emergency Keys</h5> | ||||||
|     <div *ngIf="(emergencyUtxosStats$ | async) as emergencyUtxosStats; else loadingData" class="card-text"> |     <div *ngIf="(emergencyUtxosStats$ | async) as emergencyUtxosStats; else loadingData" class="card-text"> | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ | |||||||
| 
 | 
 | ||||||
|     .card-title { |     .card-title { | ||||||
|       margin-bottom: 4px; |       margin-bottom: 4px; | ||||||
|       color: #4a68b9; |       color: var(--title-fg); | ||||||
|       font-size: 10px; |       font-size: 10px; | ||||||
|       font-size: 1rem; |       font-size: 1rem; | ||||||
|       white-space: nowrap; |       white-space: nowrap; | ||||||
|  | |||||||
| @ -141,7 +141,7 @@ export class ReservesRatioComponent implements OnInit, OnChanges { | |||||||
|             show: true, |             show: true, | ||||||
|             offsetCenter: [0, '-127%'], |             offsetCenter: [0, '-127%'], | ||||||
|             fontSize: 18, |             fontSize: 18, | ||||||
|             color: '#4a68b9', |             color: 'var(--title-fg)', | ||||||
|             fontFamily: 'inherit', |             fontFamily: 'inherit', | ||||||
|             fontWeight: 500, |             fontWeight: 500, | ||||||
|           }, |           }, | ||||||
|  | |||||||
| @ -13,7 +13,7 @@ | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .card-title { |     .card-title { | ||||||
|       color: #4a68b9; |       color: var(--title-fg); | ||||||
|       font-size: 10px; |       font-size: 10px; | ||||||
|       margin-bottom: 4px;   |       margin-bottom: 4px;   | ||||||
|       font-size: 1rem; |       font-size: 1rem; | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ | |||||||
|     flex-direction: row; |     flex-direction: row; | ||||||
|     justify-content: space-between; |     justify-content: space-between; | ||||||
|     align-items: center; |     align-items: center; | ||||||
|     background: #11131f; |     background: var(--active-bg); | ||||||
|     text-align: start; |     text-align: start; | ||||||
|     font-size: 1.8em; |     font-size: 1.8em; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| li.nav-item.active { | li.nav-item.active { | ||||||
|   background-color: #653b9c; |   background-color: var(--tertiary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fa-icon { | fa-icon { | ||||||
| @ -58,7 +58,7 @@ li.nav-item { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .navbar-nav { | .navbar-nav { | ||||||
|   background: #212121; |   background: var(--navbar-bg); | ||||||
|   bottom: 0; |   bottom: 0; | ||||||
|   box-shadow: 0px 0px 15px 0px #000; |   box-shadow: 0px 0px 15px 0px #000; | ||||||
|   flex-direction: row; |   flex-direction: row; | ||||||
| @ -139,23 +139,23 @@ nav { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .mainnet.active { | .mainnet.active { | ||||||
|   background-color: #653b9c; |   background-color: var(--tertiary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .liquid.active { | .liquid.active { | ||||||
|   background-color: #116761; |   background-color: var(--liquid); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .liquidtestnet.active { | .liquidtestnet.active { | ||||||
|   background-color: #494a4a; |   background-color: var(--liquidtestnet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .testnet.active { | .testnet.active { | ||||||
|   background-color: #1d486f; |   background-color: var(--testnet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .signet.active { | .signet.active { | ||||||
|   background-color: #6f1d5d; |   background-color: var(--signet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .dropdown-divider { | .dropdown-divider { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| .progress { | .progress { | ||||||
|   background-color: #2d3348; |   background-color: var(--secondary); | ||||||
|   position: relative; |   position: relative; | ||||||
|   top: 5px; |   top: 5px; | ||||||
| } | } | ||||||
|  | |||||||
| @ -106,7 +106,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .black-background { | .black-background { | ||||||
|   background-color: #11131f; |   background-color: var(--active-bg); | ||||||
|   z-index: 100; |   z-index: 100; | ||||||
|   position: relative; |   position: relative; | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,12 +4,13 @@ import { MempoolBlock } from '../../interfaces/websocket.interface'; | |||||||
| import { StateService } from '../../services/state.service'; | import { StateService } from '../../services/state.service'; | ||||||
| import { Router } from '@angular/router'; | import { Router } from '@angular/router'; | ||||||
| import { map, switchMap, tap } from 'rxjs/operators'; | import { map, switchMap, tap } from 'rxjs/operators'; | ||||||
| import { feeLevels, mempoolFeeColors } from '../../app.constants'; | import { feeLevels } from '../../app.constants'; | ||||||
| import { specialBlocks } from '../../app.constants'; | import { specialBlocks } from '../../app.constants'; | ||||||
| import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; | import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; | ||||||
| import { Location } from '@angular/common'; | import { Location } from '@angular/common'; | ||||||
| import { DifficultyAdjustment, MempoolPosition } from '../../interfaces/node-api.interface'; | import { DifficultyAdjustment, MempoolPosition } from '../../interfaces/node-api.interface'; | ||||||
| import { animate, style, transition, trigger } from '@angular/animations'; | import { animate, style, transition, trigger } from '@angular/animations'; | ||||||
|  | import { ThemeService } from '../../services/theme.service'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-mempool-blocks', |   selector: 'app-mempool-blocks', | ||||||
| @ -84,6 +85,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|   constructor( |   constructor( | ||||||
|     private router: Router, |     private router: Router, | ||||||
|     public stateService: StateService, |     public stateService: StateService, | ||||||
|  |     private themeService: ThemeService, | ||||||
|     private cd: ChangeDetectorRef, |     private cd: ChangeDetectorRef, | ||||||
|     private relativeUrlPipe: RelativeUrlPipe, |     private relativeUrlPipe: RelativeUrlPipe, | ||||||
|     private location: Location, |     private location: Location, | ||||||
| @ -354,7 +356,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     trimmedFeeRange.forEach((fee: number) => { |     trimmedFeeRange.forEach((fee: number) => { | ||||||
|       let feeLevelIndex = feeLevels.slice().reverse().findIndex((feeLvl) => fee >= feeLvl); |       let feeLevelIndex = feeLevels.slice().reverse().findIndex((feeLvl) => fee >= feeLvl); | ||||||
|       feeLevelIndex = feeLevelIndex >= 0 ? feeLevels.length - feeLevelIndex : feeLevelIndex; |       feeLevelIndex = feeLevelIndex >= 0 ? feeLevels.length - feeLevelIndex : feeLevelIndex; | ||||||
|       gradientColors.push(mempoolFeeColors[feeLevelIndex - 1] || mempoolFeeColors[mempoolFeeColors.length - 1]); |       gradientColors.push(this.themeService.mempoolFeeColors[feeLevelIndex - 1] || this.themeService.mempoolFeeColors[this.themeService.mempoolFeeColors.length - 1]); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     gradientColors.forEach((color, i, gc) => { |     gradientColors.forEach((color, i, gc) => { | ||||||
|  | |||||||
| @ -432,7 +432,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { | |||||||
|         splitLine: { |         splitLine: { | ||||||
|           lineStyle: { |           lineStyle: { | ||||||
|             type: 'dotted', |             type: 'dotted', | ||||||
|             color: '#ffffff66', |             color: 'var(--transparent-fg)', | ||||||
|             opacity: 0.25, |             opacity: 0.25, | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
| @ -500,7 +500,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { | |||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     this.mempoolVsizeFeesOptions.grid.height = prevHeight + 20; |     this.mempoolVsizeFeesOptions.grid.height = prevHeight + 20; | ||||||
|     this.mempoolVsizeFeesOptions.backgroundColor = '#11131f'; |     this.mempoolVsizeFeesOptions.backgroundColor = 'var(--active-bg)'; | ||||||
|     this.chartInstance.setOption(this.mempoolVsizeFeesOptions); |     this.chartInstance.setOption(this.mempoolVsizeFeesOptions); | ||||||
|     download(this.chartInstance.getDataURL({ |     download(this.chartInstance.getDataURL({ | ||||||
|       pixelRatio: 2, |       pixelRatio: 2, | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ | |||||||
| 
 | 
 | ||||||
| .sidenav.open { | .sidenav.open { | ||||||
|   display: block; |   display: block; | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| :host-context(.ltr-layout) .sidenav.open { | :host-context(.ltr-layout) .sidenav.open { | ||||||
| @ -56,7 +56,7 @@ | |||||||
| .sidenav nav { | .sidenav nav { | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   height: calc(100vh - 65px); |   height: calc(100vh - 65px); | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
|   padding-left: 20px; |   padding-left: 20px; | ||||||
|   padding-right: 20px; |   padding-right: 20px; | ||||||
|   padding-top: 20px; |   padding-top: 20px; | ||||||
| @ -75,7 +75,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .badge-og { | .badge-og { | ||||||
|   background-color: #4a68b9; |   background-color: var(--title-fg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .badge-pleb { | .badge-pleb { | ||||||
| @ -87,7 +87,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .badge-whale { | .badge-whale { | ||||||
|   background-color: #653b9c; |   background-color: var(--tertiary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .badge-silver { | .badge-silver { | ||||||
| @ -99,5 +99,5 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .badge-platinum { | .badge-platinum { | ||||||
|   background-color: #653b9c; |   background-color: var(--tertiary); | ||||||
| } | } | ||||||
| @ -55,7 +55,7 @@ | |||||||
|           <a class="title-link" href="" [routerLink]="['/blocks' | relativeUrl]"> |           <a class="title-link" href="" [routerLink]="['/blocks' | relativeUrl]"> | ||||||
|             <h5 class="card-title d-inline" i18n="dashboard.recent-blocks">Recent Blocks</h5> |             <h5 class="card-title d-inline" i18n="dashboard.recent-blocks">Recent Blocks</h5> | ||||||
|             <span> </span> |             <span> </span> | ||||||
|             <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: #4a68b9"></fa-icon> |             <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: var(--title-fg)"></fa-icon> | ||||||
|           </a> |           </a> | ||||||
|           <app-blocks-list [attr.data-cy]="'latest-blocks'" [widget]=true></app-blocks-list> |           <app-blocks-list [attr.data-cy]="'latest-blocks'" [widget]=true></app-blocks-list> | ||||||
|         </div> |         </div> | ||||||
| @ -69,7 +69,7 @@ | |||||||
|           <a class="title-link" href="" [routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]"> |           <a class="title-link" href="" [routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]"> | ||||||
|             <h5 class="card-title d-inline" i18n="dashboard.adjustments">Adjustments</h5> |             <h5 class="card-title d-inline" i18n="dashboard.adjustments">Adjustments</h5> | ||||||
|             <span> </span> |             <span> </span> | ||||||
|             <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: #4a68b9"></fa-icon> |             <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: var(--title-fg)"></fa-icon> | ||||||
|           </a> |           </a> | ||||||
|           <app-difficulty-adjustments-table [attr.data-cy]="'difficulty-adjustments-table'"></app-difficulty-adjustments-table> |           <app-difficulty-adjustments-table [attr.data-cy]="'difficulty-adjustments-table'"></app-difficulty-adjustments-table> | ||||||
|         </div> |         </div> | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .card { | .card { | ||||||
|   background-color: #1d1f31; |   background-color: var(--bg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .graph-card { | .graph-card { | ||||||
| @ -32,10 +32,10 @@ | |||||||
| 
 | 
 | ||||||
| .card-title { | .card-title { | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
| } | } | ||||||
| .card-title > a { | .card-title > a { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .card-body.pool-ranking { | .card-body.pool-ranking { | ||||||
|  | |||||||
| @ -99,7 +99,7 @@ | |||||||
|     } |     } | ||||||
|     .card-title { |     .card-title { | ||||||
|       font-size: 1rem; |       font-size: 1rem; | ||||||
|       color: #4a68b9; |       color: var(--title-fg); | ||||||
|       overflow: hidden; |       overflow: hidden; | ||||||
|       text-overflow: ellipsis; |       text-overflow: ellipsis; | ||||||
|       white-space: nowrap; |       white-space: nowrap; | ||||||
| @ -107,7 +107,7 @@ | |||||||
|     .card-text { |     .card-text { | ||||||
|       font-size: 18px; |       font-size: 18px; | ||||||
|       span { |       span { | ||||||
|         color: #ffffff66; |         color: var(--transparent-fg); | ||||||
|         font-size: 12px; |         font-size: 12px; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -146,7 +146,7 @@ export class PoolRankingComponent implements OnInit { | |||||||
|         name: pool.name + ((isMobile() || this.widget) ? `` : ` (${pool.share}%)`), |         name: pool.name + ((isMobile() || this.widget) ? `` : ` (${pool.share}%)`), | ||||||
|         label: { |         label: { | ||||||
|           overflow: 'none', |           overflow: 'none', | ||||||
|           color: '#b1b1b1', |           color: 'var(--tooltip-grey)', | ||||||
|           alignTo: 'edge', |           alignTo: 'edge', | ||||||
|           edgeDistance: edgeDistance, |           edgeDistance: edgeDistance, | ||||||
|         }, |         }, | ||||||
| @ -156,7 +156,7 @@ export class PoolRankingComponent implements OnInit { | |||||||
|           borderRadius: 4, |           borderRadius: 4, | ||||||
|           shadowColor: 'rgba(0, 0, 0, 0.5)', |           shadowColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|           textStyle: { |           textStyle: { | ||||||
|             color: '#b1b1b1', |             color: 'var(--tooltip-grey)', | ||||||
|           }, |           }, | ||||||
|           borderColor: '#000', |           borderColor: '#000', | ||||||
|           formatter: () => { |           formatter: () => { | ||||||
| @ -186,7 +186,7 @@ export class PoolRankingComponent implements OnInit { | |||||||
|       name:  $localize`Other (${percentage})`, |       name:  $localize`Other (${percentage})`, | ||||||
|       label: { |       label: { | ||||||
|         overflow: 'none', |         overflow: 'none', | ||||||
|         color: '#b1b1b1', |         color: 'var(--tooltip-grey)', | ||||||
|         alignTo: 'edge', |         alignTo: 'edge', | ||||||
|         edgeDistance: edgeDistance |         edgeDistance: edgeDistance | ||||||
|       }, |       }, | ||||||
| @ -195,7 +195,7 @@ export class PoolRankingComponent implements OnInit { | |||||||
|         borderRadius: 4, |         borderRadius: 4, | ||||||
|         shadowColor: 'rgba(0, 0, 0, 0.5)', |         shadowColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|         textStyle: { |         textStyle: { | ||||||
|           color: '#b1b1b1', |           color: 'var(--tooltip-grey)', | ||||||
|         }, |         }, | ||||||
|         borderColor: '#000', |         borderColor: '#000', | ||||||
|         formatter: () => { |         formatter: () => { | ||||||
| @ -306,7 +306,7 @@ export class PoolRankingComponent implements OnInit { | |||||||
| 
 | 
 | ||||||
|   onSaveChart() { |   onSaveChart() { | ||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     this.chartOptions.backgroundColor = '#11131f'; |     this.chartOptions.backgroundColor = 'var(--active-bg)'; | ||||||
|     this.chartInstance.setOption(this.chartOptions); |     this.chartInstance.setOption(this.chartOptions); | ||||||
|     download(this.chartInstance.getDataURL({ |     download(this.chartInstance.getDataURL({ | ||||||
|       pixelRatio: 2, |       pixelRatio: 2, | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ | |||||||
|     justify-content: space-between; |     justify-content: space-between; | ||||||
|     width: 100%; |     width: 100%; | ||||||
|     margin-left: 15px; |     margin-left: 15px; | ||||||
|     background: #181b2d; |     background: var(--stat-box-bg); | ||||||
|     padding: 0.75rem; |     padding: 0.75rem; | ||||||
|     width: 0; |     width: 0; | ||||||
|     flex-grow: 1; |     flex-grow: 1; | ||||||
| @ -43,7 +43,7 @@ | |||||||
| .chart { | .chart { | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   height: 315px; |   height: 315px; | ||||||
|   background: #181b2d; |   background: var(--stat-box-bg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .row { | .row { | ||||||
| @ -65,7 +65,7 @@ | |||||||
|     position: absolute; |     position: absolute; | ||||||
|     right: 0; |     right: 0; | ||||||
|     top: 0; |     top: 0; | ||||||
|     background: #24273e; |     background: var(--box-bg); | ||||||
| 
 | 
 | ||||||
|     &.noimg { |     &.noimg { | ||||||
|       opacity: 0; |       opacity: 0; | ||||||
|  | |||||||
| @ -88,7 +88,7 @@ div.scrollable { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .progress { | .progress { | ||||||
|   background-color: #2d3348; |   background-color: var(--secondary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .coinbase { | .coinbase { | ||||||
| @ -190,7 +190,7 @@ div.scrollable { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .data-title { | .data-title { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
|   font-size: 14px; |   font-size: 14px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -175,7 +175,7 @@ export class PoolComponent implements OnInit { | |||||||
|         borderRadius: 4, |         borderRadius: 4, | ||||||
|         shadowColor: 'rgba(0, 0, 0, 0.5)', |         shadowColor: 'rgba(0, 0, 0, 0.5)', | ||||||
|         textStyle: { |         textStyle: { | ||||||
|           color: '#b1b1b1', |           color: 'var(--tooltip-grey)', | ||||||
|           align: 'left', |           align: 'left', | ||||||
|         }, |         }, | ||||||
|         borderColor: '#000', |         borderColor: '#000', | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .timeline-wrapper.mined { |   .timeline-wrapper.mined { | ||||||
|     border: solid 4px #1a9436; |     border: solid 4px var(--success); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .no-replacements { |   .no-replacements { | ||||||
|  | |||||||
| @ -15,12 +15,12 @@ | |||||||
| 
 | 
 | ||||||
|   &::before { |   &::before { | ||||||
|     left: 0; |     left: 0; | ||||||
|     background: linear-gradient(to right, #24273e, #24273e, transparent); |     background: linear-gradient(to right, var(--box-bg), var(--box-bg), transparent); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &::after { |   &::after { | ||||||
|     right: 0; |     right: 0; | ||||||
|     background: linear-gradient(to left, #24273e, #24273e, transparent); |     background: linear-gradient(to left, var(--box-bg), var(--box-bg), transparent); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .timeline-wrapper { |   .timeline-wrapper { | ||||||
| @ -45,7 +45,7 @@ | |||||||
|       width: 100%; |       width: 100%; | ||||||
|       height: 70px; |       height: 70px; | ||||||
|       top: -70px; |       top: -70px; | ||||||
|       background: linear-gradient(to bottom, rgba(36, 39, 62, 0) 0%, rgba(36, 39, 62, 1) 100%); |       background: linear-gradient(to bottom, var(--fade-out-box-bg-start), var(--fade-out-box-bg-end)); | ||||||
|       z-index: 1; |       z-index: 1; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -101,7 +101,7 @@ | |||||||
|       right: -5px; |       right: -5px; | ||||||
|       top: 0; |       top: 0; | ||||||
|       transform: translateY(-50%); |       transform: translateY(-50%); | ||||||
|       background: #105fb0; |       background: var(--primary); | ||||||
|       border-radius: 5px; |       border-radius: 5px; | ||||||
| 
 | 
 | ||||||
|       &.left { |       &.left { | ||||||
| @ -112,7 +112,7 @@ | |||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       &.fullrbf { |       &.fullrbf { | ||||||
|         background: #1bd8f4; |         background: var(--info); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     &.first-node { |     &.first-node { | ||||||
| @ -165,20 +165,20 @@ | |||||||
| 
 | 
 | ||||||
|       &.mined { |       &.mined { | ||||||
|         .shape-border { |         .shape-border { | ||||||
|           background: #1a9436; |           background: var(--success); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       .shape-border:hover { |       .shape-border:hover { | ||||||
|         padding: 0px; |         padding: 0px; | ||||||
|         .shape { |         .shape { | ||||||
|           background: #1bd8f4; |           background: var(--info); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       &.selected.mined { |       &.selected.mined { | ||||||
|         .shape-border { |         .shape-border { | ||||||
|           background: #1a9436; |           background: var(--success); | ||||||
|           height: calc(1em + 16px); |           height: calc(1em + 16px); | ||||||
|           width: calc(1em + 16px); |           width: calc(1em + 16px); | ||||||
| 
 | 
 | ||||||
| @ -190,7 +190,7 @@ | |||||||
|             padding: 4px; |             padding: 4px; | ||||||
|             .shape { |             .shape { | ||||||
|               border-width: 1px; |               border-width: 1px; | ||||||
|               border-color: #1bd8f4 |               border-color: var(--info) | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
| @ -207,9 +207,9 @@ | |||||||
|         width: 20px; |         width: 20px; | ||||||
|         height: 108px; |         height: 108px; | ||||||
|         bottom: 50%; |         bottom: 50%; | ||||||
|         border-right: solid 10px #105fb0; |         border-right: solid 10px var(--primary); | ||||||
|         &.fullrbf { |         &.fullrbf { | ||||||
|           border-right: solid 10px #1bd8f4; |           border-right: solid 10px var(--info); | ||||||
|         } |         } | ||||||
|         &.last-pipe { |         &.last-pipe { | ||||||
|           height: 150px; |           height: 150px; | ||||||
| @ -218,10 +218,10 @@ | |||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       .corner { |       .corner { | ||||||
|         border-bottom: solid 10px #105fb0; |         border-bottom: solid 10px var(--primary); | ||||||
|         border-bottom-right-radius: 10px; |         border-bottom-right-radius: 10px; | ||||||
|         &.fullrbf { |         &.fullrbf { | ||||||
|           border-bottom: solid 10px #1bd8f4; |           border-bottom: solid 10px var(--info); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| .card-title { | .card-title { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
|   font-size: 10px; |   font-size: 10px; | ||||||
|   margin-bottom: 4px;   |   margin-bottom: 4px;   | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
| @ -50,7 +50,7 @@ | |||||||
|       margin-bottom: 0; |       margin-bottom: 0; | ||||||
|     } |     } | ||||||
|     .card-text span { |     .card-text span { | ||||||
|       color: #ffffff66; |       color: var(--transparent-fg); | ||||||
|       font-size: 12px; |       font-size: 12px; | ||||||
|       top: 0px; |       top: 0px; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| .card-title { | .card-title { | ||||||
|   color: #4a68b9; |   color: var(--title-fg); | ||||||
|   font-size: 10px; |   font-size: 10px; | ||||||
|   margin-bottom: 4px; |   margin-bottom: 4px; | ||||||
|   font-size: 1rem; |   font-size: 1rem; | ||||||
|  | |||||||
| @ -32,7 +32,7 @@ | |||||||
|     cursor: pointer; |     cursor: pointer; | ||||||
|     opacity: 0.8; |     opacity: 0.8; | ||||||
|     transition: opacity 500ms; |     transition: opacity 500ms; | ||||||
|     background: radial-gradient(#1d1f31 0%, transparent 50%); |     background: radial-gradient(var(--bg) 0%, transparent 50%); | ||||||
| 
 | 
 | ||||||
|     &:hover { |     &:hover { | ||||||
|       opacity: 1; |       opacity: 1; | ||||||
|  | |||||||
| @ -117,7 +117,7 @@ | |||||||
|   } |   } | ||||||
|   .inactive { |   .inactive { | ||||||
|     .square { |     .square { | ||||||
|       background-color: #ffffff66 !important; |       background-color: var(--transparent-fg) !important; | ||||||
|     } |     } | ||||||
|     .fee-text { |     .fee-text { | ||||||
|       text-decoration: line-through; |       text-decoration: line-through; | ||||||
|  | |||||||
| @ -0,0 +1,6 @@ | |||||||
|  | <div [formGroup]="themeForm" class="text-small text-center"> | ||||||
|  |     <select formControlName="theme" class="custom-select custom-select-sm form-control-secondary form-control mx-auto" (change)="changeTheme()"> | ||||||
|  |         <option value="default" i18n="theme.mempool-theme">Classic</option> | ||||||
|  |         <option value="contrast" i18n="theme.high-contrast">BlueMatt</option> | ||||||
|  |     </select> | ||||||
|  | </div> | ||||||
| @ -0,0 +1,3 @@ | |||||||
|  | .custom-select { | ||||||
|  |   width: 100px; | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user