Automaticly color theme changer
// ==UserScript==
// @name Web3 OKX Color Theme Changer
// @namespace http://tampermonkey.net/
// @version 3.2.1
// @description Automaticly color theme changer
// @author mamiis
// @match https://*.okx.com/*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const DEFAULT_UP_COLOR = { r: 189, g: 255, b: 42 }; // #bdff2a
const DEFAULT_DOWN_COLOR = { r: 255, g: 66, b: 172 }; // #ff42ac
let UP_COLOR = { ...DEFAULT_UP_COLOR };
let DOWN_COLOR = { ...DEFAULT_DOWN_COLOR };
let CHART_FILTERS = {
green: { hue: 90, saturation: 1.6, brightness: 1.05 },
red: { hue: 320, saturation: 1.3, brightness: 1.1 }
};
const THEME_PRESETS = [
// Row 1 (fixed up color)
{ key: 'classic', name: 'Classic', up: { r: 189, g: 255, b: 42 }, down: { r: 255, g: 66, b: 172 } },
{ key: 'ocean-sunset', name: 'Ocean Sunset', up: { r: 189, g: 255, b: 42 }, down: { r: 249, g: 115, b: 22 } },
{ key: 'violet-gold', name: 'Violet Gold', up: { r: 189, g: 255, b: 42 }, down: { r: 239, g: 68, b: 68 } },
{ key: 'arctic-lava', name: 'Arctic Lava', up: { r: 189, g: 255, b: 42 }, down: { r: 245, g: 158, b: 11 } },
{ key: 'sky-amber', name: 'Sky Amber', up: { r: 189, g: 255, b: 42 }, down: { r: 251, g: 113, b: 133 } },
{ key: 'midnight-peach', name: 'Midnight Peach', up: { r: 189, g: 255, b: 42 }, down: { r: 217, g: 70, b: 239 } },
{ key: 'electric-cyan', name: 'Electric Cyan', up: { r: 189, g: 255, b: 42 }, down: { r: 194, g: 65, b: 12 } },
// Row 2 (fixed up color)
{ key: 'indigo-coral', name: 'Indigo Coral', up: { r: 14, g: 165, b: 233 }, down: { r: 251, g: 113, b: 133 } },
{ key: 'royal-citrine', name: 'Royal Citrine', up: { r: 14, g: 165, b: 233 }, down: { r: 250, g: 204, b: 21 } },
{ key: 'plum-tangerine', name: 'Plum Tangerine', up: { r: 14, g: 165, b: 233 }, down: { r: 167, g: 139, b: 250 } },
{ key: 'navy-rose', name: 'Navy Rose', up: { r: 14, g: 165, b: 233 }, down: { r: 132, g: 204, b: 22 } },
{ key: 'azure-copper', name: 'Azure Copper', up: { r: 14, g: 165, b: 233 }, down: { r: 244, g: 114, b: 182 } },
{ key: 'lilac-sand', name: 'Lilac Sand', up: { r: 14, g: 165, b: 233 }, down: { r: 251, g: 146, b: 60 } },
{ key: 'mint-violet', name: 'Mint Violet', up: { r: 14, g: 165, b: 233 }, down: { r: 31, g: 41, b: 55 } },
// Row 3 (fixed up color)
{ key: 'steel-orange', name: 'Steel Orange', up: { r: 139, g: 92, b: 246 }, down: { r: 20, g: 184, b: 166 } },
{ key: 'turquoise-maroon', name: 'Turquoise Maroon', up: { r: 139, g: 92, b: 246 }, down: { r: 34, g: 211, b: 238 } },
{ key: 'ultramarine-lemon', name: 'Ultramarine Lemon', up: { r: 139, g: 92, b: 246 }, down: { r: 56, g: 189, b: 248 } },
{ key: 'slate-pink', name: 'Slate Pink', up: { r: 139, g: 92, b: 246 }, down: { r: 96, g: 165, b: 250 } },
{ key: 'aqua-bronze', name: 'Aqua Bronze', up: { r: 139, g: 92, b: 246 }, down: { r: 45, g: 212, b: 191 } },
{ key: 'cobalt-apricot', name: 'Cobalt Apricot', up: { r: 139, g: 92, b: 246 }, down: { r: 125, g: 211, b: 252 } },
{ key: 'iris-mango', name: 'Iris Mango', up: { r: 139, g: 92, b: 246 }, down: { r: 186, g: 230, b: 253 } },
// Row 4 (fixed up color)
{ key: 'denim-salmon', name: 'Denim Salmon', up: { r: 59, g: 130, b: 246 }, down: { r: 236, g: 72, b: 153 } },
{ key: 'teal-lavender', name: 'Teal Lavender', up: { r: 59, g: 130, b: 246 }, down: { r: 234, g: 88, b: 12 } },
{ key: 'periwinkle-gold', name: 'Periwinkle Gold', up: { r: 59, g: 130, b: 246 }, down: { r: 202, g: 138, b: 4 } },
{ key: 'cyan-plum', name: 'Cyan Plum', up: { r: 59, g: 130, b: 246 }, down: { r: 132, g: 204, b: 22 } },
{ key: 'graphite-electric', name: 'Graphite Electric', up: { r: 59, g: 130, b: 246 }, down: { r: 194, g: 65, b: 12 } },
{ key: 'iceberry', name: 'Iceberry', up: { r: 59, g: 130, b: 246 }, down: { r: 146, g: 64, b: 14 } },
{ key: 'orchid-citrus', name: 'Orchid Citrus', up: { r: 59, g: 130, b: 246 }, down: { r: 15, g: 23, b: 42 } },
// Row 5 (fixed up color)
{ key: 'cerulean-blush', name: 'Cerulean Blush', up: { r: 251, g: 146, b: 60 }, down: { r: 67, g: 56, b: 202 } },
{ key: 'sapphire-sunset', name: 'Sapphire Sunset', up: { r: 251, g: 146, b: 60 }, down: { r: 37, g: 99, b: 235 } },
{ key: 'pastel-pop', name: 'Pastel Pop', up: { r: 251, g: 146, b: 60 }, down: { r: 30, g: 64, b: 175 } },
{ key: 'deep-space', name: 'Deep Space', up: { r: 251, g: 146, b: 60 }, down: { r: 79, g: 70, b: 229 } },
{ key: 'mono-contrast', name: 'Mono Contrast', up: { r: 251, g: 146, b: 60 }, down: { r: 14, g: 116, b: 144 } },
{ key: 'frost-fire', name: 'Frost Fire', up: { r: 251, g: 146, b: 60 }, down: { r: 6, g: 182, b: 212 } },
{ key: 'dusk-dawn', name: 'Dusk Dawn', up: { r: 251, g: 146, b: 60 }, down: { r: 13, g: 148, b: 136 } },
// Row 6 (fixed up color)
{ key: 'aurora-bloom', name: 'Aurora Bloom', up: { r: 236, g: 72, b: 153 }, down: { r: 34, g: 211, b: 238 } },
{ key: 'polar-candy', name: 'Polar Candy', up: { r: 236, g: 72, b: 153 }, down: { r: 59, g: 130, b: 246 } },
{ key: 'storm-pearl', name: 'Storm Pearl', up: { r: 236, g: 72, b: 153 }, down: { r: 129, g: 140, b: 248 } },
{ key: 'blueberry-honey', name: 'Blueberry Honey', up: { r: 236, g: 72, b: 153 }, down: { r: 167, g: 139, b: 250 } },
{ key: 'amethyst-ember', name: 'Amethyst Ember', up: { r: 236, g: 72, b: 153 }, down: { r: 196, g: 181, b: 253 } },
{ key: 'lagoon-ivory', name: 'Lagoon Ivory', up: { r: 236, g: 72, b: 153 }, down: { r: 45, g: 212, b: 191 } },
{ key: 'nebula-pearl', name: 'Nebula Pearl', up: { r: 236, g: 72, b: 153 }, down: { r: 148, g: 163, b: 184 } },
// Row 7 (fixed up color)
{ key: 'glacier-rust', name: 'Glacier Rust', up: { r: 20, g: 184, b: 166 }, down: { r: 225, g: 29, b: 72 } },
{ key: 'plum-sky', name: 'Plum Sky', up: { r: 20, g: 184, b: 166 }, down: { r: 239, g: 68, b: 68 } },
{ key: 'pearl-ink', name: 'Pearl Ink', up: { r: 20, g: 184, b: 166 }, down: { r: 249, g: 115, b: 22 } },
{ key: 'cyan-saffron', name: 'Cyan Saffron', up: { r: 20, g: 184, b: 166 }, down: { r: 245, g: 158, b: 11 } },
{ key: 'twilight-mint', name: 'Twilight Mint', up: { r: 20, g: 184, b: 166 }, down: { r: 250, g: 204, b: 21 } },
{ key: 'obsidian-cream', name: 'Obsidian Cream', up: { r: 20, g: 184, b: 166 }, down: { r: 217, g: 119, b: 6 } },
{ key: 'sunrise-indigo', name: 'Sunrise Indigo', up: { r: 20, g: 184, b: 166 }, down: { r: 194, g: 120, b: 3 } },
// Row 8 (fixed up color)
{ key: 'lavender-olive', name: 'Lavender Olive', up: { r: 100, g: 116, b: 139 }, down: { r: 226, g: 232, b: 240 } },
{ key: 'copper-ice', name: 'Copper Ice', up: { r: 100, g: 116, b: 139 }, down: { r: 255, g: 251, b: 235 } },
{ key: 'neon-orchid', name: 'Neon Orchid', up: { r: 100, g: 116, b: 139 }, down: { r: 255, g: 237, b: 213 } },
{ key: 'sandstorm-teal', name: 'Sandstorm Teal', up: { r: 100, g: 116, b: 139 }, down: { r: 221, g: 214, b: 254 } },
{ key: 'moonlight-amber', name: 'Moonlight Amber', up: { r: 100, g: 116, b: 139 }, down: { r: 192, g: 132, b: 252 } },
{ key: 'grape-cyan', name: 'Grape Cyan', up: { r: 100, g: 116, b: 139 }, down: { r: 217, g: 70, b: 239 } },
{ key: 'ruby-aqua', name: 'Ruby Aqua', up: { r: 100, g: 116, b: 139 }, down: { r: 126, g: 34, b: 206 } },
// Row 9 (fixed up color - black tones)
{ key: 'obsidian-ivory', name: 'Obsidian Ivory', up: { r: 15, g: 23, b: 42 }, down: { r: 255, g: 255, b: 255 } },
{ key: 'obsidian-midnight', name: 'Obsidian Midnight', up: { r: 15, g: 23, b: 42 }, down: { r: 10, g: 25, b: 47 } },
{ key: 'carbon-silver', name: 'Carbon Silver', up: { r: 15, g: 23, b: 42 }, down: { r: 203, g: 213, b: 225 } },
{ key: 'coal-steel', name: 'Coal Steel', up: { r: 15, g: 23, b: 42 }, down: { r: 148, g: 163, b: 184 } },
{ key: 'noir-sky', name: 'Noir Sky', up: { r: 15, g: 23, b: 42 }, down: { r: 96, g: 165, b: 250 } },
{ key: 'ink-cobalt', name: 'Ink Cobalt', up: { r: 15, g: 23, b: 42 }, down: { r: 59, g: 130, b: 246 } },
{ key: 'graphite-indigo', name: 'Graphite Indigo', up: { r: 15, g: 23, b: 42 }, down: { r: 67, g: 56, b: 202 } },
{ key: 'abyss-azure', name: 'Abyss Azure', up: { r: 15, g: 23, b: 42 }, down: { r: 30, g: 64, b: 175 } },
{ key: 'raven-slate', name: 'Raven Slate', up: { r: 15, g: 23, b: 42 }, down: { r: 71, g: 85, b: 105 } },
{ key: 'shadow-navy', name: 'Shadow Navy', up: { r: 15, g: 23, b: 42 }, down: { r: 30, g: 41, b: 59 } }
];
let selectedThemeKey = 'classic';
let activeModal = null;
let currentColorType = null;
let isThemeReversed = false;
let LAST_UP_COLOR = { ...UP_COLOR };
let LAST_DOWN_COLOR = { ...DOWN_COLOR };
function normalizeRgbColor(input, fallback = { r: 0, g: 0, b: 0 }) {
const source = input || fallback;
const clamp = (v, fb) => {
const num = Number.isFinite(+v) ? +v : fb;
return Math.max(0, Math.min(255, Math.round(num)));
};
return {
r: clamp(source.r, fallback.r || 0),
g: clamp(source.g, fallback.g || 0),
b: clamp(source.b, fallback.b || 0)
};
}
function setThemeColors(nextUp, nextDown) {
const normalizedUp = normalizeRgbColor(nextUp, UP_COLOR);
const normalizedDown = normalizeRgbColor(nextDown, DOWN_COLOR);
LAST_UP_COLOR = { ...UP_COLOR };
LAST_DOWN_COLOR = { ...DOWN_COLOR };
UP_COLOR = normalizedUp;
DOWN_COLOR = normalizedDown;
}
function loadUserSettings() {
try {
const saved = localStorage.getItem('okx_color_settings');
if (saved) {
const settings = JSON.parse(saved);
const loadedUp = settings.upColor ? normalizeRgbColor(settings.upColor, UP_COLOR) : UP_COLOR;
const loadedDown = settings.downColor ? normalizeRgbColor(settings.downColor, DOWN_COLOR) : DOWN_COLOR;
setThemeColors(loadedUp, loadedDown);
if (settings.filters) CHART_FILTERS = settings.filters;
if (settings.selectedThemeKey) selectedThemeKey = settings.selectedThemeKey;
if (typeof settings.isThemeReversed === 'boolean') isThemeReversed = settings.isThemeReversed;
}
} catch (e) {
console.log('Settings not loaded, using defaults');
}
selectedThemeKey = getMatchingThemePresetKey();
}
function saveUserSettings() {
try {
const settings = {
upColor: UP_COLOR,
downColor: DOWN_COLOR,
filters: CHART_FILTERS,
selectedThemeKey,
isThemeReversed
};
localStorage.setItem('okx_color_settings', JSON.stringify(settings));
} catch (e) {
console.log('Settings not saved');
}
}
function colorsEqual(a, b) {
return !!a && !!b && a.r === b.r && a.g === b.g && a.b === b.b;
}
function colorsClose(a, b, tolerance = 18) {
if (!a || !b) return false;
return Math.abs(a.r - b.r) <= tolerance && Math.abs(a.g - b.g) <= tolerance && Math.abs(a.b - b.b) <= tolerance;
}
function getAppliedThemeColors(preset) {
if (!preset) return null;
if (isThemeReversed) {
return { up: { ...preset.down }, down: { ...preset.up } };
}
return { up: { ...preset.up }, down: { ...preset.down } };
}
function refreshThemePresetSwatchesInModal() {
if (!activeModal || currentColorType !== 'theme') return;
activeModal.querySelectorAll('.theme-preset-option').forEach((btn) => {
const key = btn.getAttribute('data-theme');
const preset = THEME_PRESETS.find((item) => item.key === key);
if (!preset) return;
const applied = getAppliedThemeColors(preset);
const swatches = btn.querySelectorAll('.theme-preset-swatch');
if (swatches[0]) {
swatches[0].style.backgroundColor = `rgb(${applied.up.r}, ${applied.up.g}, ${applied.up.b})`;
}
if (swatches[1]) {
swatches[1].style.backgroundColor = `rgb(${applied.down.r}, ${applied.down.g}, ${applied.down.b})`;
}
});
}
function updateThemeReverseToggleUI() {
const reverseButtons = document.querySelectorAll('.nav-r-color-item[data-color="reverse"], .theme-reverse-toggle-btn');
reverseButtons.forEach((btn) => {
btn.classList.toggle('active', isThemeReversed);
btn.setAttribute('aria-pressed', isThemeReversed ? 'true' : 'false');
btn.setAttribute('title', isThemeReversed ? 'Reverse Theme Colors: ON' : 'Reverse Theme Colors: OFF');
});
}
function setThemeReverse(enabled, shouldSwapCurrentColors = true) {
const nextValue = !!enabled;
if (isThemeReversed === nextValue) {
updateThemeReverseToggleUI();
return;
}
isThemeReversed = nextValue;
if (shouldSwapCurrentColors) {
setThemeColors(DOWN_COLOR, UP_COLOR);
}
selectedThemeKey = getMatchingThemePresetKey();
updateColorSwatches();
updateThemeReverseToggleUI();
updateThemePresetSelection();
applySettings();
saveUserSettings();
showNotification(isThemeReversed ? 'Theme color direction reversed' : 'Theme color direction normal');
}
function toggleThemeReverse() {
setThemeReverse(!isThemeReversed, true);
}
function getMatchingThemePresetKey() {
const matchedPreset = THEME_PRESETS.find((preset) => {
const appliedColors = getAppliedThemeColors(preset);
return colorsEqual(appliedColors.up, UP_COLOR) && colorsEqual(appliedColors.down, DOWN_COLOR);
});
return matchedPreset ? matchedPreset.key : 'custom';
}
function updateThemePresetSelection() {
document.querySelectorAll('.theme-preset-option').forEach((btn) => {
const key = btn.getAttribute('data-theme');
btn.classList.toggle('active', key === selectedThemeKey);
});
refreshThemePresetSwatchesInModal();
updateThemeReverseToggleUI();
}
function applyThemePreset(themeKey) {
const preset = THEME_PRESETS.find((item) => item.key === themeKey);
if (!preset) return;
const appliedColors = getAppliedThemeColors(preset);
setThemeColors(appliedColors.up, appliedColors.down);
selectedThemeKey = themeKey;
updateColorSwatches();
updateThemePresetSelection();
updateModalColorSelection();
applySettings();
saveUserSettings();
showNotification(`Theme applied: ${preset.name}`);
}
function updateModalColorSelection() {
if (!activeModal) return;
const currentColor = currentColorType === 'up' ? UP_COLOR : DOWN_COLOR;
const selectedHex = rgbToHex(currentColor.r, currentColor.g, currentColor.b);
activeModal.querySelectorAll('.color-option').forEach((option) => {
const optionHex = (option.getAttribute('data-color') || '').toUpperCase();
option.classList.toggle('selected', optionHex === selectedHex);
});
}
function shouldSkipElementForColorConversion(el) {
return !!(el && el.closest && el.closest('.nav-r-color-picker-item, .color-picker-modal, .okx-color-notification, [data-testid="okd-popup"], .dex-popup'));
}
function applySettings() {
kickAll();
applyChartColorFilters();
}
function refreshPage() {
// Refresh intentionally disabled
}
function toggleThemeForRefresh() {
const themeButtons = document.querySelectorAll('.nav-r-theme-item');
if (themeButtons.length >= 3) {
const currentTheme = document.querySelector('.nav-r-theme-item.nav-r-th-it-sel');
if (currentTheme) {
const lightTheme = themeButtons[1];
if (lightTheme && !lightTheme.classList.contains('nav-r-th-it-sel')) {
lightTheme.click();
setTimeout(() => {
currentTheme.click();
setTimeout(() => {
applySettings();
}, 100);
}, 100);
} else {
const darkTheme = themeButtons[2];
if (darkTheme && !darkTheme.classList.contains('nav-r-th-it-sel')) {
darkTheme.click();
setTimeout(() => {
currentTheme.click();
setTimeout(() => {
applySettings();
}, 100);
}, 100);
} else {
applySettings();
}
}
} else {
applySettings();
}
} else {
applySettings();
}
}
/* ---------- IMPROVED COLOR PICKER MENU ---------- */
function addColorPickerToMenu() {
const themeSection = document.querySelector('.nav-r-pan-item:has(.nav-r-item-name)');
if (!themeSection || !themeSection.querySelector('.nav-r-theme-box')) {
setTimeout(addColorPickerToMenu, 1000);
return;
}
if (!document.querySelector('.nav-r-color-picker-item')) {
const colorPickerHTML = `
<div class="nav-r-pan-item nav-r-color-picker-item" style="margin: 8px 0;">
<span class="nav-r-item-name">Chart Colors</span>
<div class="nav-r-theme-box" style="display: flex; align-items: center; gap: 4px; margin: 0 -2px;">
<button type="button" class="nav-r-theme-item nav-r-color-item" data-color="up" title="Up Color">
<div class="color-swatch" style="width: 100%; height: 100%; background-color: rgb(${UP_COLOR.r}, ${UP_COLOR.g}, ${UP_COLOR.b})"></div>
</button>
<button type="button" class="nav-r-theme-item nav-r-color-item" data-color="down" title="Down Color">
<div class="color-swatch" style="width: 100%; height: 100%; background-color: rgb(${DOWN_COLOR.r}, ${DOWN_COLOR.g}, ${DOWN_COLOR.b})"></div>
</button>
<button type="button" class="nav-r-theme-item nav-r-color-item" data-color="theme" title="Theme Presets">
<div class="theme-mini-swatches">
<span class="theme-mini-swatch theme-mini-swatch-up" style="background-color: rgb(${UP_COLOR.r}, ${UP_COLOR.g}, ${UP_COLOR.b})"></span>
<span class="theme-mini-swatch theme-mini-swatch-down" style="background-color: rgb(${DOWN_COLOR.r}, ${DOWN_COLOR.g}, ${DOWN_COLOR.b})"></span>
</div>
</button>
<button type="button" class="nav-r-theme-item nav-r-color-item nav-r-reverse-item ${isThemeReversed ? 'active' : ''}" data-color="reverse" title="Reverse Theme Colors" aria-pressed="${isThemeReversed ? 'true' : 'false'}">
<span class="theme-reverse-icon">⇅</span>
</button>
<button type="button" class="nav-r-theme-item nav-r-color-item" data-color="reset" title="Reset to Default Colors">
<i class="icon okx-header-footer-reset"></i>
</button>
<button type="button" class="nav-r-theme-item nav-r-apply-item" data-action="apply" title="Apply Colors">
<i class="icon okx-header-footer-check"></i>
</button>
</div>
</div>
`;
themeSection.insertAdjacentHTML('afterend', colorPickerHTML);
}
addColorPickerStyles();
addColorPickerEvents();
updateColorSwatches();
updateThemeReverseToggleUI();
}
function addColorPickerStyles() {
if (document.getElementById('okx-color-picker-styles')) {
return;
}
const style = document.createElement('style');
style.id = 'okx-color-picker-styles';
style.textContent = `
.nav-r-color-picker-item {
min-height: 36px !important;
padding: 2px 0 !important;
}
.nav-r-color-picker-item .nav-r-item-name {
margin-bottom: 2px !important;
display: block;
}
.nav-r-color-picker-item .nav-r-theme-box {
display: flex !important;
align-items: center !important;
gap: 4px !important;
margin: 0 -2px !important;
margin-top: 2px !important;
}
.nav-r-color-picker-item .nav-r-theme-item {
position: relative;
width: 30px !important;
height: 30px !important;
border-radius: 6px;
border: 2px solid var(--border-color, #2a2a2a);
background: transparent;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
padding: 0 !important;
margin: 0 !important;
overflow: hidden;
flex-shrink: 0;
box-sizing: border-box !important;
}
.nav-r-color-picker-item .nav-r-theme-item:hover {
border-color: #cccccc;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(204, 204, 204, 0.3);
}
.nav-r-color-picker-item .color-swatch {
width: 100% !important;
height: 100% !important;
border-radius: 4px;
border: 1px solid rgba(255,255,255,0.3);
transition: all 0.3s ease;
display: block !important;
box-sizing: border-box !important;
margin: 0 !important;
padding: 0 !important;
min-width: 100% !important;
min-height: 100% !important;
}
.nav-r-color-picker-item .nav-r-theme-item:hover .color-swatch {
transform: scale(1.01);
}
.theme-mini-swatches {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 1px;
padding: 2px;
box-sizing: border-box;
}
.theme-mini-swatch {
width: 100%;
height: 100%;
border-radius: 3px;
border: 1px solid rgba(255,255,255,0.25);
}
.nav-r-reverse-item {
background: #2a2a2a;
border-color: #3a3a3a;
}
.nav-r-reverse-item.active {
background: linear-gradient(135deg, #3b82f6, #06b6d4) !important;
border-color: #bae6fd;
box-shadow: 0 0 0 1px rgba(186, 230, 253, 0.45);
}
.theme-reverse-icon {
font-size: 16px;
color: #d1d5db;
font-weight: 700;
line-height: 1;
}
.nav-r-reverse-item.active .theme-reverse-icon {
color: #ffffff;
}
.theme-reverse-toggle-row {
margin-bottom: 10px;
}
.theme-reverse-toggle-btn {
width: 100%;
padding: 8px 10px;
border: 1px solid #3a3a3a;
background: #262626;
color: #d1d5db;
border-radius: 8px;
cursor: pointer;
font-size: 12px;
font-weight: 600;
transition: all 0.2s ease;
}
.theme-reverse-toggle-btn:hover {
border-color: #6b7280;
background: #303030;
}
.theme-reverse-toggle-btn.active {
background: linear-gradient(135deg, #3b82f6, #06b6d4);
border-color: #bae6fd;
color: #fff;
}
.nav-r-color-picker-item .nav-r-theme-item i {
font-size: 14px;
color: var(--text-color, #fff);
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.nav-r-color-picker-item .nav-r-theme-item:hover i {
color: #cccccc;
}
.nav-r-apply-item {
background: linear-gradient(135deg, #666666, #888888) !important;
border: none !important;
}
.nav-r-apply-item:hover {
background: linear-gradient(135deg, #888888, #aaaaaa) !important;
transform: translateY(-2px) scale(1.05);
}
/* Improved Color Picker Modal */
.color-picker-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
opacity: 0;
animation: modalFadeIn 0.2s ease forwards;
}
@keyframes modalFadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes modalFadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
.color-picker-content {
background: #1a1a1a;
border-radius: 16px;
padding: 20px;
width: 350px;
max-width: 90vw;
border: 1px solid #333;
box-shadow: 0 20px 40px rgba(0,0,0,0.5);
transform: scale(0.9);
animation: contentSlideIn 0.2s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
.color-picker-content.theme-picker-content {
width: 560px;
max-width: 96vw;
}
@keyframes contentSlideIn {
from { transform: scale(0.9); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
@keyframes contentSlideOut {
from { transform: scale(1); opacity: 1; }
to { transform: scale(0.9); opacity: 0; }
}
.color-picker-title {
color: white;
margin-bottom: 12px;
font-size: 16px;
text-align: center;
font-weight: 600;
}
.color-type-switcher {
display: flex;
gap: 6px;
margin-bottom: 12px;
justify-content: center;
}
.color-type-btn {
padding: 6px 10px;
border: 1px solid #333;
background: #2a2a2a;
color: white;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s ease;
font-size: 11px;
flex: 1;
max-width: 100px;
}
.color-type-btn:hover {
background: #3a3a3a;
}
.color-type-btn.active {
background: #444;
border-color: #666;
}
.color-categories-container {
max-height: 350px;
overflow-y: auto;
padding-right: 3px;
margin-bottom: 12px;
}
.color-category {
margin-bottom: 12px;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.color-category-title {
color: white;
font-size: 11px;
font-weight: 600;
margin-bottom: 5px;
padding-bottom: 2px;
border-bottom: 1px solid #333;
width: 321px;
max-width: 100%;
margin-left: 2px;
}
.color-category-grid {
display: grid;
grid-template-columns: repeat(12, 24px);
justify-content: start;
gap: 3px;
margin-bottom: 6px;
width: max-content;
margin-left: 2px;
margin-right: auto;
}
.color-option {
width: 24px;
height: 24px;
border-radius: 3px;
border: 2px solid transparent;
cursor: pointer;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
flex-shrink: 0;
}
.color-option:hover {
transform: scale(1.15);
border-color: #cccccc;
box-shadow: 0 4px 8px rgba(204, 204, 204, 0.3);
}
.color-option.selected {
border-color: #cccccc;
border-width: 2px;
box-shadow: 0 0 0 2px rgba(204, 204, 204, 0.3);
}
.color-picker-actions {
display: flex;
gap: 8px;
margin-top: 10px;
}
.color-action-btn {
flex: 1;
padding: 8px 12px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
font-weight: 600;
transition: all 0.3s ease;
text-align: center;
}
.color-apply-btn {
background: linear-gradient(135deg, #666666, #888888);
color: white;
}
.color-apply-btn:hover {
background: linear-gradient(135deg, #888888, #aaaaaa);
transform: translateY(-1px);
}
.color-default-btn {
background: linear-gradient(135deg, #444444, #666666);
color: white;
}
.color-default-btn:hover {
background: linear-gradient(135deg, #666666, #888888);
transform: translateY(-1px);
}
.custom-hex-section {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #333;
border-radius: 8px;
background: #202020;
}
.custom-hex-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 122px));
justify-content: center;
gap: 8px;
margin-bottom: 8px;
}
.custom-hex-field {
width: 122px;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.custom-hex-control {
width: 100%;
display: flex;
align-items: center;
gap: 6px;
}
.custom-hex-control-right {
justify-content: flex-end;
}
.hex-palette-btn {
width: 30px;
height: 30px;
border: 1px solid #3a3a3a;
border-radius: 6px;
background: #141414;
cursor: pointer;
padding: 0;
margin: 0;
flex: 0 0 30px;
position: relative;
overflow: hidden;
transition: all 0.2s ease;
}
.hex-palette-btn::after {
content: '';
position: absolute;
inset: 4px;
border-radius: 4px;
border: 1px solid rgba(255, 255, 255, 0.35);
background: var(--palette-color, #000000);
}
.hex-palette-btn:hover {
border-color: #6b7280;
transform: translateY(-1px);
}
.hex-palette-input {
position: absolute;
width: 0;
height: 0;
opacity: 0;
pointer-events: none;
}
.custom-hex-label {
color: #d1d5db;
font-size: 11px;
font-weight: 600;
line-height: 1;
}
.custom-hex-input {
width: auto;
flex: 1;
min-width: 0;
height: 30px;
border: 1px solid #3a3a3a;
border-radius: 6px;
background: #141414;
color: #fff;
font-size: 12px;
font-weight: 600;
padding: 0 8px;
text-transform: uppercase;
outline: none;
box-sizing: border-box;
}
.custom-hex-input:focus {
border-color: #6b7280;
box-shadow: 0 0 0 1px rgba(107, 114, 128, 0.35);
}
.custom-hex-input.invalid {
border-color: #ef4444;
box-shadow: 0 0 0 1px rgba(239, 68, 68, 0.35);
}
.custom-hex-apply-btn {
width: 252px;
max-width: 100%;
display: block;
margin: 0 auto;
padding: 7px 10px;
border: 1px solid #475569;
background: linear-gradient(135deg, #374151, #4b5563);
color: #fff;
}
.custom-hex-apply-btn:hover {
border-color: #64748b;
background: linear-gradient(135deg, #4b5563, #6b7280);
transform: translateY(-1px);
}
/* Scrollbar styling */
.color-categories-container::-webkit-scrollbar {
width: 4px;
}
.color-categories-container::-webkit-scrollbar-track {
background: #2a2a2a;
border-radius: 2px;
}
.color-categories-container::-webkit-scrollbar-thumb {
background: #555;
border-radius: 2px;
}
.color-categories-container::-webkit-scrollbar-thumb:hover {
background: #777;
}
.theme-presets-section {
margin-bottom: 12px;
}
.theme-presets-grid {
display: grid;
grid-template-columns: repeat(10, minmax(0, 1fr));
gap: 6px;
}
.theme-preset-option {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
border: 1px solid #2f2f2f;
background: #232323;
color: #ddd;
border-radius: 6px;
padding: 6px 4px;
cursor: pointer;
transition: all 0.2s ease;
min-height: 56px;
}
.theme-preset-option:hover {
border-color: #666;
background: #2c2c2c;
transform: translateY(-1px);
}
.theme-preset-option.active {
border-color: #cccccc;
box-shadow: 0 0 0 1px rgba(204, 204, 204, 0.35);
background: #313131;
color: #fff;
}
.theme-preset-swatches {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 3px;
}
.theme-preset-swatch {
width: 18px;
height: 18px;
border-radius: 3px;
border: 1px solid rgba(255,255,255,0.3);
}
.theme-preset-name {
font-size: 10px;
line-height: 1;
white-space: nowrap;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
`;
document.head.appendChild(style);
}
function addColorPickerEvents() {
if (document.body.dataset.okxColorPickerEventsBound === '1') {
return;
}
document.body.dataset.okxColorPickerEventsBound = '1';
document.addEventListener('click', function(e) {
if (e.target.closest('.nav-r-color-item')) {
const btn = e.target.closest('.nav-r-color-item');
e.stopPropagation();
const colorType = btn.getAttribute('data-color');
if (colorType === 'reverse') {
toggleThemeReverse();
} else if (colorType === 'reset') {
resetToDefaultColors();
} else if (colorType === 'theme') {
closeActiveModal();
setTimeout(() => {
showThemePicker();
}, 50);
} else {
closeActiveModal();
setTimeout(() => {
showColorPicker(colorType);
}, 50);
}
}
if (e.target.closest('.nav-r-apply-item')) {
e.stopPropagation();
saveUserSettings();
toggleThemeForRefresh();
showNotification('Colors applied successfully!');
}
});
}
function showNotification(message) {
const oldNotifications = document.querySelectorAll('.okx-color-notification');
oldNotifications.forEach(notif => notif.remove());
const notification = document.createElement('div');
notification.className = 'okx-color-notification';
notification.style.cssText = `
position: fixed;
top: 20px;
right: 24px;
background: #a3dd27ff;
color: white;
padding: 10px 20px;
border-radius: 4px;
z-index: 10001;
font-size: 14px;
animation: slideIn 0.3s ease;
`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 3000);
}
function closeActiveModal() {
if (activeModal) {
const escapeHandler = activeModal._escapeHandler;
if (escapeHandler) {
document.removeEventListener('keydown', escapeHandler);
}
activeModal.style.animation = 'modalFadeOut 0.2s ease forwards';
const content = activeModal.querySelector('.color-picker-content');
if (content) {
content.style.animation = 'contentSlideOut 0.2s ease forwards';
}
setTimeout(() => {
if (activeModal && activeModal.parentNode) {
activeModal.parentNode.removeChild(activeModal);
}
activeModal = null;
currentColorType = null;
}, 200);
}
}
function showColorPicker(colorType) {
if (activeModal) {
closeActiveModal();
setTimeout(() => {
createColorPickerModal(colorType);
}, 200);
} else {
createColorPickerModal(colorType);
}
}
function showThemePicker() {
if (activeModal) {
closeActiveModal();
setTimeout(() => {
createThemePickerModal();
}, 200);
} else {
createThemePickerModal();
}
}
function createThemePickerModal() {
currentColorType = 'theme';
activeModal = document.createElement('div');
activeModal.className = 'color-picker-modal';
activeModal.innerHTML = `
<div class="color-picker-content theme-picker-content">
<div class="color-picker-title">Select Theme</div>
<div class="theme-reverse-toggle-row">
<button class="theme-reverse-toggle-btn ${isThemeReversed ? 'active' : ''}" data-action="toggle-reverse" aria-pressed="${isThemeReversed ? 'true' : 'false'}" title="${isThemeReversed ? 'Reverse Theme Colors: ON' : 'Reverse Theme Colors: OFF'}">⇅ Reverse Theme Colors</button>
</div>
<div class="theme-presets-section">
<div class="theme-presets-grid">
${THEME_PRESETS.map((preset) => {
const applied = getAppliedThemeColors(preset);
return `
<button class="theme-preset-option ${selectedThemeKey === preset.key ? 'active' : ''}"
data-theme="${preset.key}"
title="${preset.name}">
<div class="theme-preset-swatches">
<span class="theme-preset-swatch" style="background-color: rgb(${applied.up.r}, ${applied.up.g}, ${applied.up.b})"></span>
<span class="theme-preset-swatch" style="background-color: rgb(${applied.down.r}, ${applied.down.g}, ${applied.down.b})"></span>
</div>
<span class="theme-preset-name">${preset.name}</span>
</button>
`;
}).join('')}
</div>
</div>
<div class="color-picker-actions">
<button class="color-action-btn color-default-btn" data-action="default">Default Colors</button>
<button class="color-action-btn color-apply-btn" data-action="apply">Apply Colors</button>
</div>
</div>
`;
document.body.appendChild(activeModal);
const modalReverseToggleBtn = activeModal.querySelector('.theme-reverse-toggle-btn');
if (modalReverseToggleBtn) {
modalReverseToggleBtn.addEventListener('click', function(e) {
e.stopPropagation();
setThemeReverse(!isThemeReversed, true);
refreshThemePresetSwatchesInModal();
});
}
activeModal.querySelectorAll('.theme-preset-option').forEach((option) => {
option.addEventListener('click', function(e) {
e.stopPropagation();
const themeKey = this.getAttribute('data-theme');
applyThemePreset(themeKey);
});
});
updateThemePresetSelection();
activeModal.querySelectorAll('.color-action-btn').forEach(btn => {
btn.addEventListener('click', function(e) {
e.stopPropagation();
const action = this.getAttribute('data-action');
if (action === 'apply') {
updateColorSwatches();
saveUserSettings();
showNotification('Colors applied successfully!');
closeActiveModal();
setTimeout(() => {
toggleThemeForRefresh();
}, 200);
} else if (action === 'default') {
resetToDefaultColors();
closeActiveModal();
}
});
});
activeModal.addEventListener('click', function(e) {
if (e.target === activeModal) {
closeActiveModal();
}
});
const escapeHandler = function(e) {
if (e.key === 'Escape') {
closeActiveModal();
}
};
document.addEventListener('keydown', escapeHandler);
activeModal._escapeHandler = escapeHandler;
}
function createColorPickerModal(colorType) {
currentColorType = colorType;
const colorCategories = [{
name: "Red",
colors: ["#2F0202", "#4A0404", "#660808", "#7F1D1D", "#991B1B", "#B91C1C", "#DC2626", "#EF4444", "#F87171", "#FCA5A5", "#FECACA", "#FEE2E2"]
},
{
name: "Orange",
colors: ["#331100", "#4A1A00", "#663300", "#7A3E00", "#9A4E00", "#B45309", "#D97706", "#F59E0B", "#FBBF24", "#FCD34D", "#FDE68A", "#FEF3C7"]
},
{
name: "Yellow",
colors: ["#2B2200", "#3F3200", "#544300", "#6B5500", "#826700", "#9A7B00", "#B08D00", "#C9A227", "#DDBA4A", "#EED37A", "#F8E8B0", "#FFF7D6"]
},
{
name: "Green",
colors: ["#021F0E", "#032E15", "#064E2A", "#166534", "#15803D", "#16A34A", "#22C55E", "#4ADE80", "#86EFAC", "#BBF7D0", "#DCFCE7", "#F0FDF4"]
},
{
name: "Blue",
colors: ["#071238", "#0A1A4A", "#0F2A66", "#1E3A8A", "#1D4ED8", "#2563EB", "#3B82F6", "#60A5FA", "#93C5FD", "#BFDBFE", "#DBEAFE", "#EFF6FF"]
},
{
name: "Purple",
colors: ["#1E0B45", "#2E1065", "#4C1D95", "#5B21B6", "#6D28D9", "#7C3AED", "#8B5CF6", "#A78BFA", "#C4B5FD", "#DDD6FE", "#EDE9FE", "#F5F3FF"]
},
{
name: "Gray",
colors: ["#0B1220", "#111827", "#1F2937", "#374151", "#4B5563", "#6B7280", "#9CA3AF", "#B6BCC6", "#CAD0D8", "#DDE2E8", "#ECEFF3", "#F7F8FA"]
},
{
name: "Brown",
colors: ["#1A100A", "#2B1B12", "#3A2418", "#4A2C1D", "#5C3624", "#6F422B", "#854D32", "#9C5E3A", "#B9774D", "#D09A6E", "#E5BE9A", "#F3E1D2"]
},
{
name: "Light Gray",
colors: ["#5C6472", "#6B7280", "#7E8693", "#9099A7", "#A3ACB8", "#B6BEC8", "#C8CFD7", "#D7DDE3", "#E4E8EC", "#EEF1F4", "#F6F8FA", "#FFFFFF"]
}
];
const currentColor = colorType === 'up' ? UP_COLOR : DOWN_COLOR;
activeModal = document.createElement('div');
activeModal.className = 'color-picker-modal';
activeModal.innerHTML = `
<div class="color-picker-content">
<div class="color-picker-title">
Select ${colorType === 'up' ? 'Up Color' : 'Down Color'}
</div>
<div class="color-type-switcher">
<button class="color-type-btn ${colorType === 'up' ? 'active' : ''}" data-type="up">Up Color</button>
<button class="color-type-btn ${colorType === 'down' ? 'active' : ''}" data-type="down">Down Color</button>
</div>
<div class="color-categories-container">
${colorCategories.map(category => `
<div class="color-category">
<div class="color-category-title">${category.name}</div>
<div class="color-category-grid">
${category.colors.map((color, index) => {
const isSelected = color === rgbToHex(currentColor.r, currentColor.g, currentColor.b);
return `
<div class="color-option ${isSelected ? 'selected' : ''}"
style="background-color: ${color}"
data-color="${color}"
title="${color}">
</div>
`;
}).join('')}
</div>
</div>
`).join('')}
</div>
<div class="custom-hex-section">
<div class="custom-hex-grid">
<label class="custom-hex-field">
<span class="custom-hex-label">1. Color (Up)</span>
<div class="custom-hex-control">
<button type="button" class="hex-palette-btn" data-palette-btn="up" title="Pick Up Color" style="--palette-color: ${rgbToHex(UP_COLOR.r, UP_COLOR.g, UP_COLOR.b)}"></button>
<input type="color" class="hex-palette-input" data-palette-target="up" value="${rgbToHex(UP_COLOR.r, UP_COLOR.g, UP_COLOR.b)}">
<input type="text" class="custom-hex-input" data-hex-target="up" maxlength="7" value="${rgbToHex(UP_COLOR.r, UP_COLOR.g, UP_COLOR.b)}" placeholder="#RRGGBB">
</div>
</label>
<label class="custom-hex-field">
<span class="custom-hex-label">2. Color (Down)</span>
<div class="custom-hex-control custom-hex-control-right">
<input type="text" class="custom-hex-input" data-hex-target="down" maxlength="7" value="${rgbToHex(DOWN_COLOR.r, DOWN_COLOR.g, DOWN_COLOR.b)}" placeholder="#RRGGBB">
<input type="color" class="hex-palette-input" data-palette-target="down" value="${rgbToHex(DOWN_COLOR.r, DOWN_COLOR.g, DOWN_COLOR.b)}">
<button type="button" class="hex-palette-btn" data-palette-btn="down" title="Pick Down Color" style="--palette-color: ${rgbToHex(DOWN_COLOR.r, DOWN_COLOR.g, DOWN_COLOR.b)}"></button>
</div>
</label>
</div>
<button class="color-action-btn custom-hex-apply-btn" data-action="apply-hex">Apply HEX Colors</button>
</div>
<div class="color-picker-actions">
<button class="color-action-btn color-default-btn" data-action="default">Default Colors</button>
<button class="color-action-btn color-apply-btn" data-action="apply">Apply Colors</button>
</div>
</div>
`;
document.body.appendChild(activeModal);
const normalizeHexInput = (value) => {
const raw = (value || '').trim().toUpperCase();
if (!raw) return '';
const prefixed = raw.startsWith('#') ? raw : `#${raw}`;
return prefixed;
};
const isValidHexInput = (value) => /^#([0-9A-F]{3}|[0-9A-F]{6})$/.test(value);
const toColorInputHex = (value) => {
const normalized = normalizeHexInput(value);
if (!isValidHexInput(normalized)) return null;
if (normalized.length === 4) {
return `#${normalized.slice(1).split('').map((ch) => ch + ch).join('')}`;
}
return normalized;
};
const setPaletteButtonColor = (target, value) => {
if (!activeModal) return;
const btn = activeModal.querySelector(`.hex-palette-btn[data-palette-btn="${target}"]`);
const colorInput = activeModal.querySelector(`.hex-palette-input[data-palette-target="${target}"]`);
const normalizedColor = toColorInputHex(value);
if (!normalizedColor) return;
if (btn) {
btn.style.setProperty('--palette-color', normalizedColor);
}
if (colorInput) {
colorInput.value = normalizedColor;
}
};
const syncCustomHexInputsInModal = () => {
const upInput = activeModal ? activeModal.querySelector('.custom-hex-input[data-hex-target="up"]') : null;
const downInput = activeModal ? activeModal.querySelector('.custom-hex-input[data-hex-target="down"]') : null;
const upHex = rgbToHex(UP_COLOR.r, UP_COLOR.g, UP_COLOR.b);
const downHex = rgbToHex(DOWN_COLOR.r, DOWN_COLOR.g, DOWN_COLOR.b);
if (upInput) upInput.value = upHex;
if (downInput) downInput.value = downHex;
setPaletteButtonColor('up', upHex);
setPaletteButtonColor('down', downHex);
};
const applyCustomHexColors = (showToast = true) => {
const upInput = activeModal ? activeModal.querySelector('.custom-hex-input[data-hex-target="up"]') : null;
const downInput = activeModal ? activeModal.querySelector('.custom-hex-input[data-hex-target="down"]') : null;
if (!upInput || !downInput) return;
const upHex = normalizeHexInput(upInput.value);
const downHex = normalizeHexInput(downInput.value);
const isUpValid = isValidHexInput(upHex);
const isDownValid = isValidHexInput(downHex);
upInput.classList.toggle('invalid', !isUpValid);
downInput.classList.toggle('invalid', !isDownValid);
if (!isUpValid || !isDownValid) {
if (showToast) showNotification('Invalid HEX. Use #RGB or #RRGGBB');
return;
}
const parsedUp = parseHexColor(upHex);
const parsedDown = parseHexColor(downHex);
setThemeColors(parsedUp, parsedDown);
selectedThemeKey = getMatchingThemePresetKey();
updateColorSwatches();
updateThemePresetSelection();
updateModalColorSelection();
applySettings();
saveUserSettings();
syncCustomHexInputsInModal();
if (showToast) showNotification('Custom HEX colors applied');
};
activeModal.querySelectorAll('.color-type-btn').forEach(btn => {
btn.addEventListener('click', function(e) {
e.stopPropagation();
const newType = this.getAttribute('data-type');
if (newType !== currentColorType) {
closeActiveModal();
setTimeout(() => {
showColorPicker(newType);
}, 50);
}
});
});
updateModalColorSelection();
syncCustomHexInputsInModal();
activeModal.querySelectorAll('.custom-hex-input').forEach((input) => {
input.addEventListener('input', function() {
this.classList.remove('invalid');
const target = this.getAttribute('data-hex-target');
const normalized = normalizeHexInput(this.value);
if (isValidHexInput(normalized)) {
setPaletteButtonColor(target, normalized);
}
});
input.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
e.preventDefault();
applyCustomHexColors();
}
});
});
activeModal.querySelectorAll('.hex-palette-btn').forEach((button) => {
button.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const target = this.getAttribute('data-palette-btn');
const colorInput = activeModal.querySelector(`.hex-palette-input[data-palette-target="${target}"]`);
if (colorInput) colorInput.click();
});
});
activeModal.querySelectorAll('.hex-palette-input').forEach((picker) => {
picker.addEventListener('input', function(e) {
e.stopPropagation();
const target = this.getAttribute('data-palette-target');
const linkedInput = activeModal.querySelector(`.custom-hex-input[data-hex-target="${target}"]`);
const normalized = normalizeHexInput(this.value);
if (linkedInput) {
linkedInput.value = normalized;
linkedInput.classList.remove('invalid');
}
setPaletteButtonColor(target, normalized);
applyCustomHexColors(false);
});
});
const applyHexBtn = activeModal.querySelector('[data-action="apply-hex"]');
if (applyHexBtn) {
applyHexBtn.addEventListener('click', function(e) {
e.stopPropagation();
applyCustomHexColors();
});
}
activeModal.querySelectorAll('.color-option').forEach((option) => {
option.addEventListener('click', function(e) {
e.stopPropagation();
const selectedHex = this.getAttribute('data-color');
const parsedColor = parseHexColor(selectedHex);
// Apply selected side while preserving history for reverse-safe chart mapping
if (currentColorType === 'up') {
setThemeColors(parsedColor, DOWN_COLOR);
} else {
setThemeColors(UP_COLOR, parsedColor);
}
selectedThemeKey = getMatchingThemePresetKey();
// Update selection visually
activeModal.querySelectorAll('.color-option').forEach(opt => {
opt.classList.remove('selected');
});
this.classList.add('selected');
// Immediately update swatches and apply settings
updateColorSwatches();
updateThemePresetSelection();
syncCustomHexInputsInModal();
applySettings();
saveUserSettings();
showNotification(`${currentColorType === 'up' ? 'Up' : 'Down'} color updated to ${selectedHex}`);
});
});
// Action buttons
activeModal.querySelectorAll('.color-action-btn').forEach(btn => {
btn.addEventListener('click', function(e) {
e.stopPropagation();
const action = this.getAttribute('data-action');
if (action === 'apply') {
updateColorSwatches();
saveUserSettings();
showNotification('Colors applied successfully!');
closeActiveModal();
setTimeout(() => {
toggleThemeForRefresh();
}, 200);
} else if (action === 'default') {
resetToDefaultColors();
closeActiveModal();
}
});
});
// Close on background click
activeModal.addEventListener('click', function(e) {
if (e.target === activeModal) {
closeActiveModal();
}
});
// Close on Escape key
const escapeHandler = function(e) {
if (e.key === 'Escape') {
closeActiveModal();
}
};
document.addEventListener('keydown', escapeHandler);
activeModal._escapeHandler = escapeHandler;
}
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
}
function resetToDefaultColors() {
if (isThemeReversed) {
setThemeColors(DEFAULT_DOWN_COLOR, DEFAULT_UP_COLOR);
} else {
setThemeColors(DEFAULT_UP_COLOR, DEFAULT_DOWN_COLOR);
}
selectedThemeKey = getMatchingThemePresetKey();
// Chart filters artık dinamik olduğu için sabit değerlere gerek yok
// CHART_FILTERS değişkenini kaldırabilirsiniz veya boş bırakabilirsiniz
saveUserSettings();
applySettings();
updateColorSwatches();
updateThemePresetSelection();
showNotification('Default colors restored!');
setTimeout(() => {
toggleThemeForRefresh();
}, 1000);
}
function updateColorSwatches() {
const upSwatch = document.querySelector('.nav-r-color-item[data-color="up"] .color-swatch');
const downSwatch = document.querySelector('.nav-r-color-item[data-color="down"] .color-swatch');
const themeUpSwatch = document.querySelector('.nav-r-color-item[data-color="theme"] .theme-mini-swatch-up');
const themeDownSwatch = document.querySelector('.nav-r-color-item[data-color="theme"] .theme-mini-swatch-down');
if (upSwatch) {
upSwatch.style.backgroundColor = `rgb(${UP_COLOR.r}, ${UP_COLOR.g}, ${UP_COLOR.b})`;
}
if (downSwatch) {
downSwatch.style.backgroundColor = `rgb(${DOWN_COLOR.r}, ${DOWN_COLOR.g}, ${DOWN_COLOR.b})`;
}
if (themeUpSwatch) {
themeUpSwatch.style.backgroundColor = `rgb(${UP_COLOR.r}, ${UP_COLOR.g}, ${UP_COLOR.b})`;
}
if (themeDownSwatch) {
themeDownSwatch.style.backgroundColor = `rgb(${DOWN_COLOR.r}, ${DOWN_COLOR.g}, ${DOWN_COLOR.b})`;
}
updateThemeReverseToggleUI();
}
/* ---------- EXISTING FUNCTIONS (Fixed) ---------- */
const hexRegex = /#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\b/g;
const rgbRegex = /rgba?\([^\)]+\)/gi;
const hslRegex = /hsla?\([^\)]+\)/gi;
const _tmp = document.createElement('div');
_tmp.style.position = 'absolute';
_tmp.style.left = '-9999px';
_tmp.style.width = _tmp.style.height = '1px';
document.documentElement.appendChild(_tmp);
function clamp(v, a=0, b=255){ return Math.max(a, Math.min(b, v)); }
function parseHexColor(str){
let s = str.replace('#','');
if(s.length === 3) s = s.split('').map(ch => ch+ch).join('');
else if(s.length === 4) s = s.split('').map(ch => ch+ch).join('');
let r=0,g=0,b=0,a=1;
if(s.length === 6){
r = parseInt(s.substr(0,2),16); g = parseInt(s.substr(2,2),16); b = parseInt(s.substr(4,2),16);
} else if(s.length === 8){
r = parseInt(s.substr(0,2),16); g = parseInt(s.substr(2,2),16); b = parseInt(s.substr(4,2),16);
a = parseInt(s.substr(6,2),16) / 255;
}
return {r,g,b,a};
}
function parseRgbString(str){
const nums = str.match(/[\d\.%]+/g);
if(!nums) return null;
let [r,g,b,a] = [0,0,0,1];
if(nums.length >= 3){
const parseComponent = (v) => v.endsWith('%') ? Math.round(parseFloat(v) * 2.55) : Math.round(parseFloat(v));
r = parseComponent(nums[0]); g = parseComponent(nums[1]); b = parseComponent(nums[2]);
}
if(nums.length >= 4) a = parseFloat(nums[3]);
return {r,g,b,a};
}
function parseHslString(str){
const parts = str.match(/[\d\.%]+/g);
if(!parts) return null;
let h = parseFloat(parts[0]), s = parseFloat(parts[1]) / 100, l = parseFloat(parts[2]) / 100;
let a = parts.length >= 4 ? parseFloat(parts[3]) : 1;
const rgb = hslToRgb(h, s, l);
return {r: Math.round(rgb.r), g: Math.round(rgb.g), b: Math.round(rgb.b), a};
}
function hslToRgb(h, s, l){
h = ((h % 360) + 360) % 360;
const c = (1 - Math.abs(2*l - 1)) * s;
const x = c * (1 - Math.abs((h / 60) % 2 - 1));
const m = l - c/2;
let r=0,g=0,b=0;
if(h < 60) { r=c; g=x; b=0; } else if(h < 120) { r=x; g=c; b=0; } else if(h < 180) { r=0; g=c; b=x; }
else if(h < 240) { r=0; g=x; b=c; } else if(h < 300) { r=x; g=0; b=c; } else { r=c; g=0; b=x; }
return { r: (r+m)*255, g: (g+m)*255, b: (b+m)*255 };
}
function rgbToHsl(r,g,b){
r/=255; g/=255; b/=255;
const max = Math.max(r,g,b), min = Math.min(r,g,b);
let h=0,s=0,l=(max+min)/2;
if(max !== min){
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max){
case r: h = ((g - b) / d + (g < b ? 6 : 0)) * 60; break;
case g: h = ((b - r) / d + 2) * 60; break;
case b: h = ((r - g) / d + 4) * 60; break;
}
}
return {h, s, l};
}
function parseColorString(str){
if(!str) return null; str = str.trim();
if(str.toLowerCase() === 'transparent' || str === 'none') return {r:0,g:0,b:0,a:0};
try{
if(str[0] === '#') return parseHexColor(str);
if(str.toLowerCase().startsWith('rgb')) return parseRgbString(str);
if(str.toLowerCase().startsWith('hsl')) return parseHslString(str);
_tmp.style.color = ''; _tmp.style.color = str;
const cs = getComputedStyle(_tmp).color;
return parseRgbString(cs);
}catch(e){ return null; }
}
function rgbaToCss(o){
const a = (typeof o.a === 'number') ? o.a : 1;
return `rgba(${Math.round(o.r)}, ${Math.round(o.g)}, ${Math.round(o.b)}, ${+a.toFixed(3)})`;
}
function invertColor(color) {
const clamp = (v) => Math.max(0, Math.min(255, Math.round(v)));
return {
r: 255 - clamp(color.r),
g: 255 - clamp(color.g),
b: 255 - clamp(color.b),
a: (typeof color.a === 'number') ? color.a : 1
};
}
function isLightColor(color) {
if (!color) return false;
const a = (typeof color.a === 'number') ? color.a : 1;
if (a === 0) return true;
const luminance = (0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b) / 255;
return luminance >= 0.72;
}
function getPopupTextColorFromBackground(backgroundCssValue) {
const parsedBackground = parseColorString(backgroundCssValue || '');
if (!parsedBackground) return rgbaToCss(DOWN_COLOR);
return isLightColor(parsedBackground) ? rgbaToCss(DOWN_COLOR) : 'rgba(255, 255, 255, 1)';
}
function updatePopupTextColor(root = document) {
try {
const scope = (root && typeof root.querySelectorAll === 'function') ? root : document;
const hasVisibleBackground = (value) => {
if (!value) return false;
const normalized = String(value).trim().toLowerCase();
return normalized !== 'transparent' && normalized !== 'rgba(0, 0, 0, 0)' && normalized !== 'initial' && normalized !== 'none';
};
scope.querySelectorAll('[data-testid="okd-popup"] > div').forEach((container) => {
const ownBg = getComputedStyle(container).backgroundColor;
const parentBg = container.parentElement ? getComputedStyle(container.parentElement).backgroundColor : '';
const effectiveBg = hasVisibleBackground(ownBg) ? ownBg : (hasVisibleBackground(parentBg) ? parentBg : ownBg);
const textColor = getPopupTextColorFromBackground(effectiveBg);
container.style.setProperty('--okx-popup-text-color', textColor);
});
} catch (e) {}
}
// BU FONKSİYON DEĞİŞTİ: Artık UP_COLOR ve DOWN_COLOR doğrudan kullanılıyor
function shouldConvertByHue(rgba){
if(!rgba || rgba.a === 0) return null;
// Özel div için istisna - bu Color değişmesin
const {h,s,l} = rgbToHsl(rgba.r, rgba.g, rgba.b);
if(rgba.r === 230 && rgba.g === 181 && rgba.b === 117) return null;
if(s > 0.08 && h >= 70 && h <= 170) return 'greenish';
if(s > 0.08 && (h <= 25 || h >= 300)) return 'reddish';
return null;
}
// BU FONKSİYON DEĞİŞTİ: Artık CHART_FILTERS yerine UP_COLOR ve DOWN_COLOR kullanılıyor
function convertBasedOnDetection(rgba){
if(!rgba || rgba.a === 0) return rgba;
// Önce güncel renkleri stabilize et (idempotent davranış)
if (colorsClose(rgba, UP_COLOR)) return { ...UP_COLOR, a: rgba.a };
if (colorsClose(rgba, DOWN_COLOR)) return { ...DOWN_COLOR, a: rgba.a };
// Sonra bir önceki aktif temayı yeni tarafa taşı (reverse sonrası geçiş)
if (!colorsClose(LAST_UP_COLOR, UP_COLOR) && colorsClose(rgba, LAST_UP_COLOR)) return { ...UP_COLOR, a: rgba.a };
if (!colorsClose(LAST_DOWN_COLOR, DOWN_COLOR) && colorsClose(rgba, LAST_DOWN_COLOR)) return { ...DOWN_COLOR, a: rgba.a };
const det = shouldConvertByHue(rgba);
if(det === 'greenish'){
return { ...UP_COLOR, a: rgba.a };
} else if(det === 'reddish'){
return { ...DOWN_COLOR, a: rgba.a };
}
return rgba;
}
function replaceColorTokensInText(text){
if(!text || typeof text !== 'string') return text;
let out = text;
out = out.replace(hexRegex, (m) => {
const p = parseColorString(m); if(!p) return m;
const conv = convertBasedOnDetection(p);
if(conv && (conv.r !== p.r || conv.g !== p.g || conv.b !== p.b || conv.a !== p.a)) return rgbaToCss(conv);
return m;
}).replace(rgbRegex, (m) => {
const p = parseColorString(m); if(!p) return m;
const conv = convertBasedOnDetection(p);
if(conv && (conv.r !== p.r || conv.g !== p.g || conv.b !== p.b || conv.a !== p.a)) return rgbaToCss(conv);
return m;
}).replace(hslRegex, (m) => {
const p = parseColorString(m); if(!p) return m;
const conv = convertBasedOnDetection(p);
if(conv && (conv.r !== p.r || conv.g !== p.g || conv.b !== p.b || conv.a !== p.a)) return rgbaToCss(conv);
return m;
});
return out;
}
function processCssRuleList(rules){
for(let i=0;i<rules.length;i++){
const rule = rules[i];
try{
if(rule.type === CSSRule.STYLE_RULE){
const style = rule.style;
for(let j=0;j<style.length;j++){
const prop = style[j], val = style.getPropertyValue(prop);
const newVal = replaceColorTokensInText(val);
if(newVal !== val) try{ style.setProperty(prop, newVal, style.getPropertyPriority(prop)); }catch(e){}
}
} else if(rule.cssRules) processCssRuleList(rule.cssRules);
}catch(e){ continue; }
}
}
function processStyleSheets(){ for(const sheet of document.styleSheets){ try{ if(sheet.cssRules) processCssRuleList(sheet.cssRules); }catch(e){} } }
function processStyleTags(){ document.querySelectorAll('style').forEach(tag=>{ try{ const old = tag.textContent, neu = replaceColorTokensInText(old); if(neu !== old) tag.textContent = neu; }catch(e){} }); }
function processInlineAndSvg(root=document){
root.querySelectorAll('[style]').forEach(el=>{
if (shouldSkipElementForColorConversion(el)) return;
try{ const old = el.getAttribute('style'), neu = replaceColorTokensInText(old); if(neu !== old) el.setAttribute('style', neu); }catch(e){}
});
root.querySelectorAll('[fill],[stroke]').forEach(el=>{
if (shouldSkipElementForColorConversion(el)) return;
['fill','stroke'].forEach(attr=>{ try{ if(el.hasAttribute(attr)){ const old = el.getAttribute(attr), neu = replaceColorTokensInText(old); if(neu !== old) el.setAttribute(attr, neu); } }catch(e){} });
});
}
const computedCheckProps = ['background-color','color','border-top-color','border-right-color','border-bottom-color','border-left-color','outline-color','caret-color','column-rule-color'];
function isTransparentValue(v){ if(!v) return true; v = v.trim(); return v === 'transparent' || v === 'rgba(0, 0, 0, 0)' || v === 'initial' || v === 'none'; }
function processComputedStylesBatch(elements, start=0){
const batch = 250, end = Math.min(elements.length, start + batch);
for(let i=start;i<end;i++){
const el = elements[i];
if (shouldSkipElementForColorConversion(el)) continue;
try{
const cs = getComputedStyle(el);
computedCheckProps.forEach(prop=>{
try{
const val = cs.getPropertyValue(prop);
if(!val || isTransparentValue(val)) return;
const parsed = parseColorString(val);
if(!parsed) return;
const conv = convertBasedOnDetection(parsed);
if(conv && (conv.r !== parsed.r || conv.g !== parsed.g || conv.b !== parsed.b || conv.a !== parsed.a)) el.style.setProperty(prop, rgbaToCss(conv), 'important');
}catch(e){}
});
try{ const bs = cs.getPropertyValue('box-shadow'); if(bs && bs !== 'none' && /#|rgba?\(|hsla?\(/i.test(bs)){ const newBs = replaceColorTokensInText(bs); if(newBs !== bs) el.style.setProperty('box-shadow', newBs, 'important'); } }catch(e){}
try{ const bg = cs.getPropertyValue('background-image'); if(bg && bg !== 'none' && /#|rgba?\(|hsla?\(/i.test(bg)){ const newBg = replaceColorTokensInText(bg); if(newBg !== bg) el.style.setProperty('background-image', newBg, 'important'); } }catch(e){}
}catch(e){}
}
if(end < elements.length) setTimeout(()=> processComputedStylesBatch(elements, end), 20);
}
function processAllComputedStylesRoot(root=document){ const elements = Array.from(root.querySelectorAll('*')); processComputedStylesBatch(elements, 0); }
function patchCanvasContext(ctx){
try{
if(!ctx || ctx.__colorPatched) return;
ctx.__colorPatched = true;
const convertMaybe = (v) => {
if(typeof v !== 'string') return v;
const parsed = parseColorString(v); if(!parsed) return v;
const conv = convertBasedOnDetection(parsed);
if(conv && (conv.r !== parsed.r || conv.g !== parsed.g || conv.b !== parsed.b || conv.a !== parsed.a)) return rgbaToCss(conv);
return v;
};
let _fill = ctx.fillStyle, _stroke = ctx.strokeStyle, _shadow = ctx.shadowColor;
Object.defineProperty(ctx, 'fillStyle', { get(){ return _fill; }, set(v){ _fill = convertMaybe(v); } });
Object.defineProperty(ctx, 'strokeStyle', { get(){ return _stroke; }, set(v){ _stroke = convertMaybe(v); } });
Object.defineProperty(ctx, 'shadowColor', { get(){ return _shadow; }, set(v){ _shadow = convertMaybe(v); } });
}catch(e){}
}
const origGetCtx = HTMLCanvasElement.prototype.getContext;
HTMLCanvasElement.prototype.getContext = function(type, ...args){
const ctx = origGetCtx.apply(this, [type, ...args]);
try{ if(type === '2d' && ctx && (!this.closest || !this.closest('.tv-lightweight-charts'))) patchCanvasContext(ctx); }catch(e){}
return ctx;
};
// Yeni fonksiyon: Chart canvas'ını direkt override et
function overrideChartCanvas() {
setTimeout(() => {
const canvases = document.querySelectorAll('.tv-lightweight-charts canvas');
canvases.forEach(canvas => {
const ctx = canvas.getContext('2d');
if (ctx && !ctx.__colorOverridden) {
ctx.__colorOverridden = true;
const origFill = ctx.fill;
const origStroke = ctx.stroke;
const origFillRect = ctx.fillRect;
const origStrokeRect = ctx.strokeRect;
// Fill override
ctx.fill = function() {
if (this.fillStyle) {
if (this.fillStyle === '#26a69a' || this.fillStyle === '#bdff2a' ||
this.fillStyle === 'rgb(38, 166, 154)' || this.fillStyle === 'rgb(189, 255, 42)') {
this.fillStyle = rgbaToCss(UP_COLOR);
} else if (this.fillStyle === '#ef5350' || this.fillStyle === '#ff42ac' ||
this.fillStyle === 'rgb(239, 83, 80)' || this.fillStyle === 'rgb(255, 66, 172)') {
this.fillStyle = rgbaToCss(DOWN_COLOR);
}
}
return origFill.apply(this, arguments);
};
// Stroke override
ctx.stroke = function() {
if (this.strokeStyle) {
if (this.strokeStyle === '#26a69a' || this.strokeStyle === '#bdff2a' ||
this.strokeStyle === 'rgb(38, 166, 154)' || this.strokeStyle === 'rgb(189, 255, 42)') {
this.strokeStyle = rgbaToCss(UP_COLOR);
} else if (this.strokeStyle === '#ef5350' || this.strokeStyle === '#ff42ac' ||
this.strokeStyle === 'rgb(239, 83, 80)' || this.strokeStyle === 'rgb(255, 66, 172)') {
this.strokeStyle = rgbaToCss(DOWN_COLOR);
}
}
return origStroke.apply(this, arguments);
};
// FillRect override
ctx.fillRect = function(x, y, w, h) {
if (this.fillStyle) {
if (this.fillStyle === '#26a69a' || this.fillStyle === '#bdff2a' ||
this.fillStyle === 'rgb(38, 166, 154)' || this.fillStyle === 'rgb(189, 255, 42)') {
this.fillStyle = rgbaToCss(UP_COLOR);
} else if (this.fillStyle === '#ef5350' || this.fillStyle === '#ff42ac' ||
this.fillStyle === 'rgb(239, 83, 80)' || this.fillStyle === 'rgb(255, 66, 172)') {
this.fillStyle = rgbaToCss(DOWN_COLOR);
}
}
return origFillRect.apply(this, arguments);
};
}
});
}, 1000);
}
// Chart observer'ı ekle - chart değişikliklerini takip et
function observeChartChanges() {
const chartObserver = new MutationObserver(() => {
const charts = document.querySelectorAll('.tv-lightweight-charts');
if (charts.length > 0) {
applyChartColorFilters();
}
});
chartObserver.observe(document.body, {
childList: true,
subtree: true
});
}
// BU FONKSİYON DEĞİŞTİ: Chart filtreleri artık UP_COLOR ve DOWN_COLOR'a göre dinamik olarak hesaplanıyor
// BU FONKSİYON TAMAMEN DEĞİŞTİ: Chart Colorleri için daha etkili bir yaklaşım
function applyChartColorFilters() {
try {
const oldStyle = document.getElementById('okx-chart-colors-style');
if (oldStyle) oldStyle.remove();
const chartStyle = document.createElement('style');
chartStyle.id = 'okx-chart-colors-style';
const popupLightBgText = rgbaToCss(DOWN_COLOR);
const buyTabReversedText = rgbaToCss(invertColor(UP_COLOR));
const sellTabReversedText = rgbaToCss(invertColor(DOWN_COLOR));
chartStyle.textContent = `
/* TradingView chart genel zorlaması kaldırıldı; yön eşleşmesi hedefli dönüşüm ile korunur */
/* Yeşil/Yukarı Colorli elemanlar */
.tv-lightweight-charts [fill="#26a69a"],
.tv-lightweight-charts [fill="#bdff2a"],
.tv-lightweight-charts [fill*="26a69a"],
.tv-lightweight-charts [fill*="bdff2a"],
.tv-lightweight-charts [stroke="#26a69a"],
.tv-lightweight-charts [stroke="#bdff2a"],
.tv-lightweight-charts [stroke*="26a69a"],
.tv-lightweight-charts [stroke*="bdff2a"],
.tv-lightweight-charts [style*="26a69a"],
.tv-lightweight-charts [style*="bdff2a"] {
fill: ${rgbaToCss(UP_COLOR)} !important;
stroke: ${rgbaToCss(UP_COLOR)} !important;
}
/* Kırmızı/Aşağı Colorli elemanlar */
.tv-lightweight-charts [fill="#ef5350"],
.tv-lightweight-charts [fill="#ff42ac"],
.tv-lightweight-charts [fill*="ef5350"],
.tv-lightweight-charts [fill*="ff42ac"],
.tv-lightweight-charts [stroke="#ef5350"],
.tv-lightweight-charts [stroke="#ff42ac"],
.tv-lightweight-charts [stroke*="ef5350"],
.tv-lightweight-charts [stroke*="ff42ac"],
.tv-lightweight-charts [style*="ef5350"],
.tv-lightweight-charts [style*="ff42ac"] {
fill: ${rgbaToCss(DOWN_COLOR)} !important;
stroke: ${rgbaToCss(DOWN_COLOR)} !important;
}
/* Canvas filtreleri - daha agresif yaklaşım */
.tv-lightweight-charts canvas {
filter: none !important;
}
/* Özel olarak chart çubukları için */
.tv-lightweight-charts [fill="rgba(38, 166, 154, 0.2)"],
.tv-lightweight-charts [fill="rgba(37, 167, 80, 0.2)"] {
fill: ${rgbaToCss({...UP_COLOR, a: 0.2})} !important;
}
.tv-lightweight-charts [fill="rgba(239, 83, 80, 0.2)"],
.tv-lightweight-charts [fill="rgba(202, 63, 100, 0.2)"] {
fill: ${rgbaToCss({...DOWN_COLOR, a: 0.2})} !important;
}
/* Chart arkaplanındaki metin Colorleri */
.tv-lightweight-charts text,
.tv-lightweight-charts tspan {
fill: ${rgbaToCss(UP_COLOR)} !important;
color: ${rgbaToCss(UP_COLOR)} !important;
}
/* Buy/Sell tab text: otomatik reverse/invert (tüm segmented varyantlar) */
.dex-tabs-pane-list-flex .dex-tabs-pane.dex-tabs-pane-segmented[data-pane-id="buy"],
.dex-tabs-pane-list-flex .dex-tabs-pane.dex-tabs-pane-segmented[data-pane-id="buy"] *,
.dex-tabs-pane.dex-tabs-pane-sm.dex-tabs-pane-green.dex-tabs-pane-segmented[data-pane-id="buy"],
.dex-tabs-pane.dex-tabs-pane-sm.dex-tabs-pane-green.dex-tabs-pane-segmented[data-pane-id="buy"] * {
color: ${buyTabReversedText} !important;
}
.dex-tabs-pane-list-flex .dex-tabs-pane.dex-tabs-pane-segmented[data-pane-id="sell"],
.dex-tabs-pane-list-flex .dex-tabs-pane.dex-tabs-pane-segmented[data-pane-id="sell"] *,
.dex-tabs-pane.dex-tabs-pane-sm.dex-tabs-pane-red.dex-tabs-pane-segmented[data-pane-id="sell"],
.dex-tabs-pane.dex-tabs-pane-sm.dex-tabs-pane-red.dex-tabs-pane-segmented[data-pane-id="sell"] * {
color: ${sellTabReversedText} !important;
}
/* Leaderboard ve diğer UI text Colorleri */
.GbIs1T__dex,
.GbIs1T__dex *,
.T7vNAe__dex,
.T7vNAe__dex *,
.PE9jLx__dex,
.PE9jLx__dex * {
color: white !important;
}
/* Tüm OKD popup varyantları: arka plana göre kontrast (açık bg -> DOWN_COLOR, koyu bg -> beyaz) */
[data-testid="okd-popup"] > div,
[data-testid="okd-popup"] > div *,
[data-testid="okd-popup"] > div i,
[data-testid="okd-popup"] > div i::before {
color: var(--okx-popup-text-color, ${popupLightBgText}) !important;
fill: var(--okx-popup-text-color, ${popupLightBgText}) !important;
}
`;
document.head.appendChild(chartStyle);
updatePopupTextColor();
// Canvas context'ini de override et
overrideChartCanvas();
} catch (e) {
console.error('Chart style error:', e);
}
}
function monitorChartColors() {
const origFill = CanvasRenderingContext2D.prototype.fill;
const origStroke = CanvasRenderingContext2D.prototype.stroke;
const origFillRect = CanvasRenderingContext2D.prototype.fillRect;
CanvasRenderingContext2D.prototype.fill = function() {
if (this.fillStyle && typeof this.fillStyle === 'string') {
const parsed = parseColorString(this.fillStyle);
if (parsed) {
const converted = convertBasedOnDetection(parsed);
if (converted && (converted.r !== parsed.r || converted.g !== parsed.g || converted.b !== parsed.b)) this.fillStyle = rgbaToCss(converted);
}
}
origFill.apply(this, arguments);
};
CanvasRenderingContext2D.prototype.stroke = function() {
if (this.strokeStyle && typeof this.strokeStyle === 'string') {
const parsed = parseColorString(this.strokeStyle);
if (parsed) {
const converted = convertBasedOnDetection(parsed);
if (converted && (converted.r !== parsed.r || converted.g !== parsed.g || converted.b !== parsed.b)) this.strokeStyle = rgbaToCss(converted);
}
}
origStroke.apply(this, arguments);
};
CanvasRenderingContext2D.prototype.fillRect = function(x, y, w, h) {
if (this.fillStyle && typeof this.fillStyle === 'string') {
const parsed = parseColorString(this.fillStyle);
if (parsed) {
const converted = convertBasedOnDetection(parsed);
if (converted && (converted.r !== parsed.r || converted.g !== parsed.g || converted.b !== parsed.b)) this.fillStyle = rgbaToCss(converted);
}
}
origFillRect.apply(this, arguments);
};
}
function processNodeAndChildren(node){
try{ if(node.nodeType !== 1) return; processInlineAndSvg(node); processAllComputedStylesRoot(node); }catch(e){}
}
const mo = new MutationObserver((mutations)=>{
const added = [];
for(const m of mutations){
if(m.type === 'attributes'){
const target = m.target;
try{ if(['style','class','fill','stroke'].includes(m.attributeName)) processNodeAndChildren(target); }catch(e){}
}
if(m.addedNodes) m.addedNodes.forEach(n => { if(n.nodeType === 1) added.push(n); });
}
if(added.length) {
setTimeout(() => {
added.forEach(n => processNodeAndChildren(n));
updatePopupTextColor();
}, 10);
}
});
function kickAll(){
try{
processStyleSheets(); processStyleTags(); processInlineAndSvg(document); processAllComputedStylesRoot(document);
applyChartColorFilters();
}catch(e){}
}
function init() {
loadUserSettings();
kickAll();
mo.observe(document.body || document.documentElement, {
childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class', 'fill', 'stroke']
});
monitorChartColors();
addColorPickerToMenu();
observeChartChanges(); // BU SATIRI EKLEYİN
const menuObserver = new MutationObserver(() => addColorPickerToMenu());
menuObserver.observe(document.body, { childList: true, subtree: true });
window.addEventListener('load', () => {
setTimeout(kickAll, 500);
setTimeout(kickAll, 2000);
setTimeout(kickAll, 5000);
setTimeout(addColorPickerToMenu, 1000);
setTimeout(applyChartColorFilters, 1500); // BU SATIRI EKLEYİN
});
let lastUrl = location.href;
setInterval(() => {
if (location.href !== lastUrl) {
lastUrl = location.href;
setTimeout(() => {
kickAll();
addColorPickerToMenu();
applyChartColorFilters(); // BU SATIRI EKLEYİN
}, 1000);
}
}, 1000);
}
if(document.body) init();
else window.addEventListener('DOMContentLoaded', init);
})();