Add light theme

This commit is contained in:
natsoni 2026-03-30 11:27:28 +09:00
parent 0099541716
commit 0503315c6d
No known key found for this signature in database
GPG key ID: 5554443C889C720E
7 changed files with 328 additions and 14 deletions

View file

@ -3,7 +3,7 @@ const fs = require('fs');
const path = require('path'); const path = require('path');
const crypto = require('crypto'); const crypto = require('crypto');
const THEMES = ['contrast', 'softsimon', 'bukele']; const THEMES = ['contrast', 'softsimon', 'bukele', 'nymkappa'];
const STAGING_DIR = path.join(__dirname, '.theme-build'); const STAGING_DIR = path.join(__dirname, '.theme-build');
const DIST_DIR = path.join(__dirname, 'dist/mempool/browser'); const DIST_DIR = path.join(__dirname, 'dist/mempool/browser');
const MANIFEST_FILE = path.join(__dirname, 'theme-manifest.json'); const MANIFEST_FILE = path.join(__dirname, 'theme-manifest.json');

View file

@ -82,6 +82,48 @@ export const contrastMempoolFeeColors = [
'ffb700', '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 = [ export const chartColors = [
'#A81524', '#A81524',
'#D81B60', '#D81B60',

View file

@ -3,5 +3,6 @@
<option value="default">wiz</option> <option value="default">wiz</option>
<option value="contrast">BlueMatt</option> <option value="contrast">BlueMatt</option>
<option value="softsimon">softsimon</option> <option value="softsimon">softsimon</option>
<option value="nymkappa">nymkappa</option>
</select> </select>
</div> </div>

View file

@ -12,7 +12,7 @@ import { Subscription } from 'rxjs';
}) })
export class ThemeSelectorComponent implements OnInit, OnDestroy { export class ThemeSelectorComponent implements OnInit, OnDestroy {
themeForm: UntypedFormGroup; themeForm: UntypedFormGroup;
themes = ['default', 'contrast', 'softsimon', 'bukele']; themes = ['default', 'contrast', 'softsimon', 'bukele', 'nymkappa'];
themeStateSubscription: Subscription; themeStateSubscription: Subscription;
constructor( constructor(

View file

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; 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 { StorageService } from '@app/services/storage.service';
import { StateService } from '@app/services/state.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'; let theme = this.stateService.env.customize?.theme || this.storageService.getValue('theme-preference') || 'default';
// theme preference must be a valid known public theme // 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'; theme = 'default';
this.storageService.setValue('theme-preference', 'default'); this.storageService.setValue('theme-preference', 'default');
} }
@ -64,7 +64,7 @@ export class ThemeService {
this.style.media = 'all'; this.style.media = 'all';
this.initialLoad = false; this.initialLoad = false;
} }
this.mempoolFeeColors = theme === 'contrast' || theme === 'bukele' ? contrastMempoolFeeColors : defaultMempoolFeeColors; this.mempoolFeeColors = this.getMempoolFeeColors(theme);
this.themeState$.next({ theme, loading: false }); this.themeState$.next({ theme, loading: false });
}; };
this.style.onerror = () => this.apply('default'); this.style.onerror = () => this.apply('default');
@ -86,4 +86,16 @@ export class ThemeService {
} }
return `${theme}.css`; return `${theme}.css`;
} }
private getMempoolFeeColors(theme: string): string[] {
switch (theme) {
case 'contrast':
case 'bukele':
return contrastMempoolFeeColors;
case 'nymkappa':
return lightMempoolFeeColors;
default:
return defaultMempoolFeeColors;
}
}
} }

View file

@ -97,6 +97,8 @@ $dropdown-link-active-bg: $active-bg;
--hover-bg: #{$hover-bg}; --hover-bg: #{$hover-bg};
--fg: #{$fg}; --fg: #{$fg};
--nav-bg: #{$nav-bg}; --nav-bg: #{$nav-bg};
--nav-icon: #fff;
--nav-shadow: #000;
--title-fg: #{$title-fg}; --title-fg: #{$title-fg};
--primary: #{$primary}; --primary: #{$primary};
@ -112,9 +114,17 @@ $dropdown-link-active-bg: $active-bg;
--box-bg: #171c2a; --box-bg: #171c2a;
--stat-box-bg: #0b1018; --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; --alert-bg: #3a1c61;
--navbar-bg: #212121; --navbar-bg: #212121;
--transparent-fg: #ffffffbb; --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-start: rgba(23, 28, 42, 0);
--fade-out-box-bg-end: rgba(23, 28, 42, 1); --fade-out-box-bg-end: rgba(23, 28, 42, 1);
--opacity: 0.57; --opacity: 0.57;
@ -148,6 +158,9 @@ $dropdown-link-active-bg: $active-bg;
--search-button-focus: #533180; --search-button-focus: #533180;
--search-button-shadow: #7c58ab80; --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-border-radius: 0.25rem;
--bs-btn-border-color: transparent; --bs-btn-border-color: transparent;
--bs-btn-disabled-border-color: transparent; --bs-btn-disabled-border-color: transparent;
@ -159,6 +172,7 @@ html, body {
body { body {
background-color: var(--active-bg); background-color: var(--active-bg);
color: var(--fg);
padding-bottom: 60px; padding-bottom: 60px;
} }
@ -227,11 +241,13 @@ main {
.form-control:focus { .form-control:focus {
color: var(--fg); color: var(--fg);
background-color: var(--secondary); background-color: var(--secondary);
border-color: rgba(17, 19, 31, 0.2);
} }
.btn-purple { .btn-purple {
background-color: var(--tertiary); background-color: var(--tertiary);
border-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 { .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 { .form-control.form-control-secondary {
color: #fff; color: var(--fg);
background-color: var(--secondary); background-color: var(--secondary);
border: 1px solid var(--secondary); border: 1px solid var(--secondary);
} }
@ -325,14 +341,14 @@ main {
.progress-text { .progress-text {
span { span {
color: #fff !important; color: var(--fg) !important;
} }
} }
.block-size, .blocks-container { .block-size, .blocks-container {
.symbol { .symbol {
font-size: 16px; font-size: 16px;
color: #fff !important; color: var(--fg) !important;
} }
} }
@ -345,7 +361,7 @@ main {
color: var(--fg); color: var(--fg);
padding-top: 20px; padding-top: 20px;
padding-bottom: 10px; padding-bottom: 10px;
border-top: 3px solid var(--fg); border-top: 3px solid var(--nav-icon);
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
@ -381,6 +397,8 @@ main {
.table { .table {
margin-bottom: 0; margin-bottom: 0;
font-size: 0.9rem; font-size: 0.9rem;
color: var(--fg);
--bs-table-color: var(--fg);
@media (min-width: 576px) { @media (min-width: 576px) {
font-size: 1rem; font-size: 1rem;
} }
@ -488,6 +506,9 @@ html:lang(ru) .card-title {
color: #fff; color: #fff;
.total-value { .total-value {
float: right; float: right;
.symbol {
color: #ffffffbb;
}
} }
} }
.active { .active {
@ -593,6 +614,11 @@ html:lang(ru) .card-title {
span { span {
font-size: 10px; font-size: 10px;
} }
.total-parcial-vbytes {
.symbol {
color: #ffffffbb;
}
}
.symbol { .symbol {
font-size: 9px; font-size: 9px;
} }
@ -1289,7 +1315,7 @@ th {
display: block; display: block;
width: 100%; width: 100%;
padding: 1rem 2rem; padding: 1rem 2rem;
color: #fff; color: var(--fg);
font-weight: bold; font-weight: bold;
&:focus, &:hover, &:active { &:focus, &:hover, &:active {
text-decoration: none; text-decoration: none;
@ -1346,6 +1372,7 @@ th {
border: 1px solid var(--tertiary); border: 1px solid var(--tertiary);
} }
.page-item.disabled .page-link { .page-item.disabled .page-link {
color: var(--transparent-fg);
background-color: var(--bg); background-color: var(--bg);
border: 1px solid var(--bg); border: 1px solid var(--bg);
} }
@ -1373,7 +1400,7 @@ th {
} }
.blink-bg { .blink-bg {
color: #fff; color: var(--fg);
background: repeating-linear-gradient($taproot-dark, $taproot-dark 0.163525%, $taproot-light 100%) !important; background: repeating-linear-gradient($taproot-dark, $taproot-dark 0.163525%, $taproot-light 100%) !important;
animation: shadowyBackground 1s infinite; animation: shadowyBackground 1s infinite;
box-shadow: -10px -15px 75px rgba($taproot, 1); box-shadow: -10px -15px 75px rgba($taproot, 1);
@ -1414,13 +1441,17 @@ app-global-footer {
} }
.info-link fa-icon { .info-link fa-icon {
color: rgba(255, 255, 255, 0.4); color: var(--transparent-fg);
margin-left: 5px; margin-left: 5px;
} }
.dropdown-menu { .dropdown-menu {
background-color: var(--bg); background-color: var(--bg);
color: var(--fg); color: var(--fg);
.dropdown-item {
color: var(--fg);
}
.dropdown-item:hover, .dropdown-item:focus { .dropdown-item:hover, .dropdown-item:focus {
background-color: var(--active-bg); background-color: var(--active-bg);
color: var(--fg); color: var(--fg);
@ -1430,11 +1461,12 @@ app-global-footer {
.btn-secondary { .btn-secondary {
background-color: var(--secondary); background-color: var(--secondary);
border-color: var(--secondary); border-color: var(--secondary);
color: var(--fg);
} }
a { a {
color: var(--link-color); color: var(--link-color);
&:hover { &:hover:where(:not(.health-badge):not(.btn-purple)) {
color: var(--link-hover-color); color: var(--link-hover-color);
} }
} }
@ -1484,6 +1516,10 @@ button {
} }
.btn-success { .btn-success {
--bs-btn-color: #fff;
--bs-btn-hover-color: #fff;
--bs-btn-active-color: #fff;
--bs-btn-disabled-color: #fff;
color: #fff; color: #fff;
&:focus, &:hover, &:active, &:disabled { &:focus, &:hover, &:active, &:disabled {
color: #fff; color: #fff;
@ -1494,6 +1530,10 @@ button {
padding: 0.25em 0.4em; padding: 0.25em 0.4em;
} }
a.badge:hover, a.badge:focus {
text-decoration: none;
}
.table th, .table td { .table th, .table td {
padding: 0.75rem; padding: 0.75rem;
} }
@ -1572,7 +1612,7 @@ button {
} }
.nav-tabs .nav-link.active { .nav-tabs .nav-link.active {
color: #fff; color: var(--fg);
} }
.text-muted { .text-muted {

View file

@ -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;
}
}