Created
May 6, 2025 19:18
-
-
Save Darep/1063370b09c589866e63daa430ae8dae to your computer and use it in GitHub Desktop.
convert css file with hsl to oklch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Simple script to convert hsl() to oklch() in a CSS file. | |
* Used for converting shadcn theme from HSL to OKLCH during Tailwind v4 upgrade. | |
* | |
* IMPORTANT! DOES NOT CHANGE THE FILE IN PLACE! Only outputs the converted CSS to the console. | |
* | |
* Usage: | |
* npm install culori | |
* node hsl-to-oklch.js /home/user/projects/my-project/globals.css | |
**/ | |
const fs = require('node:fs'); | |
const culori = require('culori'); | |
function processCssFile(filePath) { | |
try { | |
const cssContent = fs.readFileSync(filePath, 'utf8'); | |
const lines = cssContent.split('\n'); | |
const newLines = []; | |
const hslPattern = /hsl\([^)]+\)/; | |
console.log('Starting CSS processing...\n'); | |
for (const line of lines) { | |
const match = line.match(hslPattern); | |
if (match) { | |
const colorInputString = match[0]; | |
try { | |
const parsedColor = culori.parse(colorInputString); | |
if (parsedColor) { | |
const oklchColor = culori.oklch(parsedColor); | |
if (oklchColor) { | |
oklchColor.l = culori.round(5)(oklchColor.l); | |
oklchColor.c = culori.round(5)(oklchColor.c); | |
oklchColor.h = culori.round(5)(oklchColor.h); | |
oklchColor.a = oklchColor.a ? culori.round(3)(oklchColor.a) : undefined; | |
const oklchString = culori.formatCss(oklchColor); | |
const newLine = line.replace( | |
hslPattern, | |
oklchString, | |
); | |
newLines.push(newLine); | |
console.log( | |
`CONVERTED: "${line.trim()}" => "${newLine.trim()}"`, | |
); | |
} else { | |
console.warn( | |
`[WARN] Could not convert parsed color to OKLCH. Original HSL: "${colorInputString}", Line: "${line.trim()}"`, | |
); | |
newLines.push(line); | |
} | |
} else { | |
console.warn( | |
`[WARN] Culori could not parse as HSL. Input: "${colorInputString}", Line: "${line.trim()}"`, | |
); | |
newLines.push(line); | |
} | |
} catch (e) { | |
console.error( | |
`[ERROR] Processing line: "${line.trim()}". HSL input: "${colorInputString}". Error: ${e.message}`, | |
); | |
newLines.push(line); | |
} | |
} else { | |
newLines.push(line); | |
} | |
} | |
const newCssContent = newLines.join('\n'); | |
console.log('\n\n--- Processed CSS Content (copy this to your file) ---\n'); | |
console.log(newCssContent); | |
} catch (error) { | |
console.error( | |
`[FATAL ERROR] Processing CSS file ${filePath}: ${error.message}`, | |
); | |
process.exit(1); | |
} | |
} | |
if (require.main === module) { | |
const filePath = process.argv[2]; | |
if (!filePath) { | |
console.error( | |
'ERROR: Please provide the path to the CSS file as an argument.', | |
); | |
console.log(`Usage: node ${process.argv[1]} <path-to-your-css-file.css>`); | |
process.exit(1); | |
} | |
processCssFile(filePath); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment