<main v-scope>
  <h1>Color Palette Builder</h1>
  <ul class="colors">
    
    <li v-if="colors.length === 0" style="grid-column:1/-1;">Add a color to get started</li>
   
    <li v-for="color,i in colors">
      <article class="color" :style="{'--color':color}" :class="{dark:isDark(color)}">
        <p>{{color}}</p>
        <button class="remove-color-btn" :class="{dark:isDark(color)}" @click="removeColor(i)">x</button>
        <button class="copy-color-btn" :class="{dark:isDark(color)}" @click="copyString(color)">copy</button>
      </article>
    </li>
    
    <li class="color-add">
      <button @click="addColor">Add Color</button>
    </li>
    
  </ul>
  <pre>{{cssString()}}</pre>
  <button @click="copyString(cssString())">Copy CSS</button>
</main>
* {
  box-sizing:border-box;
}

:root {
  --bg-color:#fff;
}

body {
  background-color:var(--bg-color);
  margin:0;
  
  display:grid;
  place-items:center;
  min-height:100vh;
  
  font-family:sans-serif;
}

ul {
  list-style:none;
  padding:0;
  width:100%;
}

main {
  width:100%;
  padding:20px;
  display:grid;
  place-items:center;
}

.colors {
  background-color:#dfdfdf;
  
  display:grid;
  gap:1rem;
  grid-template-columns: repeat( auto-fill, minmax(120px, 1fr) );
  place-items:center;
  padding:2rem;
  
  .color-add {
    grid-column: 1 / -1;
  }
}

.color {
  --color:#fff;
  
  border:2px solid #222;
  background-color:var(--color);
  width:120px;
  height:120px;
  padding:10px;
  border-radius:10px;
  
  display:grid;
  grid-template-columns:1fr 1fr;
  gap: .5rem;
  
  p {
    grid-column: 1 / -1;
    text-align:center;
    font-weight:bold;
  }
  
  &.dark {
    
    p {
      color:White;
    }
  }
  
}

button {
  border:none;
  padding:4px 10px;
  color:#fff;
  background-color:#222;
  border-radius:4px;
  cursor:pointer;
  
  &.dark {
    background-color:#dfdfdf;
    color:#222;
  }
  
}
View Compiled
if(!window.EyeDropper) {
  document.querySelector('main').innerHTML = "Oops, not supported, try Chrome Canary (95)";
}

import { createApp } from 'https://unpkg.com/petite-vue?module';

createApp({
  colors:[],
  async addColor() {
    let eyeDropper = new EyeDropper();
    const {sRGBHex} = await eyeDropper.open();
    this.colors.push( sRGBHex );
  },
  isDark( color ) {
    const c = color.substring(1);
    const rgb = parseInt(c, 16);
    const [r,g,b] = [(rgb >> 16) & 0xff, (rgb >>  8) & 0xff, (rgb >>  0) & 0xff];
    const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;

    if (luma < 50) {
      return true;
    }

    return false;
  },
  copyString(str) {
    const el = document.createElement('textarea');
    el.value = str;
    document.body.appendChild(el);
    el.select();
    document.execCommand('copy');
    document.body.removeChild(el);
  },
  removeColor(i) {
    this.colors.splice(i, 1);
  },
  cssString() {
    return ":root {\n" + this.colors.map( (c,i) => {
      return `  --c-color${i+1}: ${c};`
    }).join('\n') + "\n}";
  }
}).mount();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.