sparkle-design-cli
Version:
Sparkle Design CSS Generator - デザインシステムCSSを設定ファイルから生成するツール
111 lines (94 loc) • 3.66 kB
JavaScript
/**
* カラー変換ユーティリティ
*/
import { oklch } from 'culori';
import { COLOR_PRECISION, GRAY_LEVEL_MAP, MESSAGES } from './constants.js';
/**
* 16進数カラーをrgba形式に変換
* @param {string} hex 16進数のカラーコード(#付きまたは無し)
* @returns {string} rgba形式の文字列
*/
export function hexToRgba(hex) {
// #を削除
let cleanHex = hex.replace('#', '');
// 3桁の場合は6桁に拡張
if (cleanHex.length === 3) {
cleanHex = cleanHex
.split('')
.map((char) => char + char)
.join('');
}
const r = parseInt(cleanHex.substring(0, 2), 16);
const g = parseInt(cleanHex.substring(2, 4), 16);
const b = parseInt(cleanHex.substring(4, 6), 16);
return `rgba(${r}, ${g}, ${b}, 1)`;
}
/**
* 16進数カラーをOKLCH形式に変換
* @param {string} hex 16進数のカラーコード(#付きまたは無し)
* @returns {string} OKLCH形式の文字列
*/
export function hexToOklch(hex) {
// #を削除
const cleanHex = hex.replace('#', '');
// 3桁の場合は6桁に、4桁の場合は8桁に拡張
let fullHex = cleanHex;
if (cleanHex.length === 3 || cleanHex.length === 4) {
fullHex = cleanHex
.split('')
.map((char) => char + char)
.join('');
}
// culoriを使用してHEXからOKLCHに変換
const oklchColor = oklch(`#${fullHex}`);
if (!oklchColor) {
console.warn(MESSAGES.COLOR_CONVERSION_FAILED(hex));
return `oklch(0 0 0)`;
}
// 精度を調整して出力
const l = Math.round((oklchColor.l || 0) * COLOR_PRECISION.OKLCH_L) / COLOR_PRECISION.OKLCH_L;
const c = Math.round((oklchColor.c || 0) * COLOR_PRECISION.OKLCH_C) / COLOR_PRECISION.OKLCH_C;
const h = oklchColor.h
? Math.round(oklchColor.h * COLOR_PRECISION.OKLCH_H) / COLOR_PRECISION.OKLCH_H
: 0;
// アルファ値がある場合(1未満の場合のみ出力に追加)
if (oklchColor.alpha !== undefined && oklchColor.alpha < 1) {
const a =
Math.round(oklchColor.alpha * COLOR_PRECISION.OKLCH_ALPHA) / COLOR_PRECISION.OKLCH_ALPHA;
return `oklch(${l} ${c} ${h} / ${a})`;
}
return `oklch(${l} ${c} ${h})`;
}
/**
* 色のトークンを生成する
* @param {Object} colors colors.jsonから読み込んだ色の定義
* @param {Object} grayMapping gray.jsonから読み込んだグレーの定義
* @param {string} primaryColor プライマリカラーの名前
* @returns {string} 色のトークンのCSS文字列
*/
export function generateColorTokens(colors, grayMapping, primaryColor) {
const colorTokens = [];
// 通常の色トークンを生成
Object.entries(colors).forEach(([colorName, colorValues]) => {
if (typeof colorValues === 'object' && colorValues !== null) {
Object.entries(colorValues).forEach(([level, hexValue]) => {
const oklchValue = hexToOklch(hexValue);
colorTokens.push(` --color-${colorName}-${level}: ${oklchValue};`);
});
} else if (typeof colorValues === 'string') {
// black, white, web-focusなどの単色
const oklchValue = hexToOklch(colorValues);
colorTokens.push(` --color-${colorName}: ${oklchValue};`);
}
});
// グレーの色トークンを生成(プライマリカラーに基づく)
if (primaryColor && grayMapping[primaryColor]) {
const grayColors = grayMapping[primaryColor];
Object.entries(grayColors).forEach(([key, hexValue]) => {
const grayLevel = GRAY_LEVEL_MAP[key] || key;
const oklchValue = hexToOklch(hexValue);
colorTokens.push(` --color-gray-${grayLevel}: ${oklchValue};`);
});
}
return colorTokens.join('\n');
}