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); }