feat: Picker-Tab mit Upload, Paste und Eyedropper
This commit is contained in:
29
index.html
29
index.html
@@ -19,7 +19,34 @@
|
||||
|
||||
<main>
|
||||
<section id="tab-picker" class="tab-content active">
|
||||
<p>Picker kommt hier</p>
|
||||
<h2>Farbe aus Bild</h2>
|
||||
<div id="picker-dropzone">
|
||||
<p>Bild hierher ziehen, einfügen (Strg+V) oder</p>
|
||||
<button class="action-btn" id="picker-file-trigger">Datei wählen</button>
|
||||
<input type="file" id="picker-file-input" accept="image/*" style="display:none">
|
||||
</div>
|
||||
<canvas id="picker-canvas" style="display:none;max-width:100%;cursor:crosshair;border-radius:8px;border:1px solid #ddd"></canvas>
|
||||
<div id="picker-result" style="display:none;margin-top:1rem">
|
||||
<div id="picker-preview" class="color-preview"></div>
|
||||
<div class="color-codes">
|
||||
<div class="color-code-group">
|
||||
<label for="picker-hex">Hex</label>
|
||||
<input id="picker-hex" type="text" readonly>
|
||||
</div>
|
||||
<div class="color-code-group">
|
||||
<label for="picker-rgb">RGB</label>
|
||||
<input id="picker-rgb" type="text" readonly>
|
||||
</div>
|
||||
<div class="color-code-group">
|
||||
<label for="picker-hsl">HSL</label>
|
||||
<input id="picker-hsl" type="text" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:0.5rem">
|
||||
<button class="action-btn" id="picker-fav-btn">Zu Favoriten</button>
|
||||
<button class="action-btn" id="picker-schema-btn">Zu Schema hinzufügen</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="tab-eingabe" class="tab-content">
|
||||
<h2>Farbe eingeben</h2>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { initEingabe } from './eingabe.js';
|
||||
import { initPicker } from './picker.js';
|
||||
|
||||
// Globaler State — aktive Farbe als { h, s, l } (HSL, 0-360, 0-100, 0-100)
|
||||
// state.color is read-only from outside — always use setColor() to update,
|
||||
@@ -28,3 +29,4 @@ function addFavorit(hsl) { console.log('addFavorit', hsl); }
|
||||
function addColorToSchema(hsl) { console.log('addColorToSchema', hsl); }
|
||||
|
||||
initEingabe(addFavorit, addColorToSchema);
|
||||
initPicker(addFavorit, addColorToSchema);
|
||||
|
||||
83
js/picker.js
Normal file
83
js/picker.js
Normal file
@@ -0,0 +1,83 @@
|
||||
import { rgbToHex, rgbToHsl } from './converter.js';
|
||||
import { state } from './app.js';
|
||||
|
||||
function rgbToDisplay({ r, g, b }) { return r + ', ' + g + ', ' + b; }
|
||||
function hslToDisplay({ h, s, l }) { return h + ', ' + s + '%, ' + l + '%'; }
|
||||
|
||||
function showColor(r, g, b) {
|
||||
const hex = rgbToHex({ r, g, b });
|
||||
const hsl = rgbToHsl({ r, g, b });
|
||||
state.setColor(hsl);
|
||||
document.getElementById('picker-preview').style.background = hex;
|
||||
document.getElementById('picker-hex').value = hex;
|
||||
document.getElementById('picker-rgb').value = rgbToDisplay({ r, g, b });
|
||||
document.getElementById('picker-hsl').value = hslToDisplay(hsl);
|
||||
document.getElementById('picker-result').style.display = 'block';
|
||||
}
|
||||
|
||||
function loadImage(file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
const canvas = document.getElementById('picker-canvas');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0);
|
||||
canvas.style.display = 'block';
|
||||
|
||||
// Mittlerer Pixel als Vorschlag
|
||||
const mx = Math.floor(img.width / 2);
|
||||
const my = Math.floor(img.height / 2);
|
||||
const px = ctx.getImageData(mx, my, 1, 1).data;
|
||||
showColor(px[0], px[1], px[2]);
|
||||
|
||||
// Eyedropper: Klick wählt Pixel frei
|
||||
canvas.onclick = (ev) => {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const scaleX = canvas.width / rect.width;
|
||||
const scaleY = canvas.height / rect.height;
|
||||
const x = Math.floor((ev.clientX - rect.left) * scaleX);
|
||||
const y = Math.floor((ev.clientY - rect.top) * scaleY);
|
||||
const d = ctx.getImageData(x, y, 1, 1).data;
|
||||
showColor(d[0], d[1], d[2]);
|
||||
};
|
||||
};
|
||||
img.src = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
export function initPicker(onSaveFavorit, onSaveSchema) {
|
||||
const dropzone = document.getElementById('picker-dropzone');
|
||||
|
||||
document.getElementById('picker-file-trigger').addEventListener('click', () => {
|
||||
document.getElementById('picker-file-input').click();
|
||||
});
|
||||
|
||||
document.getElementById('picker-file-input').addEventListener('change', (e) => {
|
||||
if (e.target.files[0]) loadImage(e.target.files[0]);
|
||||
});
|
||||
|
||||
dropzone.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
dropzone.classList.add('drag-over');
|
||||
});
|
||||
dropzone.addEventListener('dragleave', () => dropzone.classList.remove('drag-over'));
|
||||
dropzone.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
dropzone.classList.remove('drag-over');
|
||||
const file = e.dataTransfer.files[0];
|
||||
if (file && file.type.startsWith('image/')) loadImage(file);
|
||||
});
|
||||
|
||||
// Paste (Strg+V / Cmd+V)
|
||||
document.addEventListener('paste', (e) => {
|
||||
const item = Array.from(e.clipboardData.items).find(i => i.type.startsWith('image/'));
|
||||
if (item) loadImage(item.getAsFile());
|
||||
});
|
||||
|
||||
document.getElementById('picker-fav-btn').addEventListener('click', () => onSaveFavorit(state.color));
|
||||
document.getElementById('picker-schema-btn').addEventListener('click', () => onSaveSchema(state.color));
|
||||
}
|
||||
16
style.css
16
style.css
@@ -87,3 +87,19 @@ button.action-btn:hover { background: #f0f0f0; }
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#picker-dropzone {
|
||||
border: 2px dashed #ccc;
|
||||
border-radius: 8px;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
margin-bottom: 1rem;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
#picker-dropzone.drag-over {
|
||||
border-color: #222;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
#picker-dropzone p { margin-bottom: 0.75rem; color: #666; font-size: 0.9rem; }
|
||||
|
||||
Reference in New Issue
Block a user