From 3c1b6516a5d1eb1f6d629ad33c8e6a4cd6c28526 Mon Sep 17 00:00:00 2001
From: okplanb <26038255+ok-plan-b@users.noreply.github.com>
Date: Sat, 25 Nov 2023 14:07:48 +0400
Subject: [PATCH 1/2] feat: removed ripple effect
---
src/main.tsx | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/main.tsx b/src/main.tsx
index 744deb9..ed796cc 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,12 +1,25 @@
import React from "react";
import ReactDOM from "react-dom/client";
+import { createTheme, ThemeProvider } from '@mui/material';
import App from "./App.tsx";
import "@fontsource/roboto/latin-300.css";
+const theme = createTheme({
+ components: {
+ MuiButtonBase: {
+ defaultProps: {
+ disableRipple: true,
+ },
+ },
+ },
+});
+
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
-
+
+
+
);
From dcfc62c5a02841f8060def0f6771ef8caca03c09 Mon Sep 17 00:00:00 2001
From: okplanb <26038255+ok-plan-b@users.noreply.github.com>
Date: Fri, 15 Dec 2023 03:03:15 +0400
Subject: [PATCH 2/2] feat: [S1] edit modal implemented
---
index.html | 2 +-
package.json | 6 +-
src/App.scss | 8 ++
src/App.tsx | 223 +++++++++++++++++++++++++++++++++++++++--------
src/constants.ts | 6 +-
src/helpers.ts | 13 +++
yarn.lock | 10 +++
7 files changed, 226 insertions(+), 42 deletions(-)
create mode 100644 src/helpers.ts
diff --git a/index.html b/index.html
index 8b53bb5..d4e76fd 100644
--- a/index.html
+++ b/index.html
@@ -8,7 +8,7 @@
-
Vite + React + TS
+ Sia | Minimalistic ToDo list
diff --git a/package.json b/package.json
index fe31dbd..e0364cb 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "sia",
"private": true,
- "version": "0.1.0",
+ "version": "0.2.0",
"type": "module",
"scripts": {
"dev": "vite",
@@ -24,12 +24,14 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-infinite-scroll-component": "^6.1.0",
- "react-router-dom": "^6.12.1"
+ "react-router-dom": "^6.12.1",
+ "uuid": "^9.0.1"
},
"devDependencies": {
"@types/node": "^20.2.5",
"@types/react": "^18.0.37",
"@types/react-dom": "^18.0.11",
+ "@types/uuid": "^9.0.7",
"@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^5.59.0",
"@vitejs/plugin-react": "^4.0.0",
diff --git a/src/App.scss b/src/App.scss
index 6f3187b..c5aaf52 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -36,6 +36,14 @@ a {
.item {
padding: 0.2rem;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.item span:last-child {
+ overflow: hidden;
+ text-overflow: ellipsis;
}
#root .progress {
diff --git a/src/App.tsx b/src/App.tsx
index 18e3896..ff92573 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,24 +1,33 @@
-import { useCallback, useState } from "react";
+import { useCallback, useState, useRef } from "react";
+import { v4 as uuidv4 } from 'uuid';
import { Paper, Tooltip, FormControlLabel, Checkbox, Dialog, DialogActions,
DialogContent, DialogContentText, DialogTitle, Typography, LinearProgress,
- Button, useMediaQuery, Box } from "@mui/material";
+ Button, IconButton, useMediaQuery, Box, Input } from "@mui/material";
+import AddIcon from '@mui/icons-material/Add';
+import DeleteIcon from '@mui/icons-material/Delete';
import { useTheme } from '@mui/material/styles';
-import { basicList, storage_key, tooptip_offset, total_percent } from ":src/constants";
+import { debounce } from ":src/helpers";
+import { basicList, debounce_delay, storage_key,
+ task_input_limit, tooptip_offset, total_percent } from ":src/constants";
import "./App.scss";
type Task = {
description: string;
checked: boolean;
+ key: string;
};
-const initialTasks: Task[] = basicList.map(description => {
- return { description, checked: false }
-});
-initialTasks[0].checked = true;
+function getInitialTasks() {
+ const initialTasks: Task[] = basicList.map(description => {
+ return { description, checked: false, key: uuidv4() }
+ });
+ initialTasks[0].checked = true;
+ return initialTasks;
+}
const saved_tasks = localStorage.getItem(storage_key);
@@ -33,11 +42,14 @@ const calcProgress = (tasks: Task[]) => {
}
export default function App(): JSX.Element {
- const [tasks, setTasks] = useState(saved_tasks ? JSON.parse(saved_tasks) : initialTasks);
+ const [tasks, setTasks] = useState(saved_tasks ? JSON.parse(saved_tasks) : getInitialTasks());
+ const [editedTasks, setEditedTasks] = useState([]);
const [progress, setProgress] = useState(calcProgress(tasks));
- const [open, setOpen] = useState(false);
+ const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
+ const [isConfirmOpen, setIsConfirmOpen] = useState(false);
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down('md'));
+ const addButtonRef = useRef(null);
const updateTasks = (newTasks: Task[]) => {
localStorage.setItem(storage_key, JSON.stringify(newTasks));
@@ -52,22 +64,72 @@ export default function App(): JSX.Element {
}, [tasks]);
const handleRestart = useCallback(() => {
- const newTasks = initialTasks;
+ const newTasks = tasks.slice();
+ newTasks.forEach(task => task.checked = false);
+ updateTasks(newTasks);
+ setIsConfirmOpen(false);
+ }, [tasks]);
+
+ const handleConfirmOpen = () => {
+ setIsConfirmOpen(true);
+ };
+
+ const handleConfirmClose = () => {
+ setIsConfirmOpen(false);
+ };
+
+ const handleEdit = () => {
+ setEditedTasks(tasks.slice());
+ setIsEditDialogOpen(true);
+ };
+
+ const handleCancelEdit = () => {
+ setIsEditDialogOpen(false);
+ };
+
+ const handleAddNewTask = () => {
+ const newTasks = editedTasks.slice();
+ newTasks.push({
+ key: uuidv4(),
+ description: '',
+ checked: false
+ });
+ setEditedTasks(newTasks);
+ addButtonRef.current?.scrollIntoView({behavior: 'smooth', inline: 'end' });
+ };
+
+ const handleSaveChanges = () => {
+ setIsEditDialogOpen(false);
+ const newTasks = editedTasks.filter(task => task.description);
updateTasks(newTasks);
- setOpen(false);
- }, []);
+ };
+
+ const debouncedUpdate = debounce((newDescription: string, key: string) => {
+ const tasks = editedTasks.map(task => {
+ if (task.key === key) {
+ task.description = newDescription;
+ }
+ return task;
+ });
+ setEditedTasks(tasks);
+ }, debounce_delay);
- const handleDialogOpen = () => {
- setOpen(true);
+ const handleTaskEdit = (value: string, key: string) => {
+ debouncedUpdate(value, key);
};
-
- const handleDialogClose = () => {
- setOpen(false);
+
+ const handleDeleteTask = (key: string) => {
+ const tasks = editedTasks.filter(task => task.key !== key);
+ setEditedTasks(tasks);
};
return (
<>
-
+
-
- {tasks.map((task, index) => (
- toggleTask(index)}
- />
- }
- />
- ))}
-
+
+ { tasks.length === 0 ? (
+
+ It is so empty here... What's the plan? :)
+
+ ) : (
+
+ {tasks.map((task, index) => (
+ toggleTask(index)}
+ />
+ }
+ />
+ ))}
+
+ )}
+
-
+
+
+
+
+
+
+ {/* Editing */}
+
+
+
+ {/* Restart Confirmation */}
+