UI fixes: emoji icons, modal form, Czech labels, polish
- Fixed group emoji icons in DB (💼🛒📚🗺️🏃✨🏠🌿) - Added TaskModal component for + button - Czech status labels (Čeká, Probíhá, Hotovo, Zrušeno) - Improved TaskCard, GroupSelector, Header, StatusBadge - Better dark/light mode transitions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
98
apps/tasks/components/TaskModal.tsx
Normal file
98
apps/tasks/components/TaskModal.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { Group, Task } from "@/lib/api";
|
||||
import TaskForm from "@/components/TaskForm";
|
||||
|
||||
interface TaskModalProps {
|
||||
groups: Group[];
|
||||
onSubmit: (data: Partial<Task>) => Promise<void>;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export default function TaskModal({ groups, onSubmit, onClose }: TaskModalProps) {
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setVisible(false);
|
||||
setTimeout(onClose, 200);
|
||||
}, [onClose]);
|
||||
|
||||
useEffect(() => {
|
||||
// Trigger enter animation on next frame
|
||||
requestAnimationFrame(() => setVisible(true));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
function handleKeyDown(e: KeyboardEvent) {
|
||||
if (e.key === "Escape") handleClose();
|
||||
}
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
// Prevent body scroll
|
||||
document.body.style.overflow = "hidden";
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
document.body.style.overflow = "";
|
||||
};
|
||||
}, [handleClose]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 z-50 flex items-end sm:items-center justify-center"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label="Nov\u00fd \u00fakol"
|
||||
>
|
||||
{/* Backdrop */}
|
||||
<div
|
||||
className={`absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-200 ${
|
||||
visible ? "opacity-100" : "opacity-0"
|
||||
}`}
|
||||
onClick={handleClose}
|
||||
/>
|
||||
|
||||
{/* Modal panel with slide-up animation */}
|
||||
<div
|
||||
className={`relative w-full sm:max-w-lg bg-white dark:bg-gray-900 rounded-t-2xl sm:rounded-2xl shadow-2xl p-6 transition-all duration-200 ease-out ${
|
||||
visible
|
||||
? "translate-y-0 opacity-100"
|
||||
: "translate-y-8 opacity-0"
|
||||
}`}
|
||||
>
|
||||
{/* Drag handle for mobile */}
|
||||
<div className="flex justify-center mb-3 sm:hidden">
|
||||
<div className="w-10 h-1 bg-gray-300 dark:bg-gray-600 rounded-full" />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between mb-5">
|
||||
<h2 className="text-lg font-semibold">Nov\u00fd \u00fakol</h2>
|
||||
<button
|
||||
onClick={handleClose}
|
||||
className="p-2 rounded-lg text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors min-w-[44px] min-h-[44px] flex items-center justify-center"
|
||||
aria-label="Zav\u0159\u00edt"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<TaskForm
|
||||
groups={groups}
|
||||
onSubmit={onSubmit}
|
||||
onCancel={handleClose}
|
||||
submitLabel="Vytvo\u0159it"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user