Hashrate R
{{ i + 1 }}
|
{{ domain | hashSuffix }}
diff --git a/main/http_server/axe-os/src/app/components/home/home.component.scss b/main/http_server/axe-os/src/app/components/home/home.component.scss
index 3a5789407d..6ae23c0131 100644
--- a/main/http_server/axe-os/src/app/components/home/home.component.scss
+++ b/main/http_server/axe-os/src/app/components/home/home.component.scss
@@ -17,6 +17,8 @@
td {
transition: background-color 2s ease-in-out;
+ background-color: var(--heatmap-bg);
+ color: contrast-color(var(--primary-color));
}
}
diff --git a/main/http_server/axe-os/src/app/layout/service/app.layout.service.ts b/main/http_server/axe-os/src/app/layout/service/app.layout.service.ts
index 9fa231f42d..11d5aac906 100644
--- a/main/http_server/axe-os/src/app/layout/service/app.layout.service.ts
+++ b/main/http_server/axe-os/src/app/layout/service/app.layout.service.ts
@@ -100,40 +100,23 @@ export class LayoutService {
...this._config,
colorScheme: settings.colorScheme,
};
- // Apply accent colors if they exist
- if (settings.accentColors) {
- Object.entries(settings.accentColors).forEach(([key, value]) => {
- document.documentElement.style.setProperty(key, value);
- });
- }
+ // Apply accent colors dynamically
+ const accentColors = ThemeService.generateThemeVariables(settings.primaryColor);
+ Object.entries(accentColors).forEach(([key, value]) => {
+ document.documentElement.style.setProperty(key, value);
+ });
} else {
// Save default red dark theme if no settings exist
+ const defaultPrimary = '#F80421';
this.themeService.saveThemeSettings({
colorScheme: 'dark',
- accentColors: {
- '--primary-color': '#F80421',
- '--primary-color-text': '#ffffff',
- '--highlight-bg': '#F80421',
- '--highlight-text-color': '#ffffff',
- '--focus-ring': '0 0 0 0.2rem rgba(248,4,33,0.2)',
- '--slider-bg': '#dee2e6',
- '--slider-range-bg': '#F80421',
- '--slider-handle-bg': '#F80421',
- '--progressbar-bg': '#dee2e6',
- '--progressbar-value-bg': '#F80421',
- '--checkbox-border': '#F80421',
- '--checkbox-bg': '#F80421',
- '--checkbox-hover-bg': '#df031d',
- '--button-bg': '#F80421',
- '--button-hover-bg': '#df031d',
- '--button-focus-shadow': '0 0 0 2px #ffffff, 0 0 0 4px #F80421',
- '--togglebutton-bg': '#F80421',
- '--togglebutton-border': '1px solid #F80421',
- '--togglebutton-hover-bg': '#df031d',
- '--togglebutton-hover-border': '1px solid #df031d',
- '--togglebutton-text-color': '#ffffff'
- }
+ primaryColor: defaultPrimary
}).subscribe();
+
+ const accentColors = ThemeService.generateThemeVariables(defaultPrimary);
+ Object.entries(accentColors).forEach(([key, value]) => {
+ document.documentElement.style.setProperty(key, value);
+ });
}
// Update signal with config
this.config.set(this._config);
@@ -215,8 +198,9 @@ export class LayoutService {
// Load theme settings from NVS
this.themeService.getThemeSettings().subscribe(
settings => {
- if (settings && settings.accentColors) {
- Object.entries(settings.accentColors).forEach(([key, value]) => {
+ if (settings && settings.primaryColor) {
+ const accentColors = ThemeService.generateThemeVariables(settings.primaryColor);
+ Object.entries(accentColors).forEach(([key, value]) => {
document.documentElement.style.setProperty(key, value);
});
}
diff --git a/main/http_server/axe-os/src/app/services/theme.service.ts b/main/http_server/axe-os/src/app/services/theme.service.ts
index 64c9094e22..5ea0b0bad6 100644
--- a/main/http_server/axe-os/src/app/services/theme.service.ts
+++ b/main/http_server/axe-os/src/app/services/theme.service.ts
@@ -6,9 +6,7 @@ import { catchError, tap } from 'rxjs/operators';
export interface ThemeSettings {
colorScheme: string;
- accentColors?: {
- [key: string]: string;
- };
+ primaryColor: string;
}
@Injectable({
@@ -17,35 +15,64 @@ export interface ThemeSettings {
export class ThemeService {
private readonly mockSettings: ThemeSettings = {
colorScheme: 'dark',
- accentColors: {
- '--primary-color': '#F80421',
+ primaryColor: '#F80421'
+ };
+
+ static generateThemeVariables(primaryColor: string): { [key: string]: string } {
+ const hoverColor = this.shadeColor(primaryColor, -10);
+ const focusRingColor = this.hexToRgba(primaryColor, 0.2);
+
+ return {
+ '--primary-color': primaryColor,
'--primary-color-text': '#ffffff',
- '--highlight-bg': '#F80421',
+ '--highlight-bg': primaryColor,
'--highlight-text-color': '#ffffff',
- '--focus-ring': '0 0 0 0.2rem rgba(255,64,50,0.2)',
- // PrimeNG Slider
+ '--focus-ring': `0 0 0 0.2rem ${focusRingColor}`,
'--slider-bg': '#dee2e6',
- '--slider-range-bg': '#F80421',
- '--slider-handle-bg': '#F80421',
- // Progress Bar
+ '--slider-range-bg': primaryColor,
+ '--slider-handle-bg': primaryColor,
'--progressbar-bg': '#dee2e6',
- '--progressbar-value-bg': '#F80421',
- // PrimeNG Checkbox
- '--checkbox-border': '#F80421',
- '--checkbox-bg': '#F80421',
- '--checkbox-hover-bg': '#e63c2e',
- // PrimeNG Button
- '--button-bg': '#F80421',
- '--button-hover-bg': '#e63c2e',
- '--button-focus-shadow': '0 0 0 2px #ffffff, 0 0 0 4px #F80421',
- // Toggle button
- '--togglebutton-bg': '#F80421',
- '--togglebutton-border': '1px solid #F80421',
- '--togglebutton-hover-bg': '#e63c2e',
- '--togglebutton-hover-border': '1px solid #e63c2e',
+ '--progressbar-value-bg': primaryColor,
+ '--checkbox-border': primaryColor,
+ '--checkbox-bg': primaryColor,
+ '--checkbox-hover-bg': hoverColor,
+ '--button-bg': primaryColor,
+ '--button-hover-bg': hoverColor,
+ '--button-focus-shadow': `0 0 0 2px #ffffff, 0 0 0 4px ${primaryColor}`,
+ '--togglebutton-bg': primaryColor,
+ '--togglebutton-border': `1px solid ${primaryColor}`,
+ '--togglebutton-hover-bg': hoverColor,
+ '--togglebutton-hover-border': `1px solid ${hoverColor}`,
'--togglebutton-text-color': '#ffffff'
- }
- };
+ };
+ }
+
+ private static shadeColor(color: string, percent: number): string {
+ let R = parseInt(color.substring(1, 3), 16);
+ let G = parseInt(color.substring(3, 5), 16);
+ let B = parseInt(color.substring(5, 7), 16);
+
+ R = Math.floor(R * (100 + percent) / 100);
+ G = Math.floor(G * (100 + percent) / 100);
+ B = Math.floor(B * (100 + percent) / 100);
+
+ R = Math.min(255, Math.max(0, R));
+ G = Math.min(255, Math.max(0, G));
+ B = Math.min(255, Math.max(0, B));
+
+ const RR = R.toString(16).padStart(2, '0');
+ const GG = G.toString(16).padStart(2, '0');
+ const BB = B.toString(16).padStart(2, '0');
+
+ return "#" + RR + GG + BB;
+ }
+
+ private static hexToRgba(hex: string, alpha: number): string {
+ const r = parseInt(hex.substring(1, 3), 16);
+ const g = parseInt(hex.substring(3, 5), 16);
+ const b = parseInt(hex.substring(5, 7), 16);
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
+ }
private themeSettingsSubject = new BehaviorSubject(this.mockSettings);
private themeSettings$ = this.themeSettingsSubject.asObservable();
diff --git a/main/http_server/axe-os/src/styles.scss b/main/http_server/axe-os/src/styles.scss
index ab6cc268c9..78f99e2362 100644
--- a/main/http_server/axe-os/src/styles.scss
+++ b/main/http_server/axe-os/src/styles.scss
@@ -259,3 +259,7 @@ button.color-dot {
font-family: monospace;
font-size: medium;
}
+
+.text-primary {
+ color: var(--primary-color) !important;
+}
diff --git a/main/http_server/theme_api.c b/main/http_server/theme_api.c
index 6f1428cff7..dda0a470c4 100644
--- a/main/http_server/theme_api.c
+++ b/main/http_server/theme_api.c
@@ -23,21 +23,16 @@ static esp_err_t theme_get_handler(httpd_req_t *req)
set_cors_headers(req);
char *scheme = nvs_config_get_string(NVS_CONFIG_THEME_SCHEME);
- char *colors = nvs_config_get_string(NVS_CONFIG_THEME_COLORS);
+ char *primary_color = nvs_config_get_string(NVS_CONFIG_THEME_COLOR);
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "colorScheme", scheme);
-
- // Parse stored colors JSON string
- cJSON *colors_json = cJSON_Parse(colors);
- if (colors_json) {
- cJSON_AddItemToObject(root, "accentColors", colors_json);
- }
+ cJSON_AddStringToObject(root, "primaryColor", primary_color);
esp_err_t res = HTTP_send_json(req, root, &theme_prebuffer_len);
free(scheme);
- free(colors);
+ free(primary_color);
cJSON_Delete(root);
@@ -69,10 +64,8 @@ static esp_err_t theme_post_handler(httpd_req_t *req)
if ((item = cJSON_GetObjectItem(root, "colorScheme")) != NULL) {
nvs_config_set_string(NVS_CONFIG_THEME_SCHEME, item->valuestring);
}
- if ((item = cJSON_GetObjectItem(root, "accentColors")) != NULL) {
- char *colors_str = cJSON_Print(item);
- nvs_config_set_string(NVS_CONFIG_THEME_COLORS, colors_str);
- free(colors_str);
+ if ((item = cJSON_GetObjectItem(root, "primaryColor")) != NULL) {
+ nvs_config_set_string(NVS_CONFIG_THEME_COLOR, item->valuestring);
}
cJSON_Delete(root);
diff --git a/main/http_server/theme_api.h b/main/http_server/theme_api.h
index f5f7114b83..e2b4bd9168 100644
--- a/main/http_server/theme_api.h
+++ b/main/http_server/theme_api.h
@@ -4,29 +4,7 @@
#include "esp_http_server.h"
#define DEFAULT_THEME "dark"
-#define DEFAULT_COLORS "{ "\
- "\"--primary-color\":\"#F80421\", "\
- "\"--primary-color-text\":\"#ffffff\", "\
- "\"--highlight-bg\":\"#F80421\", "\
- "\"--highlight-text-color\":\"#ffffff\", "\
- "\"--focus-ring\":\"0 0 0 0.2rem rgba(248,4,33,0.2)\", "\
- "\"--slider-bg\":\"#dee2e6\", "\
- "\"--slider-range-bg\":\"#F80421\", "\
- "\"--slider-handle-bg\":\"#F80421\", "\
- "\"--progressbar-bg\":\"#dee2e6\", "\
- "\"--progressbar-value-bg\":\"#F80421\", "\
- "\"--checkbox-border\":\"#F80421\", "\
- "\"--checkbox-bg\":\"#F80421\", "\
- "\"--checkbox-hover-bg\":\"#df031d\", "\
- "\"--button-bg\":\"#F80421\", "\
- "\"--button-hover-bg\":\"#df031d\", "\
- "\"--button-focus-shadow\":\"0 0 0 2px #ffffff, 0 0 0 4px #F80421\", "\
- "\"--togglebutton-bg\":\"#F80421\", "\
- "\"--togglebutton-border\":\"1px solid #F80421\", "\
- "\"--togglebutton-hover-bg\":\"#df031d\", "\
- "\"--togglebutton-hover-border\":\"1px solid #df031d\", "\
- "\"--togglebutton-text-color\":\"#ffffff\" "\
- "}"
+#define DEFAULT_COLOR "#F80421"
// Register theme API endpoints
esp_err_t register_theme_api_endpoints(httpd_handle_t server, void* ctx);
diff --git a/main/nvs_config.c b/main/nvs_config.c
index 2513a8be86..d076e10a30 100644
--- a/main/nvs_config.c
+++ b/main/nvs_config.c
@@ -13,6 +13,7 @@
#include "display.h"
#include "theme_api.h"
#include "scoreboard.h"
+#include "cJSON.h"
#define NVS_CONFIG_NAMESPACE "main"
#define NVS_STR_LIMIT (4000 - 1) // See nvs_set_str
@@ -92,7 +93,7 @@ static Settings settings[NVS_CONFIG_COUNT] = {
[NVS_CONFIG_SELF_TEST] = {.nvs_key_name = "selftest", .type = TYPE_BOOL},
[NVS_CONFIG_SWARM] = {.nvs_key_name = "swarmconfig", .type = TYPE_STR},
[NVS_CONFIG_THEME_SCHEME] = {.nvs_key_name = "themescheme", .type = TYPE_STR, .default_value = {.str = DEFAULT_THEME}},
- [NVS_CONFIG_THEME_COLORS] = {.nvs_key_name = "themecolors", .type = TYPE_STR, .default_value = {.str = DEFAULT_COLORS}},
+ [NVS_CONFIG_THEME_COLOR] = {.nvs_key_name = "themecolor", .type = TYPE_STR, .default_value = {.str = DEFAULT_COLOR}},
[NVS_CONFIG_SCOREBOARD] = {.nvs_key_name = "scoreboard", .type = TYPE_STR, .array_size = MAX_SCOREBOARD},
[NVS_CONFIG_BOARD_VERSION] = {.nvs_key_name = "boardversion", .type = TYPE_STR, .default_value = {.str = "000"}},
@@ -173,6 +174,30 @@ static void nvs_config_init_fallback(NvsConfigKey key, Settings * setting)
}
}
}
+ if (key == NVS_CONFIG_THEME_COLOR) {
+ if (nvs_find_key(handle, setting->nvs_key_name, NULL) == ESP_ERR_NVS_NOT_FOUND) {
+ size_t len = 0;
+ esp_err_t ret = nvs_get_str(handle, "themecolors", NULL, &len);
+ if (ret == ESP_OK && len > 1) {
+ char *buf = malloc(len);
+ if (buf) {
+ ret = nvs_get_str(handle, "themecolors", buf, &len);
+ if (ret == ESP_OK) {
+ cJSON *root = cJSON_Parse(buf);
+ if (root) {
+ cJSON *primary = cJSON_GetObjectItem(root, "--primary-color");
+ if (primary && primary->valuestring) {
+ ESP_LOGI(TAG, "Migrating NVS config themecolors to %s (%s)", setting->nvs_key_name, primary->valuestring);
+ nvs_set_str(handle, setting->nvs_key_name, primary->valuestring);
+ }
+ cJSON_Delete(root);
+ }
+ }
+ free(buf);
+ }
+ }
+ }
+ }
}
static void nvs_config_apply_fallback(NvsConfigKey key, Settings * setting)
diff --git a/main/nvs_config.h b/main/nvs_config.h
index e761ca4975..63ad302c75 100644
--- a/main/nvs_config.h
+++ b/main/nvs_config.h
@@ -52,7 +52,7 @@ typedef enum {
NVS_CONFIG_SELF_TEST,
NVS_CONFIG_SWARM,
NVS_CONFIG_THEME_SCHEME,
- NVS_CONFIG_THEME_COLORS,
+ NVS_CONFIG_THEME_COLOR,
NVS_CONFIG_SCOREBOARD,
NVS_CONFIG_BOARD_VERSION,
|