+54
-3
@@ -5,2 +5,40 @@ #!/usr/bin/env node | ||
| import { toFilterColor } from './utils/toFilterColor.js'; | ||
| // HSL 변환 함수들 (verbose 모드용) | ||
| function hexToHsl(hex) { | ||
| let r = 0, g = 0, b = 0; | ||
| if (hex.startsWith("#")) | ||
| hex = hex.slice(1); | ||
| if (hex.length === 3) { | ||
| r = parseInt(hex[0] + hex[0], 16); | ||
| g = parseInt(hex[1] + hex[1], 16); | ||
| b = parseInt(hex[2] + hex[2], 16); | ||
| } | ||
| else if (hex.length === 6) { | ||
| r = parseInt(hex.slice(0, 2), 16); | ||
| g = parseInt(hex.slice(2, 4), 16); | ||
| b = parseInt(hex.slice(4, 6), 16); | ||
| } | ||
| 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); | ||
| break; | ||
| case g: | ||
| h = (b - r) / d + 2; | ||
| break; | ||
| case b: | ||
| h = (r - g) / d + 4; | ||
| break; | ||
| } | ||
| h /= 6; | ||
| } | ||
| return [h * 360, s * 100, l * 100]; | ||
| } | ||
| const program = new Command(); | ||
@@ -10,7 +48,20 @@ program | ||
| .description('Convert hex colors to dark mode equivalent colors.') | ||
| .action((colors) => { | ||
| colors.forEach(color => { | ||
| .option('-v, --verbose', 'Show detailed conversion information') | ||
| .action((colors, options) => { | ||
| colors.forEach((color, index) => { | ||
| try { | ||
| if (options.verbose && index > 0) | ||
| console.log('---'); | ||
| const darkModeColor = toDarkModeColor(color); | ||
| console.log(`#${darkModeColor}`); | ||
| if (options.verbose) { | ||
| console.log(`Original: #${color}`); | ||
| console.log(`Dark Mode: #${darkModeColor}`); | ||
| // HSL 값도 표시 | ||
| const [h1, s1, l1] = hexToHsl(color); | ||
| const [h2, s2, l2] = hexToHsl(darkModeColor); | ||
| console.log(`HSL: ${h1.toFixed(0)}°, ${s1.toFixed(1)}%, ${l1.toFixed(1)}% → ${h2.toFixed(0)}°, ${s2.toFixed(1)}%, ${l2.toFixed(1)}%`); | ||
| } | ||
| else { | ||
| console.log(`#${darkModeColor}`); | ||
| } | ||
| } | ||
@@ -17,0 +68,0 @@ catch (error) { |
@@ -1,91 +0,36 @@ | ||
| function hexToHsl(hex) { | ||
| let r = 0, g = 0, b = 0; | ||
| if (hex.startsWith("#")) | ||
| hex = hex.slice(1); | ||
| if (hex.length === 3) { | ||
| r = parseInt(hex[0] + hex[0], 16); | ||
| g = parseInt(hex[1] + hex[1], 16); | ||
| b = parseInt(hex[2] + hex[2], 16); | ||
| } | ||
| else if (hex.length === 6) { | ||
| r = parseInt(hex.slice(0, 2), 16); | ||
| g = parseInt(hex.slice(2, 4), 16); | ||
| b = parseInt(hex.slice(4, 6), 16); | ||
| } | ||
| 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); | ||
| break; | ||
| case g: | ||
| h = (b - r) / d + 2; | ||
| break; | ||
| case b: | ||
| h = (r - g) / d + 4; | ||
| break; | ||
| import { argbFromHex, hexFromArgb, themeFromSourceColor, Hct } from '@material/material-color-utilities'; | ||
| export function toDarkModeColor(hex) { | ||
| try { | ||
| const sourceColor = argbFromHex(hex); | ||
| const hct = Hct.fromInt(sourceColor); | ||
| // 원본 색상의 명도를 체크해서 적절한 변환 적용 | ||
| let targetColor; | ||
| if (hct.tone > 80) { | ||
| // 매우 밝은 색상 (배경색 같은) → 어두운 배경색으로 | ||
| const theme = themeFromSourceColor(sourceColor); | ||
| targetColor = theme.schemes.dark.surface; | ||
| } | ||
| h /= 6; | ||
| else if (hct.tone > 60) { | ||
| // 밝은 색상 → 색조는 유지하되 다크모드에 적합한 톤으로 | ||
| const newHct = Hct.from(hct.hue, Math.max(hct.chroma * 0.8, 16), 25); | ||
| targetColor = newHct.toInt(); | ||
| } | ||
| else if (hct.tone < 30) { | ||
| // 어두운 색상 (텍스트 같은) → 밝은 색상으로 | ||
| const theme = themeFromSourceColor(sourceColor); | ||
| targetColor = theme.schemes.dark.onSurface; | ||
| } | ||
| else { | ||
| // 중간 톤 → 색조와 채도 유지하며 톤만 조정 | ||
| let newTone = hct.tone > 50 ? hct.tone - 30 : hct.tone + 30; | ||
| newTone = Math.max(20, Math.min(80, newTone)); | ||
| const newHct = Hct.from(hct.hue, hct.chroma, newTone); | ||
| targetColor = newHct.toInt(); | ||
| } | ||
| return hexFromArgb(targetColor).replace('#', ''); | ||
| } | ||
| return [h * 360, s * 100, l * 100]; | ||
| } | ||
| function hslToHex(h, s, l) { | ||
| s /= 100; | ||
| l /= 100; | ||
| 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; | ||
| catch (error) { | ||
| // 완전한 fallback | ||
| return hex.replace('#', ''); | ||
| } | ||
| 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; | ||
| } | ||
| r = Math.round((r + m) * 255); | ||
| g = Math.round((g + m) * 255); | ||
| b = Math.round((b + m) * 255); | ||
| return [r, g, b].map(x => x.toString(16).padStart(2, "0")).join(""); | ||
| } | ||
| export function toDarkModeColor(hex) { | ||
| let [h, s, l] = hexToHsl(hex); | ||
| // 채도 줄이기 | ||
| s = Math.max(0, s - 15); | ||
| // 명도 반전 + 보정 | ||
| l = 100 - l; | ||
| if (l < 20) | ||
| l = 20; // 너무 어둡지 않게 | ||
| if (l > 80) | ||
| l = 80; // 너무 밝지 않게 | ||
| return hslToHex(h, s, l); | ||
| } |
+2
-1
| { | ||
| "name": "neato", | ||
| "version": "0.0.20", | ||
| "version": "0.0.21", | ||
| "description": "A powerful utility library for efficient CSS class management in React applications", | ||
@@ -65,2 +65,3 @@ "keywords": [ | ||
| "@ilokesto/caro-kann": "^4.0.1", | ||
| "@material/material-color-utilities": "^0.3.0", | ||
| "clsx": "^2.1.1", | ||
@@ -67,0 +68,0 @@ "commander": "^14.0.1", |
58935
2.1%6
20%1071
-0.37%+ Added