This commit is contained in:
lubiana 2025-07-24 11:35:37 +02:00
parent ba1f43fd8e
commit 0f9fbc9375
Signed by: lubiana
SSH key fingerprint: SHA256:vW1EA0fRR3Fw+dD/sM0K+x3Il2gSry6YRYHqOeQwrfk
15 changed files with 381 additions and 297 deletions

View file

@ -124,27 +124,33 @@ export default function ChecklistItem({
}
return (
<div className={`${depth > 0 ? 'ml-4 border-l-2 border-gray-200 dark:border-gray-700 pl-3' : ''}`}>
<div className="flex items-center justify-between py-2 hover:bg-gray-50 dark:hover:bg-gray-800 rounded-lg px-2 transition-colors duration-200">
<div className="flex items-center gap-3 flex-1 min-w-0">
<li className="group">
<div className="flex items-start gap-3 p-3 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-all duration-200 border border-transparent hover:border-gray-200 dark:hover:border-gray-700">
{/* Checkbox */}
<div className="flex-shrink-0 mt-0.5">
<input
type="checkbox"
checked={item.checked}
onChange={handleToggleCheck}
disabled={Boolean(isLocked && !isLockedByMe)}
className="w-4 h-4 text-blue-600 bg-gray-100 dark:bg-gray-700 border-gray-300 dark:border-gray-600 rounded focus:ring-blue-500 focus:ring-2 disabled:opacity-50 disabled:cursor-not-allowed"
className="w-5 h-5 text-blue-600 bg-white dark:bg-gray-800 border-2 border-gray-300 dark:border-gray-600 rounded-md focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 hover:border-blue-400 dark:hover:border-blue-500"
/>
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<span
ref={contentRef}
contentEditable={isEditing}
suppressContentEditableWarning={true}
className={`flex-1 text-sm text-gray-700 dark:text-gray-300 break-words outline-none ${
className={`block w-full text-base leading-relaxed break-words outline-none transition-all duration-200 ${
isEditing
? 'px-2 py-1 border-2 border-blue-500 rounded focus:ring-2 focus:ring-blue-200 dark:focus:ring-blue-800 bg-white dark:bg-gray-800'
: 'cursor-pointer hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200'
? 'px-3 py-2 border-2 border-blue-500 rounded-lg focus:ring-2 focus:ring-blue-200 dark:focus:ring-blue-800 bg-white dark:bg-gray-800 shadow-sm'
: 'cursor-pointer hover:text-blue-600 dark:hover:text-blue-400'
} ${
item.checked ? 'line-through text-gray-500 dark:text-gray-500' : ''
item.checked
? 'line-through text-gray-500 dark:text-gray-500 opacity-75'
: 'text-gray-900 dark:text-gray-100'
}`}
onClick={!isEditing ? handleEdit : undefined}
onKeyDown={isEditing ? handleKeyDown : undefined}
@ -154,30 +160,35 @@ export default function ChecklistItem({
</span>
</div>
<div className="flex items-center gap-2 ml-2">
{/* Actions */}
<div className="flex items-center gap-2 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
{isLocked && !isLockedByMe && (
<span className="text-xs text-red-600 dark:text-red-400 bg-red-100 dark:bg-red-900/30 px-2 py-1 rounded-full whitespace-nowrap">
🔒 {item.locked_by}
<span className="inline-flex items-center gap-1 text-xs font-medium text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 px-2 py-1 rounded-full whitespace-nowrap border border-red-200 dark:border-red-800">
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clipRule="evenodd" />
</svg>
{item.locked_by}
</span>
)}
{!isEditing && (
<>
<button
onClick={handleDelete}
disabled={isDeleting}
className="p-1 text-gray-500 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/30 rounded transition-colors duration-200 disabled:opacity-30 disabled:cursor-not-allowed"
title="Delete item"
>
🗑
</button>
</>
<button
onClick={handleDelete}
disabled={isDeleting}
className="p-1.5 text-gray-400 hover:text-red-600 dark:hover:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-md transition-all duration-200 disabled:opacity-30 disabled:cursor-not-allowed group/delete"
title="Delete item"
>
<svg className="w-4 h-4 group-hover/delete:scale-110 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
</button>
)}
</div>
</div>
{/* Children */}
{children.length > 0 && (
<div className="mt-1">
<div className="ml-8 mt-2 space-y-2 border-l-2 border-gray-200 dark:border-gray-700 pl-4">
{children.map(child => (
<ChecklistItem
key={child.id}
@ -190,6 +201,6 @@ export default function ChecklistItem({
))}
</div>
)}
</div>
</li>
)
}