├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
└── index.html
├── screenshots
├── Archive_notes.png
├── Deleted_Notes.png
├── Home.png
├── Notes_searching-1.png
├── Notes_searching-2.png
└── Pinned&Other_Notes.png
└── src
├── App.css
├── App.js
├── App.test.js
├── assets
└── logo192.png
├── components
├── Bar
│ └── Header.js
├── List
│ └── List.js
├── Note
│ ├── Check.js
│ ├── EditForm.js
│ ├── Note.js
│ ├── NoteForm.js
│ └── addChecklist.js
└── Search
│ └── SearchBar.js
├── containers
├── Archieve.js
├── Bin.js
├── Notes.js
└── SearchList.js
├── context
├── Context.js
└── NoteContext.js
├── index.css
├── index.js
└── navigation
└── Navigation.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | screenshots/
4 |
5 | # dependencies
6 | /node_modules
7 | /.pnp
8 | .pnp.js
9 |
10 | # testing
11 | /coverage
12 |
13 | # production
14 | /build
15 |
16 | # misc
17 | .DS_Store
18 | .env.local
19 | .env.development.local
20 | .env.test.local
21 | .env.production.local
22 |
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Note-Taking-App
3 |
4 | ## About
5 | Note-Taking-App allows users to make different kinds of notes. Users can edit, delete and pin the notes. Users can also change the colors of any notes. One of the important feature is that users can search the note among multiple notes.
6 |
7 |
8 | ## Preview
9 | ### [1] Home Page
10 | 
11 |
12 | ### [2] Home Page After Notes Added(Pinned & Other Notes)
13 | 
14 |
15 | ### [3] Searching Notes
16 | 
17 |
18 | 
19 |
20 | ### [4] Deleted Notes Page
21 | 
22 |
23 | ### [5] Archived Notes Page
24 | 
25 |
26 |
27 | ## Tech Stack
28 |
29 | React.js, HTML, CSS, React-Router-Dom, React-Icons
30 |
31 |
32 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "google-keep-clone",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@emotion/react": "^11.10.5",
7 | "@emotion/styled": "^11.10.5",
8 | "@icons/material": "^0.4.1",
9 | "@material-ui/core": "^4.12.4",
10 | "@material-ui/icons": "^4.11.3",
11 | "@mui/icons-material": "^5.11.0",
12 | "@mui/material": "^5.11.6",
13 | "@testing-library/jest-dom": "^5.14.1",
14 | "@testing-library/react": "^11.2.7",
15 | "@testing-library/user-event": "^12.8.3",
16 | "@trendmicro/react-sidenav": "^0.5.0",
17 | "bootstrap": "^5.2.3",
18 | "debounce": "^1.2.1",
19 | "react": "^17.0.2",
20 | "react-bootstrap": "^2.0.0-beta.6",
21 | "react-color": "^2.19.3",
22 | "react-dom": "^17.0.2",
23 | "react-icons": "^4.7.1",
24 | "react-router-dom": "^5.3.0",
25 | "react-scripts": "4.0.3",
26 | "uuid": "^8.3.2",
27 | "web-vitals": "^1.1.2"
28 | },
29 | "scripts": {
30 | "start": "react-scripts start",
31 | "build": "react-scripts build",
32 | "test": "react-scripts test",
33 | "eject": "react-scripts eject"
34 | },
35 | "eslintConfig": {
36 | "extends": [
37 | "react-app",
38 | "react-app/jest"
39 | ]
40 | },
41 | "browserslist": {
42 | "production": [
43 | ">0.2%",
44 | "not dead",
45 | "not op_mini all"
46 | ],
47 | "development": [
48 | "last 1 chrome version",
49 | "last 1 firefox version",
50 | "last 1 safari version"
51 | ]
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
14 | Notes Taking App
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/screenshots/Archive_notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RitikKumar202/notes-taking-app/4dc67d4120561f05ebdf447a29bcbec42217a2b4/screenshots/Archive_notes.png
--------------------------------------------------------------------------------
/screenshots/Deleted_Notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RitikKumar202/notes-taking-app/4dc67d4120561f05ebdf447a29bcbec42217a2b4/screenshots/Deleted_Notes.png
--------------------------------------------------------------------------------
/screenshots/Home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RitikKumar202/notes-taking-app/4dc67d4120561f05ebdf447a29bcbec42217a2b4/screenshots/Home.png
--------------------------------------------------------------------------------
/screenshots/Notes_searching-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RitikKumar202/notes-taking-app/4dc67d4120561f05ebdf447a29bcbec42217a2b4/screenshots/Notes_searching-1.png
--------------------------------------------------------------------------------
/screenshots/Notes_searching-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RitikKumar202/notes-taking-app/4dc67d4120561f05ebdf447a29bcbec42217a2b4/screenshots/Notes_searching-2.png
--------------------------------------------------------------------------------
/screenshots/Pinned&Other_Notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RitikKumar202/notes-taking-app/4dc67d4120561f05ebdf447a29bcbec42217a2b4/screenshots/Pinned&Other_Notes.png
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;500&family=Krub:wght@300;400;500&family=Lora:ital,wght@1,400;1,500;1,600&family=Poppins:wght@100;200;300;400;500;600&family=Ubuntu:ital,wght@1,300;1,400&family=Varela+Round&display=swap');
2 | * {
3 | font-family: 'Kanit', sans-serif;
4 | }
5 |
6 | input {
7 | outline: none;
8 | }
9 |
10 |
11 | /* Components */
12 |
13 |
14 | /* ------Header----- */
15 |
16 | .header {
17 | display: flex;
18 | justify-content: space-between;
19 | padding: 15px 25px;
20 | align-items: center;
21 | box-shadow: rgba(0, 0, 0, 0.25) 0px 0.0625em 0.0625em, rgba(0, 0, 0, 0.25) 0px 0.125em 0.5em, rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset;
22 | }
23 |
24 | .brand {
25 | display: flex;
26 | align-items: center;
27 | justify-content: flex-start;
28 | }
29 |
30 | .brand img,
31 | i,
32 | h4 {
33 | margin: 0px 5px;
34 | color: #606469;
35 | }
36 |
37 | .brand h4 {
38 | margin: 1px 7px;
39 | }
40 |
41 | .brand h4:hover {
42 | text-decoration: underline;
43 | }
44 |
45 | .brand img {
46 | width: 38px;
47 | height: 38px;
48 | }
49 |
50 | .user {
51 | display: flex;
52 | justify-content: flex-end;
53 | }
54 |
55 | .user h6 {
56 | margin: 0px 10px;
57 | color: #606469;
58 | }
59 |
60 | .search-bar {
61 | display: flex;
62 | justify-content: center;
63 | }
64 |
65 |
66 | /* ------Search Bar----- */
67 |
68 | .search {
69 | width: 700px;
70 | display: flex;
71 | align-items: center;
72 | padding: 10px 20px;
73 | border-radius: 10px;
74 | box-shadow: rgba(0, 0, 0, 0.02) 0px 1px 3px 0px, rgba(27, 31, 35, 0.15) 0px 0px 0px 1px;
75 | }
76 |
77 | .mobile-search {
78 | display: none;
79 | margin-top: 10px;
80 | width: auto;
81 | align-items: center;
82 | padding: 10px 20px;
83 | }
84 |
85 | .search i {
86 | color: #606469;
87 | }
88 |
89 | .search input {
90 | border: none;
91 | margin-left: 10px;
92 | }
93 |
94 | .search input::placeholder {
95 | color: #606469;
96 | }
97 |
98 |
99 | /* Navbar */
100 |
101 | .nav__cont {
102 | position: fixed;
103 | width: 40px;
104 | top: 50px;
105 | height: 100vh;
106 | overflow: hidden;
107 | transition: width 0.3s ease;
108 | cursor: pointer;
109 | }
110 |
111 | .nav__cont:hover {
112 | width: 150px;
113 | }
114 |
115 | .nav {
116 | list-style-type: none;
117 | color: white;
118 | }
119 |
120 | .nav:first-child {
121 | padding-top: 1.5rem;
122 | }
123 |
124 | .nav__items {
125 | display: flex;
126 | font-family: 'roboto';
127 | align-items: center;
128 | justify-content: flex-start;
129 | }
130 |
131 | .nav__items p {
132 | position: relative;
133 | top: 7px;
134 | left: 20px;
135 | padding: 0px 20px;
136 | transition: all 0.3s ease;
137 | color: #606469;
138 | font-family: 'roboto';
139 | border-bottom: none !important;
140 | font-size: 20px;
141 | }
142 |
143 | .nav__items p:after {
144 | content: '';
145 | width: 100%;
146 | top: 0;
147 | left: 20px;
148 | border-radius: 2px;
149 | opacity: 0;
150 | transition: all 0.5s ease;
151 | z-index: -10;
152 | }
153 |
154 | .nav__items:hover p:after {
155 | opacity: 1;
156 | }
157 |
158 | .nav__items i {
159 | position: relative;
160 | left: 20px;
161 | cursor: pointer;
162 | }
163 |
164 |
165 | /* Navbar */
166 |
167 |
168 | /* Mobile Navbar */
169 |
170 | .menu-icon {
171 | display: none;
172 | }
173 |
174 | .menu-item {
175 | border-bottom: 1px solid #a1a6ac;
176 | text-align: center;
177 | color: #606469;
178 | padding: 14px 16px;
179 | text-decoration: none;
180 | font-size: 17px;
181 | display: block;
182 | transition: all 0.3s ease;
183 | }
184 |
185 | .menu-item:hover {
186 | border-bottom: 1px solid rgb(243, 206, 40);
187 | color: rgb(243, 206, 40);
188 | }
189 |
190 |
191 | /* Mobile Navbar */
192 |
193 |
194 | /* Note */
195 |
196 | #note {
197 | height: fit-content;
198 | padding: 10px;
199 | border: 1px solid #bec1c3;
200 | border-radius: 10px;
201 | box-shadow: rgba(67, 71, 85, 0.27) 0px 0px 0.25em, rgba(90, 125, 188, 0.05) 0px 0.25em 1em;
202 | }
203 |
204 | .text {
205 | display: block;
206 | max-width: 250px;
207 | word-break: break-all;
208 | /* optional */
209 | }
210 |
211 | .icons-container {
212 | display: flex;
213 | padding: 5px;
214 | }
215 |
216 | .icons-container div {
217 | padding: 5px;
218 | cursor: pointer;
219 | }
220 |
221 | .note-icon {
222 | width: 17px;
223 | height: 17px;
224 | color: #252627;
225 | }
226 |
227 |
228 | /* Note */
229 | .text h6{
230 | color: #5c5b5b;
231 | }
232 | .text h4{
233 | color: #000;
234 | }
235 |
236 |
237 | /* Note form */
238 |
239 | .note-form-con {
240 | display: flex;
241 | justify-content: center;
242 | align-items: center;
243 | padding: 5px;
244 | }
245 |
246 | .note-form {
247 | opacity: 0.9;
248 | width: 60%;
249 | padding: 20px;
250 | border-radius: 10px;
251 | /* border: 1px solid black; */
252 | /* box-shadow: 2px 3px 4px 2px #edf0f1; */
253 | box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 0px 1px, rgb(209, 213, 219) 0px 0px 0px 1px inset;
254 | }
255 |
256 | .edit-note-form {
257 | opacity: 0.9;
258 | width: 60%;
259 | padding: 20px;
260 | border-radius: 10px;
261 | }
262 |
263 | input::placeholder {
264 | color: #4f5153;
265 | }
266 |
267 | textarea::placeholder {
268 | color: #ccc;
269 | }
270 |
271 | textarea {
272 | width: 100%;
273 | border: none;
274 | padding-top: 2px;
275 | display: block;
276 | outline: none;
277 | color: #747970;
278 | }
279 |
280 | input {
281 | width: 100%;
282 | border: none;
283 | color: #383a3b;
284 | }
285 |
286 | .show {
287 | display: block;
288 | background-color: #fff;
289 | border-radius: 10px;
290 | position: absolute;
291 | box-shadow: 2px 3px 4px 2px #dfe4e7;
292 | }
293 |
294 | .hide {
295 | display: none;
296 | }
297 |
298 | .submit {
299 | outline: none;
300 | padding: 0px 15px;
301 | border: none;
302 | border-radius: 10px;
303 | background-color: #f3ce28;
304 | }
305 |
306 | .submit:hover {
307 | opacity: 0.7;
308 | }
309 |
310 |
311 | /* Note form */
312 |
313 |
314 | /* Edit Modal */
315 |
316 |
317 | /* The Modal (background) */
318 |
319 | .modal {
320 | display: none;
321 | z-index: 1;
322 | left: 0;
323 | top: 0;
324 | width: 100%;
325 | height: 100%;
326 | overflow: auto;
327 | background-color: #817f7f66;
328 | }
329 |
330 |
331 | /* Edit Model */
332 |
333 |
334 | /* Check */
335 |
336 | .check {
337 | display: flex;
338 | cursor: pointer;
339 | position: relative;
340 | }
341 |
342 | .check input {
343 | background: #a1a6ac;
344 | }
345 |
346 |
347 | /* Check */
348 |
349 |
350 | /* Containers */
351 |
352 | .container {
353 | padding: 20px;
354 | }
355 |
356 | .container h2 {
357 | font-size: 17px;
358 | color: #606469;
359 | }
360 |
361 | .row {
362 | padding: 20px 10px;
363 | }
364 |
365 | .heading-con {
366 | display: flex;
367 | justify-content: center;
368 | margin: 25px 0px;
369 | }
370 |
371 | .heading-con h1 {
372 | color: #606469;
373 | }
374 |
375 |
376 | /* Containers */
377 |
378 |
379 | /* Media Queries */
380 |
381 | @media screen and (max-width: 765px) {
382 | .edit-note-form,
383 | .note-form {
384 | width: 85%;
385 | }
386 | .search-bar {
387 | display: none;
388 | }
389 | .mobile-search {
390 | display: flex;
391 | justify-content: space-around;
392 | }
393 | .menu-icon {
394 | display: block;
395 | }
396 | .nav__cont {
397 | display: none;
398 | }
399 | }
400 |
401 | @media screen and (max-width: 1010px) {
402 | .search {
403 | width: auto;
404 | }
405 | }
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import './App.css';
2 |
3 | // Note Context
4 | import ContextProvider from './context/Context';
5 |
6 | //React Components
7 | import Navigation from './navigation/Navigation';
8 |
9 | function App() {
10 | return (
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | export default App;
18 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render();
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/src/assets/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RitikKumar202/notes-taking-app/4dc67d4120561f05ebdf447a29bcbec42217a2b4/src/assets/logo192.png
--------------------------------------------------------------------------------
/src/components/Bar/Header.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | // Styled Components
4 | import { BiMenu } from 'react-icons/bi';
5 |
6 | // Custom Components
7 | import SearchBar from '../Search/SearchBar';
8 |
9 | // Link for linking to other page
10 | import { Link } from 'react-router-dom';
11 |
12 | // Assets
13 | import Logo from '../../assets/logo192.png';
14 |
15 | const Header = () => {
16 | const [show, setShow] = useState(false);
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
setShow(!show)}
26 | size={25}
27 | />
28 |
29 | Notes Taking App
30 |
31 |
32 |
33 |
34 |
35 |
36 |
40 |
41 | Notes
42 |
43 |
44 | Archive
45 |
46 |
47 | Bin
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
77 |
78 | );
79 | };
80 |
81 | export default Header;
82 |
--------------------------------------------------------------------------------
/src/components/List/List.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | // Custom Components
4 | import Note from '../Note/Note';
5 |
6 | const List = (props) => {
7 | // Destructuring props
8 | const { notesList, list } = props;
9 |
10 | return (
11 |
12 | {notesList.map((data, index) => (
13 |
24 | ))}
25 |
26 | );
27 | };
28 |
29 | export default List;
30 |
--------------------------------------------------------------------------------
/src/components/Note/Check.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const CheckNote = (props) => {
4 | const { data } = props;
5 | return (
6 |
7 |
8 |
{data.subnote}
9 |
10 | );
11 | };
12 |
13 | export { CheckNote };
14 |
--------------------------------------------------------------------------------
/src/components/Note/EditForm.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from 'react';
2 |
3 | // Styled Components
4 | import { CirclePicker } from 'react-color';
5 |
6 | // Icons
7 | import { RiPushpin2Fill, RiPushpin2Line, RiCloseFill } from 'react-icons/ri';
8 | import { BiArchiveIn, BiArchiveOut } from 'react-icons/bi';
9 | import { IoColorPaletteOutline } from 'react-icons/io5';
10 | import { AiOutlinePlusSquare, AiOutlineMinusSquare } from 'react-icons/ai';
11 |
12 | // Unique uid generator
13 | import { v4 as uuidv4 } from 'uuid';
14 |
15 | // Context
16 | import { NoteActionContext } from '../../context/NoteContext';
17 |
18 | const EditForm = (props) => {
19 | // Destructuring props
20 | const { setModalShow, note, id } = props;
21 |
22 | // Calling Context
23 | const { handleEdit } = useContext(NoteActionContext);
24 |
25 | // Concatenated note array
26 | var noteTxt = '';
27 | note.forEach((data) => {
28 | noteTxt += data.subnote + '\n';
29 | });
30 |
31 | // Creating states
32 | const [title, setTitle] = useState(props.title);
33 | const [pin, setPin] = useState(props.pin);
34 | const [archive, setArchive] = useState(props.archiev);
35 | const [color, setColor] = useState(props.bgColor);
36 | const [showPicker, setShowPicker] = useState(false);
37 | const [noteText, setNoteText] = useState(noteTxt);
38 | const [addChecklist, setAddChecklist] = useState(props.checkList);
39 | // const [checkArray, setCheckArray] = useState([]);
40 |
41 | // Edit Function
42 | const Edit = () => {
43 | if (addChecklist) {
44 | alert(
45 | 'Edit Checklist Functionality not added yet to edit it change its form to text by clicking on the same icon'
46 | );
47 | } else {
48 | let newArray = [];
49 | if (noteText !== '') {
50 | var noteArray = noteText.split(/^/gm);
51 | for (let i = 0; i < noteArray.length; i++) {
52 | if (note[i]) {
53 | var obj = {
54 | id: note[i].id,
55 | subnote: noteArray[i],
56 | check: note[i].check,
57 | };
58 | } else {
59 | obj = {
60 | id: uuidv4(),
61 | subnote: noteArray[i],
62 | check: false,
63 | };
64 | }
65 | newArray.push(obj);
66 | }
67 | }
68 | handleEdit(id, title, newArray, pin, archive, color, addChecklist);
69 | setModalShow(false);
70 | }
71 | };
72 |
73 | const CheckInput = () => {};
74 |
75 | return (
76 |
163 | );
164 | };
165 |
166 | export default EditForm;
167 |
--------------------------------------------------------------------------------
/src/components/Note/Note.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from 'react';
2 |
3 | // Styled Components
4 | import { CirclePicker } from 'react-color';
5 |
6 | // Custom Components
7 | import EditForm from './EditForm';
8 | import { CheckNote } from './Check';
9 |
10 | // Icons
11 | import {
12 | RiPushpin2Fill,
13 | RiDeleteBin5Fill,
14 | RiPushpin2Line,
15 | } from 'react-icons/ri';
16 | import { IoColorPaletteOutline } from 'react-icons/io5';
17 | import { BiArchiveIn, BiArchiveOut, BiEdit } from 'react-icons/bi';
18 | import { AiOutlinePlusSquare, AiOutlineMinusSquare } from 'react-icons/ai';
19 |
20 | // Context
21 | import { NoteActionContext } from '../../context/NoteContext';
22 |
23 | const Note = (props) => {
24 | // Destruncturing props
25 | const { id, title, note, pin, archiev, listname, bgColor, checkList } = props;
26 |
27 | // Calling Context
28 | const {
29 | handlePin,
30 | handleArchive,
31 | handleDelete,
32 | handleBgColor,
33 | handleCheckList,
34 | } = useContext(NoteActionContext);
35 |
36 | // Creating states
37 | const [showPicker, setShowPicker] = useState(false);
38 | const [modalShow, setModalShow] = useState(false);
39 |
40 | // Archieve
41 | const Archive = () => {
42 | handleArchive(id);
43 | };
44 |
45 | // Pin
46 | const Pin = () => {
47 | handlePin(id);
48 | };
49 |
50 | // Delete
51 | const Delete = () => {
52 | handleDelete(id);
53 | };
54 |
55 | // Background Color
56 | const BackgroundColor = (color) => {
57 | handleBgColor(id, color);
58 | };
59 |
60 | const CheckList = () => {
61 | handleCheckList(id);
62 | };
63 |
64 | return (
65 |
66 |
67 |
68 |
{title}
69 |
70 | {note.length >= 0 ? (
71 | checkList ? (
72 | note.map((data, index) =>
)
73 | ) : (
74 | note.map((data, index) => (
75 |
76 |
{data.subnote}
77 |
78 | ))
79 | )
80 | ) : (
81 | <>>
82 | )}
83 |
84 | {listname === 'delete' ? (
85 | <>>
86 | ) : (
87 |
88 |
89 | {pin ? (
90 |
91 | ) : (
92 |
93 | )}
94 |
95 |
96 |
97 |
98 |
99 | {archiev ? (
100 |
101 | ) : (
102 |
103 | )}
104 |
105 |
106 |
setShowPicker(!showPicker)}
108 | className='note-icon'
109 | />
110 |
111 |
112 |
115 | BackgroundColor(color.hex)
116 | }
117 | width={220}
118 | height={100}
119 | />
120 |
121 |
122 | {checkList ? (
123 |
126 | ) : (
127 |
130 | )}
131 |
132 |
133 | setModalShow(true)}
136 | />
137 |
138 |
152 |
153 | )}
154 |
155 |
156 | );
157 | };
158 |
159 | export default Note;
160 |
--------------------------------------------------------------------------------
/src/components/Note/NoteForm.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from 'react';
2 |
3 | // Styled Components
4 | import { CirclePicker } from 'react-color';
5 | import { FaFileImage } from "react-icons/fa";
6 | import { FaPaintBrush } from "react-icons/fa";
7 |
8 | // Icons
9 | import { RiPushpin2Fill, RiPushpin2Line } from 'react-icons/ri';
10 | // import { BiArchiveIn, BiArchiveOut } from 'react-icons/bi';
11 | import { IoColorPaletteOutline } from 'react-icons/io5';
12 | // import { AiOutlinePlusSquare, AiOutlineMinusSquare } from 'react-icons/ai';
13 |
14 | // Unique uid generator
15 | import { v4 as uuidv4 } from 'uuid';
16 |
17 | // Context
18 | import { NoteActionContext } from '../../context/NoteContext';
19 |
20 | const NoteForm = () => {
21 | // Calling Context
22 | const { addNote } = useContext(NoteActionContext);
23 |
24 | // Creating Context
25 | const [title, setTitle] = useState('');
26 | const [note, setNote] = useState('');
27 | const [image, setImage] = useState("");
28 | const [pin, setPin] = useState(false);
29 | const [archive, setArchive] = useState(false);
30 | const [color, setColor] = useState('#fff');
31 | const [showPicker, setShowPicker] = useState(false);
32 | const [addChecklist, setAddChecklist] = useState(false);
33 |
34 |
35 | // Add Note Function
36 | const Submit = () => {
37 | if (title !== '' && note !== '') {
38 | let newArray = [];
39 | let id = uuidv4();
40 | if (note !== '') {
41 | var noteArray = note.split(/^/gm);
42 | noteArray.forEach((data) => {
43 | let obj = {
44 | id: uuidv4(),
45 | subnote: data,
46 | check: false,
47 | };
48 | newArray.push(obj);
49 | });
50 | }
51 | let obj = {
52 | id: id,
53 | title: title,
54 | note: newArray,
55 | pin: pin,
56 | archieve: archive,
57 | bgColor: color,
58 | checklist: addChecklist,
59 | };
60 | addNote(obj);
61 | resetForm();
62 | } else {
63 | alert('Title and Description is a required field');
64 | }
65 | };
66 |
67 | const resetForm = () => {
68 | setNote('');
69 | setTitle('');
70 | setPin(false);
71 | setArchive(false);
72 | setAddChecklist(false);
73 | setColor('#fff');
74 | };
75 |
76 | return (
77 |
156 | );
157 | };
158 |
159 | export default NoteForm;
160 |
--------------------------------------------------------------------------------
/src/components/Note/addChecklist.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const AddChecklist = () => {
4 | return Add Checklist
;
5 | };
6 |
7 | export default AddChecklist;
8 |
--------------------------------------------------------------------------------
/src/components/Search/SearchBar.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState, useEffect } from 'react';
2 |
3 | // Link
4 | import { Link } from 'react-router-dom';
5 |
6 | import { NoteContext } from '../../context/NoteContext';
7 | import { NoteActionContext } from '../../context/NoteContext';
8 |
9 | const SearchBar = () => {
10 | const [search, setSearch] = useState('');
11 | const { notes } = useContext(NoteContext);
12 | const { setSearchedNotes } = useContext(NoteActionContext);
13 |
14 | useEffect(() => {
15 | let FilteredNotes = notes.filter((item) => {
16 | return item.title.toLowerCase().includes(search.toLowerCase()) !== false;
17 | });
18 | setSearchedNotes(FilteredNotes);
19 | }, [search, setSearchedNotes, notes]);
20 |
21 | return (
22 |
23 |
24 |
25 |
26 | setSearch(e.target.value)} placeholder='Search' />
27 |
28 | );
29 | };
30 |
31 | export default SearchBar;
32 |
--------------------------------------------------------------------------------
/src/containers/Archieve.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 |
3 | // Custom Components
4 | import Note from '../components/Note/Note';
5 |
6 | // Context
7 | import { NoteContext } from '../context/NoteContext';
8 |
9 | const Archieve = () => {
10 | // Calling Context
11 | const { notes } = useContext(NoteContext);
12 |
13 | // Filtered Notes
14 | const archivedNotes = notes.filter((note) => note.archieve === true);
15 |
16 | return (
17 |
18 | {notes ? (
19 |
20 |
21 |
Archive Notes
22 |
23 |
24 |
25 |
26 | {archivedNotes.map((data, index) => (
27 |
37 | ))}
38 |
39 |
40 |
41 | ) : (
42 |
No Archieved Notes Yet
43 | )}
44 |
45 | );
46 | };
47 |
48 | export default Archieve;
49 |
--------------------------------------------------------------------------------
/src/containers/Bin.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 |
3 | // Custom Components
4 | import List from '../components/List/List';
5 |
6 | // Context
7 | import { NoteContext } from '../context/NoteContext';
8 |
9 | const Bin = () => {
10 | // Calling Context
11 | const { deletedNotes } = useContext(NoteContext);
12 |
13 | return (
14 |
15 |
16 |
Deleted Notes
17 |
18 |
19 |
24 |
25 | );
26 | };
27 |
28 | export default Bin;
29 |
--------------------------------------------------------------------------------
/src/containers/Notes.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 |
3 | // Custom Components
4 | import List from '../components/List/List';
5 | import NoteForm from '../components/Note/NoteForm';
6 |
7 | // Context
8 | import { NoteContext } from '../context/NoteContext';
9 |
10 | const Notes = () => {
11 | // Calling Context
12 | const { notes } = useContext(NoteContext);
13 |
14 | // Filtered Arrays
15 | const nonArchieved = notes.filter((note) => note.archieve === false);
16 | const pinnedNotes = nonArchieved.filter((note) => note.pin === true);
17 | const others = nonArchieved.filter((note) => note.pin === false);
18 |
19 | return (
20 |
21 |
22 |
23 |
24 |
25 | {pinnedNotes ? (
26 |
27 |
Pinned
28 |
29 |
30 |
31 |
32 | ) : (
33 | <>>
34 | )}
35 | {others ? (
36 |
37 |
Others
38 |
39 |
40 |
41 |
42 | ) : (
43 |
No Notes
44 | )}
45 |
46 | );
47 | };
48 |
49 | export default Notes;
50 |
--------------------------------------------------------------------------------
/src/containers/SearchList.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 |
3 | // Custom Components
4 | import Note from '../components/Note/Note';
5 |
6 | // Context
7 | import { NoteContext } from '../context/NoteContext';
8 |
9 | const SearchList = () => {
10 | // Calling Context
11 | const { searchedNotes } = useContext(NoteContext);
12 |
13 | return (
14 |
15 | {searchedNotes ? (
16 |
17 |
18 | {searchedNotes.map((data, index) => (
19 |
29 | ))}
30 |
31 |
32 | ) : (
33 |
No Archieved Notes Yet
34 | )}
35 |
36 | );
37 | };
38 |
39 | export default SearchList;
40 |
--------------------------------------------------------------------------------
/src/context/Context.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import NoteContextProvider from './NoteContext';
3 |
4 | const ContextProvider = (props) => {
5 | return {props.children};
6 | };
7 | export default ContextProvider;
8 |
--------------------------------------------------------------------------------
/src/context/NoteContext.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useState, useEffect} from 'react';
2 |
3 | // Context Creating using createContext
4 | export const NoteContext = createContext();
5 | export const NoteActionContext = createContext();
6 |
7 | const NoteContextProvider = (props) => {
8 | const [notes, setNotes] = useState(JSON.parse(localStorage.getItem('notes')) || []);
9 | const [deletedNotes, setDeletedNotes] = useState(JSON.parse(localStorage.getItem('deletedNotes')) || []);
10 | const [searchedNotes, setSearchedNotes] = useState([]);
11 |
12 | useEffect(() =>{
13 | localStorage.setItem('notes', JSON.stringify(notes))
14 | }, [notes])
15 |
16 | useEffect(() =>{
17 | localStorage.setItem('deletedNotes', JSON.stringify(deletedNotes))
18 | }, [deletedNotes])
19 |
20 | // Add Note Functionality
21 | const addNote = (obj) => {
22 | setNotes([...notes, obj]);
23 | };
24 |
25 | // Archieve Functionality
26 | const handleArchive = (id) => {
27 | const index = notes.findIndex((note) => note.id === id);
28 | let newNotes = [...notes];
29 | newNotes[index] = {
30 | ...newNotes[index],
31 | archieve: !newNotes[index].archieve,
32 | };
33 | setNotes(newNotes);
34 | };
35 |
36 | // Pin Functionality
37 | const handlePin = (id) => {
38 | const index = notes.findIndex((note) => note.id === id);
39 | let newNotes = [...notes];
40 | newNotes[index] = {
41 | ...newNotes[index],
42 | pin: !newNotes[index].pin,
43 | };
44 | setNotes(newNotes);
45 | };
46 |
47 | // Background Color Functionality
48 | const handleBgColor = (id, color) => {
49 | const index = notes.findIndex((note) => note.id === id);
50 | let newNotes = [...notes];
51 | newNotes[index] = {
52 | ...newNotes[index],
53 | bgColor: color,
54 | };
55 | setNotes(newNotes);
56 | };
57 |
58 | // CheckList Functionality
59 | const handleCheckList = (id) => {
60 | const index = notes.findIndex((note) => note.id === id);
61 | let newNotes = [...notes];
62 | newNotes[index] = {
63 | ...newNotes[index],
64 | checklist: !newNotes[index].checklist,
65 | };
66 | setNotes(newNotes);
67 | };
68 |
69 | // Delete Note Functionality
70 | const handleDelete = (id) => {
71 | const index = notes.findIndex((note) => note.id === id);
72 | let deletedElement = notes.splice(index, 1);
73 | setDeletedNotes([...deletedNotes, deletedElement[0]]);
74 | setNotes(notes.filter((note) => note.id !== id));
75 | };
76 |
77 | // Edit Funtcionality
78 | const handleEdit = (id, title, note, pin, archive, color, addChecklist) => {
79 | const index = notes.findIndex((note) => note.id === id);
80 | let newNotes = [...notes];
81 | newNotes[index] = {
82 | ...newNotes[index],
83 | title: title,
84 | note: note,
85 | pin: pin,
86 | archieve: archive,
87 | bgColor: color,
88 | checklist: addChecklist,
89 | };
90 | setNotes(newNotes);
91 | };
92 |
93 | return (
94 |
95 |
107 | {props.children}
108 |
109 |
110 | );
111 | };
112 |
113 | export default NoteContextProvider;
114 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
4 | -webkit-font-smoothing: antialiased;
5 | -moz-osx-font-smoothing: grayscale;
6 | }
7 |
8 | code {
9 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
10 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import './index.css';
5 | import 'bootstrap/dist/css/bootstrap.min.css';
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById('root')
12 | );
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/navigation/Navigation.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | // Navigation
4 | import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
5 |
6 | // Custom Components
7 | import Notes from '../containers/Notes';
8 | import Archieve from '../containers/Archieve';
9 | import Bin from '../containers/Bin';
10 | import Header from '../components/Bar/Header';
11 | import SearchList from '../containers/SearchList';
12 |
13 | const Navigation = () => {
14 | return (
15 |
16 |
17 |
18 |
19 | } />
20 | } />
21 | } />
22 | } />
23 |
24 |
25 |
26 | );
27 | };
28 |
29 | export default Navigation;
30 |
--------------------------------------------------------------------------------