diff --git a/components/Custom/Colors/ColorPicker.vue b/components/Custom/Colors/ColorPicker.vue
new file mode 100644
index 0000000..7a7f10c
--- /dev/null
+++ b/components/Custom/Colors/ColorPicker.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
diff --git a/components/Custom/Colors/Index.vue b/components/Custom/Colors/Index.vue
index 7e672de..fae02e4 100644
--- a/components/Custom/Colors/Index.vue
+++ b/components/Custom/Colors/Index.vue
@@ -1,18 +1,14 @@
-
diff --git a/composables/useAccentColors.js b/composables/useAccentColors.js
new file mode 100644
index 0000000..80ec5ab
--- /dev/null
+++ b/composables/useAccentColors.js
@@ -0,0 +1,61 @@
+// composables/useAccentColors.js
+import { ref, computed } from 'vue'
+import { accentLightItem, accentDarkItem } from '@/utils/storage'
+import { hexToHSL } from '@/composables/useColorConversion'
+
+export function useAccentColors() {
+ const lightHex = ref(accentLightItem.fallback)
+ const darkHex = ref(accentDarkItem.fallback)
+
+ // Load stored values
+ const load = async () => {
+ try {
+ const [storedLight, storedDark] = await Promise.all([accentLightItem.getValue(), accentDarkItem.getValue()])
+ if (storedLight) lightHex.value = storedLight
+ if (storedDark) darkHex.value = storedDark
+ } catch (err) {
+ console.error('Failed to load accent colors', err)
+ }
+ }
+
+ // Save on change
+ const saveLight = () => accentLightItem.setValue(lightHex.value)
+ const saveDark = () => accentDarkItem.setValue(darkHex.value)
+
+ const reset = () => {
+ lightHex.value = accentLightItem.fallback
+ darkHex.value = accentDarkItem.fallback
+ saveLight()
+ saveDark()
+ }
+
+ // Compute HSL for CSS injection
+ const lightHSL = computed(() => hexToHSL(lightHex.value))
+ const darkHSL = computed(() => hexToHSL(darkHex.value))
+
+ // // CSS string
+ const cssString = computed(
+ () => `
+ body.light {
+ --accent-h: ${lightHSL.value[0]} !important;
+ --accent-s: ${lightHSL.value[1]}% !important;
+ --accent-l: ${lightHSL.value[2]}% !important;
+ }
+ body.dark {
+ --accent-h: ${darkHSL.value[0]} !important;
+ --accent-s: ${darkHSL.value[1]}% !important;
+ --accent-l: ${darkHSL.value[2]}% !important;
+ }
+ `
+ )
+
+ return {
+ lightHex,
+ darkHex,
+ load,
+ saveLight,
+ saveDark,
+ reset,
+ cssString,
+ }
+}
diff --git a/composables/useColorConversion.js b/composables/useColorConversion.js
index 2d26b73..bf47f1c 100644
--- a/composables/useColorConversion.js
+++ b/composables/useColorConversion.js
@@ -1,89 +1,68 @@
-// src/composables/useColorConversion.js
-
-/**
- * Converts a hex color string (e.g. "#ff9800") into an HSL array: [h, s, l]
- */
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('')
.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
+
+ 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)
- 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)
- break
- case g:
- h = (b - r) / d + 2
- break
- case b:
- h = (r - g) / d + 4
- break
- }
- h = h * 60
+ const diff = max - min
+
+ 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)
+
+ 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)]
+
+ return [h, s * 100, l * 100] // keep floats internally for better round-trip
}
-/**
- * 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
+ 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
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
+ const h60 = h / 60
- if (h >= 0 && h < 60) {
- r = c
- g = x
- b = 0
- } else if (h >= 60 && h < 120) {
- r = x
- g = c
- b = 0
- } else if (h >= 120 && h < 180) {
- r = 0
- g = c
- b = x
- } else if (h >= 180 && h < 240) {
- r = 0
- g = x
- b = c
- } else if (h >= 240 && h < 300) {
- r = x
- g = 0
- b = c
- } else if (h >= 300 && h < 360) {
- r = c
- g = 0
- b = x
- }
+ 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 hex = Math.round((n + m) * 255).toString(16)
- return hex.length === 1 ? '0' + hex : hex
+ 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)}`
diff --git a/utils/storage.js b/utils/storage.js
index 406d50e..2d78f50 100644
--- a/utils/storage.js
+++ b/utils/storage.js
@@ -14,8 +14,8 @@ export const THEMES = Object.freeze({
})
// Pre-compute hex values instead of doing it every time
-const DEFAULT_ACCENT_LIGHT_HEX = hslToHex(DEFAULT_ACCENT_LIGHT_HSL)
-const DEFAULT_ACCENT_DARK_HEX = hslToHex(DEFAULT_ACCENT_DARK_HSL)
+export const DEFAULT_ACCENT_LIGHT_HEX = hslToHex(DEFAULT_ACCENT_LIGHT_HSL)
+export const DEFAULT_ACCENT_DARK_HEX = hslToHex(DEFAULT_ACCENT_DARK_HSL)
// ---------- Helper ----------
export async function getAllStorageItems() {