diff --git a/frontend/generate-themes.js b/frontend/generate-themes.js index da7f06c20..ef8785203 100644 --- a/frontend/generate-themes.js +++ b/frontend/generate-themes.js @@ -3,7 +3,7 @@ const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); -const THEMES = ['contrast', 'softsimon', 'bukele']; +const THEMES = ['contrast', 'softsimon', 'bukele', 'nymkappa']; const STAGING_DIR = path.join(__dirname, '.theme-build'); const DIST_DIR = path.join(__dirname, 'dist/mempool/browser'); const MANIFEST_FILE = path.join(__dirname, 'theme-manifest.json'); diff --git a/frontend/src/app/app.constants.ts b/frontend/src/app/app.constants.ts index 730da5a81..8bf6b73a2 100644 --- a/frontend/src/app/app.constants.ts +++ b/frontend/src/app/app.constants.ts @@ -82,6 +82,48 @@ export const contrastMempoolFeeColors = [ 'ffb700', ]; + export const lightMempoolFeeColors = [ + '49c284', + '99c246', + 'a0c343', + 'a7c240', + 'b0c13c', + 'b8c03b', + 'bebe3a', + 'beb238', + 'bcac37', + 'bba336', + 'b99e35', + 'b79334', + 'b68f33', + 'b68a32', + 'b48430', + 'b17f30', + 'b07b2f', + 'ae722e', + 'ad6b2d', + 'ab652b', + 'aa5b2a', + 'a95629', + 'a74c28', + 'a34126', + 'a13a25', + 'a02d24', + '9e2423', + '9c222a', + '9c2132', + '9b203a', + '99203e', + '972043', + '951f45', + '931e48', + '921d49', + '921c4e', + '901b50', + '8e1a53', + '8b1954', +]; + export const chartColors = [ '#A81524', '#D81B60', diff --git a/frontend/src/app/components/theme-selector/theme-selector.component.html b/frontend/src/app/components/theme-selector/theme-selector.component.html index e74767e21..63fce0263 100644 --- a/frontend/src/app/components/theme-selector/theme-selector.component.html +++ b/frontend/src/app/components/theme-selector/theme-selector.component.html @@ -3,5 +3,6 @@ + diff --git a/frontend/src/app/components/theme-selector/theme-selector.component.ts b/frontend/src/app/components/theme-selector/theme-selector.component.ts index 72846de6b..25a410dd9 100644 --- a/frontend/src/app/components/theme-selector/theme-selector.component.ts +++ b/frontend/src/app/components/theme-selector/theme-selector.component.ts @@ -12,7 +12,7 @@ import { Subscription } from 'rxjs'; }) export class ThemeSelectorComponent implements OnInit, OnDestroy { themeForm: UntypedFormGroup; - themes = ['default', 'contrast', 'softsimon', 'bukele']; + themes = ['default', 'contrast', 'softsimon', 'bukele', 'nymkappa']; themeStateSubscription: Subscription; constructor( diff --git a/frontend/src/app/services/theme.service.ts b/frontend/src/app/services/theme.service.ts index 0f184e9d2..a4c90b7cb 100644 --- a/frontend/src/app/services/theme.service.ts +++ b/frontend/src/app/services/theme.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; -import { defaultMempoolFeeColors, contrastMempoolFeeColors } from '@app/app.constants'; +import { defaultMempoolFeeColors, contrastMempoolFeeColors, lightMempoolFeeColors } from '@app/app.constants'; import { StorageService } from '@app/services/storage.service'; import { StateService } from '@app/services/state.service'; @@ -20,7 +20,7 @@ export class ThemeService { ) { let theme = this.stateService.env.customize?.theme || this.storageService.getValue('theme-preference') || 'default'; // theme preference must be a valid known public theme - if (!this.stateService.env.customize?.theme && !['default', 'contrast', 'softsimon'].includes(theme)) { + if (!this.stateService.env.customize?.theme && !['default', 'contrast', 'softsimon', 'nymkappa'].includes(theme)) { theme = 'default'; this.storageService.setValue('theme-preference', 'default'); } @@ -64,7 +64,7 @@ export class ThemeService { this.style.media = 'all'; this.initialLoad = false; } - this.mempoolFeeColors = theme === 'contrast' || theme === 'bukele' ? contrastMempoolFeeColors : defaultMempoolFeeColors; + this.mempoolFeeColors = this.getMempoolFeeColors(theme); this.themeState$.next({ theme, loading: false }); }; this.style.onerror = () => this.apply('default'); @@ -86,4 +86,16 @@ export class ThemeService { } return `${theme}.css`; } + + private getMempoolFeeColors(theme: string): string[] { + switch (theme) { + case 'contrast': + case 'bukele': + return contrastMempoolFeeColors; + case 'nymkappa': + return lightMempoolFeeColors; + default: + return defaultMempoolFeeColors; + } + } } diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index b4c73b2e9..ebd6de61e 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -97,6 +97,8 @@ $dropdown-link-active-bg: $active-bg; --hover-bg: #{$hover-bg}; --fg: #{$fg}; --nav-bg: #{$nav-bg}; + --nav-icon: #fff; + --nav-shadow: #000; --title-fg: #{$title-fg}; --primary: #{$primary}; @@ -112,9 +114,17 @@ $dropdown-link-active-bg: $active-bg; --box-bg: #171c2a; --stat-box-bg: #0b1018; + --border-subtle: rgba(255, 255, 255, 0.11); + --block-top: #232838; + --block-side: #191c27; + --block-goggles-overlay: #181b2d7f; + --mempool-block-top: #403834; + --mempool-block-side: #2d2825; + --mempool-block-loading: #554b45; --alert-bg: #3a1c61; --navbar-bg: #212121; --transparent-fg: #ffffffbb; + --footer-fg: rgba(255, 255, 255, 0.4); --fade-out-box-bg-start: rgba(23, 28, 42, 0); --fade-out-box-bg-end: rgba(23, 28, 42, 1); --opacity: 0.57; @@ -148,6 +158,9 @@ $dropdown-link-active-bg: $active-bg; --search-button-focus: #533180; --search-button-shadow: #7c58ab80; + --bs-body-color: var(--fg); + --bs-body-bg: var(--active-bg); + --bs-card-color: var(--fg); --bs-border-radius: 0.25rem; --bs-btn-border-color: transparent; --bs-btn-disabled-border-color: transparent; @@ -159,6 +172,7 @@ html, body { body { background-color: var(--active-bg); + color: var(--fg); padding-bottom: 60px; } @@ -227,11 +241,13 @@ main { .form-control:focus { color: var(--fg); background-color: var(--secondary); + border-color: rgba(17, 19, 31, 0.2); } .btn-purple { background-color: var(--tertiary); border-color: var(--tertiary); + color: #fff; } .btn-purple:not(:disabled):not(.disabled):active, .btn-purple:not(:disabled):not(.disabled).active, .show > .btn-purple.dropdown-toggle { @@ -254,7 +270,7 @@ main { } .form-control.form-control-secondary { - color: #fff; + color: var(--fg); background-color: var(--secondary); border: 1px solid var(--secondary); } @@ -325,14 +341,14 @@ main { .progress-text { span { - color: #fff !important; + color: var(--fg) !important; } } .block-size, .blocks-container { .symbol { font-size: 16px; - color: #fff !important; + color: var(--fg) !important; } } @@ -345,7 +361,7 @@ main { color: var(--fg); padding-top: 20px; padding-bottom: 10px; - border-top: 3px solid var(--fg); + border-top: 3px solid var(--nav-icon); display: flex; flex-direction: row; justify-content: space-between; @@ -381,6 +397,8 @@ main { .table { margin-bottom: 0; font-size: 0.9rem; + color: var(--fg); + --bs-table-color: var(--fg); @media (min-width: 576px) { font-size: 1rem; } @@ -488,6 +506,9 @@ html:lang(ru) .card-title { color: #fff; .total-value { float: right; + .symbol { + color: #ffffffbb; + } } } .active { @@ -593,6 +614,11 @@ html:lang(ru) .card-title { span { font-size: 10px; } + .total-parcial-vbytes { + .symbol { + color: #ffffffbb; + } + } .symbol { font-size: 9px; } @@ -1289,7 +1315,7 @@ th { display: block; width: 100%; padding: 1rem 2rem; - color: #fff; + color: var(--fg); font-weight: bold; &:focus, &:hover, &:active { text-decoration: none; @@ -1346,6 +1372,7 @@ th { border: 1px solid var(--tertiary); } .page-item.disabled .page-link { + color: var(--transparent-fg); background-color: var(--bg); border: 1px solid var(--bg); } @@ -1373,7 +1400,7 @@ th { } .blink-bg { - color: #fff; + color: var(--fg); background: repeating-linear-gradient($taproot-dark, $taproot-dark 0.163525%, $taproot-light 100%) !important; animation: shadowyBackground 1s infinite; box-shadow: -10px -15px 75px rgba($taproot, 1); @@ -1414,13 +1441,17 @@ app-global-footer { } .info-link fa-icon { - color: rgba(255, 255, 255, 0.4); + color: var(--transparent-fg); margin-left: 5px; } .dropdown-menu { background-color: var(--bg); color: var(--fg); + + .dropdown-item { + color: var(--fg); + } .dropdown-item:hover, .dropdown-item:focus { background-color: var(--active-bg); color: var(--fg); @@ -1430,11 +1461,12 @@ app-global-footer { .btn-secondary { background-color: var(--secondary); border-color: var(--secondary); + color: var(--fg); } a { color: var(--link-color); - &:hover { + &:hover:where(:not(.health-badge):not(.btn-purple)) { color: var(--link-hover-color); } } @@ -1484,6 +1516,10 @@ button { } .btn-success { + --bs-btn-color: #fff; + --bs-btn-hover-color: #fff; + --bs-btn-active-color: #fff; + --bs-btn-disabled-color: #fff; color: #fff; &:focus, &:hover, &:active, &:disabled { color: #fff; @@ -1494,6 +1530,10 @@ button { padding: 0.25em 0.4em; } +a.badge:hover, a.badge:focus { + text-decoration: none; +} + .table th, .table td { padding: 0.75rem; } @@ -1572,7 +1612,7 @@ button { } .nav-tabs .nav-link.active { - color: #fff; + color: var(--fg); } .text-muted { diff --git a/frontend/src/theme-nymkappa.scss b/frontend/src/theme-nymkappa.scss new file mode 100644 index 000000000..f75036b28 --- /dev/null +++ b/frontend/src/theme-nymkappa.scss @@ -0,0 +1,219 @@ +@use "sass:color"; + +/* Theme */ +$bg: #fefefe; +$active-bg: #eef2f9; +$hover-bg: #eaeff8; +$fg: #182033; +$nav-bg: #fdfdfd; +$title-fg: #2055e3; + +$taproot: #eba814; +$taproot-light: #d5a90a; +$taproot-dark: #9d7c05; + +/* Bootstrap */ +$body-bg: $bg; +$body-color: $fg; +$gray-800: $bg; +$gray-700: $fg; + +$nav-tabs-link-active-bg: $active-bg; + +$primary: #6bb8dc; +$secondary: #dadce1; +$tertiary: #a377ff; +$success: #258751; +$info: #426de6; + +$h5-font-size: 1.15rem !default; + +$pagination-bg: $body-bg; +$pagination-border-color: $gray-800; +$pagination-disabled-bg: $fg; +$pagination-disabled-border-color: $bg; +$pagination-active-color: $fg; +$pagination-active-bg: $tertiary; +$pagination-hover-bg: $hover-bg; +$pagination-hover-border-color: $bg; +$pagination-disabled-bg: $bg; + +$form-select-indicator-color: $fg; + +.input-group-text { + background-color: #eef2f7 !important; + border: 1px solid #d6dbe7 !important; +} + +$link-color: color.adjust($info, $lightness: -10%); +$link-decoration: none !default; +$link-hover-color: color.adjust($link-color, $lightness: -15%) !default; +$link-hover-decoration: underline !default; + +$dropdown-bg: $bg; +$dropdown-link-color: $fg; + +$dropdown-link-hover-color: $fg; +$dropdown-link-hover-bg: $hover-bg; + +$dropdown-link-active-color: $fg; +$dropdown-link-active-bg: $hover-bg; + +:root { + --bg: #{$bg}; + --active-bg: #{$active-bg}; + --hover-bg: #{$hover-bg}; + --fg: #{$fg}; + --nav-bg: #{$nav-bg}; + --nav-icon: #485464; + --nav-shadow: #dddddd; + --title-fg: #{$title-fg}; + + --primary: #{$primary}; + --secondary: #{$secondary}; + --tertiary: #{$tertiary}; + --success: #{$success}; + --info: #{$info}; + --link-color: #{$link-color}; + --link-hover-color: #{$link-hover-color}; + --icon: #f1f1f1; + --skeleton-bg: #cdd8eb; + --skeleton-bg-light: #f3f6fc; + + --box-bg: #ffffff; + --stat-box-bg: #e2e9f6; + --border-subtle: rgba(15, 23, 42, 0.12); + --block-top: #c9d1e2; + --block-side: #b6c1d8; + --block-goggles-overlay: #eef2f8cc; + --mempool-block-top: #d9dde1; + --mempool-block-side: #c8cdd3; + --mempool-block-loading: #b3bac2; + --alert-bg: #c4b5fd; + --transparent-fg: #2a2d40b3; + --footer-fg: rgba(15, 23, 42, 0.6); + --fade-out-box-bg-start: rgba(255, 255, 255, 0); + --fade-out-box-bg-end: rgba(255, 255, 255, 1); + --opacity: 0.7; + --address-chunk-color: #119d90; + + --testnet: #93c5fd; + --signet: #f0abfc; + --liquid: #5eead4; + --liquidtestnet: #d1d5db; + + --mainnet-alt: #a78bfa; + --testnet-alt: #bfdbfe; + --signet-alt: #f5d0fe; + --liquidtestnet-alt: #e5e7eb; + + --taproot: #eba814; + --taproot-light: #d5a90a; + --taproot-dark: #9d7c05; + + --green: #22a559; + --red: #e24d5e; + --yellow: #1f2747; + --grey: #94a3b8; + --tooltip-grey: #b1b1b1; + --orange: #f7931a; + --pink: #db2777; + + --search-button: #a377ff; + --search-button-border: #a377ff; + --search-button-focus: #9c6dff; + --search-button-shadow: #9c6dff; + + --bs-btn-hover-bg: #{$secondary}; + --bs-btn-hover-border-color: #{$secondary}; +} + +.form-select { + --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23182033' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); +} + +.nav-tabs { + --bs-nav-tabs-link-active-bg: var(--active-bg); + --bs-nav-tabs-link-active-color: var(--fg); + --bs-nav-tabs-link-active-border-color: var(--secondary) var(--secondary) var(--active-bg); +} + +#divider { + background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='104%25' height='100%25' fill='none' stroke='%23485464' stroke-width='4' stroke-dasharray='10%2c17' stroke-dashoffset='18' stroke-linecap='square'/%3e%3c/svg%3e"); +} + +.btn-primary { + --bs-btn-hover-bg: #56aed7; + --bs-btn-hover-border-color: #56aed7; + --bs-btn-focus-shadow-rgb: 86, 174, 215; + --bs-btn-active-bg: #42a4d2; + --bs-btn-active-border-color: #42a4d2; +} + +.btn-secondary { + --bs-btn-hover-bg: #c8cdd3; + --bs-btn-hover-border-color: #c8cdd3; + --bs-btn-focus-shadow-rgb: 200, 205, 211; + --bs-btn-active-bg: #b6c1d8; + --bs-btn-active-border-color: #b6c1d8; + --bs-btn-hover-color: var(--fg); +} + +.btn-outline-secondary { + --bs-btn-hover-bg: var(--secondary); + --bs-btn-hover-border-color: var(--secondary); + --bs-btn-focus-shadow-rgb: 218, 220, 225; + --bs-btn-active-bg: var(--secondary); + --bs-btn-active-border-color: var(--secondary); + --bs-btn-hover-color: var(--fg); +} + +.btn-outline-info { + --bs-btn-color: var(--link-color); + --bs-btn-border-color: var(--link-color); + --bs-btn-hover-color: var(--bg); + --bs-btn-hover-bg: var(--link-color); + --bs-btn-hover-border-color: var(--link-color); + --bs-btn-active-color: var(--bg); + --bs-btn-active-bg: var(--link-color); + --bs-btn-active-border-color: var(--link-color); +} + +.tooltip-inner { + color: #fff; +} + +.bg-info { + background-color: var(--info) !important; +} + +.bg-warning { + color: var(--fg); +} + +.bg-secondary { + background-color: var(--secondary) !important; + color: var(--fg); +} + +.constants { color: #d27300 } +.control { color: #4ab5e1 } +.stack { color: #d78b00 } +.splice { color: #34aedf } +.logic { color: #34aedf } +.arithmetic { color: #9cd4a7 } +.crypto { color: #fa3d3d } +.locktime { color: #d27300 } +.reserved { color: #d27300 } + +.text-light { + color: var(--fg) !important; +} + +.dropdown-menu { + --bs-dropdown-link-active-bg: #c0c0c0; + + .dropdown-item:hover, .dropdown-item:focus { + background-color: #d0d0d0; + } +}