{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "detail-task-card-shadcnui", "type": "registry:component", "title": "Detail Task Card", "description": "Task management detail panel with animated assignee chips and editor controls", "dependencies": [ "framer-motion", "react" ], "files": [ { "path": "@uitripled/react-shadcn/src/components/components/cards/shadcnui/detail-task.tsx", "content": "\"use client\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@/components/ui/card\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { Input } from \"@/components/ui/input\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport {\n Bold,\n ChevronDown,\n Italic,\n List,\n ListOrdered,\n Plus,\n RotateCcw,\n Save,\n Underline,\n X,\n} from \"lucide-react\";\nimport { useMemo, useState } from \"react\";\n\ntype Priority = \"high\" | \"medium\" | \"low\";\n\ntype TeamMember = {\n id: string;\n name: string;\n role: string;\n initials: string;\n accent: string;\n};\n\nconst allMembers: TeamMember[] = [\n {\n id: \"sophia\",\n name: \"Sophia Williams\",\n role: \"Product Designer\",\n initials: \"SW\",\n accent: \"ring-foreground text-foreground\",\n },\n {\n id: \"liam\",\n name: \"Liam Johnson\",\n role: \"Design Manager\",\n initials: \"LJ\",\n accent: \"ring-foreground text-foreground\",\n },\n {\n id: \"olivia\",\n name: \"Olivia Smith\",\n role: \"UX Researcher\",\n initials: \"OS\",\n accent: \"ring-foreground text-foreground\",\n },\n {\n id: \"mia\",\n name: \"Mia Chen\",\n role: \"Product Owner\",\n initials: \"MC\",\n accent: \"ring-foreground text-foreground\",\n },\n {\n id: \"ethan\",\n name: \"Ethan Davis\",\n role: \"UI Engineer\",\n initials: \"ED\",\n accent: \"ring-foreground text-foreground\",\n },\n];\n\nconst priorityMap: Record<\n Priority,\n { label: string; badge: string; dot: string; description: string }\n> = {\n high: {\n label: \"High\",\n badge:\n \"border border-destructive/40 bg-destructive/20 text-destructive dark:text-red-400\",\n dot: \"bg-destructive\",\n description: \"Requires immediate focus and dedicated resources\",\n },\n medium: {\n label: \"Medium\",\n badge:\n \"border border-amber-500/30 bg-amber-500/20 text-amber-600 dark:text-amber-400\",\n dot: \"bg-amber-500\",\n description: \"Important but not blocking other work\",\n },\n low: {\n label: \"Low\",\n badge:\n \"border border-emerald-500/30 bg-emerald-500/20 text-emerald-600 dark:text-emerald-400\",\n dot: \"bg-emerald-500\",\n description: \"Nice-to-have improvements to schedule later\",\n },\n};\n\nconst defaultDescription =\n \"The goal is to update the current design system with the latest components and styles. This includes reviewing existing elements, identifying areas for improvement, and implementing changes to ensure consistency and usability across all platforms.\";\nconst maxDescriptionLength = 200;\n\nexport function DetailTaskCard() {\n const [title, setTitle] = useState(\"Edit Design System\");\n const [priority, setPriority] = useState(\"high\");\n const [assignees, setAssignees] = useState(\n allMembers.slice(0, 3)\n );\n const [description, setDescription] = useState(defaultDescription);\n const [reminderEnabled, setReminderEnabled] = useState(true);\n const [isSaving, setIsSaving] = useState(false);\n const [isSaved, setIsSaved] = useState(false);\n\n const remainingCharacters = maxDescriptionLength - description.length;\n\n const availableMembers = useMemo(\n () =>\n allMembers.filter(\n (member) => !assignees.some((assigned) => assigned.id === member.id)\n ),\n [assignees]\n );\n\n const handleRemoveAssignee = (id: string) => {\n setAssignees((prev) => prev.filter((member) => member.id !== id));\n };\n\n const handleAddPerson = () => {\n if (availableMembers.length === 0) return;\n const [nextMember] = availableMembers;\n setAssignees((prev) => [...prev, nextMember]);\n };\n\n const handleReset = () => {\n setTitle(\"Edit Design System\");\n setPriority(\"high\");\n setAssignees(allMembers.slice(0, 3));\n setDescription(defaultDescription);\n setReminderEnabled(true);\n setIsSaved(false);\n };\n\n const handleSave = () => {\n if (isSaving) return;\n setIsSaving(true);\n setIsSaved(false);\n setTimeout(() => {\n setIsSaving(false);\n setIsSaved(true);\n setTimeout(() => setIsSaved(false), 2000);\n }, 900);\n };\n\n const toolbarIcons = [Bold, Italic, Underline, List, ListOrdered];\n\n return (\n
\n \n
\n\n \n \n Task Manager\n \n \n Detail Task Overview\n \n \n Keep your task aligned with team priorities and deliverables.\n \n \n\n \n \n
\n \n Title Task\n \n setTitle(event.target.value)}\n className=\"rounded-xl border-border/40 bg-background/40 text-sm transition-colors focus-visible:border-border/60 focus-visible:ring-2 focus-visible:ring-primary/40\"\n aria-describedby=\"task-title-description\"\n />\n \n Keep it short and goal oriented.\n

\n
\n\n
\n \n Priority\n \n \n \n \n \n \n {priorityMap[priority].label}\n \n \n \n \n \n {(Object.keys(priorityMap) as Priority[]).map((option) => (\n setPriority(option)}\n className=\"flex items-center justify-between gap-2 rounded-lg text-sm text-foreground/80 focus:bg-background/60 focus:text-foreground\"\n >\n \n \n {priorityMap[option].label}\n \n {priority === option ? (\n \n Selected\n \n ) : null}\n \n ))}\n \n \n

\n {priorityMap[priority].description}\n

\n
\n \n\n
\n
\n \n Assign Task To\n \n \n Team\n \n
\n\n
\n \n {assignees.map((member) => (\n \n \n {member.initials}\n \n
\n \n {member.name}\n \n \n {member.role}\n \n
\n handleRemoveAssignee(member.id)}\n className=\"h-8 w-8 rounded-lg text-foreground/60 transition-colors hover:text-foreground\"\n aria-label={`Remove ${member.name} from this task`}\n >\n \n \n \n ))}\n
\n \n \n Add another person\n \n
\n
\n\n
\n
\n \n Description\n \n \n {Math.max(0, remainingCharacters)} / {maxDescriptionLength}\n \n
\n\n
\n
\n {toolbarIcons.map((Icon, index) => (\n \n \n \n ))}\n
\n \n setDescription(\n event.target.value.slice(0, maxDescriptionLength)\n )\n }\n className=\"h-32 resize-none border-0 bg-transparent px-3 py-3 text-sm text-foreground/80 focus-visible:ring-0 focus-visible:ring-offset-0\"\n aria-label=\"Task description\"\n />\n
\n
\n\n
\n
\n setReminderEnabled((prev) => !prev)}\n className={`relative flex h-6 w-12 items-center rounded-full border border-border/50 transition-all ${\n reminderEnabled ? \"bg-primary/20\" : \"bg-background/60\"\n }`}\n >\n \n \n
\n

\n Reminder Task\n

\n

\n {reminderEnabled\n ? \"We will notify the assignees 24 hours before the due date.\"\n : \"Enable reminders to keep everyone on track.\"}\n

\n
\n
\n\n \n Sprint Q4\n \n
\n
\n\n \n
\n \n Need to start over?\n \n Reset\n \n
\n\n
\n \n {isSaved ? (\n \n Saved!\n \n ) : null}\n \n \n \n {isSaving ? \"Saving...\" : \"Save Changes\"}\n \n
\n
\n \n
\n );\n}\n", "type": "registry:component", "target": "components/uitripled/detail-task-card-shadcnui.tsx" } ] }