111 lines
No EOL
3.5 KiB
JavaScript
111 lines
No EOL
3.5 KiB
JavaScript
import * as culori from './culori.js';
|
|
|
|
window.culori = culori;
|
|
|
|
const convertToOklch = culori.converter('oklch');
|
|
|
|
function parse_oklch(def) {
|
|
return convertToOklch(culori.parse(def));
|
|
}
|
|
|
|
const color_defs_input = document.getElementById('color_defs');
|
|
const named_colors_input = document.getElementById('named_colors');
|
|
const display = document.getElementById('display');
|
|
|
|
function el(name, attr, content) {
|
|
const element = document.createElementNS('http://www.w3.org/2000/svg', name);
|
|
if(attr) {
|
|
for(let [k,v] of Object.entries(attr)) {
|
|
element.setAttribute(k, v);
|
|
}
|
|
}
|
|
if(content) {
|
|
element.innerHTML = content;
|
|
}
|
|
return element;
|
|
}
|
|
|
|
function update() {
|
|
const defs = Array.from(new Set(color_defs_input.value.split(/\n/g).map(line=>line.trim().replace(';','')).filter(l=>l))).toSorted();
|
|
const colors = defs.map(def => { return {def, color: parse_oklch(def)} });
|
|
|
|
const named_colors = named_colors_input.value.trim().split(/\n/g).map(line=>line.trim().match(/.*(--.*?):\s*(.*);/)).filter(m=>m).map(([_,name,def]) => {return {name,def,color: parse_oklch(def)}});
|
|
|
|
display.innerHTML = '';
|
|
|
|
const [width, height] = [500, 500];
|
|
|
|
function project_color(color) {
|
|
const {c,h,l} = color;
|
|
const r = (1 - Math.sqrt(1-l)) * width*0.4 + width*0.1;
|
|
const an = Math.PI / 180 * (h || 0);
|
|
return {x: Math.cos(an) * r + width/2, y: Math.sin(an) * r + height/2};
|
|
}
|
|
|
|
const margin = 0.1;
|
|
colors.forEach(({def,color},i) => {
|
|
const jitter = 1;
|
|
const {c,h,l} = color;
|
|
const {x,y} = project_color(color);
|
|
const size = 10;
|
|
const g = el('g', {transform: `translate(${x} ${y})`});
|
|
const radius = size * c/0.2;
|
|
const mark = el('rect', {x:-size, y:-size, width:2*size, height: 2*size, rx: radius, ry: radius, fill: def, class: 'mark'});
|
|
g.append(mark);
|
|
const name = el('text', {x: x + size*1.2,y: y, class: 'label'}, def);
|
|
display.append(g);
|
|
|
|
mark.addEventListener('pointerover', () => display.append(name));
|
|
mark.addEventListener('pointerleave', () => display.removeChild(name));
|
|
})
|
|
|
|
named_colors.forEach(({def,name,color},i) => {
|
|
if(color === undefined) {
|
|
return;
|
|
}
|
|
const {c,h,l} = color;
|
|
const {x,y} = project_color(color);
|
|
const size = 10;
|
|
const g = el('g', {transform: `translate(${x} ${y})`});
|
|
const radius = size * c/0.2;
|
|
const mark = el('polygon', {points: `-6,0 6,-6 6,6`, fill: def, class: 'mark named'});
|
|
g.append(mark);
|
|
const tooltip = el('text', {x: x + size*1.2,y: y, class: 'label'}, `${name}: ${def}`);
|
|
display.append(g);
|
|
|
|
mark.addEventListener('pointerover', () => display.append(tooltip));
|
|
mark.addEventListener('pointerleave', () => display.removeChild(tooltip));
|
|
})
|
|
}
|
|
|
|
color_defs_input.addEventListener('input', update);
|
|
update();
|
|
|
|
|
|
|
|
|
|
function analyse_stylesheet(css) {
|
|
const colors = [];
|
|
|
|
const lines = css.split('\n');
|
|
|
|
let block = null;
|
|
let selector = null;
|
|
|
|
lines.forEach((line,i) => {
|
|
const bm = line.match(/^(\S.*?)\s*\{?$/);
|
|
if(bm) {
|
|
block = i;
|
|
selector = bm[1].trim();
|
|
} else {
|
|
const m = line.match(/\s*([^:]+):.*?(#[a-f0-9]{3,6}|(?:rgb|oklch|hsl)\([^\)]*?\))/i);
|
|
if(m) {
|
|
const [_, rule, color] = m;
|
|
console.log(selector, rule, color);
|
|
colors.push({line:i, selector, rule, color})
|
|
}
|
|
}
|
|
});
|
|
colors.sort((a,b) => a.color < b.color ? -1 : a.color > b.color ? 1 : 0);
|
|
console.table(colors);
|
|
} |