mirror of
https://github.com/TurTaskProject/TurTaskWeb.git
synced 2025-12-19 22:14:07 +01:00
Fix Style of Kanban
This commit is contained in:
parent
438d9b74b5
commit
297529472d
@ -1,6 +1,6 @@
|
|||||||
import { SortableContext, useSortable } from "@dnd-kit/sortable";
|
import { SortableContext, useSortable } from "@dnd-kit/sortable";
|
||||||
import { BsFillTrashFill } from "react-icons/bs"
|
import { BsFillTrashFill } from "react-icons/bs";
|
||||||
import { AiOutlinePlusCircle } from "react-icons/ai"
|
import { AiOutlinePlusCircle } from "react-icons/ai";
|
||||||
import { CSS } from "@dnd-kit/utilities";
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import TaskCard from "./taskCard";
|
import TaskCard from "./taskCard";
|
||||||
@ -32,13 +32,11 @@ function ColumnContainer({ column, deleteColumn, updateColumn, createTask, tasks
|
|||||||
ref={setNodeRef}
|
ref={setNodeRef}
|
||||||
style={style}
|
style={style}
|
||||||
className="
|
className="
|
||||||
bg-columnBackgroundColor
|
|
||||||
opacity-40
|
opacity-40
|
||||||
border-2
|
border-2
|
||||||
border-pink-500
|
border-blue-500
|
||||||
w-[350px]
|
w-[350px]
|
||||||
h-[500px]
|
max-h-[400px]
|
||||||
max-h-[500px]
|
|
||||||
rounded-md
|
rounded-md
|
||||||
flex
|
flex
|
||||||
flex-col
|
flex-col
|
||||||
@ -51,10 +49,9 @@ function ColumnContainer({ column, deleteColumn, updateColumn, createTask, tasks
|
|||||||
ref={setNodeRef}
|
ref={setNodeRef}
|
||||||
style={style}
|
style={style}
|
||||||
className="
|
className="
|
||||||
bg-columnBackgroundColor
|
bg-[#f1f2f4]
|
||||||
w-[350px]
|
w-[280px]
|
||||||
h-[500px]
|
max-h-[400px]
|
||||||
max-h-[500px]
|
|
||||||
rounded-md
|
rounded-md
|
||||||
flex
|
flex
|
||||||
flex-col
|
flex-col
|
||||||
@ -82,23 +79,10 @@ function ColumnContainer({ column, deleteColumn, updateColumn, createTask, tasks
|
|||||||
justify-between
|
justify-between
|
||||||
">
|
">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<div
|
|
||||||
className="
|
|
||||||
flex
|
|
||||||
justify-center
|
|
||||||
items-center
|
|
||||||
bg-columnBackgroundColor
|
|
||||||
px-2
|
|
||||||
py-1
|
|
||||||
text-sm
|
|
||||||
rounded-full
|
|
||||||
">
|
|
||||||
0
|
|
||||||
</div>
|
|
||||||
{!editMode && column.title}
|
{!editMode && column.title}
|
||||||
{editMode && (
|
{editMode && (
|
||||||
<input
|
<input
|
||||||
className="bg-black focus:border-rose-500 border rounded outline-none px-2"
|
className="bg-gray-200 focus:border-blue-500 border rounded-md outline-none px-2"
|
||||||
value={column.title}
|
value={column.title}
|
||||||
onChange={e => updateColumn(column.id, e.target.value)}
|
onChange={e => updateColumn(column.id, e.target.value)}
|
||||||
autoFocus
|
autoFocus
|
||||||
@ -138,7 +122,7 @@ function ColumnContainer({ column, deleteColumn, updateColumn, createTask, tasks
|
|||||||
</div>
|
</div>
|
||||||
{/* Column footer */}
|
{/* Column footer */}
|
||||||
<button
|
<button
|
||||||
className="flex gap-2 items-center border-columnBackgroundColor border-2 rounded-md p-4 border-x-columnBackgroundColor hover:bg-mainBackgroundColor hover:text-rose-500 active:bg-black"
|
className="flex gap-2 items-center rounded-md p-2 my-2 hover:bg-zinc-200 active:bg-zinc-400"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
createTask(column.id);
|
createTask(column.id);
|
||||||
}}>
|
}}>
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
import ColumnContainer from "./columnContainer";
|
||||||
|
|
||||||
|
function ColumnContainerCard({ column, deleteColumn, updateColumn, createTask, tasks, deleteTask, updateTask }) {
|
||||||
|
return (
|
||||||
|
<div className="card bg-[#f1f2f4] shadow p-4 my-2 border-2">
|
||||||
|
<ColumnContainer
|
||||||
|
column={column}
|
||||||
|
deleteColumn={deleteColumn}
|
||||||
|
updateColumn={updateColumn}
|
||||||
|
createTask={createTask}
|
||||||
|
tasks={tasks}
|
||||||
|
deleteTask={deleteTask}
|
||||||
|
updateTask={updateTask}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ColumnContainerCard;
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import ColumnContainer from "./columnContainer";
|
import ColumnContainerCard from "./columnContainerWrapper";
|
||||||
import { DndContext, DragOverlay, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
|
import { DndContext, DragOverlay, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
|
||||||
import { SortableContext, arrayMove } from "@dnd-kit/sortable";
|
import { SortableContext, arrayMove } from "@dnd-kit/sortable";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
@ -124,7 +124,7 @@ function KanbanBoard() {
|
|||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<SortableContext items={columnsId}>
|
<SortableContext items={columnsId}>
|
||||||
{columns.map(col => (
|
{columns.map(col => (
|
||||||
<ColumnContainer
|
<ColumnContainerCard
|
||||||
key={col.id}
|
key={col.id}
|
||||||
column={col}
|
column={col}
|
||||||
deleteColumn={deleteColumn}
|
deleteColumn={deleteColumn}
|
||||||
@ -164,7 +164,7 @@ function KanbanBoard() {
|
|||||||
{createPortal(
|
{createPortal(
|
||||||
<DragOverlay>
|
<DragOverlay>
|
||||||
{activeColumn && (
|
{activeColumn && (
|
||||||
<ColumnContainer
|
<ColumnContainerCard
|
||||||
column={activeColumn}
|
column={activeColumn}
|
||||||
deleteColumn={deleteColumn}
|
deleteColumn={deleteColumn}
|
||||||
updateColumn={updateColumn}
|
updateColumn={updateColumn}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { BsFillTrashFill } from "react-icons/bs"
|
import { BsFillTrashFill } from "react-icons/bs";
|
||||||
import { useSortable } from "@dnd-kit/sortable";
|
import { useSortable } from "@dnd-kit/sortable";
|
||||||
import { CSS } from "@dnd-kit/utilities";
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
|
import TaskDetailModal from "./taskDetailModal";
|
||||||
|
|
||||||
function TaskCard({ task, deleteTask, updateTask }) {
|
function TaskCard({ task, deleteTask, updateTask }) {
|
||||||
const [mouseIsOver, setMouseIsOver] = useState(false);
|
const [mouseIsOver, setMouseIsOver] = useState(false);
|
||||||
const [editMode, setEditMode] = useState(true);
|
|
||||||
|
|
||||||
const { setNodeRef, attributes, listeners, transform, transition, isDragging } = useSortable({
|
const { setNodeRef, attributes, listeners, transform, transition, isDragging } = useSortable({
|
||||||
id: task.id,
|
id: task.id,
|
||||||
@ -13,7 +13,6 @@ function TaskCard({ task, deleteTask, updateTask }) {
|
|||||||
type: "Task",
|
type: "Task",
|
||||||
task,
|
task,
|
||||||
},
|
},
|
||||||
disabled: editMode,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
@ -21,11 +20,9 @@ function TaskCard({ task, deleteTask, updateTask }) {
|
|||||||
transform: CSS.Transform.toString(transform),
|
transform: CSS.Transform.toString(transform),
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleEditMode = () => {
|
{
|
||||||
setEditMode(prev => !prev);
|
/* If card is dragged */
|
||||||
setMouseIsOver(false);
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if (isDragging) {
|
if (isDragging) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -33,65 +30,44 @@ function TaskCard({ task, deleteTask, updateTask }) {
|
|||||||
style={style}
|
style={style}
|
||||||
className="
|
className="
|
||||||
opacity-30
|
opacity-30
|
||||||
bg-mainBackgroundColor p-2.5 h-[100px] min-h-[100px] items-center flex text-left rounded-xl border-2 border-gray-400 cursor-grab relative
|
bg-mainBackgroundColor p-2.5 items-center flex text-left rounded-xl border-2 border-gray-400 cursor-grab relative
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editMode) {
|
return (
|
||||||
return (
|
<div>
|
||||||
|
<TaskDetailModal />
|
||||||
<div
|
<div
|
||||||
ref={setNodeRef}
|
ref={setNodeRef}
|
||||||
style={style}
|
|
||||||
{...attributes}
|
{...attributes}
|
||||||
{...listeners}
|
{...listeners}
|
||||||
className="bg-mainBackgroundColor p-2.5 h-[100px] min-h-[100px] items-center flex text-left rounded-xl hover:ring-2 hover:ring-inset bg-zinc-400 ring-zinc-950 cursor-grab relative">
|
onClick={() => document.getElementById("task_detail_modal").showModal()}
|
||||||
<textarea
|
style={style}
|
||||||
className="
|
className="justify-center items-center flex text-left rounded-xl cursor-grab relative hover:border-2 hover:border-blue-400 shadow bg-white"
|
||||||
h-[90%]
|
onMouseEnter={() => {
|
||||||
w-full resize-none border-none rounded bg-transparent focus:outline-none
|
setMouseIsOver(true);
|
||||||
"
|
}}
|
||||||
value={task.content}
|
onMouseLeave={() => {
|
||||||
autoFocus
|
setMouseIsOver(false);
|
||||||
placeholder="Task content here"
|
}}>
|
||||||
onBlur={toggleEditMode}
|
<p
|
||||||
onKeyDown={e => {
|
className="p-2.5 my-auto w-full overflow-y-auto overflow-x-hidden whitespace-pre-wrap rounded-xl shadow bg-white"
|
||||||
if (e.key === "Enter" && e.shiftKey) {
|
onClick={() => document.getElementById("task_detail_modal").showModal()}>
|
||||||
toggleEditMode();
|
{task.content}
|
||||||
}
|
</p>
|
||||||
}}
|
|
||||||
onChange={e => updateTask(task.id, e.target.value)}
|
{mouseIsOver && (
|
||||||
/>
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
deleteTask(task.id);
|
||||||
|
}}
|
||||||
|
className="stroke-white absolute right-0 top-1/2 rounded-full bg-white -translate-y-1/2 bg-columnBackgroundColor p-2 hover:opacity-100 ">
|
||||||
|
<BsFillTrashFill />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={setNodeRef}
|
|
||||||
style={style}
|
|
||||||
{...attributes}
|
|
||||||
{...listeners}
|
|
||||||
onClick={toggleEditMode}
|
|
||||||
className="p-1 justify-center h-[100px] min-h-[100px] items-center flex text-left rounded-xl hover:ring-2 hover:ring-gray-950 hover:bg-zinc-400 cursor-grab relative task"
|
|
||||||
onMouseEnter={() => {
|
|
||||||
setMouseIsOver(true);
|
|
||||||
}}
|
|
||||||
onMouseLeave={() => {
|
|
||||||
setMouseIsOver(false);
|
|
||||||
}}>
|
|
||||||
<p className="p-2.5 my-auto h-[100px] min-h-[100px] w-full overflow-y-auto overflow-x-hidden whitespace-pre-wrap rounded-xl ring-2 ring-gray-950 bg-zinc-100">{task.content}</p>
|
|
||||||
|
|
||||||
{mouseIsOver && (
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
deleteTask(task.id);
|
|
||||||
}}
|
|
||||||
className="stroke-white absolute right-4 top-1/2 -translate-y-1/2 bg-columnBackgroundColor p-2 rounded opacity-60 hover:opacity-100 ">
|
|
||||||
<BsFillTrashFill />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
17
frontend/src/components/kanbanBoard/taskDetailModal.jsx
Normal file
17
frontend/src/components/kanbanBoard/taskDetailModal.jsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
function TaskDetailModal() {
|
||||||
|
return (
|
||||||
|
<dialog id="task_detail_modal" className="modal">
|
||||||
|
<div className="modal-box">
|
||||||
|
<form method="dialog">
|
||||||
|
<button className="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
|
||||||
|
</form>
|
||||||
|
<h3 className="font-bold text-lg">Hello!</h3>
|
||||||
|
<p className="py-4">Press ESC key or click on ✕ button to close</p>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TaskDetailModal;
|
||||||
Loading…
Reference in New Issue
Block a user