UNPKG

@uinamic/colors

Version:

CSS color token generator centered on HSL lightness (HSL 기반 명도 중심 CSS 색상 토큰 생성기)

160 lines (154 loc) 4.92 kB
// src/index.js import fs from "fs"; // src/logic/spectrum.js function getFullSpectrumFromCenter(centerL, limit = 5) { const splitRange = centerL <= 22 || centerL >= 78; const getLimit = getDynamicLimit(splitRange, limit); const maxL = 100 - getLimit; const isLowRange = centerL <= 50; const lowRange = isLowRange ? centerL - getLimit : maxL - centerL; const highRange = isLowRange ? maxL - centerL : centerL - getLimit; if (splitRange) { const lowRange2 = isLowRange ? centerL - getLimit : maxL - centerL; const highRange2 = lowRange2 * 4; const result = calculateSpectrum(centerL, lowRange2, highRange2, isLowRange); return result; } else { const result = calculateSpectrum(centerL, lowRange, highRange, isLowRange); return result; } } function getDynamicLimit(splitRange, defaultLimit = 5) { if (splitRange) return 3; return defaultLimit; } function calculateSpectrum(centerL, lowRange, highRange, isLowRange) { let lowBias = Math.floor(lowRange * 0.1); lowBias += (lowRange - lowBias) % 4; const lowDelta = lowRange - lowBias; let highBias = Math.floor(highRange * 0.1); highBias += (highRange - highBias) % 4; const highDelta = highRange - highBias; let lowSteps; let lowValues; let highSteps; let highValues; if (isLowRange) { lowSteps = smartLowBias(lowBias).map((w) => lowDelta / 4 + w); lowValues = accumulateReverse(centerL, lowSteps); highSteps = smartHighBias(highBias).map((w) => highDelta / 4 + w).reverse(); highValues = accumulate(centerL, highSteps); } else { lowSteps = smartLowBias(lowBias).map((w) => lowDelta / 4 + w).reverse(); lowValues = accumulate(centerL, lowSteps); highSteps = smartHighBias(highBias).map((w) => highDelta / 4 + w); highValues = accumulateReverse(centerL, highSteps); } const spectrum = [.../* @__PURE__ */ new Set([...lowValues, ...highValues])].sort((a, b) => a - b); return spectrum; } function smartLowBias(total) { const result = [0, 0, 0, 0]; for (let i = 0; i < total; i++) { const index = 3 - i % 4; result[index]++; } return result; } function smartHighBias(n) { const result = [0, 0, 0, 0]; const weights = [3, 2, 1, 0]; for (let i = 0; i < n; i++) { const idx = weights[i % 4]; result[idx]++; } return result; } function accumulate(start, steps) { return steps.reduce( (acc, curr) => { const last = acc[acc.length - 1]; return [...acc, +(last + curr).toFixed(1)]; }, [start] ); } function accumulateReverse(end, steps) { return steps.reduceRight( (acc, curr) => { const next = acc[0]; return [+(next - curr).toFixed(1), ...acc]; }, [end] ); } // src/logic/writeCss.js function writeCss(map, spectrumFn, options = {}) { const { format = "css", prefix = "--color-", limit = 5 } = options; const baseColors = [` ${prefix}black: hsl(0, 0%, 0%);`, ` ${prefix}white: hsl(0, 0%, 100%);`]; const baseColorsBlock = baseColors.join("\n"); const groupBlocks = []; const groupFlatJson = {}; for (const [name, [h, s, l]] of Object.entries(map)) { const ramp = spectrumFn(l, limit); const group = ramp.map((lightness, i) => { const level = (i + 1) * 100; const key = `${name}-${level}`; const value = `hsl(${h}, ${s}%, ${lightness}%)`; if (format === "json") { groupFlatJson[key] = value; return null; } return ` ${prefix}${key}: ${value};`; }).filter(Boolean); groupBlocks.push(group.join("\n")); } if (format === "json") { return JSON.stringify(groupFlatJson, null, 2); } if (format === "scss") { return [baseColorsBlock, "", ...groupBlocks].join("\n\n"); } return `:root { ${baseColorsBlock} ${groupBlocks.join("\n\n")} }`; } // src/colorMap.js var defaultColorHSLMap = { red: [0, 100, 50], blue: [240, 100, 50], yellow: [60, 100, 50], orange: [39, 100, 50], green: [120, 100, 40], purple: [270, 100, 60], pink: [340, 100, 88], teal: [180, 100, 45], gray: [0, 0, 50], darkgray: [0, 0, 30], lightgray: [0, 0, 70], coral: [16, 100, 65], mint: [160, 100, 50], cyan: [190, 100, 60], violet: [290, 76, 72], indigo: [225, 100, 45], amber: [45, 100, 50] }; // src/index.js function generateColorTokens(map = defaultColorHSLMap, options = {}) { const { format = "css", name = "uinamic-color", path: outputPath = "./theme", prefix = "color", limit = 5 } = options; const resolvedPrefix = format === "scss" ? `$${prefix}-` : `--${prefix}-`; const content = writeCss(map, getFullSpectrumFromCenter, { format, prefix: resolvedPrefix, limit }); const ext = format === "json" ? "json" : format === "scss" ? "scss" : "css"; const filePath = `${outputPath}/${name}.${ext}`; fs.mkdirSync(outputPath, { recursive: true }); fs.writeFileSync(filePath, content, "utf-8"); return content; } export { generateColorTokens };