diff --git a/Readme.md b/Readme.md index 7dfb8e7..204a75f 100644 --- a/Readme.md +++ b/Readme.md @@ -1,10 +1,11 @@ - # QuickNotes QuickNotes is a web application that allows users to create, view, edit, delete, and organize notes into different sections such as **To do**, **Doing**, and **Done**. Notes are stored in localStorage to persist across sessions. The app includes a drag-and-drop feature for moving notes between sections and color-coding based on priority. ## Features +- **Sign Up**: Users can create an account by providing a unique username and password. The app will store user credentials in localStorage, allowing them to sign in from any session. +- **Sign In**: Registered users can log in with their username and password. After signing in, the app will load the notes specific to that user. - **Create Notes**: Users can create new notes with content, priority, and timestamp. - **Drag and Drop**: Notes can be dragged between **To do**, **Doing**, and **Done** sections. - **Edit Notes**: Users can edit existing notes and save changes. @@ -14,22 +15,30 @@ QuickNotes is a web application that allows users to create, view, edit, delete, - **Persistent Data**: Notes are stored in localStorage and persist even after page reloads. + ## Screenshots +1. **Signing Up** + + ![Main Interface](./assets/screenschots/signup.png) + +1. **Signing In** + + ![Main Interface](./assets/screenschots/signin.png) -1. **Main Interface** +3. **Main Interface** ![Main Interface](./assets/screenschots/main_interface.png) -2. **Board Interface** +4. **Board Interface** ![Note Creation](./assets/screenschots/board_interface.png) -3. **Note Creation** +5. **Note Creation** ![Note Creation](./assets/screenschots/note_creation.png) -4. **Note Editing** +6. **Note Editing** ![Note Editing](./assets/screenschots/note_editing.png) @@ -40,18 +49,28 @@ QuickNotes is a web application that allows users to create, view, edit, delete, ```bash QuickNotes/ -│ ├── assets/ │ ├── CSS/ │ │ └── styles.css │ └── Javascript/ │ ├── board.js │ ├── constants.js +│ ├── signin.js +│ ├── signup.js │ └── index.js +├── screenshots/ +│ ├── board_interface.png +│ ├── main_interface.png +│ ├── note_creation.png +│ ├── note_editing.png +│ ├── signin.png +│ ├── signup.png +│ └── userImage.webp ├── board.html ├── index.html +├── signin.html +├── signup.html └── Readme.md - ``` diff --git a/assets/CSS/styles.css b/assets/CSS/styles.css index e1917ec..ad76e89 100644 --- a/assets/CSS/styles.css +++ b/assets/CSS/styles.css @@ -262,10 +262,6 @@ } - .hidden{ - display: none; - } - /* ......................................... view note ..................................... */ /* Popup container */ @@ -449,4 +445,211 @@ .drop-section th{ width: 100%; } - } \ No newline at end of file + } + +.header a{ + text-decoration: none; + color: black; + font-size: 1.2em; + +} +.header-navs{ + display: flex; + gap: 20px; + align-items: center; +} + +.form-error{ + color: red; +} + + /* Signup Page Styling */ +.signup-container { + display: flex; + justify-content: center; + align-items: center; + height: 80vh; +} + +.signup-form { + background-color: #fff; + border-radius: 10px; + padding: 40px; + width: 350px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + text-align: center; +} + +.signup-form h2 { + font-size: 1.8rem; + margin-bottom: 20px; + color: #333; +} + +.signup-form label { + display: block; + text-align: left; + font-size: 1rem; + color: #333; + margin-bottom: 8px; +} + +.signup-form input { + width: 100%; + padding: 10px; + margin-bottom: 20px; + border: 1px solid #ddd; + border-radius: 5px; + font-size: 1rem; + outline: none; + background-color: #f9f9f9; + transition: border-color 0.3s ease; +} + +.signup-form input:focus { + border-color: #48CFCB; +} + +.signup-btn,.signin-btn { + background-color: #48CFCB; + color: #fff; + border: none; + padding: 10px 20px; + width: 100%; + border-radius: 5px; + cursor: pointer; + font-size: 1rem; + transition: background-color 0.3s ease; +} + +.signup-btn:hover { + background-color: #45b7b3; +} + + +.signed-in-header-box > img{ + width: 50px; + height: 50px; + border-radius: 100%; +} +.signed-in-header-box{ + display: flex; + align-items: center; + gap: 10px; + padding: 10px; + position: relative; + cursor: pointer; +} +.sign-in-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 70vh; + background-color: transparent; + /* border: 1px solid #ccc; */ + border-radius: 10px; + padding: 40px; + text-align: center; + grid-column: 1 / -1 +} + +.sign-in-container h2 { + font-size: 2rem; + margin-bottom: 20px; +} + +.sign-in-container p { + font-size: 1.2rem; + margin-bottom: 30px; +} + +.note-section-sign-in-btn { + background-color: #48CFCB; + color: white; + border: none; + padding: 10px 20px; + font-size: 1rem; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s ease; + text-decoration: none; +} + +.note-section-sign-in-btn:hover { + background-color: #45b7b3; +} + +.logout-box { + position: absolute; + width: 80%; + left: 50%; + transform: translateX(-50%); + bottom: -80%; + background-color: white; + padding: 10px; +} + +.logout-btn{ + background-color: #48CFCB; + color: white; + border: none; + padding: 10px 20px; + font-size: 1rem; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s ease; + text-decoration: none; + width: 100%; + +} + +.logout-btn:hover { + background-color: #45b7b3; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.hidden{ + display: none; +} \ No newline at end of file diff --git a/assets/Javascript/board.js b/assets/Javascript/board.js index a1adc21..c26d987 100644 --- a/assets/Javascript/board.js +++ b/assets/Javascript/board.js @@ -12,7 +12,7 @@ let notes = JSON.parse(localStorage.getItem("notes")) || []; const todoSection = document.querySelector(".todo-section"); const doingSection = document.querySelector(".doing-section"); const doneSection = document.querySelector(".done-section"); - +const signInContainer = document.querySelector('.sign-in-container'); todoSection.addEventListener("dragover", (e) => e.preventDefault()); doingSection.addEventListener("dragover", (e) => e.preventDefault()); doneSection.addEventListener("dragover", (e) => e.preventDefault()); @@ -52,9 +52,42 @@ doneSection.addEventListener("drop", (e) => { const sections = [todoSection, doingSection, doneSection]; let viewNoteId; +const userLoggedIn = JSON.parse(localStorage.getItem("userLoggedIn")) || null; +const loggedInUserBox = document.querySelector('.user-name'); +const headerNavs = document.querySelector(".header-navs"); +const signedInHeaderBox = document.querySelector(".signed-in-header-box"); +const logoutBtn = document.querySelector('.logout-btn'); +const logoutBox = document.querySelector('.logout-box'); + + + +signedInHeaderBox.addEventListener('click',() => logoutBox.classList.toggle('hidden')); + +logoutBtn.addEventListener('click',(e)=>{ + e.preventDefault(); + localStorage.removeItem('userLoggedIn'); + window.location.reload(); + + +}) + + + +window.addEventListener('load',() => { + console.log(headerNavs); + + if (userLoggedIn) { + headerNavs.classList.add("hidden"); + signedInHeaderBox.classList.remove("hidden"); + loggedInUserBox.textContent = userLoggedIn.name; + + signInContainer.classList.add('hidden'); + + } +}); + // Render notes -notes.forEach(renderNote); -console.log(notes); +notes.filter(note => note.user_id == userLoggedIn.id).forEach(renderNote); const createNoteSection = document.querySelector(".create-note"); const createNoteBtn = document.querySelector(".create-btn"); @@ -80,8 +113,12 @@ viewSectionSaveBtn.addEventListener("click", saveNote); viewSectionEditBtn.addEventListener("click", editNote); function renderNote(note) { + signInContainer.classList.add('hidden'); + todoSection.classList.remove('hidden'); + doingSection.classList.remove('hidden'); + doneSection.classList.remove('hidden'); const html = ` - + ${note.content} @@ -198,6 +235,7 @@ function createNote(e) { const note_id = newDate.getTime(); notes.push({ + user_id: userLoggedIn.id, note_id, timestamp: `Created on ${timestamp}`, content: createNoteTextarea.value, diff --git a/assets/Javascript/index.js b/assets/Javascript/index.js index f8ece1e..2b6942d 100644 --- a/assets/Javascript/index.js +++ b/assets/Javascript/index.js @@ -3,8 +3,37 @@ import { months, priorityBasedColouring } from "./constants.js"; // Initialize notes from localStorage first let notes = JSON.parse(localStorage.getItem("notes")) || []; +const userLoggedIn = JSON.parse(localStorage.getItem("userLoggedIn")) || null; const sortDropdownmenu = document.querySelector(".sort"); +const loggedInUserBox = document.querySelector('.user-name'); +const headerNavs = document.querySelector(".header-navs"); +const signedInHeaderBox = document.querySelector(".signed-in-header-box"); sortDropdownmenu.value = localStorage.getItem("sorted") || "default"; +const signInContainer = document.querySelector('.sign-in-container'); +const logoutBtn = document.querySelector('.logout-btn'); +const logoutBox = document.querySelector('.logout-box'); + +console.log(signedInHeaderBox); + +signedInHeaderBox.addEventListener('click',() => logoutBox.classList.toggle('hidden')); + +logoutBtn.addEventListener('click',(e)=>{ + e.preventDefault(); + localStorage.removeItem('userLoggedIn'); + window.location.reload(); +}) + +console.log(userLoggedIn); + +window.addEventListener('load',() => { + if (userLoggedIn) { + headerNavs.classList.add("hidden"); + signedInHeaderBox.classList.remove("hidden"); + loggedInUserBox.textContent = userLoggedIn.name; + + signInContainer.classList.add('hidden'); + } +}); // Define functions to manage the DOM function closeCreateSection() { @@ -37,6 +66,7 @@ function createNote(e) { const note_id = newDate.getTime(); notes.push({ + user_id: userLoggedIn.id, note_id, timestamp: `Created on ${timestamp}`, content: createNoteTextarea.value, @@ -68,7 +98,7 @@ function giveColorBasedOnPriority(e) { function renderNote(note) { const html = ` -
+

${note.content}

@@ -264,7 +294,7 @@ const viewSectionTextarea = document.querySelector(".view-note-textarea"); const viewNotePriority = document.querySelector(".view-note-priority"); // Render notes once the page is loaded -notes.forEach(renderNote); +notes.filter(note => note.user_id == userLoggedIn.id).forEach(renderNote); // Add event listeners viewSectionCloseBtn.addEventListener("click", closeViewSection); diff --git a/assets/Javascript/signin.js b/assets/Javascript/signin.js new file mode 100644 index 0000000..dda7e31 --- /dev/null +++ b/assets/Javascript/signin.js @@ -0,0 +1,26 @@ +const email = document.querySelector("#email"); +const password = document.querySelector('#password'); +const formError = document.querySelector(".form-error"); +const signInBtn = document.querySelector('.signin-btn'); + +signInBtn.addEventListener('click', (e) => { + e.preventDefault(); + + const users = JSON.parse(localStorage.getItem("users")) || []; + const user = users.find((e)=>e.email === email.value); + if(!user){ + formError.textContent = "User not found"; + formError.classList.remove("hidden"); + return; + } + + if(user.password !== password.value){ + formError.textContent = "Password didn't match"; + formError.classList.remove("hidden"); + return; + } + + localStorage.setItem("userLoggedIn", JSON.stringify(user)); + + window.location.href = "index.html"; +}) \ No newline at end of file diff --git a/assets/Javascript/signup.js b/assets/Javascript/signup.js new file mode 100644 index 0000000..b881b70 --- /dev/null +++ b/assets/Javascript/signup.js @@ -0,0 +1,57 @@ +const fullName = document.querySelector("#full-name"); +const email = document.querySelector("#email"); +const password = document.querySelector("#password"); +const signupButton = document.querySelector(".signup-btn"); +const formError = document.querySelector(".form-error"); + +function handleFocus(e) { + formError.classList.add("hidden"); +} + +fullName.addEventListener("focus", handleFocus); +email.addEventListener("focus", handleFocus); +password.addEventListener("focus", handleFocus); + +signupButton.addEventListener("click", (e) => { + e.preventDefault(); + + const users = JSON.parse(localStorage.getItem("users")) || []; + + const emailValid = true; + users.forEach((user) => { + if (user.email === email?.value) { + formError.textContent = "Email already registered"; + formError.classList.remove("hidden"); + emailValid = false; + return; + } + }); + + if (!emailValid) return; + + if ( + !email.value.includes("@") || + fullName.value.trim() === "" || + password.value.trim() === "" || + password.value.length < 8 + ) { + formError.textContent = "Enter valid Inputs"; + formError.classList.remove("hidden"); + return; + } + + const newUser = { + id: new Date().getTime(), + name: fullName.value, + email: email.value, + password: password.value, + }; + users.push(newUser); + + localStorage.setItem("users", JSON.stringify(users)); + + signupButton.style.backgroundColor = "lightgrey"; + setTimeout(() => { + window.location.href = "signin.html"; + }, 1000); +}); diff --git a/assets/screenschots/signin.png b/assets/screenschots/signin.png new file mode 100644 index 0000000..1d34314 Binary files /dev/null and b/assets/screenschots/signin.png differ diff --git a/assets/screenschots/signup.png b/assets/screenschots/signup.png new file mode 100644 index 0000000..e6bc117 Binary files /dev/null and b/assets/screenschots/signup.png differ diff --git a/assets/screenschots/userImage.webp b/assets/screenschots/userImage.webp new file mode 100644 index 0000000..f177a45 Binary files /dev/null and b/assets/screenschots/userImage.webp differ diff --git a/board.html b/board.html index 4dddd29..9d53817 100644 --- a/board.html +++ b/board.html @@ -36,6 +36,20 @@

QuickNotes A quick note taking web applicaton

+ + + + +
@@ -46,6 +60,7 @@ Table View
+ - + + - - + + - + diff --git a/index.html b/index.html index 3f6382b..1033fc9 100644 --- a/index.html +++ b/index.html @@ -36,6 +36,20 @@

QuickNotes A quick note taking web applicaton

+ + + + +
@@ -47,7 +61,13 @@ Board View
-
+
+ +
Doing