diff --git a/src/pages/trending.css b/src/pages/trending.css index 5c2c275..992305c 100644 --- a/src/pages/trending.css +++ b/src/pages/trending.css @@ -54,10 +54,6 @@ } a { - --other-color: var(--light-color); - @media (prefers-color-scheme: dark) { - --other-color: var(--dark-color); - } min-width: 240px; flex-grow: 1; max-width: 320px; @@ -65,14 +61,14 @@ color: inherit; border-radius: 16px; overflow: hidden; - background-color: var(--other-color); + background-color: var(--accent-alpha-color); border: 4px solid transparent; box-shadow: 0 4px 8px -2px var(--drop-shadow-color); transition: all 0.15s ease-out; display: flex; background-image: linear-gradient( to bottom, - var(--accent-color) -50%, + var(--accent-color, var(--link-text-color)) -50%, transparent ); background-clip: border-box; @@ -82,7 +78,7 @@ max-height: 50vh; &:not(:active):is(:hover, :focus-visible) { - border-color: var(--accent-color); + border-color: var(--accent-color, var(--link-light-color)); box-shadow: 0 4px 8px var(--drop-shadow-color), 0 8px 16px var(--drop-shadow-color); transform-origin: center bottom; @@ -107,7 +103,7 @@ background-repeat: no-repeat; background-image: linear-gradient( to bottom, - var(--other-color) 70%, + var(--accent-alpha-color) 70%, var(--bg-color) 100% ); transition: background-position-y 0.15s ease-out; diff --git a/src/pages/trending.jsx b/src/pages/trending.jsx index 742c717..891c25e 100644 --- a/src/pages/trending.jsx +++ b/src/pages/trending.jsx @@ -12,6 +12,7 @@ import Menu2 from '../components/menu2'; import RelativeTime from '../components/relative-time'; import Timeline from '../components/timeline'; import { api } from '../utils/api'; +import { oklab2rgb, rgb2oklab } from '../utils/color-utils'; import { filteredItems } from '../utils/filters'; import pmem from '../utils/pmem'; import states from '../utils/states'; @@ -161,35 +162,16 @@ function Trending({ columnMode, ...props }) { const domain = new URL(url).hostname .replace(/^www\./, '') .replace(/\/$/, ''); - const averageColor = getBlurHashAverageColor(blurhash); - const labAverageColor = rgb2oklab(averageColor); - - // const lightColor = averageColor.map((c) => { - // const v = c + 120; - // return v > 255 ? 255 : v; - // }); - // const darkColor = averageColor.map((c) => { - // const v = c - 100; - // return v < 0 ? 0 : v; - // }); - const accentColor = labAverageColor.map((c, i) => { - if (i === 0) { - return 0.65; - } - return c; - }); - const lightColor = labAverageColor.map((c, i) => { - if (i === 0) { - return 0.9; - } - return c; - }); - const darkColor = labAverageColor.map((c, i) => { - if (i === 0) { - return 0.4; - } - return c; - }); + let accentColor; + if (blurhash) { + const averageColor = getBlurHashAverageColor(blurhash); + const labAverageColor = rgb2oklab(averageColor); + accentColor = oklab2rgb([ + 0.6, + labAverageColor[1], + labAverageColor[2], + ]); + } return (
@@ -311,24 +295,4 @@ function Trending({ columnMode, ...props }) { ); } -// https://gist.github.com/earthbound19/e7fe15fdf8ca3ef814750a61bc75b5ce -const gammaToLinear = (c) => - c >= 0.04045 ? Math.pow((c + 0.055) / 1.055, 2.4) : c / 12.92; -function rgb2oklab([r, g, b]) { - r = gammaToLinear(r / 255); - g = gammaToLinear(g / 255); - b = gammaToLinear(b / 255); - var l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b; - var m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b; - var s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b; - l = Math.cbrt(l); - m = Math.cbrt(m); - s = Math.cbrt(s); - return [ - l * +0.2104542553 + m * +0.793617785 + s * -0.0040720468, - l * +1.9779984951 + m * -2.428592205 + s * +0.4505937099, - l * +0.0259040371 + m * +0.7827717662 + s * -0.808675766, - ]; -} - export default Trending; diff --git a/src/utils/color-utils.js b/src/utils/color-utils.js new file mode 100644 index 0000000..02f5eed --- /dev/null +++ b/src/utils/color-utils.js @@ -0,0 +1,52 @@ +// https://gist.github.com/earthbound19/e7fe15fdf8ca3ef814750a61bc75b5ce +function clamp(value, min, max) { + return Math.max(Math.min(value, max), min); +} + +const gammaToLinear = (c) => + c >= 0.04045 ? Math.pow((c + 0.055) / 1.055, 2.4) : c / 12.92; +const linearToGamma = (c) => + c >= 0.0031308 ? 1.055 * Math.pow(c, 1 / 2.4) - 0.055 : 12.92 * c; + +export function rgb2oklab([r, g, b]) { + r = gammaToLinear(r / 255); + g = gammaToLinear(g / 255); + b = gammaToLinear(b / 255); + var l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b; + var m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b; + var s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b; + l = Math.cbrt(l); + m = Math.cbrt(m); + s = Math.cbrt(s); + return [ + l * +0.2104542553 + m * +0.793617785 + s * -0.0040720468, + l * +1.9779984951 + m * -2.428592205 + s * +0.4505937099, + l * +0.0259040371 + m * +0.7827717662 + s * -0.808675766, + ]; +} + +export function oklab2rgb([L, a, b]) { + var l = L + a * +0.3963377774 + b * +0.2158037573; + var m = L + a * -0.1055613458 + b * -0.0638541728; + var s = L + a * -0.0894841775 + b * -1.291485548; + // The ** operator here cubes; same as l_*l_*l_ in the C++ example: + l = l ** 3; + m = m ** 3; + s = s ** 3; + var r = l * +4.0767416621 + m * -3.3077115913 + s * +0.2309699292; + var g = l * -1.2684380046 + m * +2.6097574011 + s * -0.3413193965; + var b = l * -0.0041960863 + m * -0.7034186147 + s * +1.707614701; + // Convert linear RGB values returned from oklab math to sRGB for our use before returning them: + r = 255 * linearToGamma(r); + g = 255 * linearToGamma(g); + b = 255 * linearToGamma(b); + // OPTION: clamp r g and b values to the range 0-255; but if you use the values immediately to draw, JavaScript clamps them on use: + r = clamp(r, 0, 255); + g = clamp(g, 0, 255); + b = clamp(b, 0, 255); + // OPTION: round the values. May not be necessary if you use them immediately for rendering in JavaScript, as JavaScript (also) discards decimals on render: + r = Math.round(r); + g = Math.round(g); + b = Math.round(b); + return [r, g, b]; +}