mirror of
https://github.com/akaswan/table-list.git
synced 2026-07-22 05:49:21 +00:00
Got drag and drop working
This commit is contained in:
parent
3b836f4b76
commit
ffcd1385c0
6 changed files with 369 additions and 201 deletions
58
package-lock.json
generated
58
package-lock.json
generated
|
|
@ -9,6 +9,8 @@
|
|||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@headlessui/react": "^2.2.2",
|
||||
"date-fns": "^4.1.0",
|
||||
"lucide-react": "^0.469.0",
|
||||
|
|
@ -50,6 +52,59 @@
|
|||
"w3c-keyname": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/accessibility": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
|
||||
"integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/core": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
||||
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dnd-kit/accessibility": "^3.1.1",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/sortable": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz",
|
||||
"integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@dnd-kit/core": "^6.3.0",
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/utilities": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz",
|
||||
"integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.17.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.3.tgz",
|
||||
|
|
@ -2379,8 +2434,7 @@
|
|||
"node_modules/tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
},
|
||||
"node_modules/tsutils": {
|
||||
"version": "3.21.0",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@
|
|||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@headlessui/react": "^2.2.2",
|
||||
"date-fns": "^4.1.0",
|
||||
"lucide-react": "^0.469.0",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable no-mixed-spaces-and-tabs */
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTableContext } from "../views/TableView";
|
||||
import Table from "./Table";
|
||||
|
|
@ -44,19 +45,30 @@ const App: React.FC = () => {
|
|||
|
||||
const [dates, setDates] = useState(getWeekDates(new Date()));
|
||||
|
||||
const [data, setData] = useState(() => tableContext!.loadData());
|
||||
const [data, setData] = useState(() => tableContext?.loadData());
|
||||
|
||||
const [taskStatuses, setTaskStatuses] = useState(getTaskStatuses());
|
||||
const [taskStatuses] = useState(getTaskStatuses());
|
||||
|
||||
const [projects, setProjects] = useState(
|
||||
() => tableContext!.loadData().projects as Project[]
|
||||
);
|
||||
const [nextProjectId, setNextProjectId] = useState(
|
||||
() => tableContext!.loadData().nextProjectId as number
|
||||
);
|
||||
const [nextTaskId, setNextTaskId] = useState(
|
||||
() => tableContext!.loadData().nextTaskId as number
|
||||
);
|
||||
type TableData = {
|
||||
projects: Project[];
|
||||
nextProjectId: number;
|
||||
nextTaskId: number;
|
||||
};
|
||||
|
||||
const getInitialData = (): TableData => {
|
||||
const data = tableContext?.loadData() as TableData | undefined;
|
||||
return (
|
||||
data || {
|
||||
projects: [],
|
||||
nextProjectId: 1,
|
||||
nextTaskId: 1,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const [projects, setProjects] = useState<Project[]>(() => getInitialData().projects);
|
||||
const [nextProjectId, setNextProjectId] = useState<number>(() => getInitialData().nextProjectId);
|
||||
const [nextTaskId, setNextTaskId] = useState<number>(() => getInitialData().nextTaskId);
|
||||
|
||||
const incrementDates = () => {
|
||||
setDates((prevDates) => {
|
||||
|
|
@ -201,13 +213,30 @@ const App: React.FC = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const saveSpecificData = (key: string, value: any): void => {
|
||||
setData((prevData: any) => {
|
||||
const newData = { ...prevData, [key]: value };
|
||||
const saveSpecificData = (key: string, value: unknown): void => {
|
||||
setData((prevData: unknown) => {
|
||||
const baseData = (typeof prevData === "object" && prevData !== null) ? prevData : {};
|
||||
const newData = { ...baseData, [key]: value };
|
||||
return newData;
|
||||
});
|
||||
};
|
||||
|
||||
const moveTask = (taskId: number, newDate: string) => {
|
||||
setProjects((prevProjects) => {
|
||||
const newProjects = prevProjects.map((project) => ({
|
||||
...project,
|
||||
tasks: project.tasks.map((task) =>
|
||||
task.id === taskId
|
||||
? { ...task, date: new Date(newDate) }
|
||||
: task
|
||||
),
|
||||
}));
|
||||
|
||||
saveSpecificData("projects", newProjects);
|
||||
return newProjects;
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (tableContext) {
|
||||
tableContext.saveData(data);
|
||||
|
|
@ -234,6 +263,7 @@ const App: React.FC = () => {
|
|||
handleTaskNameChange={handleTaskNameChange}
|
||||
taskStatuses={taskStatuses}
|
||||
editTaskStatus={editTaskStatus}
|
||||
moveTask={moveTask}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ import { useEffect, useRef } from "react";
|
|||
import * as React from "react";
|
||||
import { Project, TaskStatus } from "./App";
|
||||
import TaskCell from "./TaskCell";
|
||||
import {
|
||||
DndContext,
|
||||
useDroppable,
|
||||
DragEndEvent,
|
||||
} from "@dnd-kit/core";
|
||||
|
||||
interface TableProps {
|
||||
projects: Project[];
|
||||
|
|
@ -20,6 +25,30 @@ interface TableProps {
|
|||
handleTaskNameChange: (id: number, newName: string) => void;
|
||||
taskStatuses: TaskStatus[];
|
||||
editTaskStatus: (id: number, newStatusId: string) => void;
|
||||
moveTask: (taskId: number, newDate: string) => void;
|
||||
}
|
||||
|
||||
function DroppableCell({
|
||||
id,
|
||||
children,
|
||||
onClick,
|
||||
}: {
|
||||
id: string;
|
||||
children: React.ReactNode;
|
||||
onClick?: React.MouseEventHandler<HTMLTableCellElement>;
|
||||
}) {
|
||||
const { setNodeRef } = useDroppable({ id });
|
||||
|
||||
return (
|
||||
<td
|
||||
ref={setNodeRef}
|
||||
className="taskcell-enclosure"
|
||||
data-droppable-id={id}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
</td>
|
||||
);
|
||||
}
|
||||
|
||||
const Table: React.FC<TableProps> = ({
|
||||
|
|
@ -35,6 +64,7 @@ const Table: React.FC<TableProps> = ({
|
|||
handleTaskNameChange,
|
||||
taskStatuses,
|
||||
editTaskStatus,
|
||||
moveTask,
|
||||
}) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const newProjectInputRef = useRef<HTMLInputElement | null>(null);
|
||||
|
|
@ -67,119 +97,149 @@ const Table: React.FC<TableProps> = ({
|
|||
}, [containerRef]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="table-container" ref={containerRef}>
|
||||
<table className="table headings-center">
|
||||
<thead className="table-header">
|
||||
<tr>
|
||||
<th>Projects</th>
|
||||
{dates.map((date) => {
|
||||
const dateObj = parseISO(date);
|
||||
return (
|
||||
<th className="date" key={date}>
|
||||
<div className="date-header">
|
||||
<div>{format(dateObj, "EEEE")}</div>
|
||||
<div>
|
||||
{format(dateObj, "yyyy-MM-dd")}
|
||||
<DndContext
|
||||
onDragEnd={(event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
if (!over || active.id === over.id) return;
|
||||
|
||||
const taskId = Number(active.id);
|
||||
const [, newDate] = String(over.id).split("::");
|
||||
|
||||
moveTask(taskId, newDate);
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<div className="table-container" ref={containerRef}>
|
||||
<table className="table headings-center">
|
||||
<thead className="table-header">
|
||||
<tr>
|
||||
<th>Projects</th>
|
||||
{dates.map((date) => {
|
||||
const dateObj = parseISO(date);
|
||||
return (
|
||||
<th className="date" key={date}>
|
||||
<div className="date-header">
|
||||
<div>
|
||||
{format(dateObj, "EEEE")}
|
||||
</div>
|
||||
<div>
|
||||
{format(
|
||||
dateObj,
|
||||
"yyyy-MM-dd"
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{projects.map((project) => (
|
||||
<tr key={project.id}>
|
||||
<td key={project.id} className="project-column">
|
||||
<input
|
||||
ref={
|
||||
project.id === nextProjectId - 1
|
||||
? newProjectInputRef
|
||||
: null
|
||||
}
|
||||
type="text"
|
||||
value={project.name}
|
||||
className="project-input"
|
||||
placeholder="New project"
|
||||
onBlur={(e) => {
|
||||
if (e.target.value === "")
|
||||
removeProject(project.id);
|
||||
}}
|
||||
onChange={(e) =>
|
||||
handleProjectNameChange(
|
||||
project.id,
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
{dates.map((date, index) => (
|
||||
<td
|
||||
className="taskcell-enclosure"
|
||||
key={`${project.id}:${date}:${index}`}
|
||||
onClick={(e) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
addTaskToProject(project, date);
|
||||
setTimeout(() => {
|
||||
if (
|
||||
newTaskInputRef.current
|
||||
) {
|
||||
newTaskInputRef.current.focus();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{project.tasks
|
||||
.filter(
|
||||
(task) =>
|
||||
new Date(
|
||||
task.date
|
||||
).toISOString() ===
|
||||
new Date(date).toISOString()
|
||||
)
|
||||
.map((task) => (
|
||||
<TaskCell
|
||||
task={task}
|
||||
projectName={project.name}
|
||||
removeTask={removeTask}
|
||||
key={task.id}
|
||||
inputRef={
|
||||
task.id ===
|
||||
nextTaskId - 1
|
||||
? newTaskInputRef
|
||||
: null
|
||||
}
|
||||
handleTaskNameChange={
|
||||
handleTaskNameChange
|
||||
}
|
||||
status={task.status}
|
||||
taskStatuses={taskStatuses}
|
||||
editTaskStatus={
|
||||
editTaskStatus
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</td>
|
||||
))}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
{projects.map((project) => (
|
||||
<tr key={project.id}>
|
||||
<td
|
||||
key={project.id}
|
||||
className="project-column"
|
||||
>
|
||||
<input
|
||||
ref={
|
||||
project.id === nextProjectId - 1
|
||||
? newProjectInputRef
|
||||
: null
|
||||
}
|
||||
type="text"
|
||||
value={project.name}
|
||||
className="project-input"
|
||||
placeholder="New project"
|
||||
onBlur={(e) => {
|
||||
if (e.target.value === "")
|
||||
removeProject(project.id);
|
||||
}}
|
||||
onChange={(e) =>
|
||||
handleProjectNameChange(
|
||||
project.id,
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
{dates.map((date, index) => (
|
||||
<DroppableCell
|
||||
id={`${project.id}::${date}`}
|
||||
onClick={(e) => {
|
||||
if (
|
||||
e.target === e.currentTarget
|
||||
) {
|
||||
addTaskToProject(
|
||||
project,
|
||||
date
|
||||
);
|
||||
setTimeout(() => {
|
||||
newTaskInputRef.current?.focus();
|
||||
}, 0);
|
||||
}
|
||||
}}
|
||||
key={`${project.id}-${date}`} // ADD KEY HERE
|
||||
>
|
||||
{project.tasks
|
||||
.filter(
|
||||
(task) =>
|
||||
new Date(
|
||||
task.date
|
||||
).toISOString() ===
|
||||
new Date(
|
||||
date
|
||||
).toISOString()
|
||||
)
|
||||
.map((task) => (
|
||||
<TaskCell
|
||||
key={task.id}
|
||||
task={task}
|
||||
projectName={
|
||||
project.name
|
||||
}
|
||||
removeTask={removeTask}
|
||||
inputRef={
|
||||
task.id ===
|
||||
nextTaskId - 1
|
||||
? newTaskInputRef
|
||||
: null
|
||||
}
|
||||
handleTaskNameChange={
|
||||
handleTaskNameChange
|
||||
}
|
||||
status={task.status}
|
||||
taskStatuses={
|
||||
taskStatuses
|
||||
}
|
||||
editTaskStatus={
|
||||
editTaskStatus
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</DroppableCell>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="new-project-container">
|
||||
<input
|
||||
type="text"
|
||||
className="project-input"
|
||||
placeholder="New project"
|
||||
onChange={(e) => {
|
||||
createNewProject(
|
||||
e.target.value,
|
||||
newProjectInputRef
|
||||
);
|
||||
e.target.value = "";
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="new-project-container">
|
||||
<input
|
||||
type="text"
|
||||
className="project-input"
|
||||
placeholder="New project"
|
||||
onChange={(e) => {
|
||||
createNewProject(e.target.value, newProjectInputRef);
|
||||
e.target.value = "";
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DndContext>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
ListboxOption,
|
||||
ListboxOptions,
|
||||
} from "@headlessui/react";
|
||||
import { useDraggable } from "@dnd-kit/core";
|
||||
|
||||
const transColor = (color: string, percent: number): string => {
|
||||
const num = parseInt(color.replace("#", ""), 16);
|
||||
|
|
@ -55,81 +56,102 @@ const TaskCell: React.FC<TaskCellProps> = ({
|
|||
taskStatuses,
|
||||
editTaskStatus,
|
||||
}) => {
|
||||
const taskColor = status.color;
|
||||
// const taskColor = status.color;
|
||||
const taskBackground = `${status.color}33`;
|
||||
const darkTaskTextColor = transColor(status.color, -40);
|
||||
// const darkTaskTextColor = transColor(status.color, -40);
|
||||
const lightTaskTextColor = transColor(status.color, 25);
|
||||
const lightTaskBackgroundColor = `${transColor(status.color, 25)}33`;
|
||||
// const lightTaskBackgroundColor = `${transColor(status.color, 25)}33`;
|
||||
|
||||
const placeholderColor = hexToRgba(lightTaskTextColor, 0.50);
|
||||
const placeholderColor = hexToRgba(lightTaskTextColor, 0.5);
|
||||
|
||||
const { attributes, listeners, setNodeRef, transform } = useDraggable({
|
||||
id: task.id,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="task-cell" style={{ backgroundColor: taskBackground }}>
|
||||
<div
|
||||
className="task-cell-header"
|
||||
style={{
|
||||
backgroundColor: taskBackground,
|
||||
color: lightTaskTextColor,
|
||||
}}
|
||||
>
|
||||
<div className="project-name-repeat">
|
||||
{projectName}
|
||||
</div>
|
||||
<Listbox
|
||||
value={status.id}
|
||||
onChange={(value) => editTaskStatus(task.id, value)}
|
||||
>
|
||||
<div className="relative">
|
||||
<ListboxButton
|
||||
className="task-cell-status-indicator"
|
||||
style={{
|
||||
border: `1px solid ${lightTaskTextColor}`,
|
||||
color: lightTaskTextColor,
|
||||
}}
|
||||
>
|
||||
{status.name}
|
||||
</ListboxButton>
|
||||
<ListboxOptions className="task-cell-dropdown-options">
|
||||
{taskStatuses.map((s) => (
|
||||
<ListboxOption
|
||||
key={s.id}
|
||||
value={s.id}
|
||||
className={({ active }) =>
|
||||
`task-cell-dropdown-option ${active ? "active" : ""
|
||||
}`
|
||||
}
|
||||
>
|
||||
{s.name}
|
||||
</ListboxOption>
|
||||
))}
|
||||
</ListboxOptions>
|
||||
</div>
|
||||
</Listbox>
|
||||
</div>
|
||||
<div className="task-cell-content">
|
||||
<input
|
||||
style={{ color: lightTaskTextColor }}
|
||||
placeholder="Task name"
|
||||
onBlur={(e) => {
|
||||
if (e.target.value === "") removeTask(task.id);
|
||||
}}
|
||||
ref={inputRef}
|
||||
onChange={(e) =>
|
||||
handleTaskNameChange(task.id, e.target.value)
|
||||
}
|
||||
value={task.name}
|
||||
className={`task-input-${task.id}`}
|
||||
></input>
|
||||
<style>
|
||||
{`
|
||||
.task-input-${task.id}::placeholder {
|
||||
color: ${placeholderColor};
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
className="task-cell"
|
||||
style={{
|
||||
backgroundColor: taskBackground,
|
||||
...(transform
|
||||
? {
|
||||
transform: `translate(${transform.x}px, ${transform.y}px)`,
|
||||
}
|
||||
: {}),
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="task-cell-header"
|
||||
style={{
|
||||
backgroundColor: taskBackground,
|
||||
color: lightTaskTextColor,
|
||||
}}
|
||||
>
|
||||
{/* ✅ Only this part is draggable */}
|
||||
<div
|
||||
{...listeners}
|
||||
{...attributes}
|
||||
className="project-name-repeat"
|
||||
style={{
|
||||
cursor: "grab",
|
||||
userSelect: "none",
|
||||
}}
|
||||
>
|
||||
{projectName}
|
||||
</div>
|
||||
|
||||
<Listbox
|
||||
value={status.id}
|
||||
onChange={(value) => editTaskStatus(task.id, value)}
|
||||
>
|
||||
<div className="relative">
|
||||
<ListboxButton
|
||||
className="task-cell-status-indicator"
|
||||
style={{
|
||||
border: `1px solid ${lightTaskTextColor}`,
|
||||
color: lightTaskTextColor,
|
||||
}}
|
||||
>
|
||||
{status.name}
|
||||
</ListboxButton>
|
||||
<ListboxOptions className="task-cell-dropdown-options">
|
||||
{taskStatuses.map((s) => (
|
||||
<ListboxOption
|
||||
key={s.id}
|
||||
value={s.id}
|
||||
className={({ active }) =>
|
||||
`task-cell-dropdown-option ${active ? "active" : ""}`
|
||||
}
|
||||
>
|
||||
{s.name}
|
||||
</ListboxOption>
|
||||
))}
|
||||
</ListboxOptions>
|
||||
</div>
|
||||
</Listbox>
|
||||
</div>
|
||||
|
||||
<div className="task-cell-content">
|
||||
<input
|
||||
value={task.name}
|
||||
onChange={(e) => handleTaskNameChange(task.id, e.target.value)}
|
||||
onBlur={(e) => {
|
||||
if (e.target.value === "") removeTask(task.id);
|
||||
}}
|
||||
ref={inputRef}
|
||||
className={`task-input-${task.id}`}
|
||||
placeholder="Task name"
|
||||
style={{ color: lightTaskTextColor }}
|
||||
/>
|
||||
<style>{`
|
||||
.task-input-${task.id}::placeholder {
|
||||
color: ${placeholderColor};
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TaskCell;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import AppComponent from 'src/main/components/App';
|
|||
|
||||
export interface AppContext {
|
||||
app: App;
|
||||
loadData: () => any;
|
||||
saveData: (data: any) => Promise<void>;
|
||||
loadData: () => unknown;
|
||||
saveData: (data: unknown) => Promise<void>;
|
||||
}
|
||||
|
||||
export const TABLE_VIEW_TYPE = 'table-view';
|
||||
|
|
@ -20,10 +20,10 @@ export const useTableContext = (): AppContext | undefined => {
|
|||
export class TableView extends ItemView {
|
||||
root: Root | null = null;
|
||||
|
||||
loadData: () => any;
|
||||
saveData: (data: any) => Promise<void>;
|
||||
loadData: () => unknown;
|
||||
saveData: (data: unknown) => Promise<void>;
|
||||
|
||||
constructor(leaf: WorkspaceLeaf, loadData: () => any, saveData: (data: any) => Promise<void>) {
|
||||
constructor(leaf: WorkspaceLeaf, loadData: () => unknown, saveData: (data: unknown) => Promise<void>) {
|
||||
super(leaf);
|
||||
this.loadData = loadData;
|
||||
this.saveData = saveData;
|
||||
|
|
|
|||
Loading…
Reference in a new issue