feat: tag display with mandatory indicators and improve tag color structure

This commit is contained in:
Felix Zett 2025-09-16 21:54:01 +02:00
parent 71af5b911c
commit f20eef7556
4 changed files with 68 additions and 70 deletions

View file

@ -95,12 +95,11 @@ export default function ItemRow({
<span
key={tag.id}
className={
tag.mandatory
? "border-2 border-yellow-400 text-sm rounded px-1 py-0.5 flex items-center"
: `${getTagColor(tag.id)} text-sm rounded px-1 py-0.5 flex items-center`
`${getTagColor(tag.id).bg} text-sm rounded px-1 py-0.5 flex items-center font-medium`
}
>
#{tag.name}
{tag.mandatory && <span className="text-red-500 font-bold ml-0.5">!</span>}
{hover && (
<button
onClick={() => onDeleteTag(item.id, tag.id)}
@ -113,7 +112,7 @@ export default function ItemRow({
))}
{tripName && (
<span className="ml-2 px-2 py-0.5 rounded bg-yellow-100 text-yellow-800 text-xs font-semibold">
<span className="ml-2 px-2 py-0.5 rounded bg-gray-100 text-gray-800 text-sm font-semibold">
{tripName}
</span>
)}

View file

@ -180,15 +180,14 @@ export default function ItemsPage() {
<span
key={tag.id}
className={
tag.mandatory
? "border-2 border-yellow-400 text-sm rounded px-1 py-0.5 flex items-center cursor-pointer"
: `${getTagColor(tag.id)} text-sm rounded px-1 py-0.5 flex items-center cursor-pointer`
+ (newItemTags.includes(tag.id) ? " ring-2 ring-blue-400 font-bold" : "")
`${getTagColor(tag.id).bg} text-sm rounded px-1 py-0.5 flex items-center cursor-pointer font-medium` +
(newItemTags.includes(tag.id) ? " ring-2 ring-blue-400 font-bold" : "")
}
onClick={() => toggleNewItemTag(tag.id)}
title={tag.mandatory ? "Pflicht-Tag (mandatory)" : ""}
>
#{tag.name}
{tag.mandatory && <span className="text-red-500 font-bold ml-0.5">!</span>}
</span>
))}
{/* Hinweis, falls Trip gewählt */}

View file

@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import { getTags } from "../api";
import type { Tag } from "../api";
import { getTagColor } from "../utils/tagColors";
const API_BASE = "http://localhost:8000";
@ -13,7 +14,9 @@ export default function TagsPage() {
const [newMandatory, setNewMandatory] = useState(false);
async function loadTags() {
setTags(await getTags());
const loaded = await getTags();
// Alphabetisch sortieren
setTags(loaded.sort((a, b) => a.name.localeCompare(b.name)));
}
useEffect(() => {
@ -74,74 +77,71 @@ export default function TagsPage() {
Hinzufügen
</button>
</form>
<ul>
<ul className="flex flex-wrap gap-4">
{tags.map(tag =>
editingId === tag.id ? (
<li key={tag.id} className="flex gap-2 items-center mb-2">
<li
key={tag.id}
className="flex flex-col items-start p-4 mb-2 bg-white border-2 border-blue-300 rounded-xl shadow"
style={{ minWidth: "220px", maxWidth: "320px" }}
>
<input
className="border rounded px-2 py-1 flex-1"
className="border rounded px-3 py-2 w-full text-lg font-semibold mb-2"
value={editName}
onChange={e => setEditName(e.target.value)}
/>
<label className="flex items-center gap-1 text-sm">
<label className="flex items-center gap-2 text-base mb-4">
<input
type="checkbox"
checked={editMandatory}
onChange={e => setEditMandatory(e.target.checked)}
/>
mandatory
<span className="font-semibold">mandatory</span>
</label>
<button
className="bg-blue-500 text-white px-2 py-1 rounded"
onClick={() => handleSave(tag.id)}
type="button"
>
Speichern
</button>
<button
className="bg-gray-300 px-2 py-1 rounded"
onClick={() => setEditingId(null)}
type="button"
>
Abbrechen
</button>
<div className="flex gap-2 w-full justify-end">
<button
className="bg-blue-500 text-white px-3 py-1 rounded"
onClick={() => handleSave(tag.id)}
type="button"
>
Speichern
</button>
<button
className="bg-red-500 text-white px-3 py-1 rounded"
onClick={() => handleDelete(tag.id)}
type="button"
>
Löschen
</button>
<button
className="bg-gray-300 px-3 py-1 rounded"
onClick={() => setEditingId(null)}
type="button"
>
Abbrechen
</button>
</div>
</li>
) : (
<li
key={tag.id}
className="flex gap-2 items-center mb-2 group"
className="flex items-center group"
style={{ marginBottom: "0.5rem" }}
>
<span
className={
"px-2 py-0.5 rounded text-sm " +
(tag.mandatory
? "border-2 border-yellow-400 bg-yellow-50 font-bold"
: "bg-gray-100")
`${getTagColor(tag.id).bg} px-4 py-2 rounded-xl text-lg cursor-pointer font-semibold`
}
>
#{tag.name}
{tag.mandatory && (
<span className="ml-1 text-yellow-500 font-bold">*</span>
)}
</span>
<button
className="text-xs text-blue-500 underline"
onClick={() => {
setEditingId(tag.id);
setEditName(tag.name);
setEditMandatory(tag.mandatory);
}}
type="button"
title="Bearbeiten"
>
Bearbeiten
</button>
<button
className="text-xs text-red-500 underline opacity-0 group-hover:opacity-100"
onClick={() => handleDelete(tag.id)}
type="button"
>
Löschen
</button>
#{tag.name}
{tag.mandatory && <span className="text-red-500 font-bold ml-1">!</span>}
</span>
</li>
)
)}

View file

@ -1,23 +1,23 @@
export const TAG_COLORS = [
"bg-blue-200 text-blue-900",
"bg-green-200 text-green-900",
"bg-yellow-200 text-yellow-900",
"bg-pink-200 text-pink-900",
"bg-purple-200 text-purple-900",
"bg-orange-200 text-orange-900",
"bg-teal-200 text-teal-900",
"bg-red-200 text-red-900",
"bg-indigo-200 text-indigo-900",
"bg-lime-200 text-lime-900",
"bg-cyan-200 text-cyan-900",
"bg-amber-200 text-amber-900",
"bg-fuchsia-200 text-fuchsia-900",
"bg-rose-200 text-rose-900",
"bg-emerald-200 text-emerald-900",
"bg-violet-200 text-violet-900",
"bg-sky-200 text-sky-900",
"bg-orange-100 text-orange-800",
"bg-green-100 text-green-800",
{ bg: "bg-blue-200 text-blue-900", border: "border-blue-700" },
{ bg: "bg-green-200 text-green-900", border: "border-green-700" },
{ bg: "bg-yellow-200 text-yellow-900", border: "border-yellow-700" },
{ bg: "bg-pink-200 text-pink-900", border: "border-pink-700" },
{ bg: "bg-purple-200 text-purple-900", border: "border-purple-700" },
{ bg: "bg-orange-200 text-orange-900", border: "border-orange-700" },
{ bg: "bg-teal-200 text-teal-900", border: "border-teal-700" },
{ bg: "bg-red-200 text-red-900", border: "border-red-700" },
{ bg: "bg-indigo-200 text-indigo-900", border: "border-indigo-700" },
{ bg: "bg-lime-200 text-lime-900", border: "border-lime-700" },
{ bg: "bg-cyan-200 text-cyan-900", border: "border-cyan-700" },
{ bg: "bg-amber-200 text-amber-900", border: "border-amber-700" },
{ bg: "bg-fuchsia-200 text-fuchsia-900", border: "border-fuchsia-700" },
{ bg: "bg-rose-200 text-rose-900", border: "border-rose-700" },
{ bg: "bg-emerald-200 text-emerald-900", border: "border-emerald-700" },
{ bg: "bg-violet-200 text-violet-900", border: "border-violet-700" },
{ bg: "bg-sky-200 text-sky-900", border: "border-sky-700" },
{ bg: "bg-orange-100 text-orange-800", border: "border-orange-700" },
{ bg: "bg-green-100 text-green-800", border: "border-green-700" },
];
export function getTagColor(tagId: string) {