From 58258eecddc269ca5cebdc9846bb5eb8be12c3ac Mon Sep 17 00:00:00 2001 From: itsmartashub <44645238+itsmartashub@users.noreply.github.com> Date: Tue, 9 Sep 2025 16:48:17 +0200 Subject: [PATCH 1/4] refactor(colors): Rewrite and optimize the color conversion util functions - slice() > substr() (deprecated and slower) - Multiplication instead of division where possible - Bitwise OR (| 0) for faster float-to-int conversion - padStart() instead of manual zero-padding logic - Reduced conditional branches in HSL conversion --- composables/useColorConversion.js | 75 ++++++++++++++----------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/composables/useColorConversion.js b/composables/useColorConversion.js index 2d26b73..514e2c0 100644 --- a/composables/useColorConversion.js +++ b/composables/useColorConversion.js @@ -1,8 +1,3 @@ -// src/composables/useColorConversion.js - -/** - * Converts a hex color string (e.g. "#ff9800") into an HSL array: [h, s, l] - */ export function hexToHSL(hex) { hex = hex.replace(/^#/, '') if (hex.length === 3) { @@ -11,80 +6,76 @@ export function hexToHSL(hex) { .map((c) => c + c) .join('') } - const r = parseInt(hex.substr(0, 2), 16) / 255 - const g = parseInt(hex.substr(2, 2), 16) / 255 - const b = parseInt(hex.substr(4, 2), 16) / 255 + + // Bitwise parsing is faster than parseInt with radix + const r = parseInt(hex.slice(0, 2), 16) / 255 + const g = parseInt(hex.slice(2, 4), 16) / 255 + const b = parseInt(hex.slice(4, 6), 16) / 255 const max = Math.max(r, g, b) const min = Math.min(r, g, b) + const diff = max - min + let h = 0, - s = 0, - l = (max + min) / 2 + s = 0 + const l = (max + min) * 0.5 + + if (diff !== 0) { + s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min) - 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) - break - case g: - h = (b - r) / d + 2 - break - case b: - h = (r - g) / d + 4 - break - } - h = h * 60 + // Slightly optimized switch + if (max === r) h = (g - b) / diff + (g < b ? 6 : 0) + else if (max === g) h = (b - r) / diff + 2 + else h = (r - g) / diff + 4 + + h *= 60 } + return [Math.round(h), Math.round(s * 100), Math.round(l * 100)] } -/** - * Converts an HSL array [h, s, l] into a hex color string. - * h should be between 0 and 360, s and l between 0 and 100. - */ export function hslToHex([h, s, l]) { - s /= 100 - l /= 100 + s *= 0.01 // Multiplication is faster than division + l *= 0.01 const c = (1 - Math.abs(2 * l - 1)) * s const x = c * (1 - Math.abs(((h / 60) % 2) - 1)) - const m = l - c / 2 + const m = l - c * 0.5 + let r = 0, g = 0, b = 0 - if (h >= 0 && h < 60) { + // Optimized range checking + const h60 = h / 60 + if (h60 < 1) { r = c g = x b = 0 - } else if (h >= 60 && h < 120) { + } else if (h60 < 2) { r = x g = c b = 0 - } else if (h >= 120 && h < 180) { + } else if (h60 < 3) { r = 0 g = c b = x - } else if (h >= 180 && h < 240) { + } else if (h60 < 4) { r = 0 g = x b = c - } else if (h >= 240 && h < 300) { + } else if (h60 < 5) { r = x g = 0 b = c - } else if (h >= 300 && h < 360) { + } else { r = c g = 0 b = x } - const toHex = (n) => { - const hex = Math.round((n + m) * 255).toString(16) - return hex.length === 1 ? '0' + hex : hex - } + // Bitwise magic for hex conversion - much faster! + const toHex = (n) => (Math.round((n + m) * 255) | 0).toString(16).padStart(2, '0') return `#${toHex(r)}${toHex(g)}${toHex(b)}` } From e12da122c7bf6942fe486faa6483878aea3979d0 Mon Sep 17 00:00:00 2001 From: itsmartashub <44645238+itsmartashub@users.noreply.github.com> Date: Tue, 9 Sep 2025 17:34:00 +0200 Subject: [PATCH 2/4] refactor(colors): Improve color conversion logic and make it more safe and rounded --- composables/useColorConversion.js | 58 ++++++++++++------------------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/composables/useColorConversion.js b/composables/useColorConversion.js index 514e2c0..bf47f1c 100644 --- a/composables/useColorConversion.js +++ b/composables/useColorConversion.js @@ -1,5 +1,10 @@ export function hexToHSL(hex) { + console.log(hex) + + // if (typeof hex !== 'string') throw new Error('Invalid HEX value') hex = hex.replace(/^#/, '') + // if (!/^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(hex)) throw new Error('Invalid HEX value') + if (hex.length === 3) { hex = hex .split('') @@ -7,7 +12,6 @@ export function hexToHSL(hex) { .join('') } - // Bitwise parsing is faster than parseInt with radix const r = parseInt(hex.slice(0, 2), 16) / 255 const g = parseInt(hex.slice(2, 4), 16) / 255 const b = parseInt(hex.slice(4, 6), 16) / 255 @@ -16,14 +20,13 @@ export function hexToHSL(hex) { const min = Math.min(r, g, b) const diff = max - min - let h = 0, - s = 0 + let h = 0 + let s = 0 const l = (max + min) * 0.5 if (diff !== 0) { s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min) - // Slightly optimized switch if (max === r) h = (g - b) / diff + (g < b ? 6 : 0) else if (max === g) h = (b - r) / diff + 2 else h = (r - g) / diff + 4 @@ -31,11 +34,13 @@ export function hexToHSL(hex) { h *= 60 } - return [Math.round(h), Math.round(s * 100), Math.round(l * 100)] + return [h, s * 100, l * 100] // keep floats internally for better round-trip } export function hslToHex([h, s, l]) { - s *= 0.01 // Multiplication is faster than division + if (!Array.isArray([h, s, l]) || [h, s, l].some((v) => typeof v !== 'number')) throw new Error('Invalid HSL array') + + s *= 0.01 l *= 0.01 const c = (1 - Math.abs(2 * l - 1)) * s @@ -45,37 +50,20 @@ export function hslToHex([h, s, l]) { let r = 0, g = 0, b = 0 - - // Optimized range checking const h60 = h / 60 - if (h60 < 1) { - r = c - g = x - b = 0 - } else if (h60 < 2) { - r = x - g = c - b = 0 - } else if (h60 < 3) { - r = 0 - g = c - b = x - } else if (h60 < 4) { - r = 0 - g = x - b = c - } else if (h60 < 5) { - r = x - g = 0 - b = c - } else { - r = c - g = 0 - b = x - } - // Bitwise magic for hex conversion - much faster! - const toHex = (n) => (Math.round((n + m) * 255) | 0).toString(16).padStart(2, '0') + if (h60 < 1) [r, g, b] = [c, x, 0] + else if (h60 < 2) [r, g, b] = [x, c, 0] + else if (h60 < 3) [r, g, b] = [0, c, x] + else if (h60 < 4) [r, g, b] = [0, x, c] + else if (h60 < 5) [r, g, b] = [x, 0, c] + else [r, g, b] = [c, 0, x] + + const toHex = (n) => { + const val = Math.round((n + m) * 255) + const clamped = Math.min(255, Math.max(0, val)) // clamp for safety + return clamped.toString(16).padStart(2, '0') + } return `#${toHex(r)}${toHex(g)}${toHex(b)}` } From 86248078cf617b951d4180c5c3d3883849543501 Mon Sep 17 00:00:00 2001 From: itsmartashub <44645238+itsmartashub@users.noreply.github.com> Date: Tue, 9 Sep 2025 18:05:34 +0200 Subject: [PATCH 3/4] refactor(custom/colors): Wrap color picker into a separate component and clean up watchers to prevent mem leak - Refactor custom colors logic by encapsulating the color picker into a dedicated, reusable component - Clean up color watchers when the component is unmounted to prevent memory leaks and improve performance - Improve code modularity and maintainability by isolating color picker functionality Changes summary: - Refactored the custom colors implementation by wrapping the color picker into a separate component. This improves code organization and reusability. Additionally, color watchers are now cleaned up when the component is unmounted, ensuring better performance and preventing potential memory leaks. --- components/Custom/Colors/ColorPicker.vue | 109 +++++++++++++++++++ components/Custom/Colors/Index.vue | 132 +++++++++-------------- 2 files changed, 161 insertions(+), 80 deletions(-) create mode 100644 components/Custom/Colors/ColorPicker.vue diff --git a/components/Custom/Colors/ColorPicker.vue b/components/Custom/Colors/ColorPicker.vue new file mode 100644 index 0000000..d2828b4 --- /dev/null +++ b/components/Custom/Colors/ColorPicker.vue @@ -0,0 +1,109 @@ + + + + + diff --git a/components/Custom/Colors/Index.vue b/components/Custom/Colors/Index.vue index 7e672de..904883f 100644 --- a/components/Custom/Colors/Index.vue +++ b/components/Custom/Colors/Index.vue @@ -1,7 +1,7 @@