點擊色票 → 複製 HEX | 雙擊 → 鎖定 | 空白鍵 → 重生
#color-lab-root {
–bg: #0a0a0a; –surface: #111; –border: #222; –text: #e8e8e0; –muted: #555; –accent: #f0f0e8;
background-color: var(–bg); color: var(–text); font-family: ‘Space Mono’, monospace;
padding: 40px 20px; display: flex; flex-direction: column; align-items: center;
transition: all 0.3s ease; position: relative; min-height: 700px;
}
#color-lab-root.light-mode {
–bg: #f5f5f0; –surface: #ffffff; –border: #dddddd; –text: #1a1a1a; –muted: #888; –accent: #000;
}
.lab-header { text-align: center; margin-bottom: 30px; }
.lab-label { font-size: 11px; letter-spacing: 4px; color: var(–muted); text-transform: uppercase; }
.lab-title { font-family: ‘Noto Serif TC’, serif; font-weight: 300; font-size: 32px; color: var(–accent); margin: 10px 0; }
.lab-title span { font-family: ‘Space Mono’, monospace; font-size: 14px; color: var(–muted); display: block; }
#theme-toggle { cursor: pointer; background: var(–surface); color: var(–text); border: 1px solid var(–border); padding: 5px 15px; border-radius: 20px; font-size: 12px; }
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; width: 100%; max-width: 450px; background: var(–border); border: 2px solid var(–border); }
.swatch { position: relative; aspect-ratio: 1; cursor: pointer; background: var(–surface); }
.swatch-color { width: 100%; height: 100%; transition: background-color 0.4s ease; }
.swatch.locked { outline: 3px solid var(–accent); outline-offset: -3px; }
.swatch-info { position: absolute; bottom: 0; left: 0; right: 0; background: rgba(0,0,0,0.7); padding: 8px; opacity: 0; transition: 0.2s; }
.swatch:hover .swatch-info { opacity: 1; }
.swatch-hex { font-size: 12px; color: #fff; }
.controls, .scheme-row { display: flex; gap: 8px; margin-top: 20px; justify-content: center; flex-wrap: wrap; }
#color-lab-root button:not(#theme-toggle) { background: transparent; border: 1px solid var(–border); color: var(–muted); font-size: 11px; padding: 8px 15px; cursor: pointer; }
#color-lab-root button:hover, #color-lab-root button.active { border-color: var(–accent); color: var(–accent); }
.info-bar { margin-top: 20px; font-size: 11px; color: var(–muted); }
.copied-badge { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #fff; color: #000; padding: 4px 8px; font-size: 10px; opacity: 0; pointer-events: none; }
.swatch.copied .copied-badge { opacity: 1; }
(function() {
const N = 9; let scheme = ‘random’; let locked = Array(N).fill(false); let colors = Array(N).fill(‘#000000’);
const root = document.getElementById(‘color-lab-root’);
function hslToHex(h, s, l) { l /= 100; const a = s * Math.min(l, 1 – l) / 100; const f = n => { const k = (n + h / 30) % 12; const color = l – a * Math.max(Math.min(k – 3, 9 – k, 1), -1); return Math.round(255 * color).toString(16).padStart(2, ‘0’); }; return `#${f(0)}${f(8)}${f(4)}`; }
function getClr() {
if(scheme===’pastel’) return hslToHex(Math.random()*360, 50, 80);
if(scheme===’vivid’) return hslToHex(Math.random()*360, 90, 50);
if(scheme===’earth’) return hslToHex(10+Math.random()*40, 30, 40);
if(scheme===’dark’) return hslToHex(Math.random()*360, 40, 20);
return ‘#’+Math.floor(Math.random()*16777215).toString(16).padStart(6,’0’);
}
function gen() {
const sws = root.querySelectorAll(‘.swatch’);
sws.forEach((sw, i) => { if (!locked[i]) { colors[i] = getClr(); sw.querySelector(‘.swatch-color’).style.backgroundColor = colors[i]; sw.querySelector(‘.swatch-hex’).textContent = colors[i].toUpperCase(); } });
}
function init() {
const g = root.querySelector(‘#grid’); g.innerHTML = “;
for (let i=0; i<N; i++) {
const sw = document.createElement('div'); sw.className = 'swatch';
sw.innerHTML = `
COPIED
`;
sw.onclick = () => { navigator.clipboard.writeText(colors[i].toUpperCase()); sw.classList.add(‘copied’); setTimeout(()=>sw.classList.remove(‘copied’), 800); };
sw.ondblclick = (e) => { e.preventDefault(); locked[i]=!locked[i]; sw.classList.toggle(‘locked’, locked[i]); };
g.appendChild(sw);
}
gen();
}
root.querySelector(‘#btn-all’).onclick = gen;
root.querySelector(‘#btn-lock’).onclick = () => { const al=locked.every(l=>l); locked=locked.map(()=>!al); root.querySelectorAll(‘.swatch’).forEach((sw,i)=>sw.classList.toggle(‘locked’,locked[i])); };
root.querySelectorAll(‘.scheme-btn’).forEach(b => { b.onclick = () => { root.querySelectorAll(‘.scheme-btn’).forEach(x=>x.classList.remove(‘active’)); b.classList.add(‘active’); scheme=b.dataset.scheme; gen(); }; });
root.querySelector(‘#theme-toggle’).onclick = () => { const isL = root.classList.toggle(‘light-mode’); root.querySelector(‘#theme-toggle’).innerHTML = isL ? ‘切換模式 ☀️’ : ‘切換模式 🌙’; };
window.addEventListener(‘keydown’, (e) => { if (e.code === ‘Space’) { e.preventDefault(); gen(); } });
init();
})();