Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
Todo-Storybook
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Madhankumar
Todo-Storybook
Commits
98006a02
Commit
98006a02
authored
Sep 26, 2023
by
Madhankumar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
auto height textarea and loading
parent
a3281ff0
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
122 additions
and
105 deletions
+122
-105
db.json
db.json
+7
-36
index.js
src/app-context/index.js
+12
-4
layout.css
src/components/base/layout/layout.css
+6
-1
index.js
src/components/top-level/task/index.js
+62
-34
task.css
src/components/top-level/task/task.css
+12
-16
tasks.css
src/components/top-level/tasks/tasks.css
+3
-0
api.js
src/lib/api.js
+3
-4
index.js
src/pages/index.js
+17
-10
No files found.
db.json
View file @
98006a02
{
{
"task"
:
[
"task"
:
[
{
{
"title"
:
"
This HTML file is a template.
"
,
"title"
:
"
Buy a tomato
"
,
"isCompleted"
:
false
,
"isCompleted"
:
false
,
"id"
:
2
"id"
:
1
},
{
"title"
:
"This HTML file is a template. "
,
"isCompleted"
:
true
,
"id"
:
4
},
{
"title"
:
"hello"
,
"isCompleted"
:
false
,
"id"
:
5
},
{
"title"
:
"cscdcv"
,
"isCompleted"
:
false
,
"id"
:
6
},
},
{
{
"title"
:
"
vdvdcv
"
,
"title"
:
"
Go to office
"
,
"isCompleted"
:
false
,
"isCompleted"
:
false
,
"id"
:
7
"id"
:
2
},
{
"title"
:
"vdvdv"
,
"isCompleted"
:
false
,
"id"
:
8
},
{
"title"
:
"ddvdvd"
,
"isCompleted"
:
true
,
"id"
:
9
},
{
"title"
:
"dvdvdvd"
,
"isCompleted"
:
false
,
"id"
:
10
},
},
{
{
"title"
:
"
wwww
"
,
"title"
:
"
Party time
"
,
"isCompleted"
:
false
,
"isCompleted"
:
false
,
"id"
:
11
"id"
:
3
}
}
]
]
}
}
\ No newline at end of file
src/app-context/index.js
View file @
98006a02
...
@@ -6,7 +6,7 @@ export const useAppContext = () => useContext(TodoContext);
...
@@ -6,7 +6,7 @@ export const useAppContext = () => useContext(TodoContext);
export
function
TodoProvider
({
children
})
{
export
function
TodoProvider
({
children
})
{
const
[
todo
,
setTodo
]
=
useState
([]);
const
[
todo
,
setTodo
]
=
useState
([]);
const
[
loading
,
setLoading
]
=
useState
(
false
);
//POST METHOD
//POST METHOD
async
function
addTodo
({
title
})
{
async
function
addTodo
({
title
})
{
try
{
try
{
...
@@ -21,7 +21,11 @@ export function TodoProvider({ children }) {
...
@@ -21,7 +21,11 @@ export function TodoProvider({ children }) {
async
function
updateTodo
({
id
,
title
,
isCompleted
})
{
async
function
updateTodo
({
id
,
title
,
isCompleted
})
{
try
{
try
{
const
response
=
await
api
.
updateTodo
({
id
,
title
,
isCompleted
});
const
response
=
await
api
.
updateTodo
({
id
,
title
,
isCompleted
});
setTodo
(
response
);
// const index = todo.map((item) => item.id).indexOf(id);
// todo.splice(index, 1, { id, title, isCompleted });
const
data
=
await
response
.
json
();
setTodo
(
todo
.
map
((
e
)
=>
(
e
.
id
===
id
?
data
:
e
)));
}
catch
(
err
)
{
}
catch
(
err
)
{
toast
.
error
(
err
.
message
);
toast
.
error
(
err
.
message
);
}
}
...
@@ -32,6 +36,8 @@ export function TodoProvider({ children }) {
...
@@ -32,6 +36,8 @@ export function TodoProvider({ children }) {
try
{
try
{
const
response
=
await
api
.
getTodos
();
const
response
=
await
api
.
getTodos
();
setTodo
(
response
);
setTodo
(
response
);
setLoading
(
true
);
return
response
;
}
catch
(
err
)
{
}
catch
(
err
)
{
toast
.
error
(
err
.
message
);
toast
.
error
(
err
.
message
);
}
}
...
@@ -40,8 +46,9 @@ export function TodoProvider({ children }) {
...
@@ -40,8 +46,9 @@ export function TodoProvider({ children }) {
//DELETE METHOD
//DELETE METHOD
async
function
deleteTodo
(
id
)
{
async
function
deleteTodo
(
id
)
{
try
{
try
{
const
response
=
await
api
.
deleteTodo
(
id
);
await
api
.
deleteTodo
(
id
);
setTodo
(
response
);
setTodo
(
todo
.
filter
((
e
)
=>
e
.
id
!==
id
));
}
catch
(
err
)
{
}
catch
(
err
)
{
toast
.
error
(
err
.
message
);
toast
.
error
(
err
.
message
);
}
}
...
@@ -49,6 +56,7 @@ export function TodoProvider({ children }) {
...
@@ -49,6 +56,7 @@ export function TodoProvider({ children }) {
const
value
=
{
const
value
=
{
todo
,
todo
,
loading
,
addTodo
,
addTodo
,
getTodos
,
getTodos
,
deleteTodo
,
deleteTodo
,
...
...
src/components/base/layout/layout.css
View file @
98006a02
.container
{
.container
{
box-shadow
:
rgba
(
0
,
0
,
0
,
0.09
)
0px
3px
12px
;
box-shadow
:
rgba
(
0
,
0
,
0
,
0.09
)
0px
3px
12px
;
background
:
white
;
background
:
white
;
min-height
:
40vh
;
}
}
.container
h2
{
.container
h2
{
box-shadow
:
rgba
(
0
,
0
,
0
,
0.08
)
0px
3px
5px
;
box-shadow
:
rgba
(
0
,
0
,
0
,
0.08
)
0px
3px
5px
;
...
@@ -10,6 +9,12 @@
...
@@ -10,6 +9,12 @@
padding
:
1.3rem
0px
;
padding
:
1.3rem
0px
;
margin
:
0
;
margin
:
0
;
}
}
h3
{
text-align
:
center
;
min-height
:
20
dvh
;
margin
:
1rem
auto
;
}
@media
screen
and
(
min-width
:
1024px
)
{
@media
screen
and
(
min-width
:
1024px
)
{
.container
{
.container
{
...
...
src/components/top-level/task/index.js
View file @
98006a02
...
@@ -8,6 +8,25 @@ function Task({ id = 1, title, isCompleted, onChange, onDelete }) {
...
@@ -8,6 +8,25 @@ function Task({ id = 1, title, isCompleted, onChange, onDelete }) {
const
[
debouncetitle
,
setDebounceTitle
]
=
useState
(
title
);
const
[
debouncetitle
,
setDebounceTitle
]
=
useState
(
title
);
const
[
ischeck
,
setIsCheck
]
=
useState
(
isCompleted
);
const
[
ischeck
,
setIsCheck
]
=
useState
(
isCompleted
);
const
textarea_ref
=
useRef
(
null
);
const
textarea_ref
=
useRef
(
null
);
//debounce
useEffect
(()
=>
{
//checking the content height and set on page load
// Optional: To ensure the textarea resizes initially if there's content
const
scrollHeight
=
textarea_ref
.
current
.
scrollHeight
-
4
;
textarea_ref
.
current
.
style
.
height
=
`
${
scrollHeight
}
px`
;
//after 2 second it will execute
const
handler
=
setTimeout
(()
=>
{
if
(
textarea_ref
.
current
.
value
!==
title
)
{
onChange
({
id
,
title
:
debouncetitle
});
// toast.success("Task updated");
}
},
2000
);
return
()
=>
{
clearTimeout
(
handler
);
};
},
[
debouncetitle
]);
const
handleDelete
=
(
e
)
=>
{
const
handleDelete
=
(
e
)
=>
{
e
.
preventDefault
();
e
.
preventDefault
();
...
@@ -30,51 +49,59 @@ function Task({ id = 1, title, isCompleted, onChange, onDelete }) {
...
@@ -30,51 +49,59 @@ function Task({ id = 1, title, isCompleted, onChange, onDelete }) {
const
handleContent
=
(
e
)
=>
{
const
handleContent
=
(
e
)
=>
{
setDebounceTitle
(
e
.
target
.
value
);
setDebounceTitle
(
e
.
target
.
value
);
const
textareaRef
=
textarea_ref
.
current
;
const
textareaRef
=
textarea_ref
.
current
;
textareaRef
.
addEventListener
(
"input"
,
function
()
{
textareaRef
.
addEventListener
(
"input"
,
function
()
{
this
.
style
.
height
=
"
auto
"
;
// Reset the height to auto to calculate the correct scrollHeight
this
.
style
.
height
=
"
25px
"
;
// Reset the height to auto to calculate the correct scrollHeight
const
scrollHeight
=
this
.
scrollHeight
;
this
.
style
.
overflow
=
"hidden"
;
if
(
this
.
scrollTop
===
0
)
{
// Check if the textarea is empty or null and set its height accordingly
this
.
style
.
height
=
`
${
scrollHeight
}
px`
;
if
(
textareaRef
.
value
===
""
||
textareaRef
.
value
===
null
)
{
this
.
style
.
height
=
"25px"
;
// Minimum height of 25px when empty
}
else
{
}
else
{
// If there is overflow (a new line is created), increase the height
// Calculate the new scrollHeight and set the height
this
.
style
.
height
=
`
${
scrollHeight
+
this
.
scrollTop
}
px`
;
const
newScrollHeight
=
Math
.
max
(
this
.
scrollHeight
-
4
,
25
);
// Minimum height of 25px
this
.
style
.
height
=
newScrollHeight
+
"px"
;
}
});
textareaRef
.
addEventListener
(
"keyup"
,
function
(
event
)
{
if
(
event
.
key
===
"Backspace"
&&
(
textareaRef
.
value
===
""
||
textareaRef
.
value
===
null
)
)
{
this
.
style
.
height
=
"25px"
;
// Minimum height of 25px when empty
}
else
{
console
.
log
(
"dkod"
);
this
.
style
.
height
=
"25px"
;
const
newScrollHeight
=
this
.
scrollHeight
-
4
;
// Minimum height of 25px
this
.
style
.
height
=
newScrollHeight
+
"px"
;
}
}
});
});
// Optional: To ensure the textarea resizes initially if there's content
// textareaRef.addEventListener("input", function () {
textareaRef
.
dispatchEvent
(
new
Event
(
"input"
));
// this.style.height = "25px"; // Reset the height to auto to calculate the correct scrollHeight
// this.style.overflow = "hidden";
//const textarea = document.querySelector("textarea");
// // Check if the textarea is empty or null and set its height accordingly
//calculate the height of content based on scrollheight
// textarea.addEventListener("keyup", (e) => {
// let scheight = e.target.scrollHeight;
// textarea.style.height = `${scheight}px`;
// });
};
//debounce
// // Calculate the new scrollHeight and set the height
useEffect
(()
=>
{
// const newScrollHeight = Math.max(this.scrollHeight - 4, 25); // Minimum height of 25px
//
checking the content height and set on page load
//
this.style.height = newScrollHeight + "px";
const
scrollHeight
=
textarea_ref
.
current
.
scrollHeight
;
// })
;
textarea_ref
.
current
.
style
.
height
=
`
${
scrollHeight
}
px`
;
// textareaRef.addEventListener("keyup", function (event) {
//
after 2 second it will execute
//
if (
const
handler
=
setTimeout
(()
=>
{
// event.key === "Backspace" &&
if
(
textarea_ref
.
current
.
value
!==
title
)
{
// (textareaRef.value === "" || textareaRef.value === null)
onChange
({
id
,
title
:
debouncetitle
});
// ) {
// toast.success("Task updated");
// this.style.height = "29px"; // Minimum height of 25px when empty
}
//
}
},
2000
);
// else{
return
()
=>
{
// }
clearTimeout
(
handler
);
// });
};
};
},
[
debouncetitle
]);
return
(
return
(
<
div
className
=
"task-section"
>
<
div
className
=
"task-section"
>
<
div
>
<
div
className
=
"task"
>
<
Checkbox
<
Checkbox
onChange
=
{
handleChange
}
onChange
=
{
handleChange
}
checked
=
{
ischeck
}
checked
=
{
ischeck
}
...
@@ -86,8 +113,9 @@ function Task({ id = 1, title, isCompleted, onChange, onDelete }) {
...
@@ -86,8 +113,9 @@ function Task({ id = 1, title, isCompleted, onChange, onDelete }) {
className
=
{
`
${
ischeck
?
"strike-through"
:
""
}
`
}
className
=
{
`
${
ischeck
?
"strike-through"
:
""
}
`
}
value
=
{
debouncetitle
}
value
=
{
debouncetitle
}
onChange
=
{
handleContent
}
onChange
=
{
handleContent
}
// disabled={ischeck}
// disabled={ischeck}
><
/textarea
>
/
>
<
/div
>
<
/div
>
<
FaTimesCircle
className
=
"fa-close"
onClick
=
{
handleDelete
}
/
>
<
FaTimesCircle
className
=
"fa-close"
onClick
=
{
handleDelete
}
/
>
<
/div
>
<
/div
>
...
...
src/components/top-level/task/task.css
View file @
98006a02
.task-section
{
.task-section
{
padding
:
1rem
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
padding
:
0.3rem
1.4rem
;
justify-content
:
space-between
;
border-top
:
1.5px
solid
#e0e0e0
;
border-top
:
1.5px
solid
#e0e0e0
;
/* box-shadow: rgba(0, 0, 0, 0.06) 0px 2px 4px 0px inset; */
/* box-shadow: rgba(0, 0, 0, 0.06) 0px 2px 4px 0px inset; */
clip-path
:
inset
(
0
-100vmax
);
/* clip-path: inset(0 -100vmax); */
}
}
.task-section
:first-child
{
.task-section
:first-child
{
border-top
:
none
;
border-top
:
none
;
}
}
.task-section
>
div
{
.task
{
height
:
100%
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
height
:
auto
;
justify-content
:
space-between
;
width
:
9
0%
;
width
:
10
0%
;
}
}
.fa-close
{
.fa-close
{
color
:
#ccc
;
color
:
#ccc
;
...
@@ -36,15 +36,11 @@ input:focus {
...
@@ -36,15 +36,11 @@ input:focus {
resize
:
none
;
resize
:
none
;
border
:
none
;
border
:
none
;
outline
:
none
;
outline
:
none
;
position
:
relative
;
height
:
25px
;
top
:
10px
;
margin
:
0
10px
;
margin-left
:
0.4rem
;
font-size
:
17px
;
color
:
#504e4e
;
font-family
:
"Open Sans"
,
sans-serif
;
font-weight
:
500
;
}
.task-section
textarea
::-webkit-scrollbar
{
color
:
#504e4e
;
width
:
0
;
font-size
:
large
;
font-family
:
system-ui
,
-apple-system
,
BlinkMacSystemFont
,
"Segoe UI"
,
Roboto
,
Oxygen
,
Ubuntu
,
Cantarell
,
"Open Sans"
,
"Helvetica Neue"
,
sans-serif
;
}
}
src/components/top-level/tasks/tasks.css
View file @
98006a02
...
@@ -12,3 +12,6 @@
...
@@ -12,3 +12,6 @@
.fa-close
{
.fa-close
{
cursor
:
pointer
;
cursor
:
pointer
;
}
}
.tasklist
{
min-height
:
25
dvh
;
}
src/lib/api.js
View file @
98006a02
...
@@ -17,12 +17,11 @@ export async function addTodo({ title, isCompleted }) {
...
@@ -17,12 +17,11 @@ export async function addTodo({ title, isCompleted }) {
//PATCH METHOD
//PATCH METHOD
export
async
function
updateTodo
({
id
,
title
,
isCompleted
})
{
export
async
function
updateTodo
({
id
,
title
,
isCompleted
})
{
try
{
try
{
await
fetch
(
url
+
`/
${
id
}
`
,
{
const
response
=
await
fetch
(
url
+
`/
${
id
}
`
,
{
method
:
"PATCH"
,
method
:
"PATCH"
,
headers
:
{
"Content-type"
:
"application/json"
},
headers
:
{
"Content-type"
:
"application/json"
},
body
:
JSON
.
stringify
({
title
,
isCompleted
}),
body
:
JSON
.
stringify
({
title
,
isCompleted
}),
});
});
const
response
=
await
getTodos
();
return
response
;
return
response
;
}
catch
(
err
)
{
}
catch
(
err
)
{
toast
.
error
(
err
.
message
);
toast
.
error
(
err
.
message
);
...
@@ -45,8 +44,8 @@ export async function deleteTodo(id) {
...
@@ -45,8 +44,8 @@ export async function deleteTodo(id) {
await
fetch
(
url
+
`/
${
id
}
`
,
{
await
fetch
(
url
+
`/
${
id
}
`
,
{
method
:
"DELETE"
,
method
:
"DELETE"
,
});
});
const
response
=
await
getTodos
();
//
const response = await getTodos();
return
response
;
//
return response;
}
catch
(
err
)
{
}
catch
(
err
)
{
toast
.
error
(
err
.
message
);
toast
.
error
(
err
.
message
);
}
}
...
...
src/pages/index.js
View file @
98006a02
import
React
from
"react"
;
import
React
,
{
useState
}
from
"react"
;
import
Layout
from
"../components/base/layout"
;
import
Layout
from
"../components/base/layout"
;
import
Form
from
"../components/top-level/form"
;
import
Form
from
"../components/top-level/form"
;
import
Tasks
from
"../components/top-level/tasks"
;
import
Tasks
from
"../components/top-level/tasks"
;
...
@@ -6,20 +6,27 @@ import { useAppContext } from "../app-context/index";
...
@@ -6,20 +6,27 @@ import { useAppContext } from "../app-context/index";
import
{
useEffect
}
from
"react"
;
import
{
useEffect
}
from
"react"
;
export
default
function
Pages
()
{
export
default
function
Pages
()
{
const
{
todo
,
addTodo
,
getTodos
,
deleteTodo
,
updateTodo
}
=
useAppContext
();
const
{
todo
,
loading
,
addTodo
,
getTodos
,
deleteTodo
,
updateTodo
}
=
useAppContext
();
console
.
log
(
loading
);
useEffect
(()
=>
{
useEffect
(()
=>
{
getTodos
();
getTodos
();
},
[]);
},
[]);
return
(
return
(
<>
<>
<
Layout
count
=
{
todo
?.
filter
((
e
)
=>
!
e
.
isCompleted
).
length
}
>
{
loading
?
(
{
todo
?.
length
>
0
?
(
<
Layout
count
=
{
todo
?.
filter
((
e
)
=>
!
e
.
isCompleted
).
length
}
>
<
Tasks
tasks
=
{
todo
}
onChange
=
{
updateTodo
}
onDelete
=
{
deleteTodo
}
/
>
{
todo
?.
length
>
0
?
(
)
:
(
<
Tasks
tasks
=
{
todo
}
onChange
=
{
updateTodo
}
onDelete
=
{
deleteTodo
}
/
>
<
h3
>
No
task
<
/h3
>
)
:
(
)}
<
h3
>
No
task
<
/h3
>
<
Form
onSubmit
=
{
addTodo
}
/
>
)}
<
/Layout
>
<
Form
onSubmit
=
{
addTodo
}
/
>
<
/Layout
>
)
:
(
"Loading...."
)}
<
/
>
<
/
>
);
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment