263 lines
8.3 KiB
JavaScript
263 lines
8.3 KiB
JavaScript
const pc = require("picocolors")
|
|
const colorNames = require("./colorNames")
|
|
const themeDefaults = require("./themeDefaults")
|
|
|
|
const { oklch, interpolate, wcagContrast } = require("culori/require")
|
|
|
|
const colorIsInvalid = (input) => {
|
|
console.error(
|
|
`├─ ${pc.red("⚠︎")} ${pc.bgRed(" Error ")} Invalid color ${pc.red(input)} in ${pc.green(
|
|
"tailwind.config.js"
|
|
)}`
|
|
)
|
|
}
|
|
const cutNumber = (number) => {
|
|
try {
|
|
if (number) {
|
|
return +number.toFixed(6)
|
|
}
|
|
return 0
|
|
} catch (e) {
|
|
// colorIsInvalid(number)
|
|
return false
|
|
}
|
|
}
|
|
module.exports = {
|
|
isDark: (color) => {
|
|
try {
|
|
if (wcagContrast(color, "black") < wcagContrast(color, "white")) {
|
|
return true
|
|
}
|
|
return false
|
|
} catch (e) {
|
|
// colorIsInvalid(color)
|
|
return false
|
|
}
|
|
},
|
|
|
|
colorObjToString: (input) => {
|
|
const { l, c, h } = input
|
|
return `${Number.parseFloat((cutNumber(l) * 100).toFixed(6))}% ${cutNumber(c)} ${cutNumber(h)}`
|
|
},
|
|
|
|
generateForegroundColorFrom: function (input, percentage = 0.8) {
|
|
try {
|
|
const result = interpolate(
|
|
[input, this.isDark(input) ? "white" : "black"],
|
|
"oklch"
|
|
)(percentage)
|
|
return this.colorObjToString(result)
|
|
} catch (e) {
|
|
// colorIsInvalid(input)
|
|
return false
|
|
}
|
|
},
|
|
|
|
generateDarkenColorFrom: function (input, percentage = 0.07) {
|
|
try {
|
|
const result = interpolate([input, "black"], "oklch")(percentage)
|
|
return this.colorObjToString(result)
|
|
} catch (e) {
|
|
// colorIsInvalid(input)
|
|
return false
|
|
}
|
|
},
|
|
|
|
convertColorFormat: function (input) {
|
|
if (typeof input !== "object" || input === null) {
|
|
return input
|
|
}
|
|
|
|
const resultObj = {}
|
|
|
|
for (const [rule, value] of Object.entries(input)) {
|
|
if (Object.hasOwn(colorNames, rule)) {
|
|
try {
|
|
const colorObj = oklch(value)
|
|
resultObj[colorNames[rule]] = this.colorObjToString(colorObj)
|
|
} catch (e) {
|
|
colorIsInvalid(value)
|
|
return false
|
|
}
|
|
} else {
|
|
resultObj[rule] = value
|
|
}
|
|
|
|
// auto generate base colors
|
|
if (!Object.hasOwn(input, "base-100")) {
|
|
resultObj["--b1"] = "100% 0 0"
|
|
}
|
|
if (!Object.hasOwn(input, "base-200")) {
|
|
resultObj["--b2"] = this.generateDarkenColorFrom(input["base-100"], 0.07)
|
|
}
|
|
if (!Object.hasOwn(input, "base-300")) {
|
|
if (Object.hasOwn(input, "base-200")) {
|
|
resultObj["--b3"] = this.generateDarkenColorFrom(input["base-200"], 0.07)
|
|
} else {
|
|
resultObj["--b3"] = this.generateDarkenColorFrom(input["base-100"], 0.14)
|
|
}
|
|
}
|
|
|
|
// auto generate state colors
|
|
|
|
if (!Object.hasOwn(input, "info")) {
|
|
resultObj["--in"] = "72.06% 0.191 231.6"
|
|
}
|
|
if (!Object.hasOwn(input, "success")) {
|
|
resultObj["--su"] = "64.8% 0.150 160"
|
|
}
|
|
if (!Object.hasOwn(input, "warning")) {
|
|
resultObj["--wa"] = "84.71% 0.199 83.87"
|
|
}
|
|
if (!Object.hasOwn(input, "error")) {
|
|
resultObj["--er"] = "71.76% 0.221 22.18"
|
|
}
|
|
|
|
// auto generate content colors
|
|
if (!Object.hasOwn(input, "base-content")) {
|
|
resultObj["--bc"] = this.generateForegroundColorFrom(input["base-100"], 0.8)
|
|
}
|
|
if (!Object.hasOwn(input, "primary-content")) {
|
|
resultObj["--pc"] = this.generateForegroundColorFrom(input.primary, 0.8)
|
|
}
|
|
if (!Object.hasOwn(input, "secondary-content")) {
|
|
resultObj["--sc"] = this.generateForegroundColorFrom(input.secondary, 0.8)
|
|
}
|
|
if (!Object.hasOwn(input, "accent-content")) {
|
|
resultObj["--ac"] = this.generateForegroundColorFrom(input.accent, 0.8)
|
|
}
|
|
if (!Object.hasOwn(input, "neutral-content")) {
|
|
resultObj["--nc"] = this.generateForegroundColorFrom(input.neutral, 0.8)
|
|
}
|
|
if (!Object.hasOwn(input, "info-content")) {
|
|
if (Object.hasOwn(input, "info")) {
|
|
resultObj["--inc"] = this.generateForegroundColorFrom(input.info, 0.8)
|
|
} else {
|
|
resultObj["--inc"] = "0% 0 0"
|
|
}
|
|
}
|
|
if (!Object.hasOwn(input, "success-content")) {
|
|
if (Object.hasOwn(input, "success")) {
|
|
resultObj["--suc"] = this.generateForegroundColorFrom(input.success, 0.8)
|
|
} else {
|
|
resultObj["--suc"] = "0% 0 0"
|
|
}
|
|
}
|
|
if (!Object.hasOwn(input, "warning-content")) {
|
|
if (Object.hasOwn(input, "warning")) {
|
|
resultObj["--wac"] = this.generateForegroundColorFrom(input.warning, 0.8)
|
|
} else {
|
|
resultObj["--wac"] = "0% 0 0"
|
|
}
|
|
}
|
|
if (!Object.hasOwn(input, "error-content")) {
|
|
if (Object.hasOwn(input, "error")) {
|
|
resultObj["--erc"] = this.generateForegroundColorFrom(input.error, 0.8)
|
|
} else {
|
|
resultObj["--erc"] = "0% 0 0"
|
|
}
|
|
}
|
|
|
|
// add css variables if not exist
|
|
for (const item of Object.entries(themeDefaults.variables)) {
|
|
const [variable, value] = item
|
|
if (!Object.hasOwn(input, variable)) {
|
|
resultObj[variable] = value
|
|
}
|
|
}
|
|
|
|
// add other custom styles
|
|
if (!Object.hasOwn(colorNames, rule)) {
|
|
resultObj[rule] = value
|
|
}
|
|
}
|
|
|
|
return resultObj
|
|
},
|
|
|
|
injectThemes: function (addBase, config, themes) {
|
|
const includedThemesObj = {}
|
|
// add default themes
|
|
const themeRoot = config("daisyui.themeRoot") ?? ":root"
|
|
for (const [theme, value] of Object.entries(themes)) {
|
|
includedThemesObj[theme] = this.convertColorFormat(value)
|
|
}
|
|
|
|
// add custom themes
|
|
if (Array.isArray(config("daisyui.themes"))) {
|
|
for (const item of config("daisyui.themes")) {
|
|
if (typeof item === "object" && item !== null) {
|
|
for (const [customThemeName, customThemevalue] of Object.entries(item)) {
|
|
includedThemesObj[customThemeName] = this.convertColorFormat(customThemevalue)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let themeOrder = []
|
|
if (Array.isArray(config("daisyui.themes"))) {
|
|
for (const theme of config("daisyui.themes")) {
|
|
if (typeof theme === "object" && theme !== null) {
|
|
for (const customThemeName of Object.keys(theme)) {
|
|
themeOrder.push(customThemeName)
|
|
}
|
|
} else if (Object.hasOwn(includedThemesObj, theme)) {
|
|
themeOrder.push(theme)
|
|
}
|
|
}
|
|
} else if (config("daisyui.themes") === true) {
|
|
themeOrder = themeDefaults.themeOrder
|
|
} else {
|
|
themeOrder = ["light", "dark"]
|
|
}
|
|
|
|
// inject themes in order
|
|
const themesToInject = {}
|
|
themeOrder.forEach((themeName, index) => {
|
|
if (index === 0) {
|
|
// first theme as root
|
|
themesToInject[themeRoot] = includedThemesObj[themeName]
|
|
} else if (index === 1) {
|
|
// auto dark
|
|
if (config("daisyui.darkTheme")) {
|
|
if (
|
|
themeOrder[0] !== config("daisyui.darkTheme") &&
|
|
themeOrder.includes(config("daisyui.darkTheme"))
|
|
) {
|
|
themesToInject["@media (prefers-color-scheme: dark)"] = {
|
|
[themeRoot]: includedThemesObj[`${config("daisyui.darkTheme")}`],
|
|
}
|
|
}
|
|
} else if (config("daisyui.darkTheme") === false) {
|
|
// disables prefers-color-scheme: dark
|
|
} else {
|
|
if (themeOrder[0] !== "dark" && themeOrder.includes("dark")) {
|
|
themesToInject["@media (prefers-color-scheme: dark)"] = {
|
|
[themeRoot]: includedThemesObj.dark,
|
|
}
|
|
}
|
|
}
|
|
// theme 0 with name
|
|
themesToInject[`[data-theme=${themeOrder[0]}]`] = includedThemesObj[themeOrder[0]]
|
|
themesToInject[`${themeRoot}:has(input.theme-controller[value=${themeOrder[0]}]:checked)`] =
|
|
includedThemesObj[themeOrder[0]]
|
|
// theme 1 with name
|
|
themesToInject[`[data-theme=${themeOrder[1]}]`] = includedThemesObj[themeOrder[1]]
|
|
themesToInject[`${themeRoot}:has(input.theme-controller[value=${themeOrder[1]}]:checked)`] =
|
|
includedThemesObj[themeOrder[1]]
|
|
} else {
|
|
themesToInject[`[data-theme=${themeName}]`] = includedThemesObj[themeName]
|
|
themesToInject[`${themeRoot}:has(input.theme-controller[value=${themeName}]:checked)`] =
|
|
includedThemesObj[themeName]
|
|
}
|
|
})
|
|
|
|
addBase(themesToInject)
|
|
|
|
return {
|
|
includedThemesObj,
|
|
themeOrder,
|
|
}
|
|
},
|
|
}
|