From 2d1d571b17a0d6f4f2a3433ade86116e46889561 Mon Sep 17 00:00:00 2001 From: Guido Date: Sat, 24 Oct 2026 17:51:49 +0200 Subject: [PATCH] feat: Gruen ist die Vorgabe fuer Kategorien und Schlagwoerter Die Farbauswahl der App lag dreimal gleich im Code; sie steht jetzt einmal in Farbwahl, mit dem Markengruen an erster Stelle. Co-Authored-By: Claude Opus 5 --- backend/app/models.py | 6 +++--- backend/app/schemas.py | 6 +++--- ios/Bausteine/Darstellung.swift | 10 ++++++++++ ios/Bausteine/Formular.swift | 7 +------ ios/Nebenraeume/KategorieFormular.swift | 4 ++-- ios/Nebenraeume/TagsAnsicht.swift | 14 +++----------- web/src/pages/Categories.jsx | 2 +- web/src/pages/Tags.jsx | 2 +- 8 files changed, 24 insertions(+), 27 deletions(-) diff --git a/backend/app/models.py b/backend/app/models.py index f0aed89..c11edbf 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -409,7 +409,7 @@ class CategoryGroup(Base): name: Mapped[str] = mapped_column(String(120), nullable=False) kind: Mapped[CategoryKind] = mapped_column(_enum(CategoryKind), nullable=False, default=CategoryKind.expense) icon: Mapped[str] = mapped_column(String(40), nullable=False, default="list") - color: Mapped[str] = mapped_column(String(9), nullable=False, default="#6b7480") + color: Mapped[str] = mapped_column(String(9), nullable=False, default="#3f9c72") position: Mapped[int] = mapped_column(Integer, nullable=False, default=0) is_builtin: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) @@ -431,7 +431,7 @@ class Category(Base): name: Mapped[str] = mapped_column(String(120), nullable=False) type: Mapped[CategoryKind] = mapped_column(_enum(CategoryKind), nullable=False, default=CategoryKind.expense) icon: Mapped[str] = mapped_column(String(40), nullable=False, default="more-horizontal") - color: Mapped[str] = mapped_column(String(9), nullable=False, default="#6b7480") + color: Mapped[str] = mapped_column(String(9), nullable=False, default="#3f9c72") position: Mapped[int] = mapped_column(Integer, nullable=False, default=0) is_builtin: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) is_archived: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) @@ -1312,7 +1312,7 @@ class Tag(Base): ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True ) name: Mapped[str] = mapped_column(String(60), nullable=False) - color: Mapped[str] = mapped_column(String(9), nullable=False, default="#6b7480") + color: Mapped[str] = mapped_column(String(9), nullable=False, default="#3f9c72") created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=_now) __table_args__ = ( diff --git a/backend/app/schemas.py b/backend/app/schemas.py index f0b51a3..cb8ebe5 100644 --- a/backend/app/schemas.py +++ b/backend/app/schemas.py @@ -361,7 +361,7 @@ class TagOut(BaseModel): class TagCreate(BaseModel): name: str = Field(min_length=1, max_length=60) # Ohne Angabe dasselbe Grau wie bei einer neuen Kategorie. - color: str = "#6b7480" + color: str = "#3f9c72" class TagUpdate(BaseModel): @@ -406,7 +406,7 @@ class CategoryGroupCreate(BaseModel): name: str = Field(min_length=1, max_length=120) kind: CategoryKind = CategoryKind.expense icon: str = "list" - color: str = "#6b7480" + color: str = "#3f9c72" class CategoryGroupUpdate(BaseModel): @@ -420,7 +420,7 @@ class CategoryCreate(BaseModel): group_id: int name: str = Field(min_length=1, max_length=120) icon: str = "more-horizontal" - color: str = "#6b7480" + color: str = "#3f9c72" excluded_from_stats: bool = False spending_is_good: bool = False diff --git a/ios/Bausteine/Darstellung.swift b/ios/Bausteine/Darstellung.swift index b0f7ec2..130962d 100644 --- a/ios/Bausteine/Darstellung.swift +++ b/ios/Bausteine/Darstellung.swift @@ -34,6 +34,16 @@ extension Color { }) } +/// Die Farbauswahl für Kategorien, Schlagwörter und Konten – eine Liste für +/// alle drei Formulare, damit sie nicht auseinanderlaufen. Das Markengrün +/// steht vorn und ist die Vorbelegung; der Rest bleibt bunt, sonst liessen +/// sich die Kategorien in Diagrammen nicht auseinanderhalten. +enum Farbwahl { + static let standard = "#3f9c72" + static let palette = [standard, "#3f51b5", "#b3541e", "#8e24aa", + "#c62828", "#0277bd", "#6b7480", "#5d4037"] +} + /// Übersetzt die Symbolnamen aus der Datenbank in SF Symbols. /// /// Die Weboberfläche benutzt Lucide-Namen und hält dafür ein eigenes diff --git a/ios/Bausteine/Formular.swift b/ios/Bausteine/Formular.swift index edb5b59..3d9a338 100644 --- a/ios/Bausteine/Formular.swift +++ b/ios/Bausteine/Formular.swift @@ -183,11 +183,6 @@ struct SymbolUndFarbeFeld: View { "film", "music", "wifi", "phone", "gift", "briefcase", "refresh-ccw", ] - private static let farben = [ - "#3f51b5", "#2e7d55", "#b3541e", "#8e24aa", "#c62828", - "#0277bd", "#6b7480", "#5d4037", - ] - var body: some View { VStack(alignment: .leading, spacing: 12) { auswahl(Self.symbole, aktuell: symbol) { symbol = $0 } inhalt: { name in @@ -196,7 +191,7 @@ struct SymbolUndFarbeFeld: View { .foregroundStyle(Color(hex: farbe)) } - auswahl(Self.farben, aktuell: farbe) { farbe = $0 } inhalt: { wert in + auswahl(Farbwahl.palette, aktuell: farbe) { farbe = $0 } inhalt: { wert in Circle().fill(Color(hex: wert)).frame(width: 22, height: 22) } } diff --git a/ios/Nebenraeume/KategorieFormular.swift b/ios/Nebenraeume/KategorieFormular.swift index ff9636c..be2ba7a 100644 --- a/ios/Nebenraeume/KategorieFormular.swift +++ b/ios/Nebenraeume/KategorieFormular.swift @@ -25,7 +25,7 @@ struct KategorieFormular: View { @State private var name = "" @State private var symbol = "more-horizontal" - @State private var farbe = "#6b7480" + @State private var farbe = Farbwahl.standard @State private var gruppeId = 0 @State private var istSparen = false @State private var ohneAuswertung = false @@ -203,7 +203,7 @@ struct GruppenFormular: View { @State private var name = "" @State private var art: Kategorieart = .expense @State private var symbol = "list" - @State private var farbe = "#6b7480" + @State private var farbe = Farbwahl.standard @State private var fragtNachLoeschen = false @State private var vorbelegt = false diff --git a/ios/Nebenraeume/TagsAnsicht.swift b/ios/Nebenraeume/TagsAnsicht.swift index acc5b7d..1cacc2c 100644 --- a/ios/Nebenraeume/TagsAnsicht.swift +++ b/ios/Nebenraeume/TagsAnsicht.swift @@ -11,11 +11,6 @@ struct TagsAnsicht: View { @State private var bearbeitet: Schlagwort? @State private var neuerName = "" - /// Dieselbe Auswahl wie im Symbol- und Farbfeld, damit die Etiketten zu - /// den Kategorien passen. - private static let farben = ["#3f51b5", "#2e7d55", "#b3541e", "#8e24aa", - "#c62828", "#0277bd", "#6b7480", "#5d4037"] - var body: some View { List { Section { @@ -77,7 +72,7 @@ struct TagsAnsicht: View { let name = neuerName.trimmingCharacters(in: .whitespacesAndNewlines) guard !name.isEmpty else { return } // Reihum eine Farbe, damit nicht alle grau sind. Ändern geht danach. - let farbe = Self.farben[zustand.nachschlag.schlagwoerter.count % Self.farben.count] + let farbe = Farbwahl.palette[zustand.nachschlag.schlagwoerter.count % Farbwahl.palette.count] let geglueckt = await vorgang.fuehreAus { _ = try await client.legeTagAn(TagAnlegen(name: name, color: farbe)) } @@ -104,12 +99,9 @@ struct TagFormular: View { @Environment(\.dismiss) private var schliesse @State private var vorgang = Speichervorgang() @State private var name = "" - @State private var farbe = "#6b7480" + @State private var farbe = Farbwahl.standard @State private var vorbelegt = false - private static let farben = ["#3f51b5", "#2e7d55", "#b3541e", "#8e24aa", - "#c62828", "#0277bd", "#6b7480", "#5d4037"] - var body: some View { NavigationStack { Form { @@ -119,7 +111,7 @@ struct TagFormular: View { Section { ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 12) { - ForEach(Self.farben, id: \.self) { wert in + ForEach(Farbwahl.palette, id: \.self) { wert in Button { farbe = wert } label: { Circle() .fill(Color(hex: wert)) diff --git a/web/src/pages/Categories.jsx b/web/src/pages/Categories.jsx index db69897..20a7bdc 100644 --- a/web/src/pages/Categories.jsx +++ b/web/src/pages/Categories.jsx @@ -187,7 +187,7 @@ export default function Categories() { editing, form: editing ? { name: editing.name, kind: editing.kind, icon: editing.icon, color: editing.color } - : { name: "", kind: "expense", icon: "list", color: "#3f51b5" }, + : { name: "", kind: "expense", icon: "list", color: "#3f9c72" }, }); } function openCategory(groupId, editing = null) { diff --git a/web/src/pages/Tags.jsx b/web/src/pages/Tags.jsx index 362ec9a..a685305 100644 --- a/web/src/pages/Tags.jsx +++ b/web/src/pages/Tags.jsx @@ -17,7 +17,7 @@ import { useToast } from "../toast"; // // Gesetzt werden Tags nicht hier, sondern an der Buchung – in der Liste und im // Bearbeiten-Dialog. Hier geht es nur um den Vorrat. -const STANDARDFARBE = "#3f51b5"; +const STANDARDFARBE = "#3f9c72"; export default function Tags() { const { t } = useTranslation();