├── README.md ├── contract.png ├── index.html ├── manifest.json ├── myscripts.js ├── package.json ├── service-worker.js └── style.css /README.md: -------------------------------------------------------------------------------- 1 | # stick-it-notes 2 | 3 | ## How to download the project? 4 | 5 | Click on the clone/download button and download it as zip. 6 | 7 | Extract the zip by right clicking and extract it to your preferred location 8 | 9 | ## How to run the project 10 | 11 | Double click index.html file. 12 | -------------------------------------------------------------------------------- /contract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tharunShiv/stick-it-notes/9c5ad249823d59c63a8a7f3790f291c4d7eef7c6/contract.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sticky notes 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |

Stick-It Notes

18 |

By Tharun Shiv

19 |
20 |
21 |
22 | 31 | 39 | 42 |
43 |
44 | 45 |

No Notes Found, Add one!

46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Stick-it Notes by Tharun", 3 | "short_name": "Stick-it", 4 | "start_url": "index.html", 5 | "scope": "./", 6 | "icons": [ 7 | { 8 | "src": "contract.png", 9 | "sizes": "192x192", 10 | "type": "image/png" 11 | }, 12 | { 13 | "src": "contract.png", 14 | "sizes": "512x512", 15 | "type": "image/png" 16 | } 17 | ], 18 | "theme_color": "#ffd31d", 19 | "background_color": "#333", 20 | "display": "standalone" 21 | } 22 | -------------------------------------------------------------------------------- /myscripts.js: -------------------------------------------------------------------------------- 1 | if ("serviceWorker" in navigator) { 2 | // register service worker 3 | navigator.serviceWorker.register("service-worker.js"); 4 | } 5 | 6 | var itemList = document.getElementById("notes"); 7 | 8 | itemList.addEventListener("click", removeItem); 9 | 10 | let count = Number(window.localStorage.getItem("count")); 11 | if (!count) { 12 | window.localStorage.setItem("count", "0"); 13 | } 14 | 15 | console.log(count); 16 | 17 | let createNote = (noteTitle, noteBody) => { 18 | if (count > 0) { 19 | document.getElementById("no-notes").className = "hidden"; 20 | } 21 | 22 | var li = document.createElement("li"); 23 | var a = document.createElement("a"); 24 | var h2 = document.createElement("h2"); 25 | var p = document.createElement("p"); 26 | var ul = document.getElementById("notes"); 27 | 28 | let xButton = document.createElement("button"); 29 | xButton.classList.add("delete"); 30 | let xText = document.createTextNode("X"); 31 | let h2TN = document.createTextNode(noteTitle); 32 | let pTN = document.createTextNode(noteBody); 33 | 34 | h2.appendChild(h2TN); 35 | p.appendChild(pTN); 36 | xButton.appendChild(xText); 37 | 38 | a.appendChild(h2); 39 | a.appendChild(xButton); 40 | a.appendChild(p); 41 | a.setAttribute("href", "#"); 42 | 43 | li.appendChild(a); 44 | ul.appendChild(li); 45 | }; 46 | 47 | let createNoteFromInput = (e) => { 48 | e.preventDefault(); 49 | var noteTitle = document.getElementById("new-note-title-input").value; 50 | var noteBody = document.getElementById("new-note-body-input").value; 51 | 52 | document.getElementById("new-note-title-input").value = ""; 53 | document.getElementById("new-note-body-input").value = ""; 54 | 55 | console.log("yes"); 56 | if (!noteTitle || !noteBody) { 57 | alert("Both Title and body of the note must be provided"); 58 | return; 59 | } 60 | count += 1; 61 | window.localStorage.setItem("count", count); 62 | 63 | while (window.localStorage.getItem(noteTitle)) { 64 | noteTitle = noteTitle + " - 1"; 65 | } 66 | window.localStorage.setItem(noteTitle, noteBody); 67 | 68 | createNote(noteTitle, noteBody); 69 | }; 70 | 71 | function removeItem(e) { 72 | //console.log('2'); 73 | if (e.target.classList.contains("delete")) { 74 | console.log(e); 75 | if ( 76 | confirm( 77 | 'Are you sure to delete the "' + 78 | e.target.previousElementSibling.innerText + 79 | '" note?' 80 | ) 81 | ) { 82 | //grab the parent 83 | // console.log(e.target.previousSibling.data); 84 | var li = e.target.parentElement.parentElement; 85 | 86 | itemList.removeChild(li); 87 | count -= 1; 88 | window.localStorage.setItem("count", count); 89 | window.localStorage.removeItem(e.target.previousElementSibling.innerText); 90 | if (count < 1) { 91 | document.getElementById("no-notes").className = ""; 92 | } 93 | } 94 | } 95 | } 96 | 97 | for (i = 0; i < count + 1; i++) { 98 | console.log(window.localStorage.key(i)); 99 | let noteTitle = window.localStorage.key(i); 100 | let noteBody = window.localStorage.getItem(noteTitle); 101 | if (noteTitle !== "count" && noteTitle) { 102 | createNote(noteTitle, noteBody); 103 | } 104 | } 105 | 106 | document 107 | .getElementById("inputForm") 108 | .addEventListener("submit", createNoteFromInput, false); 109 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stick-it-notes", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "myscripts.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "sw-precache": "sw-precache" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/tharunShiv/stick-it-notes.git" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/tharunShiv/stick-it-notes/issues" 18 | }, 19 | "homepage": "https://github.com/tharunShiv/stick-it-notes#readme", 20 | "dependencies": { 21 | "sw-precache": "^5.2.1" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // DO NOT EDIT THIS GENERATED OUTPUT DIRECTLY! 18 | // This file should be overwritten as part of your build process. 19 | // If you need to extend the behavior of the generated service worker, the best approach is to write 20 | // additional code and include it using the importScripts option: 21 | // https://github.com/GoogleChrome/sw-precache#importscripts-arraystring 22 | // 23 | // Alternatively, it's possible to make changes to the underlying template file and then use that as the 24 | // new base for generating output, via the templateFilePath option: 25 | // https://github.com/GoogleChrome/sw-precache#templatefilepath-string 26 | // 27 | // If you go that route, make sure that whenever you update your sw-precache dependency, you reconcile any 28 | // changes made to this original template file with your modified copy. 29 | 30 | // This generated service worker JavaScript will precache your site's resources. 31 | // The code needs to be saved in a .js file at the top-level of your site, and registered 32 | // from your pages in order to be used. See 33 | // https://github.com/googlechrome/sw-precache/blob/master/demo/app/js/service-worker-registration.js 34 | // for an example of how you can register this script and handle various service worker events. 35 | 36 | /* eslint-env worker, serviceworker */ 37 | /* eslint-disable indent, no-unused-vars, no-multiple-empty-lines, max-nested-callbacks, space-before-function-paren, quotes, comma-spacing */ 38 | "use strict"; 39 | 40 | var precacheConfig = [ 41 | ["contract.png", "57f44c7e84e8db553271cc408bbaad22"], 42 | ["index.html", "09cfa67d0f55dd2591b9f9ed72f747a0"], 43 | ["manifest.json", "350a5c214307ff3d11eee259369449b7"], 44 | ["myscripts.js", "298e946e4029dce801f90d9c6ce3cc44"], 45 | ["package.json", "c3e2229df6083112cb941dd02a8eb9e2"], 46 | ["style.css", "265a2c3891fe945c12ce436f7fb85b5e"], 47 | ]; 48 | var cacheName = 49 | "sw-precache-v3-sw-precache-" + 50 | (self.registration ? self.registration.scope : ""); 51 | 52 | var ignoreUrlParametersMatching = [/^utm_/]; 53 | 54 | var addDirectoryIndex = function (originalUrl, index) { 55 | var url = new URL(originalUrl); 56 | if (url.pathname.slice(-1) === "/") { 57 | url.pathname += index; 58 | } 59 | return url.toString(); 60 | }; 61 | 62 | var cleanResponse = function (originalResponse) { 63 | // If this is not a redirected response, then we don't have to do anything. 64 | if (!originalResponse.redirected) { 65 | return Promise.resolve(originalResponse); 66 | } 67 | 68 | // Firefox 50 and below doesn't support the Response.body stream, so we may 69 | // need to read the entire body to memory as a Blob. 70 | var bodyPromise = 71 | "body" in originalResponse 72 | ? Promise.resolve(originalResponse.body) 73 | : originalResponse.blob(); 74 | 75 | return bodyPromise.then(function (body) { 76 | // new Response() is happy when passed either a stream or a Blob. 77 | return new Response(body, { 78 | headers: originalResponse.headers, 79 | status: originalResponse.status, 80 | statusText: originalResponse.statusText, 81 | }); 82 | }); 83 | }; 84 | 85 | var createCacheKey = function ( 86 | originalUrl, 87 | paramName, 88 | paramValue, 89 | dontCacheBustUrlsMatching 90 | ) { 91 | // Create a new URL object to avoid modifying originalUrl. 92 | var url = new URL(originalUrl); 93 | 94 | // If dontCacheBustUrlsMatching is not set, or if we don't have a match, 95 | // then add in the extra cache-busting URL parameter. 96 | if ( 97 | !dontCacheBustUrlsMatching || 98 | !url.pathname.match(dontCacheBustUrlsMatching) 99 | ) { 100 | url.search += 101 | (url.search ? "&" : "") + 102 | encodeURIComponent(paramName) + 103 | "=" + 104 | encodeURIComponent(paramValue); 105 | } 106 | 107 | return url.toString(); 108 | }; 109 | 110 | var isPathWhitelisted = function (whitelist, absoluteUrlString) { 111 | // If the whitelist is empty, then consider all URLs to be whitelisted. 112 | if (whitelist.length === 0) { 113 | return true; 114 | } 115 | 116 | // Otherwise compare each path regex to the path of the URL passed in. 117 | var path = new URL(absoluteUrlString).pathname; 118 | return whitelist.some(function (whitelistedPathRegex) { 119 | return path.match(whitelistedPathRegex); 120 | }); 121 | }; 122 | 123 | var stripIgnoredUrlParameters = function ( 124 | originalUrl, 125 | ignoreUrlParametersMatching 126 | ) { 127 | var url = new URL(originalUrl); 128 | // Remove the hash; see https://github.com/GoogleChrome/sw-precache/issues/290 129 | url.hash = ""; 130 | 131 | url.search = url.search 132 | .slice(1) // Exclude initial '?' 133 | .split("&") // Split into an array of 'key=value' strings 134 | .map(function (kv) { 135 | return kv.split("="); // Split each 'key=value' string into a [key, value] array 136 | }) 137 | .filter(function (kv) { 138 | return ignoreUrlParametersMatching.every(function (ignoredRegex) { 139 | return !ignoredRegex.test(kv[0]); // Return true iff the key doesn't match any of the regexes. 140 | }); 141 | }) 142 | .map(function (kv) { 143 | return kv.join("="); // Join each [key, value] array into a 'key=value' string 144 | }) 145 | .join("&"); // Join the array of 'key=value' strings into a string with '&' in between each 146 | 147 | return url.toString(); 148 | }; 149 | 150 | var hashParamName = "_sw-precache"; 151 | var urlsToCacheKeys = new Map( 152 | precacheConfig.map(function (item) { 153 | var relativeUrl = item[0]; 154 | var hash = item[1]; 155 | var absoluteUrl = new URL(relativeUrl, self.location); 156 | var cacheKey = createCacheKey(absoluteUrl, hashParamName, hash, false); 157 | return [absoluteUrl.toString(), cacheKey]; 158 | }) 159 | ); 160 | 161 | function setOfCachedUrls(cache) { 162 | return cache 163 | .keys() 164 | .then(function (requests) { 165 | return requests.map(function (request) { 166 | return request.url; 167 | }); 168 | }) 169 | .then(function (urls) { 170 | return new Set(urls); 171 | }); 172 | } 173 | 174 | self.addEventListener("install", function (event) { 175 | event.waitUntil( 176 | caches 177 | .open(cacheName) 178 | .then(function (cache) { 179 | return setOfCachedUrls(cache).then(function (cachedUrls) { 180 | return Promise.all( 181 | Array.from(urlsToCacheKeys.values()).map(function (cacheKey) { 182 | // If we don't have a key matching url in the cache already, add it. 183 | if (!cachedUrls.has(cacheKey)) { 184 | var request = new Request(cacheKey, { 185 | credentials: "same-origin", 186 | }); 187 | return fetch(request).then(function (response) { 188 | // Bail out of installation unless we get back a 200 OK for 189 | // every request. 190 | if (!response.ok) { 191 | throw new Error( 192 | "Request for " + 193 | cacheKey + 194 | " returned a " + 195 | "response with status " + 196 | response.status 197 | ); 198 | } 199 | 200 | return cleanResponse(response).then(function ( 201 | responseToCache 202 | ) { 203 | return cache.put(cacheKey, responseToCache); 204 | }); 205 | }); 206 | } 207 | }) 208 | ); 209 | }); 210 | }) 211 | .then(function () { 212 | // Force the SW to transition from installing -> active state 213 | return self.skipWaiting(); 214 | }) 215 | ); 216 | }); 217 | 218 | self.addEventListener("activate", function (event) { 219 | var setOfExpectedUrls = new Set(urlsToCacheKeys.values()); 220 | 221 | event.waitUntil( 222 | caches 223 | .open(cacheName) 224 | .then(function (cache) { 225 | return cache.keys().then(function (existingRequests) { 226 | return Promise.all( 227 | existingRequests.map(function (existingRequest) { 228 | if (!setOfExpectedUrls.has(existingRequest.url)) { 229 | return cache.delete(existingRequest); 230 | } 231 | }) 232 | ); 233 | }); 234 | }) 235 | .then(function () { 236 | return self.clients.claim(); 237 | }) 238 | ); 239 | }); 240 | 241 | self.addEventListener("fetch", function (event) { 242 | if (event.request.method === "GET") { 243 | // Should we call event.respondWith() inside this fetch event handler? 244 | // This needs to be determined synchronously, which will give other fetch 245 | // handlers a chance to handle the request if need be. 246 | var shouldRespond; 247 | 248 | // First, remove all the ignored parameters and hash fragment, and see if we 249 | // have that URL in our cache. If so, great! shouldRespond will be true. 250 | var url = stripIgnoredUrlParameters( 251 | event.request.url, 252 | ignoreUrlParametersMatching 253 | ); 254 | shouldRespond = urlsToCacheKeys.has(url); 255 | 256 | // If shouldRespond is false, check again, this time with 'index.html' 257 | // (or whatever the directoryIndex option is set to) at the end. 258 | var directoryIndex = "index.html"; 259 | if (!shouldRespond && directoryIndex) { 260 | url = addDirectoryIndex(url, directoryIndex); 261 | shouldRespond = urlsToCacheKeys.has(url); 262 | } 263 | 264 | // If shouldRespond is still false, check to see if this is a navigation 265 | // request, and if so, whether the URL matches navigateFallbackWhitelist. 266 | var navigateFallback = ""; 267 | if ( 268 | !shouldRespond && 269 | navigateFallback && 270 | event.request.mode === "navigate" && 271 | isPathWhitelisted([], event.request.url) 272 | ) { 273 | url = new URL(navigateFallback, self.location).toString(); 274 | shouldRespond = urlsToCacheKeys.has(url); 275 | } 276 | 277 | // If shouldRespond was set to true at any point, then call 278 | // event.respondWith(), using the appropriate cache key. 279 | if (shouldRespond) { 280 | event.respondWith( 281 | caches 282 | .open(cacheName) 283 | .then(function (cache) { 284 | return cache 285 | .match(urlsToCacheKeys.get(url)) 286 | .then(function (response) { 287 | if (response) { 288 | return response; 289 | } 290 | throw Error( 291 | "The cached response that was expected is missing." 292 | ); 293 | }); 294 | }) 295 | .catch(function (e) { 296 | // Fall back to just fetch()ing the request if some unexpected error 297 | // prevented the cached response from being valid. 298 | console.warn( 299 | 'Couldn\'t serve response for "%s" from cache: %O', 300 | event.request.url, 301 | e 302 | ); 303 | return fetch(event.request); 304 | }) 305 | ); 306 | } 307 | } 308 | }); 309 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | body { 7 | font-family: arial, sans-serif; 8 | font-size: 100%; 9 | margin: 3em; 10 | background: #333; 11 | color: #fff; 12 | } 13 | 14 | #heading { 15 | position: sticky; 16 | top: 0; 17 | background-color: #333; 18 | z-index: 7; 19 | padding: 15px 0px; 20 | margin-left: 15px; 21 | } 22 | 23 | #no-notes { 24 | padding: 100px 0px; 25 | text-align: center; 26 | } 27 | 28 | #ts { 29 | color: #ffd31d; 30 | } 31 | 32 | .inputText { 33 | padding: 10px; 34 | border-radius: 5px; 35 | border: 2px solid #ffd31d; 36 | width: 30%; 37 | margin: 15px; 38 | outline: none; 39 | } 40 | 41 | .hidden { 42 | display: none; 43 | } 44 | 45 | .btn { 46 | padding: 10px; 47 | border-radius: 20px; 48 | border: 2px solid #ffd31d; 49 | background-color: #ffd31d; 50 | color: #333; 51 | cursor: pointer; 52 | outline: none; 53 | -webkit-tap-highlight-color: transparent; 54 | } 55 | 56 | .btn:active { 57 | border: 2px solid #333; 58 | box-shadow: inset 0 0 5px #000000; 59 | } 60 | 61 | h2, 62 | p { 63 | font-size: 100%; 64 | font-weight: normal; 65 | } 66 | 67 | ul, 68 | li { 69 | list-style: none; 70 | } 71 | 72 | ul { 73 | overflow: hidden; 74 | padding: 3em 1em; 75 | } 76 | 77 | ul li a { 78 | text-decoration: none; 79 | color: #000; 80 | background: #ffd31d; 81 | display: block; 82 | height: 10em; 83 | width: 10em; 84 | padding: 1em; 85 | box-shadow: 5px 5px 7px rgba(33, 33, 33, 0.7); 86 | } 87 | 88 | ul li { 89 | margin: 1em; 90 | float: left; 91 | position: relative; 92 | } 93 | 94 | ul li h2 { 95 | font-size: 1.2rem; 96 | font-weight: bold; 97 | padding-bottom: 10px; 98 | } 99 | 100 | ul li p { 101 | font-family: "Reenie Beanie", cursive; 102 | font-size: 1.1rem; 103 | } 104 | 105 | .delete { 106 | float: right; 107 | position: absolute; 108 | top: 0; 109 | right: 0; 110 | width: 30px; 111 | height: 30px; 112 | background-color: red; 113 | border: 4px double white; 114 | font-weight: bold; 115 | cursor: pointer; 116 | } 117 | 118 | ul li a { 119 | transform: rotate(-6deg); 120 | -moz-transform: rotate(-6deg); 121 | cursor: default; 122 | } 123 | 124 | ul li:nth-child(even) a { 125 | transform: rotate(4deg); 126 | -moz-transform: rotate(4deg); 127 | position: relative; 128 | top: 5px; 129 | background: #ff5733; 130 | } 131 | 132 | ul li:nth-child(3n) a { 133 | transform: rotate(-3deg); 134 | -moz-transform: rotate(-3deg); 135 | position: relative; 136 | top: -5px; 137 | background: #77d8d8; 138 | } 139 | 140 | ul li:nth-child(5n) a { 141 | transform: rotate(5deg); 142 | -moz-transform: rotate(5deg); 143 | position: relative; 144 | top: -10px; 145 | } 146 | 147 | ul li a:hover, 148 | ul li a:focus { 149 | box-shadow: 10px 10px 7px rgba(0, 0, 0, 0.7); 150 | -moz-box-shadow: 10px 10px 7px rgba(0, 0, 0, 0.7); 151 | transform: scale(1.25); 152 | -moz-transform: scale(1.25); 153 | position: relative; 154 | z-index: 5; 155 | } 156 | 157 | ol { 158 | text-align: center; 159 | } 160 | 161 | ol li { 162 | display: inline; 163 | padding-right: 1em; 164 | } 165 | 166 | ol li a { 167 | color: #fff; 168 | } 169 | 170 | @media only screen and (max-width: 600px) { 171 | body { 172 | margin-top: 1em; 173 | } 174 | #new-note-title-input, 175 | #new-note-body-input { 176 | display: block; 177 | width: 90%; 178 | margin-left: 0px; 179 | } 180 | 181 | #heading { 182 | margin-left: 0px; 183 | } 184 | 185 | .btn { 186 | margin-left: 0px; 187 | } 188 | } 189 | --------------------------------------------------------------------------------