Compare commits

...

10 Commits

Author SHA1 Message Date
Ferdinand
a58058b96c feat: Klick auf Farbswatch übernimmt Farbe als Ausgangsfarbe
- Sammlung (Verlauf/Favoriten/Schemata): Klick → Farbe setzen → Harmonien-Tab
- Harmonien: Klick auf Swatch → als neue Ausgangsfarbe, bleibt auf Harmonien
- switchTab() Hilfsfunktion in app.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:52:59 +02:00
Ferdinand
1753af0bfc feat: Klick auf Logo/Titel lädt Seite neu (Home-Reset)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:46:54 +02:00
Ferdinand
d1c61cb803 fix: Logo-Einfärbung via CSS filter statt mix-blend-mode overlay
filter(grayscale+sepia+hue-rotate+saturate+brightness) töntet nur
die gerenderten SVG-Pixel, transparente Bereiche bleiben unberührt.
0.8s transition auf filter-Property.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:44:36 +02:00
Ferdinand
f06a6c6212 feat: Logo-Animation komplett einfärben via mix-blend-mode color
CSS-Overlay mit mix-blend-mode:color übernimmt Farbton der identifizierten
Farbe für die gesamte Animation. 0.8s Transition. Alle bisherige
SVG-Manipulation entfernt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:42:33 +02:00
Ferdinand
709d82bc8b fix: Logo-Farbe auch auf Gradient-Stops (mittlerer Ball) anwenden
Neben solid fills auch SVG stop-Elemente mit stop-color='rgb(255,223,0)'
markieren und per CSS stop-color überschreiben.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:39:13 +02:00
Ferdinand
446870a94c fix: Logo-Farbe via CSS-Override statt animationData-Reload
lottie cached Daten intern - Mutation+Reload funktioniert nicht.
Neuer Ansatz: gelbe fill-Elemente einmalig mit Klasse markieren,
CSS fill-Property (schlägt SVG-Attribute per Spec) per style-Element
aktualisieren. Kein Reload, kein Flicker.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:29:52 +02:00
Ferdinand
2a8b1157ab feat: Logo-Animation übernimmt exakte identifizierte Farbe
JSON wird per fetch geladen, Fill-Objekte von 'Small 4' (Gelb) werden
direkt mutiert und Animation ab aktuellem Frame neu geladen.
Kein hue-rotate mehr – eine Farbe ist exakt die gewählte Farbe.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:22:16 +02:00
Ferdinand
64614d49e7 feat: Logo-Animation synchronisiert Farben mit aktueller Farbe
hue-rotate verschiebt die Palette (Gelb/Pink/Lila) synchron zum
Farbton der identifizierten Farbe. Sanfter 0.8s Übergang.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:14:26 +02:00
Ferdinand
a7d51b9e17 feat: Hintergrund wechselt dynamisch zur Pastelversion der aktuellen Farbe
Bei jeder Farbidentifikation wird der Hue übernommen, Sättigung gedämpft
(max 45%) und Helligkeit auf 92% gesetzt. Sanfter 0.8s CSS-Übergang.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:09:58 +02:00
Ferdinand
796a568ab3 copy: Seitenüberschriften durch UX-orientierte Sätze ersetzt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:06:36 +02:00
5 changed files with 83 additions and 24 deletions

View File

@@ -9,10 +9,10 @@
<body>
<div id="lottie-bg"></div>
<header>
<div style="display:flex;align-items:center;gap:0.6rem;margin-bottom:1.25rem">
<a href="" style="display:flex;align-items:center;gap:0.6rem;margin-bottom:1.25rem;text-decoration:none;color:inherit;cursor:pointer">
<div id="lottie-logo" style="width:80px;height:80px;flex-shrink:0"></div>
<h1 style="margin-bottom:0">Pigmento</h1>
</div>
</a>
<nav id="main-nav">
<button id="menu-toggle" aria-label="Navigation öffnen">
<span></span><span></span><span></span>
@@ -29,7 +29,7 @@
<main>
<section id="tab-picker" class="tab-content active">
<h2>Farbe aus Bild</h2>
<h2>Welche Farbe ist das? Bild hochladen und draufklicken.</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>
@@ -59,7 +59,7 @@
</div>
</section>
<section id="tab-eingabe" class="tab-content">
<h2>Farbe eingeben</h2>
<h2>Farbcode eingeben und alle Formate auf einmal sehen.</h2>
<div id="eingabe-preview" class="color-preview" style="background:#3a8fc1"></div>
<div class="color-codes">
<div class="color-code-group">
@@ -81,13 +81,13 @@
</div>
</section>
<section id="tab-harmonien" class="tab-content">
<h2>Farbharmonien</h2>
<h2>Welche Farben passen dazu? Harmonien auf einen Blick.</h2>
<p class="subtitle">Ausgangsfarbe: <span id="harmonien-base-hex">#3a8fc1</span></p>
<div id="harmonien-base-preview" class="color-preview" style="height:50px"></div>
<div id="harmonien-grid" style="display:flex;flex-direction:column;gap:1.5rem;margin-top:1rem"></div>
</section>
<section id="tab-sammlung" class="tab-content">
<h2>Sammlung</h2>
<h2>Deine gespeicherten Farben, Verläufe und Schemata.</h2>
<div class="btn-row" style="margin-bottom:1.5rem">
<button class="action-btn" id="sammlung-export-btn">Exportieren</button>
@@ -178,13 +178,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js"></script>
<script type="module" src="js/app.js"></script>
<script>
lottie.loadAnimation({
container: document.getElementById('lottie-logo'),
renderer: 'svg',
loop: true,
autoplay: true,
path: 'Fluid Loading Animation.json'
});
// Hintergrund-Animation
lottie.loadAnimation({
container: document.getElementById('lottie-bg'),
renderer: 'svg',
@@ -192,6 +186,36 @@
autoplay: true,
path: 'Background Grey Wave.json'
});
// Logo-Animation
lottie.loadAnimation({
container: document.getElementById('lottie-logo'),
renderer: 'svg',
loop: true,
autoplay: true,
path: 'Fluid Loading Animation.json'
});
function _hslToHex(h, s, l) {
s /= 100; l /= 100;
const a = s * Math.min(l, 1 - l);
const f = n => {
const k = (n + h / 30) % 12;
return Math.round(255 * (l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1)))
.toString(16).padStart(2, '0');
};
return '#' + f(0) + f(8) + f(4);
}
document.addEventListener('colorChanged', (e) => {
const { h, s, l } = e.detail;
// grayscale → sepia (Basis ~38°) → Zielfarbe drehen → Sättigung + Helligkeit
const rot = h - 38;
const sat = s < 5 ? 0 : 3;
const bri = Math.max(0.5, l / 50);
document.getElementById('lottie-logo').style.filter =
`grayscale(1) sepia(1) hue-rotate(${rot}deg) saturate(${sat}) brightness(${bri})`;
});
</script>
</body>
</html>

View File

@@ -1,7 +1,7 @@
import { initEingabe } from './eingabe.js';
import { initPicker } from './picker.js';
import { initHarmonien } from './harmonien.js';
import { addFavorit, addColorToSchema, addToHistory, renderSammlung, exportCollection, importCollection, saveSchema, setEditSchemaHandler } from './collection.js';
import { addFavorit, addColorToSchema, addToHistory, renderSammlung, exportCollection, importCollection, saveSchema, setEditSchemaHandler, setSwatchClickHandler } from './collection.js';
import { initSchemaModal, openForEdit } from './schema-modal.js';
// state.color is read-only from outside — always use setColor() to update,
@@ -15,6 +15,16 @@ export const state = {
}
};
function switchTab(name) {
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(s => s.classList.remove('active'));
const btn = document.querySelector(`.tab-btn[data-tab="${name}"]`);
if (btn) { btn.classList.add('active'); document.getElementById('menu-active-label').textContent = btn.textContent; }
const section = document.getElementById('tab-' + name);
if (section) section.classList.add('active');
document.getElementById('menu-dropdown').classList.remove('open');
}
// Hamburger-Menü
const menuToggle = document.getElementById('menu-toggle');
const menuDropdown = document.getElementById('menu-dropdown');
@@ -44,9 +54,16 @@ document.querySelectorAll('.tab-btn').forEach(btn => {
// Every color change goes into history
document.addEventListener('colorChanged', (e) => addToHistory(e.detail));
// Hintergrundfarbe als extrem helles Pastell + Logo-Animation synchron einfärben
document.addEventListener('colorChanged', (e) => {
const { h, s } = e.detail;
const pastelS = Math.round(Math.min(s * 0.5, 45));
document.body.style.background = `hsl(${h}, ${pastelS}%, 92%)`;
});
initEingabe(addFavorit, addColorToSchema);
initPicker(addFavorit, addColorToSchema);
initHarmonien(addFavorit, addColorToSchema);
initHarmonien(addFavorit, addColorToSchema, (hsl) => state.setColor(hsl));
document.getElementById('sammlung-export-btn').addEventListener('click', exportCollection);
document.getElementById('sammlung-import-btn').addEventListener('click', importCollection);
@@ -54,3 +71,4 @@ document.getElementById('sammlung-import-btn').addEventListener('click', importC
renderSammlung();
initSchemaModal(saveSchema);
setEditSchemaHandler(openForEdit);
setSwatchClickHandler((hsl) => { state.setColor(hsl); switchTab('harmonien'); });

View File

@@ -4,6 +4,9 @@ const STORAGE_KEY = 'pigmento';
let editSchemaHandler = null;
export function setEditSchemaHandler(fn) { editSchemaHandler = fn; }
let swatchClickHandler = null;
export function setSwatchClickHandler(fn) { swatchClickHandler = fn; }
const HISTORY_MAX = 20;
function load() {
@@ -325,6 +328,11 @@ function makeSwatch(hsl) {
swatch.style.background = hex;
swatch.title = hex;
if (swatchClickHandler) {
swatch.style.cursor = 'pointer';
swatch.addEventListener('click', () => swatchClickHandler(hsl));
}
const label = document.createElement('span');
label.style.cssText = 'font-size:0.75rem;font-family:Poppins,sans-serif';
label.textContent = hex;

View File

@@ -8,7 +8,7 @@ const DESCRIPTIONS = {
'Split-Komplementär': 'Die zwei Farben neben der Komplementärfarbe (150°/210°). Weniger Spannung als Komplementär, mehr Vielfalt.',
};
function renderHarmony(label, colors, onSaveFavorit, onSaveSchema) {
function renderHarmony(label, colors, onSaveFavorit, onSaveSchema, onSetColor) {
const row = document.createElement('div');
row.className = 'harmony-row';
@@ -48,6 +48,10 @@ function renderHarmony(label, colors, onSaveFavorit, onSaveSchema) {
swatch.className = 'swatch';
swatch.style.background = hex;
swatch.title = hex;
if (onSetColor) {
swatch.style.cursor = 'pointer';
swatch.addEventListener('click', () => onSetColor(hsl));
}
const hexLabel = document.createElement('span');
hexLabel.textContent = hex;
@@ -80,7 +84,7 @@ function renderHarmony(label, colors, onSaveFavorit, onSaveSchema) {
return row;
}
function render(onSaveFavorit, onSaveSchema) {
function render(onSaveFavorit, onSaveSchema, onSetColor) {
const hsl = state.color;
const hex = hslToHex(hsl);
@@ -91,13 +95,13 @@ function render(onSaveFavorit, onSaveSchema) {
grid.textContent = '';
const h = getHarmonies(hsl);
grid.appendChild(renderHarmony('Komplementär', h.komplementaer, onSaveFavorit, onSaveSchema));
grid.appendChild(renderHarmony('Analog', h.analog, onSaveFavorit, onSaveSchema));
grid.appendChild(renderHarmony('Triade', h.triade, onSaveFavorit, onSaveSchema));
grid.appendChild(renderHarmony('Split-Komplementär', h.splitKomplementaer, onSaveFavorit, onSaveSchema));
grid.appendChild(renderHarmony('Komplementär', h.komplementaer, onSaveFavorit, onSaveSchema, onSetColor));
grid.appendChild(renderHarmony('Analog', h.analog, onSaveFavorit, onSaveSchema, onSetColor));
grid.appendChild(renderHarmony('Triade', h.triade, onSaveFavorit, onSaveSchema, onSetColor));
grid.appendChild(renderHarmony('Split-Komplementär', h.splitKomplementaer, onSaveFavorit, onSaveSchema, onSetColor));
}
export function initHarmonien(onSaveFavorit, onSaveSchema) {
document.addEventListener('colorChanged', () => render(onSaveFavorit, onSaveSchema));
render(onSaveFavorit, onSaveSchema);
export function initHarmonien(onSaveFavorit, onSaveSchema, onSetColor) {
document.addEventListener('colorChanged', () => render(onSaveFavorit, onSaveSchema, onSetColor));
render(onSaveFavorit, onSaveSchema, onSetColor);
}

View File

@@ -7,6 +7,11 @@ body {
background: #DFE9F5;
color: #222;
min-height: 100vh;
transition: background 0.8s ease;
}
#lottie-logo {
transition: filter 0.8s ease;
}
#lottie-bg {