├── .gitignore
├── README.md
├── package.json
├── public
└── index.html
├── src
├── App.css
├── App.js
├── Components
│ ├── Note
│ │ ├── Note.css
│ │ └── Note.js
│ ├── NoteContainer
│ │ ├── NoteContainer.css
│ │ └── NoteContainer.js
│ └── Sidebar
│ │ ├── Sidebar.css
│ │ └── Sidebar.js
├── assets
│ ├── delete.png
│ ├── delete.svg
│ └── plus.png
├── index.css
└── index.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Notes App in React.js
2 |
3 | 
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "notes-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.11.4",
7 | "@testing-library/react": "^11.1.0",
8 | "@testing-library/user-event": "^12.1.10",
9 | "react": "^17.0.2",
10 | "react-dom": "^17.0.2",
11 | "react-scripts": "4.0.3",
12 | "web-vitals": "^1.0.1"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": [
22 | "react-app",
23 | "react-app/jest"
24 | ]
25 | },
26 | "browserslist": {
27 | "production": [
28 | ">0.2%",
29 | "not dead",
30 | "not op_mini all"
31 | ],
32 | "development": [
33 | "last 1 chrome version",
34 | "last 1 firefox version",
35 | "last 1 safari version"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Notes App
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | height: 100vh;
3 | display: flex;
4 | gap: 20px;
5 | padding: 40px;
6 | }
7 |
8 | .custom-scroll::-webkit-scrollbar {
9 | width: 8px;
10 | }
11 | .custom-scroll::-webkit-scrollbar-track {
12 | background-color: transparent;
13 | }
14 |
15 | .custom-scroll::-webkit-scrollbar-thumb {
16 | border-radius: 20px;
17 | background-color: lightgray;
18 | transition: 300ms;
19 | }
20 |
21 | .custom-scroll::-webkit-scrollbar-thumb:hover {
22 | background-color: gray;
23 | }
24 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 |
3 | import NoteContainer from "./Components/NoteContainer/NoteContainer";
4 | import Sidebar from "./Components/Sidebar/Sidebar";
5 |
6 | import "./App.css";
7 |
8 | function App() {
9 | const [notes, setNotes] = useState(
10 | JSON.parse(localStorage.getItem("notes-app")) || []
11 | );
12 |
13 | const addNote = (color) => {
14 | const tempNotes = [...notes];
15 |
16 | tempNotes.push({
17 | id: Date.now() + "" + Math.floor(Math.random() * 78),
18 | text: "",
19 | time: Date.now(),
20 | color,
21 | });
22 | setNotes(tempNotes);
23 | };
24 |
25 | const deleteNote = (id) => {
26 | const tempNotes = [...notes];
27 |
28 | const index = tempNotes.findIndex((item) => item.id === id);
29 | if (index < 0) return;
30 |
31 | tempNotes.splice(index, 1);
32 | setNotes(tempNotes);
33 | };
34 |
35 | const updateText = (text, id) => {
36 | const tempNotes = [...notes];
37 |
38 | const index = tempNotes.findIndex((item) => item.id === id);
39 | if (index < 0) return;
40 |
41 | tempNotes[index].text = text;
42 | setNotes(tempNotes);
43 | };
44 |
45 | useEffect(() => {
46 | localStorage.setItem("notes-app", JSON.stringify(notes));
47 | }, [notes]);
48 |
49 | return (
50 |
51 |
52 |
57 |
58 | );
59 | }
60 |
61 | export default App;
62 |
--------------------------------------------------------------------------------
/src/Components/Note/Note.css:
--------------------------------------------------------------------------------
1 | .note {
2 | padding: 25px;
3 | height: 280px;
4 | width: 260px;
5 | display: flex;
6 | flex-direction: column;
7 | background-color: blueviolet;
8 | border-radius: 30px;
9 | }
10 |
11 | .note_text {
12 | flex: 1;
13 | resize: none;
14 | background-color: transparent;
15 | font-size: 1rem;
16 | line-height: 1.875rem;
17 | outline: none;
18 | border: none;
19 | }
20 |
21 | .note_footer {
22 | display: flex;
23 | justify-content: space-between;
24 | align-items: center;
25 | }
26 |
27 | .note_footer img {
28 | cursor: pointer;
29 | opacity: 0;
30 | transition: 300ms;
31 | }
32 |
33 | .note:hover .note_footer img {
34 | opacity: 1;
35 | }
36 |
--------------------------------------------------------------------------------
/src/Components/Note/Note.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import deleteIcon from "../../assets/delete.svg";
4 |
5 | import "./Note.css";
6 |
7 | let timer = 500,
8 | timeout;
9 | function Note(props) {
10 | const formatDate = (value) => {
11 | if (!value) return "";
12 |
13 | const date = new Date(value);
14 | const monthNames = [
15 | "Jan",
16 | "Feb",
17 | "March",
18 | "April",
19 | "May",
20 | "Jun",
21 | "Jul",
22 | "Aug",
23 | "Sept",
24 | "Oct",
25 | "Nov",
26 | "Dec",
27 | ];
28 |
29 | let hrs = date.getHours();
30 | let amPm = hrs >= 12 ? "PM" : "AM";
31 | hrs = hrs ? hrs : "12";
32 | hrs = hrs > 12 ? (hrs = 24 - hrs) : hrs;
33 |
34 | let min = date.getMinutes();
35 | min = min < 10 ? "0" + min : min;
36 |
37 | let day = date.getDate();
38 | const month = monthNames[date.getMonth()];
39 |
40 | return `${hrs}:${min} ${amPm} ${day} ${month}`;
41 | };
42 |
43 | const debounce = (func) => {
44 | clearTimeout(timeout);
45 | timeout = setTimeout(func, timer);
46 | };
47 |
48 | const updateText = (text, id) => {
49 | debounce(() => props.updateText(text, id));
50 | };
51 |
52 | return (
53 |
68 | );
69 | }
70 |
71 | export default Note;
72 |
--------------------------------------------------------------------------------
/src/Components/NoteContainer/NoteContainer.css:
--------------------------------------------------------------------------------
1 | .note-container {
2 | height: 100%;
3 | }
4 |
5 | .note-container h2 {
6 | margin-bottom: 20px;
7 | }
8 |
9 | .note-container_notes {
10 | height: 90%;
11 | display: flex;
12 | flex-wrap: wrap;
13 | gap: 20px;
14 | overflow-y: scroll;
15 | }
16 |
--------------------------------------------------------------------------------
/src/Components/NoteContainer/NoteContainer.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Note from "../Note/Note";
4 |
5 | import "./NoteContainer.css";
6 |
7 | function NoteContainer(props) {
8 | const reverArray = (arr) => {
9 | const array = [];
10 |
11 | for (let i = arr.length - 1; i >= 0; --i) {
12 | array.push(arr[i]);
13 | }
14 |
15 | return array;
16 | };
17 |
18 | const notes = reverArray(props.notes);
19 |
20 | return (
21 |
22 |
Notes
23 |
24 | {notes?.length > 0 ? (
25 | notes.map((item) => (
26 |
32 | ))
33 | ) : (
34 |
No Notes present
35 | )}
36 |
37 |
38 | );
39 | }
40 |
41 | export default NoteContainer;
42 |
--------------------------------------------------------------------------------
/src/Components/Sidebar/Sidebar.css:
--------------------------------------------------------------------------------
1 | .sidebar {
2 | display: flex;
3 | flex-direction: column;
4 | gap: 40px;
5 | }
6 |
7 | .sidebar img {
8 | width: 60px;
9 | cursor: pointer;
10 | }
11 |
12 | .sidebar_list {
13 | display: flex;
14 | flex-direction: column;
15 | gap: 20px;
16 | align-items: center;
17 | height: 0;
18 | transition: 300ms;
19 | }
20 |
21 | .sidebar_list_active {
22 | height: 300px;
23 | }
24 |
25 | .sidebar_list_item {
26 | border-radius: 50%;
27 | height: 24px;
28 | width: 24px;
29 | list-style: none;
30 | }
31 |
--------------------------------------------------------------------------------
/src/Components/Sidebar/Sidebar.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | import plusIcon from "../../assets/plus.png";
4 |
5 | import "./Sidebar.css";
6 |
7 | function Sidebar(props) {
8 | const colors = ["#fe9b72", "#fec971", " #00d4fe", "#b693fd", "#e4ee91"];
9 |
10 | const [listOpen, setListOpen] = useState(false);
11 |
12 | return (
13 |
14 |

setListOpen(!listOpen)} />
15 |
16 | {colors.map((item, index) => (
17 | - props.addNote(item)}
22 | />
23 | ))}
24 |
25 |
26 | );
27 | }
28 |
29 | export default Sidebar;
30 |
--------------------------------------------------------------------------------
/src/assets/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/handyDev2/notes-app/f365dd6b2a4c350539f0622d5fbdf9afc740e168/src/assets/delete.png
--------------------------------------------------------------------------------
/src/assets/delete.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/handyDev2/notes-app/f365dd6b2a4c350539f0622d5fbdf9afc740e168/src/assets/plus.png
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | margin: 0;
9 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
10 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
11 | sans-serif;
12 | -webkit-font-smoothing: antialiased;
13 | -moz-osx-font-smoothing: grayscale;
14 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import App from "./App";
5 |
6 | ReactDOM.render(
7 |
8 |
9 | ,
10 | document.getElementById("root")
11 | );
12 |
--------------------------------------------------------------------------------