Fixed projects
This commit is contained in:
15
src/client/src/components/common/buttons/outlinedButton.tsx
Normal file
15
src/client/src/components/common/buttons/outlinedButton.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ButtonHTMLAttributes, FC, forwardRef } from "react";
|
||||
|
||||
export const OutlinedButton: FC<ButtonHTMLAttributes<HTMLButtonElement>> = (
|
||||
props
|
||||
) => (
|
||||
<button
|
||||
{...props}
|
||||
tabIndex={3}
|
||||
type="button"
|
||||
className={"base-button " + props.className}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
19
src/client/src/components/common/buttons/primaryButton.tsx
Normal file
19
src/client/src/components/common/buttons/primaryButton.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { ButtonHTMLAttributes, FC } from "react";
|
||||
|
||||
export const PrimaryButton: FC<ButtonHTMLAttributes<HTMLButtonElement>> = (
|
||||
props
|
||||
) => (
|
||||
<button
|
||||
{...props}
|
||||
type="submit"
|
||||
onClick={props.onClick}
|
||||
tabIndex={2}
|
||||
disabled={props.disabled}
|
||||
className={
|
||||
"base-button bg-accent-500 disabled:bg-accent-800 active:bg-accent-400 border-none text-white " +
|
||||
props.className
|
||||
}
|
||||
>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
62
src/client/src/components/todos/add/addProjectButton.tsx
Normal file
62
src/client/src/components/todos/add/addProjectButton.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { ButtonHTMLAttributes, FC, useState } from "react";
|
||||
import { OutlinedButton } from "@src/components/common/buttons/outlinedButton";
|
||||
import Tippy from "@tippyjs/react";
|
||||
|
||||
interface AddProjectButtonProps
|
||||
extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
initialProject: string;
|
||||
onProjectChanged: (project: string) => void;
|
||||
}
|
||||
|
||||
export const AddProjectButton: FC<AddProjectButtonProps> = (props) => {
|
||||
const [menuIsOpen, setMenuIsOpen] = useState(false);
|
||||
const [project, setProject] = useState(props.initialProject);
|
||||
return (
|
||||
<Tippy
|
||||
placement="bottom"
|
||||
visible={menuIsOpen}
|
||||
onClickOutside={() => {
|
||||
setMenuIsOpen(false);
|
||||
}}
|
||||
delay={0}
|
||||
interactive={true}
|
||||
duration={0}
|
||||
content={
|
||||
<div
|
||||
className="py-2 px-4 bg-white dark:bg-gray-700 border border-accent-500 rounded-md flex flex-col gap-4"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
tabIndex={0}
|
||||
autoFocus
|
||||
value={project}
|
||||
className="whitespace-nowrap"
|
||||
onChange={(e) => setProject(e.target.value)}
|
||||
placeholder="Project"
|
||||
onKeyDown={(k) => {
|
||||
if (k.key === "Enter") {
|
||||
props.onProjectChanged(project);
|
||||
}
|
||||
}}
|
||||
onBlur={() => {
|
||||
props.onProjectChanged(project);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<OutlinedButton
|
||||
className="whitespace-nowrap"
|
||||
{...props}
|
||||
onClick={() => setMenuIsOpen(true)}
|
||||
>
|
||||
{props.children || "Add project"}
|
||||
</OutlinedButton>
|
||||
</span>
|
||||
</Tippy>
|
||||
);
|
||||
};
|
42
src/client/src/components/todos/add/addTodoForm.tsx
Normal file
42
src/client/src/components/todos/add/addTodoForm.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { FC, useState } from "react";
|
||||
import { OutlinedButton } from "@src/components/common/buttons/outlinedButton";
|
||||
import { PrimaryButton } from "@src/components/common/buttons/primaryButton";
|
||||
import { TodoShortForm } from "@src/components/todos/collapsed/todoShortForm";
|
||||
|
||||
export const AddTodoForm: FC<{
|
||||
onAdd: (todoName: string, project: string) => void;
|
||||
onClose: () => void;
|
||||
project: string;
|
||||
}> = ({ onAdd, onClose, ...props }) => {
|
||||
const [todoName, setTodoName] = useState("");
|
||||
const [todoDescription, setTodoDescription] = useState("");
|
||||
const [project, setProject] = useState(props.project);
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
onAdd(todoName, project);
|
||||
setTodoName("");
|
||||
setTodoDescription("");
|
||||
}}
|
||||
>
|
||||
<div className="py-2 space-y-3">
|
||||
<TodoShortForm
|
||||
project={project}
|
||||
onProjectChanged={(p) => setProject(p)}
|
||||
name={todoName}
|
||||
onNameChange={(e) => setTodoName(e.target.value)}
|
||||
description={todoDescription}
|
||||
onDescriptionChange={(e) => setTodoDescription(e.target.value)}
|
||||
/>
|
||||
<div className="space-x-2">
|
||||
<PrimaryButton disabled={!todoName} type="submit">
|
||||
Add todo
|
||||
</PrimaryButton>
|
||||
<OutlinedButton onClick={onClose}>Cancel</OutlinedButton>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
@@ -1,6 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import { CollapsedAddTodo } from "@src/components/todos/collapsed/collapsedAddTodo";
|
||||
import { AddTodoForm } from "@src/components/todos/collapsed/addTodoForm";
|
||||
import { AddTodoForm } from "@src/components/todos/add/addTodoForm";
|
||||
import { CollapsedState } from "@src/components/todos/collapsed/collapsedState";
|
||||
import { useCreateTodo } from "@src/presentation/hooks/socketHooks";
|
||||
|
||||
|
@@ -1,64 +0,0 @@
|
||||
import { FC, useState } from "react";
|
||||
|
||||
export const AddTodoForm: FC<{
|
||||
onAdd: (todoName: string, project: string) => void;
|
||||
onClose: () => void;
|
||||
project: string;
|
||||
}> = ({ onAdd, onClose, ...props }) => {
|
||||
const [todoName, setTodoName] = useState("");
|
||||
const [project, setProject] = useState(props.project);
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
onAdd(todoName, project);
|
||||
setTodoName("");
|
||||
}}
|
||||
>
|
||||
<div className="py-2 space-y-3">
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<div className="todo-input-form md:flex-grow py-2 px-4 bg-gray-800 border border-gray-500 rounded-lg">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Todo name"
|
||||
className="text-sm w-full"
|
||||
autoFocus
|
||||
value={todoName}
|
||||
tabIndex={1}
|
||||
onChange={(e) => setTodoName(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="todo-project py-2 px-4 bg-gray-700 border border-gray-500 rounded-lg ">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Project name"
|
||||
className="text-sm w-full placeholder-gray-400"
|
||||
value={project}
|
||||
tabIndex={2}
|
||||
onChange={(e) => setProject(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-x-2">
|
||||
<button
|
||||
type="submit"
|
||||
tabIndex={2}
|
||||
disabled={!todoName}
|
||||
className="base-button dark:bg-accent-500 disabled:bg-accent-800 active:bg-accent-400"
|
||||
>
|
||||
Add todo
|
||||
</button>
|
||||
<button
|
||||
tabIndex={3}
|
||||
type="button"
|
||||
className="base-button"
|
||||
onClick={onClose}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
48
src/client/src/components/todos/collapsed/todoShortForm.tsx
Normal file
48
src/client/src/components/todos/collapsed/todoShortForm.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import TextareaAutosize from "react-textarea-autosize";
|
||||
import { AddProjectButton } from "@src/components/todos/add/addProjectButton";
|
||||
|
||||
export const TodoShortForm = (props: {
|
||||
project: string;
|
||||
onProjectChanged: (project: string) => void;
|
||||
name: string;
|
||||
onNameChange: (e) => void;
|
||||
description: string;
|
||||
onDescriptionChange: (e) => void;
|
||||
}) => (
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<div className="todo-input-form md:flex-grow py-2 px-4 dark:bg-gray-800 border border-gray-200 rounded-lg space-y-2">
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Todo name"
|
||||
className="text-sm w-full"
|
||||
autoFocus
|
||||
value={props.name}
|
||||
tabIndex={1}
|
||||
onChange={props.onNameChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="h-px bg-gray-200 dark:bg-gray-500" />
|
||||
<div>
|
||||
<TextareaAutosize
|
||||
placeholder="Description"
|
||||
className="text-sm w-full h-full resize-none overflow-auto"
|
||||
value={props.description}
|
||||
tabIndex={2}
|
||||
onChange={props.onDescriptionChange}
|
||||
minRows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row pb-1">
|
||||
<AddProjectButton
|
||||
onProjectChanged={props.onProjectChanged}
|
||||
initialProject={props.project}
|
||||
>
|
||||
{props.project}
|
||||
</AddProjectButton>
|
||||
<div className="flex-grow w-1/2" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
Reference in New Issue
Block a user