style: compact layout for TripChecklist header
This commit is contained in:
parent
f263225180
commit
68f2d202f0
2 changed files with 88 additions and 83 deletions
|
|
@ -46,7 +46,7 @@ function Navigation() {
|
||||||
const isTripDetail = /^\/trips\/[^/]+$/.test(location.pathname);
|
const isTripDetail = /^\/trips\/[^/]+$/.test(location.pathname);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="mb-8 flex items-center gap-4 bg-white/80 backdrop-blur border-b border-gray-200 px-2 py-2 rounded-xl shadow-sm">
|
<nav className="mb-2 flex items-center gap-4 bg-white/80 backdrop-blur border-b border-gray-200 px-2 py-2 rounded-xl shadow-sm">
|
||||||
<button
|
<button
|
||||||
className="text-2xl font-extrabold text-blue-700 tracking-tight mr-4 select-none hover:underline bg-transparent p-0"
|
className="text-2xl font-extrabold text-blue-700 tracking-tight mr-4 select-none hover:underline bg-transparent p-0"
|
||||||
style={{ background: "none", border: "none" }}
|
style={{ background: "none", border: "none" }}
|
||||||
|
|
|
||||||
|
|
@ -241,112 +241,117 @@ export default function TripChecklist({ trips }: { trips: any[] }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="py-4 max-w-5xl mx-auto">
|
<div className="py-4 max-w-5xl mx-auto">
|
||||||
{/* Trip-Titel und Zeitraum */}
|
{/* Kompakter Header für Trip-Titel und Zeitraum */}
|
||||||
<div className="mb-6 p-6 rounded-xl border-2 border-blue-200 bg-blue-50 shadow flex flex-col gap-2">
|
<div className="mb-6 px-4 py-3 rounded-xl border border-blue-200 bg-blue-50 shadow flex flex-wrap items-center gap-4">
|
||||||
<h2 className="text-2xl font-bold text-blue-900">{trip.name}</h2>
|
<div className="flex flex-col flex-1 min-w-[180px]">
|
||||||
<div className="text-gray-600 text-base">
|
<div className="flex items-center gap-2">
|
||||||
{trip.start_date} – {trip.end_date}
|
<h2 className="text-xl font-bold text-blue-900 m-0">{trip.name}</h2>
|
||||||
</div>
|
<span className="text-xs text-blue-700 bg-blue-100 px-2 py-0.5 rounded font-semibold">
|
||||||
<div className="flex flex-wrap gap-2 items-center">
|
{trip.start_date} – {trip.end_date}
|
||||||
<span className="font-semibold">Tags: </span>
|
</span>
|
||||||
{selectedTags.length === 0 ? (
|
</div>
|
||||||
<span className="text-gray-400">keine</span>
|
<div className="flex flex-wrap gap-2 items-center mt-2">
|
||||||
) : (
|
<span className="font-semibold text-sm">Tags:</span>
|
||||||
selectedTags.map((tag: any) => {
|
{selectedTags.length === 0 ? (
|
||||||
const isMarked = markedTags.some((mt: any) => mt.id === tag.id);
|
<span className="text-gray-400 text-sm">keine</span>
|
||||||
return (
|
) : (
|
||||||
<span
|
selectedTags.map((tag: any) => {
|
||||||
key={tag.id}
|
const isMarked = markedTags.some((mt: any) => mt.id === tag.id);
|
||||||
className={
|
return (
|
||||||
"relative px-2 py-0.5 rounded mr-1 text-sm cursor-pointer transition " +
|
<span
|
||||||
(isMarked
|
key={tag.id}
|
||||||
? "bg-yellow-200 text-yellow-900 font-bold"
|
className={
|
||||||
: "bg-blue-100 text-blue-800")
|
"relative px-2 py-0.5 rounded mr-1 text-xs cursor-pointer transition " +
|
||||||
}
|
(isMarked
|
||||||
onClick={() => handleToggleMark(tag.id)}
|
? "bg-yellow-200 text-yellow-900 font-bold"
|
||||||
onMouseEnter={() => setHoveredTag(tag.id)}
|
: "bg-blue-100 text-blue-800")
|
||||||
onMouseLeave={() => setHoveredTag(null)}
|
}
|
||||||
>
|
onClick={() => handleToggleMark(tag.id)}
|
||||||
#{tag.name}
|
onMouseEnter={() => setHoveredTag(tag.id)}
|
||||||
{hoveredTag === tag.id && (
|
onMouseLeave={() => setHoveredTag(null)}
|
||||||
<button
|
>
|
||||||
className="absolute -top-2 -right-2 text-xs text-red-500 bg-white rounded-full px-1 shadow"
|
#{tag.name}
|
||||||
onClick={e => {
|
{hoveredTag === tag.id && (
|
||||||
e.stopPropagation();
|
<button
|
||||||
handleRemoveTag(tag.id);
|
className="absolute -top-2 -right-2 text-xs text-red-500 bg-white rounded-full px-1 shadow"
|
||||||
}}
|
onClick={e => {
|
||||||
>
|
e.stopPropagation();
|
||||||
×
|
handleRemoveTag(tag.id);
|
||||||
</button>
|
}}
|
||||||
)}
|
>
|
||||||
</span>
|
×
|
||||||
);
|
</button>
|
||||||
})
|
)}
|
||||||
)}
|
</span>
|
||||||
{/* "+Tag" link and dropdown */}
|
);
|
||||||
{!addingTag ? (
|
})
|
||||||
<button
|
)}
|
||||||
className="text-blue-500 underline text-sm ml-2"
|
{/* "+Tag" link and dropdown */}
|
||||||
onClick={() => {
|
{!addingTag ? (
|
||||||
setAddingTag(true);
|
<button
|
||||||
setTimeout(() => {
|
className="text-blue-500 underline text-xs ml-2"
|
||||||
inputRef.current?.focus();
|
onClick={() => {
|
||||||
}, 0);
|
setAddingTag(true);
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
+ Tag
|
|
||||||
</button>
|
|
||||||
) : (
|
|
||||||
<TagAutocompleteInput
|
|
||||||
ref={inputRef}
|
|
||||||
allTags={allTags}
|
|
||||||
selectedTags={selectedTags}
|
|
||||||
onAddTag={(tagId, viaTab) => {
|
|
||||||
handleAddTag(tagId);
|
|
||||||
if (viaTab) {
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setAddingTag(true);
|
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
}, 0);
|
}, 0);
|
||||||
} else {
|
}}
|
||||||
setAddingTag(false);
|
type="button"
|
||||||
}
|
>
|
||||||
}}
|
+ Tag
|
||||||
onEscape={() => setAddingTag(false)}
|
</button>
|
||||||
placeholder="Tag suchen..."
|
) : (
|
||||||
/>
|
<TagAutocompleteInput
|
||||||
)}
|
ref={inputRef}
|
||||||
|
allTags={allTags}
|
||||||
|
selectedTags={selectedTags}
|
||||||
|
onAddTag={(tagId, viaTab) => {
|
||||||
|
handleAddTag(tagId);
|
||||||
|
if (viaTab) {
|
||||||
|
setTimeout(() => {
|
||||||
|
setAddingTag(true);
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}, 0);
|
||||||
|
} else {
|
||||||
|
setAddingTag(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onEscape={() => setAddingTag(false)}
|
||||||
|
placeholder="Tag suchen..."
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Progressbar integriert am unteren Rand */}
|
{/* Fortschrittsbalken kompakt rechts */}
|
||||||
<div className="mt-6">
|
<div className="flex flex-col items-end min-w-[160px]">
|
||||||
<div className="flex justify-between items-center mb-1">
|
<div className="flex items-center gap-2 mb-1">
|
||||||
<span className="font-semibold text-gray-700">Fortschritt</span>
|
<span className="font-semibold text-gray-700 text-sm">Fortschritt</span>
|
||||||
<span className="text-sm text-gray-500">{checkedItems} / {totalItems} erledigt</span>
|
<span className="text-xs text-gray-500">{checkedItems} / {totalItems}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="w-full h-5 rounded-full overflow-hidden shadow"
|
className="w-full h-4 rounded-full overflow-hidden shadow"
|
||||||
style={{
|
style={{
|
||||||
background: "linear-gradient(90deg, #f59e42 0%, #facc15 50%, #22c55e 100%)",
|
background: "linear-gradient(90deg, #f59e42 0%, #facc15 50%, #22c55e 100%)",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
|
minWidth: "120px",
|
||||||
|
maxWidth: "180px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="h-full"
|
className="h-full"
|
||||||
style={{
|
style={{
|
||||||
width: `${progress}%`,
|
width: `${progress}%`,
|
||||||
background: "none", // inherit the gradient from parent
|
background: "none",
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
transition: "width 0.3s",
|
transition: "width 0.3s",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* gray overlay for unfilled part */}
|
|
||||||
<div
|
<div
|
||||||
className="h-full w-full"
|
className="h-full w-full"
|
||||||
style={{
|
style={{
|
||||||
background: "rgba(243,244,246,0.9)", // tailwind gray-200 with opacity
|
background: "rgba(243,244,246,0.9)",
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue