243 lines
7.5 KiB
JavaScript
243 lines
7.5 KiB
JavaScript
import { hslToHex } from './converter.js';
|
|
|
|
const STORAGE_KEY = 'farbhelfer';
|
|
const HISTORY_MAX = 20;
|
|
|
|
function load() {
|
|
try {
|
|
return JSON.parse(localStorage.getItem(STORAGE_KEY)) || { favoriten: [], history: [], schemata: [] };
|
|
} catch {
|
|
return { favoriten: [], history: [], schemata: [] };
|
|
}
|
|
}
|
|
|
|
function save(data) {
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
}
|
|
|
|
export function addFavorit(hsl) {
|
|
const data = load();
|
|
const hex = hslToHex(hsl);
|
|
if (!data.favoriten.some(f => hslToHex(f) === hex)) {
|
|
data.favoriten.push(hsl);
|
|
save(data);
|
|
renderSammlung();
|
|
}
|
|
}
|
|
|
|
export function removeFavorit(hex) {
|
|
const data = load();
|
|
data.favoriten = data.favoriten.filter(f => hslToHex(f) !== hex);
|
|
save(data);
|
|
renderSammlung();
|
|
}
|
|
|
|
export function addToHistory(hsl) {
|
|
const data = load();
|
|
const hex = hslToHex(hsl);
|
|
data.history = data.history.filter(h => hslToHex(h) !== hex);
|
|
data.history.unshift(hsl);
|
|
if (data.history.length > HISTORY_MAX) data.history = data.history.slice(0, HISTORY_MAX);
|
|
save(data);
|
|
}
|
|
|
|
export function addColorToSchema(hsl) {
|
|
const name = prompt('Schema-Name (leer = letztes Schema):');
|
|
if (name === null) return; // user pressed Cancel — do nothing
|
|
const data = load();
|
|
if (name) {
|
|
const existing = data.schemata.find(s => s.name === name);
|
|
if (existing) {
|
|
if (existing.farben.length < 4) {
|
|
existing.farben.push(hsl);
|
|
save(data);
|
|
renderSammlung();
|
|
} else {
|
|
alert('Schema hat bereits 4 Farben.');
|
|
}
|
|
} else {
|
|
data.schemata.push({ name, farben: [hsl] });
|
|
save(data);
|
|
renderSammlung();
|
|
}
|
|
} else if (data.schemata.length > 0) {
|
|
const last = data.schemata[data.schemata.length - 1];
|
|
if (last.farben.length < 4) {
|
|
last.farben.push(hsl);
|
|
save(data);
|
|
renderSammlung();
|
|
} else {
|
|
alert('Letztes Schema hat bereits 4 Farben.');
|
|
}
|
|
} else {
|
|
alert('Kein Schema vorhanden. Bitte Name eingeben.');
|
|
}
|
|
}
|
|
|
|
export function deleteSchema(name) {
|
|
const data = load();
|
|
data.schemata = data.schemata.filter(s => s.name !== name);
|
|
save(data);
|
|
renderSammlung();
|
|
}
|
|
|
|
export function exportCollection() {
|
|
const data = load();
|
|
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = 'farbhelfer-sammlung.json';
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
export function importCollection() {
|
|
const input = document.createElement('input');
|
|
input.type = 'file';
|
|
input.accept = '.json';
|
|
input.onchange = (e) => {
|
|
const file = e.target.files[0];
|
|
if (!file) return;
|
|
const reader = new FileReader();
|
|
reader.onload = (ev) => {
|
|
try {
|
|
const imported = JSON.parse(ev.target.result);
|
|
const data = load();
|
|
const existingFavHexes = new Set(data.favoriten.map(hslToHex));
|
|
(imported.favoriten || []).forEach(hsl => {
|
|
if (!existingFavHexes.has(hslToHex(hsl))) data.favoriten.push(hsl);
|
|
});
|
|
const existingSchemaNames = new Set(data.schemata.map(s => s.name));
|
|
(imported.schemata || []).forEach(s => {
|
|
if (!existingSchemaNames.has(s.name)) data.schemata.push(s);
|
|
});
|
|
const existingHistHexes = new Set(data.history.map(hslToHex));
|
|
(imported.history || []).forEach(hsl => {
|
|
if (!existingHistHexes.has(hslToHex(hsl))) data.history.push(hsl);
|
|
});
|
|
if (data.history.length > 20) data.history = data.history.slice(0, 20);
|
|
save(data);
|
|
renderSammlung();
|
|
alert('Import erfolgreich.');
|
|
} catch {
|
|
alert('Ungültige Datei.');
|
|
}
|
|
};
|
|
reader.readAsText(file);
|
|
};
|
|
input.click();
|
|
}
|
|
|
|
function makeSwatch(hsl) {
|
|
const hex = hslToHex(hsl);
|
|
|
|
const wrapper = document.createElement('div');
|
|
wrapper.style.cssText = 'display:inline-flex;flex-direction:column;align-items:center;gap:0.25rem';
|
|
|
|
const swatch = document.createElement('div');
|
|
swatch.className = 'swatch';
|
|
swatch.style.background = hex;
|
|
swatch.title = hex;
|
|
|
|
const label = document.createElement('span');
|
|
label.style.cssText = 'font-size:0.75rem;font-family:monospace';
|
|
label.textContent = hex;
|
|
|
|
wrapper.appendChild(swatch);
|
|
wrapper.appendChild(label);
|
|
return wrapper;
|
|
}
|
|
|
|
export function renderSammlung() {
|
|
const data = load();
|
|
|
|
// Favoriten
|
|
const favContainer = document.getElementById('sammlung-favoriten');
|
|
if (favContainer) {
|
|
favContainer.textContent = '';
|
|
if (data.favoriten.length === 0) {
|
|
const msg = document.createElement('p');
|
|
msg.style.cssText = 'color:#999;font-size:0.85rem';
|
|
msg.textContent = 'Noch keine Favoriten.';
|
|
favContainer.appendChild(msg);
|
|
} else {
|
|
data.favoriten.forEach(hsl => {
|
|
const hex = hslToHex(hsl);
|
|
const cell = document.createElement('div');
|
|
cell.style.cssText = 'display:inline-flex;flex-direction:column;align-items:center;gap:0.25rem;margin:0.25rem';
|
|
cell.appendChild(makeSwatch(hsl));
|
|
|
|
const del = document.createElement('button');
|
|
del.className = 'action-btn';
|
|
del.textContent = 'Löschen';
|
|
del.style.fontSize = '0.7rem';
|
|
del.addEventListener('click', () => removeFavorit(hex));
|
|
cell.appendChild(del);
|
|
favContainer.appendChild(cell);
|
|
});
|
|
}
|
|
}
|
|
|
|
// Historie
|
|
const histContainer = document.getElementById('sammlung-history');
|
|
if (histContainer) {
|
|
histContainer.textContent = '';
|
|
if (data.history.length === 0) {
|
|
const msg = document.createElement('p');
|
|
msg.style.cssText = 'color:#999;font-size:0.85rem';
|
|
msg.textContent = 'Noch kein Verlauf.';
|
|
histContainer.appendChild(msg);
|
|
} else {
|
|
data.history.forEach(hsl => {
|
|
const cell = document.createElement('div');
|
|
cell.style.cssText = 'display:inline-block;margin:0.25rem';
|
|
cell.appendChild(makeSwatch(hsl));
|
|
histContainer.appendChild(cell);
|
|
});
|
|
}
|
|
}
|
|
|
|
// Schemata
|
|
const schemataContainer = document.getElementById('sammlung-schemata');
|
|
if (schemataContainer) {
|
|
schemataContainer.textContent = '';
|
|
if (data.schemata.length === 0) {
|
|
const msg = document.createElement('p');
|
|
msg.style.cssText = 'color:#999;font-size:0.85rem';
|
|
msg.textContent = 'Noch keine Schemata.';
|
|
schemataContainer.appendChild(msg);
|
|
} else {
|
|
data.schemata.forEach(schema => {
|
|
const card = document.createElement('div');
|
|
card.style.cssText = 'border:1px solid #ddd;border-radius:8px;padding:1rem;margin-bottom:0.75rem;background:#fff';
|
|
|
|
const header = document.createElement('div');
|
|
header.style.cssText = 'display:flex;justify-content:space-between;align-items:center;margin-bottom:0.5rem';
|
|
|
|
const nameEl = document.createElement('strong');
|
|
nameEl.textContent = schema.name;
|
|
|
|
const delBtn = document.createElement('button');
|
|
delBtn.className = 'action-btn';
|
|
delBtn.textContent = 'Schema löschen';
|
|
delBtn.style.fontSize = '0.75rem';
|
|
delBtn.addEventListener('click', () => deleteSchema(schema.name));
|
|
|
|
header.appendChild(nameEl);
|
|
header.appendChild(delBtn);
|
|
|
|
const swatchesDiv = document.createElement('div');
|
|
swatchesDiv.style.cssText = 'display:flex;gap:0.5rem;flex-wrap:wrap';
|
|
schema.farben.forEach(hsl => swatchesDiv.appendChild(makeSwatch(hsl)));
|
|
|
|
card.appendChild(header);
|
|
card.appendChild(swatchesDiv);
|
|
schemataContainer.appendChild(card);
|
|
});
|
|
}
|
|
}
|
|
}
|