feat: tag display with mandatory indicators and improve tag color structure
This commit is contained in:
parent
71af5b911c
commit
f20eef7556
4 changed files with 68 additions and 70 deletions
|
|
@ -95,12 +95,11 @@ export default function ItemRow({
|
||||||
<span
|
<span
|
||||||
key={tag.id}
|
key={tag.id}
|
||||||
className={
|
className={
|
||||||
tag.mandatory
|
`${getTagColor(tag.id).bg} text-sm rounded px-1 py-0.5 flex items-center font-medium`
|
||||||
? "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`
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
#{tag.name}
|
#{tag.name}
|
||||||
|
{tag.mandatory && <span className="text-red-500 font-bold ml-0.5">!</span>}
|
||||||
{hover && (
|
{hover && (
|
||||||
<button
|
<button
|
||||||
onClick={() => onDeleteTag(item.id, tag.id)}
|
onClick={() => onDeleteTag(item.id, tag.id)}
|
||||||
|
|
@ -113,7 +112,7 @@ export default function ItemRow({
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{tripName && (
|
{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}
|
{tripName}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -180,15 +180,14 @@ export default function ItemsPage() {
|
||||||
<span
|
<span
|
||||||
key={tag.id}
|
key={tag.id}
|
||||||
className={
|
className={
|
||||||
tag.mandatory
|
`${getTagColor(tag.id).bg} text-sm rounded px-1 py-0.5 flex items-center cursor-pointer font-medium` +
|
||||||
? "border-2 border-yellow-400 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)} text-sm rounded px-1 py-0.5 flex items-center cursor-pointer`
|
|
||||||
+ (newItemTags.includes(tag.id) ? " ring-2 ring-blue-400 font-bold" : "")
|
|
||||||
}
|
}
|
||||||
onClick={() => toggleNewItemTag(tag.id)}
|
onClick={() => toggleNewItemTag(tag.id)}
|
||||||
title={tag.mandatory ? "Pflicht-Tag (mandatory)" : ""}
|
title={tag.mandatory ? "Pflicht-Tag (mandatory)" : ""}
|
||||||
>
|
>
|
||||||
#{tag.name}
|
#{tag.name}
|
||||||
|
{tag.mandatory && <span className="text-red-500 font-bold ml-0.5">!</span>}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
{/* Hinweis, falls Trip gewählt */}
|
{/* Hinweis, falls Trip gewählt */}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { getTags } from "../api";
|
import { getTags } from "../api";
|
||||||
import type { Tag } from "../api";
|
import type { Tag } from "../api";
|
||||||
|
import { getTagColor } from "../utils/tagColors";
|
||||||
|
|
||||||
const API_BASE = "http://localhost:8000";
|
const API_BASE = "http://localhost:8000";
|
||||||
|
|
||||||
|
|
@ -13,7 +14,9 @@ export default function TagsPage() {
|
||||||
const [newMandatory, setNewMandatory] = useState(false);
|
const [newMandatory, setNewMandatory] = useState(false);
|
||||||
|
|
||||||
async function loadTags() {
|
async function loadTags() {
|
||||||
setTags(await getTags());
|
const loaded = await getTags();
|
||||||
|
// Alphabetisch sortieren
|
||||||
|
setTags(loaded.sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -74,74 +77,71 @@ export default function TagsPage() {
|
||||||
Hinzufügen
|
Hinzufügen
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<ul>
|
<ul className="flex flex-wrap gap-4">
|
||||||
{tags.map(tag =>
|
{tags.map(tag =>
|
||||||
editingId === tag.id ? (
|
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
|
<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}
|
value={editName}
|
||||||
onChange={e => setEditName(e.target.value)}
|
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
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={editMandatory}
|
checked={editMandatory}
|
||||||
onChange={e => setEditMandatory(e.target.checked)}
|
onChange={e => setEditMandatory(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
mandatory
|
<span className="font-semibold">mandatory</span>
|
||||||
</label>
|
</label>
|
||||||
<button
|
<div className="flex gap-2 w-full justify-end">
|
||||||
className="bg-blue-500 text-white px-2 py-1 rounded"
|
<button
|
||||||
onClick={() => handleSave(tag.id)}
|
className="bg-blue-500 text-white px-3 py-1 rounded"
|
||||||
type="button"
|
onClick={() => handleSave(tag.id)}
|
||||||
>
|
type="button"
|
||||||
Speichern
|
>
|
||||||
</button>
|
Speichern
|
||||||
<button
|
</button>
|
||||||
className="bg-gray-300 px-2 py-1 rounded"
|
<button
|
||||||
onClick={() => setEditingId(null)}
|
className="bg-red-500 text-white px-3 py-1 rounded"
|
||||||
type="button"
|
onClick={() => handleDelete(tag.id)}
|
||||||
>
|
type="button"
|
||||||
Abbrechen
|
>
|
||||||
</button>
|
Löschen
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="bg-gray-300 px-3 py-1 rounded"
|
||||||
|
onClick={() => setEditingId(null)}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Abbrechen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
) : (
|
) : (
|
||||||
<li
|
<li
|
||||||
key={tag.id}
|
key={tag.id}
|
||||||
className="flex gap-2 items-center mb-2 group"
|
className="flex items-center group"
|
||||||
|
style={{ marginBottom: "0.5rem" }}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={
|
className={
|
||||||
"px-2 py-0.5 rounded text-sm " +
|
`${getTagColor(tag.id).bg} px-4 py-2 rounded-xl text-lg cursor-pointer font-semibold`
|
||||||
(tag.mandatory
|
|
||||||
? "border-2 border-yellow-400 bg-yellow-50 font-bold"
|
|
||||||
: "bg-gray-100")
|
|
||||||
}
|
}
|
||||||
>
|
|
||||||
#{tag.name}
|
|
||||||
{tag.mandatory && (
|
|
||||||
<span className="ml-1 text-yellow-500 font-bold">*</span>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
className="text-xs text-blue-500 underline"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setEditingId(tag.id);
|
setEditingId(tag.id);
|
||||||
setEditName(tag.name);
|
setEditName(tag.name);
|
||||||
setEditMandatory(tag.mandatory);
|
setEditMandatory(tag.mandatory);
|
||||||
}}
|
}}
|
||||||
type="button"
|
title="Bearbeiten"
|
||||||
>
|
>
|
||||||
Bearbeiten
|
#{tag.name}
|
||||||
</button>
|
{tag.mandatory && <span className="text-red-500 font-bold ml-1">!</span>}
|
||||||
<button
|
</span>
|
||||||
className="text-xs text-red-500 underline opacity-0 group-hover:opacity-100"
|
|
||||||
onClick={() => handleDelete(tag.id)}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Löschen
|
|
||||||
</button>
|
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,23 @@
|
||||||
export const TAG_COLORS = [
|
export const TAG_COLORS = [
|
||||||
"bg-blue-200 text-blue-900",
|
{ bg: "bg-blue-200 text-blue-900", border: "border-blue-700" },
|
||||||
"bg-green-200 text-green-900",
|
{ bg: "bg-green-200 text-green-900", border: "border-green-700" },
|
||||||
"bg-yellow-200 text-yellow-900",
|
{ bg: "bg-yellow-200 text-yellow-900", border: "border-yellow-700" },
|
||||||
"bg-pink-200 text-pink-900",
|
{ bg: "bg-pink-200 text-pink-900", border: "border-pink-700" },
|
||||||
"bg-purple-200 text-purple-900",
|
{ bg: "bg-purple-200 text-purple-900", border: "border-purple-700" },
|
||||||
"bg-orange-200 text-orange-900",
|
{ bg: "bg-orange-200 text-orange-900", border: "border-orange-700" },
|
||||||
"bg-teal-200 text-teal-900",
|
{ bg: "bg-teal-200 text-teal-900", border: "border-teal-700" },
|
||||||
"bg-red-200 text-red-900",
|
{ bg: "bg-red-200 text-red-900", border: "border-red-700" },
|
||||||
"bg-indigo-200 text-indigo-900",
|
{ bg: "bg-indigo-200 text-indigo-900", border: "border-indigo-700" },
|
||||||
"bg-lime-200 text-lime-900",
|
{ bg: "bg-lime-200 text-lime-900", border: "border-lime-700" },
|
||||||
"bg-cyan-200 text-cyan-900",
|
{ bg: "bg-cyan-200 text-cyan-900", border: "border-cyan-700" },
|
||||||
"bg-amber-200 text-amber-900",
|
{ bg: "bg-amber-200 text-amber-900", border: "border-amber-700" },
|
||||||
"bg-fuchsia-200 text-fuchsia-900",
|
{ bg: "bg-fuchsia-200 text-fuchsia-900", border: "border-fuchsia-700" },
|
||||||
"bg-rose-200 text-rose-900",
|
{ bg: "bg-rose-200 text-rose-900", border: "border-rose-700" },
|
||||||
"bg-emerald-200 text-emerald-900",
|
{ bg: "bg-emerald-200 text-emerald-900", border: "border-emerald-700" },
|
||||||
"bg-violet-200 text-violet-900",
|
{ bg: "bg-violet-200 text-violet-900", border: "border-violet-700" },
|
||||||
"bg-sky-200 text-sky-900",
|
{ bg: "bg-sky-200 text-sky-900", border: "border-sky-700" },
|
||||||
"bg-orange-100 text-orange-800",
|
{ bg: "bg-orange-100 text-orange-800", border: "border-orange-700" },
|
||||||
"bg-green-100 text-green-800",
|
{ bg: "bg-green-100 text-green-800", border: "border-green-700" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function getTagColor(tagId: string) {
|
export function getTagColor(tagId: string) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue