Below is the file structrue of my react notes app with the respective code written in the file.
Please make this app responsive by implementing the required changes in existing files.
Notes-app
Folder-> node_modules
Folder-> public
Folder-> src
Folder-> assets
delete1.png
plus.png
Folder-> components
Folder-> Note
Note.js
Note.css
Folder-> NoteContainer
NoteContainer.js
NoteContainer.css
Folder-> Sidebar
Sidebar.js
Sidebar.css
App.js
App.css
Index.js
Index.css
.gitignore
package
package-lock
README
1) App.js
import { useEffect, useState } from "react";
import "./App.css";
import NoteContainer from "./components/NoteContainer/NoteContainer";
import Sidebar from "./components/Sidebar/Sidebar";
function App() {
const [notes, setNotes] = useState(
JSON.parse(localStorage.getItem("notes-app")) || []
);
const addNote = (color) => {
//creating a copy of current notes array
const tempNotes = [...notes];
//adding new note to this tempNotes array
tempNotes.push({
id: Date.now() + "" + Math.floor(Math.random() * 78),
text: "",
time: Date.now(),
date: Date.now(),
color,
});
//updating the current notes array to this tempNotes
setNotes(tempNotes);
};
const deleteNote = (id) => {
// Filter out the note with the given ID and update the notes array
const updatedNotes = notes.filter((note) => note.id !== id);
setNotes(updatedNotes);
};
const updateText = (text, id) => {
const tempNotes = [...notes];
const index = tempNotes.findIndex((item) => item.id === id);
if (index < 0) return;
tempNotes[index].text = text;
setNotes(tempNotes);
};
useEffect(() => {
localStorage.setItem("notes-app", JSON.stringify(notes));
}, [notes]);
return (
<div className="App">
<Sidebar addNote={addNote} />
<NoteContainer
notes={notes}
deleteNote={deleteNote}
updateText={updateText}
/>
</div>
);
}
export default App;
2) App.css
.App {
height: 100vh;
display: flex;
gap: 20px;
padding: 40px;
}
.custom-scroll::-webkit-scrollbar {
width: 8px;
}
.custom-scroll::-webkit-scrollbar-track {
background-color: transparent;
}
.custom-scroll::-webkit-scrollbar-thumb {
border-radius: 20px;
background-color: lightgray;
transition: 300ms;
}
.custom-scroll::-webkit-scrollbar-thumb:hover {
background-color: gray;
}
3) index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
4) index.css
* {
border: 0;
padding: 0;
box-sizing: border-box;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
5) Note.js
import React from "react";
import "./Note.css";
import deleteIcon from "../../assets/delete1.png";
let timer = 500,
timeout;
const Note = (props) => {
const getDate = (value) => {
if (!value) return "";
const months = [
"JAN",
"FEB",
"MAR",
"APR",
"MAY",
"JUN",
"JUL",
"AUG",
"SEP",
"OCT",
"NOV",
"DEC",
];
const today = new Date(value);
const day = today.getDate();
const month = months[today.getMonth()];
const year = today.getFullYear();
const currentDate = day + " " + month + " " + year;
return currentDate;
};
const getTime = (value) => {
if (!value) return "";
const today = new Date(value);
const time = today.toLocaleString("en-US", {
hour: "numeric",
minute: "numeric",
hour12: true,
});
return time;
};
const debounce = (func) => {
clearTimeout(timeout);
timeout = setTimeout(func, timer);
};
const updateText = (text, id) => {
debounce(() => props.updateText(text, id));
};
return (
<div className="note" style={{ backgroundColor:
props.note.color }}>
<img
src={deleteIcon}
alt="delete-icon"
className="delete-icon"
onClick={() => props.deleteNote(props.note.id)}
/>
<textarea
className="note_content"
style={{ backgroundColor: props.note.color }}
defaultValue={props.note.text}
onChange={(event) => updateText(event.target.value,
props.note.id)}
/>
<div className="date_and_time">
<p className="time">{getTime(props.note.time)}</p>
<p className="date">{getDate(props.note.date)}</p>
</div>
</div>
);
};
export default Note;
6) Note.css
.note {
position: relative;
padding: 25px;
border: none;
height: 20rem;
width: 20rem;
display: flex;
flex-direction: column;
border-radius: 30px;
}
.note_content {
flex: 1;
resize: none;
font-size: 1rem;
line-height: 1.875rem;
border: none;
outline: none;
}
.date_and_time {
display: flex;
justify-content: space-between;
align-items: center;
}
.delete-icon {
width: 20px;
cursor: pointer;
opacity: 0;
transition: opacity 300ms ease;
}
.note:hover .delete-icon {
opacity: 1;
}
7) NoteContainer.js
import React from "react";
import Note from "../Note/Note";
import "./NoteContainer.css";
import loginIcon from "../../assets/login1.png";
import noteIcon from "../../assets/panda.png";
import signUpIcon from "../../assets/signup1.png";
const NoteContainer = (props) => {
const reverseArray = (arr) => {
const array = [];
for (let i = arr.length - 1; i >= 0; i--) {
array.push(arr[i]);
}
return array;
};
const notes = reverseArray(props.notes);
return (
<div className="note-container">
<div className="heading">
<div className="left-heading">
<button className="left-btn">
<div className="left">
<div className="left-img">
<img src={noteIcon} alt="note" />
</div>
<div className="text">
<h2 className="notes-heading">Panda-Notes</h2>
</div>
</div>
</button>
</div>
<div className="right-heading">
<button className="right-btn">
<div className="right">
<div className="right-img">
<img src={signUpIcon} alt="signUp" />
</div>
<div className="text">
<h2 className="notes-heading">Sign Up</h2>
</div>
</div>
</button>
<button className="right-btn">
<div className="right">
<div className="right-img">
<img src={loginIcon} alt="login" />
</div>
<div className="text">
<h2 className="notes-heading">Login</h2>
</div>
</div>
</button>
</div>
</div>
<div className="note-container_notes custom-scroll">
{notes.length > 0 ? (
notes.map((item) => (
<Note
key={item.id}
note={item}
deleteNote={props.deleteNote}
updateText={props.updateText}
/>
))
) : (
<h3>No Notes Present</h3>
)}
</div>
</div>
);
};
export default NoteContainer;
8) NoteContainer.css
.note-container {
height: 100%;
}
.note-container_notes {
margin-top: 10px;
height: 90%;
display: flex;
flex-wrap: wrap;
gap: 20px;
overflow-y: scroll;
}
.heading {
display: flex;
align-items: center;
justify-content: space-between;
}
.left-img img {
width: 40px;
}
.right-img img {
width: 40px;
}
.left {
display: flex;
align-items: center;
}
.right {
display: flex;
align-items: center;
}
.right-btn {
margin-right: 60px;
}
button {
padding-left: 10px;
padding-right: 10px;
border-radius: 20px;
cursor: pointer;
}
.left-btn {
background-color: #97f19e;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); /* Add shadow */
transition: box-shadow 0.3s ease-in-out; /* Add transition for
smoother hover effect */
}
.left-btn:hover {
background-color: #85de77;
}
.right-btn {
background-color: #fcf5c7;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); /* Add shadow */
transition: box-shadow 0.3s ease-in-out; /* Add transition for
smoother hover effect */
}
.right-btn:hover {
background-color: #ffee93;
}
9) Sidebar.js
import React, { useState } from "react";
import "./Sidebar.css";
import plusIcon from "../../assets/plus.png";
const Sidebar = (props) => {
const [listOpen, setListOpen] = useState(false);
const colors = [
"#8e7ff6",
"#fcc453",
"#fd8d6f",
"#89d2bf",
"#85d0ef",
"#f786a8",
"#ee9aef",
];
return (
<div className="sidebar">
<img src={plusIcon} alt="plus" onClick={() => setListOpen(!
listOpen)} />
<ul className={`sidebar_list ${listOpen ? "sidebar_list_active" :
""}`}>
{colors.map((item, index) => (
<li
key={index}
className="sidebar_list_item"
style={{ backgroundColor: item }}
onClick={() => props.addNote(item)}
/>
))}
</ul>
</div>
);
};
export default Sidebar;
10) Sidebar.css
.sidebar {
display: flex;
flex-direction: column;
gap: 40px;
}
.sidebar img {
width: 40px;
cursor: pointer;
}
.sidebar_list {
display: flex;
flex-direction: column;
gap: 20px;
align-items: center;
height: 0;
transition: 300ms;
}
.sidebar_list_active {
height: 300px;
}
.sidebar_list_item {
border-radius: 50%;
height: 25px;
width: 25px;
list-style: none;
cursor: pointer;
}