Skip to content

Commit

Permalink
Create board js
Browse files Browse the repository at this point in the history
  • Loading branch information
sasanqc committed Jun 15, 2023
1 parent af784dd commit 67286f1
Show file tree
Hide file tree
Showing 20 changed files with 745 additions and 172 deletions.
50 changes: 29 additions & 21 deletions components/BoardsList.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
import React from "react";
import BoardIcon from "@/icons/icon-board.svg";
const BoardsList = () => {
import BoardListProps from "@/model/BoardListProps";
const BoardsList: React.FC<BoardListProps> = ({
boards,
activeBoard = 0,
onChangedaActiveBoard,
onAddNewBoard,
}) => {
return (
<div>
<h4 className="text-gray3 pl-8 mb-5 mt-4">all boards (3)</h4>
<h4 className="text-gray3 pl-8 mb-5 mt-4">
all boards ({boards.length})
</h4>
<ul>
<li className=" flex pl-8 py-4 gap-x-4 mr-6 items-center text-white bg-primary2 rounded-r-full ">
<span>
<BoardIcon />
</span>
<h3>Platform Launch</h3>
</li>
<li className=" flex pl-8 py-4 gap-x-4 mr-6 items-center text-gray3 rounded-r-full ">
<span>
<BoardIcon />
</span>
<h3>Marketing Plan</h3>
</li>
<li className=" flex pl-8 py-4 gap-x-4 mr-6 items-center text-gray3 rounded-r-full ">
<span>
<BoardIcon />
</span>
<h3>Roadmap</h3>
</li>
<li className=" flex pl-8 py-4 gap-x-4 mr-6 items-center text-primary2 rounded-r-full ">
{boards.map((board, i) => (
<li
key={i}
className={`flex pl-8 py-4 gap-x-4 mr-6 items-center rounded-r-full cursor-pointer ${
activeBoard === i ? "bg-primary2 text-white" : "text-gray3"
}`}
onClick={() => onChangedaActiveBoard(i)}
>
<span>
<BoardIcon />
</span>
<h3>{board.name}</h3>
</li>
))}

<li
className=" flex pl-8 py-4 gap-x-4 mr-6 items-center text-primary2 rounded-r-full cursor-pointer"
onClick={onAddNewBoard}
>
<span>
<BoardIcon />
</span>
Expand Down
90 changes: 57 additions & 33 deletions components/CreateBoard.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,77 @@
import { useState } from "react";
import TextInput from "./UI/TextInput";
import CrossIcon from "@/icons/icon-cross.svg";
import Button from "./UI/Button";
import Select from "./UI/Select";

const CreateBoard = () => {
const [columns, setColumns] = useState(["", ""]);
const [name, setName] = useState("");

const handleDeleteColumn = (e: MouseEvent, index: number) => {
e.stopPropagation();
const updatedColumns = [...columns];
updatedColumns.splice(index, 1);
setColumns(updatedColumns);
};

const onChangedName = (e: React.FormEvent<HTMLInputElement>) => {
setName((e.target as HTMLInputElement).value);
};

const handleChangedColumn = (
e: React.FormEvent<HTMLInputElement>,
index: number
) => {
const updatedColumns = [...columns];
updatedColumns[index] = (e.target as HTMLInputElement).value;
setColumns(updatedColumns);
};

const onCreateNewBoard = () => {};
return (
<div className="modal-content space-y-6 ">
<h2 className="text-black4 ">Add New Board</h2>

<TextInput label={"Name"} placeholder={"e.g. Web Design"} name={"name"} />
<div className="mt-2 space-y-3 ">
<h2 className="text-black4 dark:text-white">Add New Board</h2>
<TextInput
label={"Name"}
placeholder={"e.g. Web Design"}
name={"name"}
value={name}
onChange={onChangedName}
/>
<div className="mt-2 space-y-2 ">
<label htmlFor="title" className="block text-gray3 text-sm font-bold">
Columns
</label>
<div className="flex items-center">
<Select
items={[
{ label: "Todo", value: "todo" },
{ label: "Doing", value: "doing" },
{ label: "Done", value: "done" },
]}
onChanged={() => {}}
/>
<div className="ml-4 cursor-pointer">
<CrossIcon />
</div>
</div>
<div className="flex items-center ">
<Select
items={[
{ label: "Todo", value: "todo" },
{ label: "Doing", value: "doing" },
{ label: "Done", value: "done" },
]}
onChanged={() => {}}
/>
<div className="ml-4 cursor-pointer">
<CrossIcon />
</div>
</div>
<ul className="space-y-2 ">
{columns.map((col, index) => (
<li className="flex items-center " key={index}>
<TextInput
placeholder={"e.g. TODO"}
name={"name"}
onChange={(e: React.FormEvent<HTMLInputElement>) =>
handleChangedColumn(e, index)
}
value={columns[index]}
/>
<div className="ml-4 cursor-pointer">
<CrossIcon
onClick={(e: MouseEvent) => handleDeleteColumn(e, index)}
/>
</div>
</li>
))}
</ul>

<Button
type={"small secondary"}
classes="w-full"
label="+ Add New Column"
onClick={() => {}}
onClick={() => setColumns((prev) => [...prev, ""])}
/>
</div>
<Button
label="Create New Board"
onClick={() => {}}
onClick={onCreateNewBoard}
classes={"w-full"}
type={"primary small"}
/>
Expand Down
2 changes: 1 addition & 1 deletion components/MobileBoards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ToggleTheme from "./ToggleTheme";
const MobileBoards = () => {
return (
<div className="bg-white rounded-md pt-2 mx-7">
<BoardsList />
{/* <BoardsList /> */}
<div className="p-4">
<ToggleTheme />
</div>
Expand Down
77 changes: 24 additions & 53 deletions components/TaskColumn.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,33 @@
const TaskColumn = () => {
import Task from "@/model/Task";

interface TaskColumnProps {
col: { name: string; tasks: Task[] };
}
const TaskColumn: React.FC<TaskColumnProps> = ({ col }) => {
const doneSubtasksNumber = (task: Task) => {
return task.subtasks.filter((el) => el.isCompleted).length;
};
return (
<div className="w-[280px] shrink-0 h-full">
<div className="flex mb-6">
<div className="w-4 h-4 bg-primary2 rounded-full inline-block mr-3"></div>
<h4 className="text-gray3">todo (4)</h4>
<h4 className="text-gray3">
{col.name} ({col.tasks.length})
</h4>
</div>
<ul className="space-y-5 pb-6 ">
<li>
<section className="py-6 px-4 bg-white dark:bg-black2 rounded-lg shadow-task">
<h3 className="mb-2">
Build UI for onboarding flow.Build UI for onboarding flow .Build
UI for onboarding flow
</h3>
<p className="text-sm text-gray3 font-bold ">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Sit vel,
voluptatum libero dolorum repudiandae nisi ducimus facilis. Illum,
provident tempore.
</p>
</section>
</li>
<li>
<section className="py-6 px-4 bg-white dark:bg-black2 rounded-lg shadow-task">
<h3 className="mb-2">Build UI for onboarding flow</h3>
<p className="text-sm text-gray3 font-bold ">0 of 3 substasks</p>
</section>
</li>
<li>
<section className="py-6 px-4 bg-white dark:bg-black2 rounded-lg shadow-task">
<h3 className="mb-2">
Build UI for onboarding flow.Build UI for onboarding flow .Build
UI for onboarding flow
</h3>
<p className="text-sm text-gray3 font-bold ">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Sit vel,
voluptatum libero dolorum repudiandae nisi ducimus facilis. Illum,
provident tempore.
</p>
</section>
</li>
<li>
<section className="py-6 px-4 bg-white dark:bg-black2 rounded-lg shadow-task">
<h3 className="mb-2">
Build UI for onboarding flow.Build UI for onboarding flow .Build
UI for onboarding flow
</h3>
<p className="text-sm text-gray3 font-bold ">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Sit vel,
voluptatum libero dolorum repudiandae nisi ducimus facilis. Illum,
provident tempore.
</p>
</section>
</li>
<li>
<section className="py-6 px-4 bg-white dark:bg-black2 rounded-lg shadow-task">
<h3 className="mb-2">Build UI for onboarding flow</h3>
<p className="text-sm text-gray3 font-bold ">0 of 3 substasks</p>
</section>
</li>
{col.tasks.map((task, index) => (
<li key={index}>
<section className="py-6 px-4 bg-white dark:bg-black2 rounded-lg shadow-task">
<h3 className="mb-2">{task.title}</h3>
<p className="text-sm text-gray3 font-bold ">
{`${doneSubtasksNumber(task)} of ${
task.subtasks.length
} subtasks`}
</p>
</section>
</li>
))}
</ul>
</div>
);
Expand Down
22 changes: 20 additions & 2 deletions components/ToggleTheme.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import React from "react";
import React, { useState, useEffect } from "react";
import DarkThemeIcon from "@/icons/icon-dark-theme.svg";
import LightThemeIcon from "@/icons/icon-light-theme.svg";

const ToggleTheme = () => {
const [toggle, setToggle] = useState("light");
const handleChangedTheme = () => {
const html = document.querySelector("html");
html?.classList.toggle("dark");
localStorage.setItem("theme", toggle === "dark" ? "light" : "dark");
setToggle(toggle === "dark" ? "light" : "dark");
};
useEffect(() => {
setToggle(localStorage.getItem("theme") || "light");
return () => {};
}, []);

return (
<div className="bg-white2 dark:bg-black3 w-full flex items-center py-4 justify-center rounded-md gap-x-6">
<LightThemeIcon />
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" value="" className="sr-only peer"></input>
<input
type="checkbox"
checked={toggle === "dark"}
onChange={handleChangedTheme}
className="sr-only peer"
></input>
<div className="w-10 h-5 bg-gray-200 peer-focus:outline-none rounded-full dark:bg-gray-700 peer-checked:after:translate-x-5 after:content-[''] after:absolute after:top-[3px] after:left-[3px] after:bg-white after:rounded-full after:h-[14px] after:w-[14px] after:transition-all bg-primary2"></div>
</label>
<DarkThemeIcon />
Expand Down
28 changes: 26 additions & 2 deletions components/UI/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,39 @@
import { useEffect, useRef, useCallback } from "react";
interface ModalProps {
children: React.ReactNode;
center?: boolean;
onClickBackdrop: () => void;
}

const Modal: React.FC<ModalProps> = ({ children, center = true }) => {
const Modal: React.FC<ModalProps> = ({
children,
center = true,
onClickBackdrop,
}) => {
const modalRef = useRef<HTMLDivElement>(null);

const backDropHandler = useCallback((e: MouseEvent) => {
if (!modalRef?.current?.contains(e.target as Node)) {
console.log("on click on backdrop");
onClickBackdrop();
}
}, []);

useEffect(() => {
setTimeout(() => {
window.addEventListener("click", backDropHandler);
});
return () => {
window.removeEventListener("click", backDropHandler);
};
}, []);
return (
<div className=" w-screen h-screen absolute top-0 left-0 z-50 bg-[#00000080]">
<div className=" w-screen h-screen absolute top-0 left-0 z-10 bg-[#00000080]">
<div
className={`w-full md:w-fit md:left-1/2 absolute md:-translate-x-1/2 px-4 ${
center ? "top-1/2 -translate-y-1/2" : "top-24"
}`}
ref={modalRef}
>
{children}
</div>
Expand Down
29 changes: 18 additions & 11 deletions components/UI/Select.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useRef, useEffect } from "react";
import { useState, useRef, useEffect, useCallback } from "react";
import ChevronDownIcon from "@/icons/icon-chevron-down.svg";

interface SelectProps {
Expand All @@ -16,7 +16,8 @@ const Select: React.FC<SelectProps> = ({ items, label, onChanged }) => {
setIsOpen(true);
};

const handleSelectedItem = (e: React.MouseEvent<HTMLUListElement>) => {
const handleSelectedItem = (e: MouseEvent) => {
e.stopPropagation();
const value = (e.target as HTMLElement).getAttribute("data-value");

if (value) {
Expand All @@ -25,16 +26,22 @@ const Select: React.FC<SelectProps> = ({ items, label, onChanged }) => {
onChanged(value);
}
};
const handleClickOnWindow = useCallback((e: MouseEvent) => {
if (
dropDownRef.current &&
!dropDownRef.current.contains(e.target as Node)
) {
setIsOpen(false);
}
}, []);

useEffect(() => {
window.document.addEventListener("click", (e: MouseEvent) => {
if (
dropDownRef.current &&
!dropDownRef.current.contains(e.target as Node)
) {
setIsOpen(false);
}
window.addEventListener("click", handleClickOnWindow, {
capture: false,
});
return () => {};
return () => {
window.removeEventListener("click", handleClickOnWindow);
};
}, []);

return (
Expand All @@ -50,7 +57,7 @@ const Select: React.FC<SelectProps> = ({ items, label, onChanged }) => {
</div>
{isOpen && (
<ul
className="bg-white p-4 text-gray3 absolute mt-2 rounded-lg w-full space-y-2 z-20"
className="bg-white dark:bg-black3 p-4 text-gray3 absolute mt-2 rounded-lg w-full space-y-2 z-20"
onClick={handleSelectedItem}
>
{items.map((el) => (
Expand Down
Loading

0 comments on commit 67286f1

Please sign in to comment.