diff --git a/src/panels/AttributesPanel.tsx b/src/panels/AttributesPanel.tsx
index ff71513..97d9867 100644
--- a/src/panels/AttributesPanel.tsx
+++ b/src/panels/AttributesPanel.tsx
@@ -29,6 +29,7 @@ import { PEN_WEIGHTS } from "../model/types";
import type { AttributeSource } from "../model/types";
import { usePanelHost } from "./host";
import { Dropdown } from "../ui/Dropdown";
+import { ColorHexField } from "../ui/ColorHexField";
/** UI-Zustand des 3-Optionen-Quellen-Dropdowns (nicht 1:1 das Modell-Feld:
* „custom" ist abgeleitet aus „ist ein expliziter Wert gesetzt?", nicht
@@ -95,11 +96,7 @@ export function AttributesPanel() {
// nur, wenn die Quelle „custom" ist — sonst zeigt allein der Dropdown den
// Zustand.
const colorValue = (value: string | undefined, onSet: (color: string) => void) => (
-
+
);
// Eine Attribut-Zeile: Label + Quellen-Dropdown + (nur bei „eigener Wert")
@@ -170,18 +167,7 @@ export function AttributesPanel() {
{/* Farbe — gilt für Wand UND Drawing2D (Kontrakt setzt beide). */}
{t("attr.color")}
-
+
{/* Strichstärke (mm) — Wand/Decke/Drawing2D, mit Nach-Ebene/Nach-Bauteil/
diff --git a/src/styles.css b/src/styles.css
index 62891c1..bb10fbe 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -4018,6 +4018,14 @@ body {
display: inline-flex;
align-items: center;
gap: 6px;
+}
+/* Swatch + natives Farb-Input — EIGENER Klick-Bereich (öffnet die Palette).
+ Der Hex-Text daneben ist jetzt ein separates (ColorHexField),
+ damit er unabhängig editierbar ist statt nur die Palette zu öffnen. */
+.attr-color-swatch-wrap {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
cursor: pointer;
}
.attr-color-swatch {
@@ -4041,6 +4049,26 @@ body {
color: var(--muted);
font-size: 11px;
}
+/* Editierbarer Hex-Code: sieht wie reiner Text aus, bis man klickt/fokussiert
+ — dann Rahmen + helle Schrift als Editier-Signal. */
+.attr-color-hex-input {
+ width: 6.5ch;
+ border: 1px solid transparent;
+ background: transparent;
+ border-radius: 3px;
+ padding: 1px 3px;
+ font-family: var(--font-mono);
+ cursor: text;
+}
+.attr-color-hex-input:hover:not(:disabled) {
+ border-color: var(--border);
+}
+.attr-color-hex-input:focus {
+ outline: none;
+ border-color: var(--accent);
+ background: var(--input);
+ color: var(--ink);
+}
.attr-color input[type="color"]:disabled {
opacity: 0.4;
cursor: not-allowed;
diff --git a/src/ui/ColorHexField.tsx b/src/ui/ColorHexField.tsx
new file mode 100644
index 0000000..df90c6b
--- /dev/null
+++ b/src/ui/ColorHexField.tsx
@@ -0,0 +1,64 @@
+// Farbfeld: Swatch (öffnet die native Farbpalette) + separat editierbarer
+// Hex-Code (Tippen/Enter übernimmt, Esc verwirft). Ersetzt die frühere reine
+// Text-Anzeige des Hex-Werts, die nicht anklickbar/editierbar war.
+
+import { useEffect, useState } from "react";
+
+export function ColorHexField({
+ value,
+ onChange,
+ disabled,
+}: {
+ value: string;
+ onChange: (hex: string) => void;
+ disabled?: boolean;
+}) {
+ const [text, setText] = useState(value.toUpperCase());
+
+ // Extern geänderter Wert (z. B. Preset-Klick) synchron halten, solange das
+ // Feld nicht gerade selbst bearbeitet wird (kein Cursor-Sprung beim Tippen).
+ useEffect(() => setText(value.toUpperCase()), [value]);
+
+ const commit = (raw: string) => {
+ const trimmed = raw.trim();
+ const withHash = trimmed.startsWith("#") ? trimmed : `#${trimmed}`;
+ if (/^#[0-9a-fA-F]{6}$/.test(withHash)) {
+ onChange(withHash.toLowerCase());
+ setText(withHash.toUpperCase());
+ } else {
+ setText(value.toUpperCase()); // ungültig → letzten gültigen Wert zeigen
+ }
+ };
+
+ return (
+
+
+ setText(e.target.value)}
+ onBlur={(e) => commit(e.target.value)}
+ onKeyDown={(e) => {
+ if (e.key === "Enter") {
+ commit(e.currentTarget.value);
+ e.currentTarget.blur();
+ } else if (e.key === "Escape") {
+ setText(value.toUpperCase());
+ e.currentTarget.blur();
+ }
+ }}
+ />
+
+ );
+}
diff --git a/src/ui/SettingsDialog.tsx b/src/ui/SettingsDialog.tsx
index 121c1e0..d9ff785 100644
--- a/src/ui/SettingsDialog.tsx
+++ b/src/ui/SettingsDialog.tsx
@@ -13,6 +13,7 @@ import { useEffect, useState } from "react";
import { t } from "../i18n";
import { ACCENT_SWATCHES } from "../theme/accents";
import type { Project } from "../model/types";
+import { ColorHexField } from "./ColorHexField";
export interface SettingsDialogProps {
marqueeColor: string;
@@ -145,11 +146,7 @@ function AccentColorField({