From 0278a785d3ae63117215050899ac4b053bfe3e55 Mon Sep 17 00:00:00 2001 From: Alexis Hovorka Date: Sun, 9 Jan 2022 19:53:09 -0700 Subject: Initial commit --- app/public/404.html | 1 + app/public/500.html | 1 + app/public/index.html | 64 +++++++++++++++++++++++++++++++++++++++++ app/public/main.js | 18 ++++++++++++ app/public/manifest.webmanifest | 26 +++++++++++++++++ app/public/sock.js | 43 +++++++++++++++++++++++++++ app/public/style.css | 14 +++++++++ app/public/sw1.js | 29 +++++++++++++++++++ app/public/sw2.js | 40 ++++++++++++++++++++++++++ 9 files changed, 236 insertions(+) create mode 100644 app/public/404.html create mode 100644 app/public/500.html create mode 100644 app/public/index.html create mode 100644 app/public/main.js create mode 100644 app/public/manifest.webmanifest create mode 100644 app/public/sock.js create mode 100644 app/public/style.css create mode 100644 app/public/sw1.js create mode 100644 app/public/sw2.js (limited to 'app/public') diff --git a/app/public/404.html b/app/public/404.html new file mode 100644 index 0000000..1a43d0a --- /dev/null +++ b/app/public/404.html @@ -0,0 +1 @@ +
404 Not Found
diff --git a/app/public/500.html b/app/public/500.html new file mode 100644 index 0000000..ee07335 --- /dev/null +++ b/app/public/500.html @@ -0,0 +1 @@ +
500 Internal Server Error
diff --git a/app/public/index.html b/app/public/index.html new file mode 100644 index 0000000..3c435f5 --- /dev/null +++ b/app/public/index.html @@ -0,0 +1,64 @@ + + + + Notes + + + + + + + + + + + + + + + +

Notes

+ + + + + diff --git a/app/public/main.js b/app/public/main.js new file mode 100644 index 0000000..ff960c2 --- /dev/null +++ b/app/public/main.js @@ -0,0 +1,18 @@ +document.addEventListener("DOMContentLoaded", async () => { "use strict"; + +const secure = location.protocol === "https:"; +const $ = (s,c) => (c||document).querySelector(s); +function $$(x,y,z,a){a=(z||document).querySelectorAll(x);if(typeof y=="function")[].forEach.call(a,y);return a} +function m(a,b,c){c=document;b=c.createElement(b||"p");b.innerHTML=a.trim();for(a=c.createDocumentFragment();c=b.firstChild;)a.appendChild(c);return a.firstChild} + +//sock.init(`ws${secure?"s":""}://${location.host}/ws`); +//sock.on("hello", e => { +// console.log("hello", e); +// sock.send("world", {foo:"bar"}); +//}); + +//if ("serviceWorker" in navigator) { +// navigator.serviceWorker.register("sw.js") +// .then(() => console.log("Service worker registered")); +//} +}); diff --git a/app/public/manifest.webmanifest b/app/public/manifest.webmanifest new file mode 100644 index 0000000..9eb9f13 --- /dev/null +++ b/app/public/manifest.webmanifest @@ -0,0 +1,26 @@ +{ + "name": "Notes", + "short_name": "Notes", + "description": "Zettelkasten-inspired note taking web app", + "categories": ["productivity", "utilities"], + "lang": "en-US", + "start_url": "/", + "scope": "/", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#000000", + "icons": [ + {"type": "image/png", "sizes": "48x48", "src": "img/favicon-48.png" }, + {"type": "image/png", "sizes": "96x96", "src": "img/favicon-96.png" }, + {"type": "image/png", "sizes": "192x192", "src": "img/favicon-192.png", "purpose": "maskable any"}, + {"type": "image/png", "sizes": "256x256", "src": "img/favicon-256.png", "purpose": "maskable any"}, + {"type": "image/png", "sizes": "512x512", "src": "img/favicon-512.png", "purpose": "maskable any"}, + + {"type": "image/png", "sizes": "72x72", "src": "img/apple-touch-icon-72.png" }, + {"type": "image/png", "sizes": "144x144", "src": "img/apple-touch-icon-144.png"}, + {"type": "image/png", "sizes": "168x168", "src": "img/apple-touch-icon-168.png"} + ], + "shortcuts": [ + {"name": "New", "url": "/new"} + ] +} diff --git a/app/public/sock.js b/app/public/sock.js new file mode 100644 index 0000000..b4905e5 --- /dev/null +++ b/app/public/sock.js @@ -0,0 +1,43 @@ +const sock = (() => { "use strict"; +const refresh = () => setTimeout(() => location.reload(), 1e3); + +let ws, pingTimeout; +const prequeue = []; +const handlers = { + "reset": [refresh], + "ping": [() => { + clearTimeout(pingTimeout); + pingTimeout = setTimeout(refresh, 3e4); + sock.send("pong", {}); + }], +}; + +const sock = { + init: url => { + ws = new WebSocket(url); + ws.addEventListener("close", refresh); + ws.addEventListener("error", refresh); + ws.addEventListener("message", e => { + const d = JSON.parse(e.data); + (handlers[d.type]||[]).forEach(cb => cb(d.data)); + }); + ws.addEventListener("open", e => { + while (prequeue.length) sock.send(...prequeue.shift()); + (handlers["open"]||[]).forEach(cb => cb()); + delete handlers["open"]; + }); + }, + + on: (type, cb) => { + if (type === "open" && ws && ws.readyState === WebSocket.OPEN) cb(); + else (handlers[type]||(handlers[type]=[])).push(cb); + }, + + send: (type, data) => { + if (ws && ws.readyState === WebSocket.OPEN) + ws.send(JSON.stringify({type, data})); + else prequeue.push([type, data]); + }, +}; + +return sock })(); diff --git a/app/public/style.css b/app/public/style.css new file mode 100644 index 0000000..655e181 --- /dev/null +++ b/app/public/style.css @@ -0,0 +1,14 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: "Roboto", "Noto Sans", sans-serif; + transition-timing-function: ease-in-out; +} + +body { + user-select: none; + -webkit-user-select: none; + -webkit-touch-callout: none; + -webkit-tap-highlight-color: transparent; +} diff --git a/app/public/sw1.js b/app/public/sw1.js new file mode 100644 index 0000000..37ae5e5 --- /dev/null +++ b/app/public/sw1.js @@ -0,0 +1,29 @@ +// https://gist.github.com/adactio/3717b7da007a9363ddf21f584aae34af + +// HTML files: try the network first, then the cache. +// Other files: try the cache first, then the network. +// Both: cache a fresh version if possible. +// (beware: the cache will grow and grow; there's no cleanup) + +const cacheName = "notes-cache-v1"; + +addEventListener("fetch", fetchEvent => { + const request = fetchEvent.request; + if (request.method !== "GET") return; + fetchEvent.respondWith(async () => { + const fetchPromise = fetch(request); + fetchEvent.waitUntil(async () => { + const responseFromFetch = await fetchPromise; + const responseCopy = responseFromFetch.clone(); + const myCache = await caches.open(cacheName); + return myCache.put(request, responseCopy); + }()); + if (request.headers.get("Accept").includes("text/html")) { + try { return await fetchPromise; } + catch(error) { return caches.match(request); } + } else { + const responseFromCache = await caches.match(request); + return responseFromCache || fetchPromise; + } + }()); +}); diff --git a/app/public/sw2.js b/app/public/sw2.js new file mode 100644 index 0000000..0dabb13 --- /dev/null +++ b/app/public/sw2.js @@ -0,0 +1,40 @@ +// https://googlechrome.github.io/samples/service-worker/basic/ + +const PRECACHE = "notes-precache-v1"; +const RUNTIME = "notes-runtime"; + +const PRECACHE_URLS = [ + "./", // Alias for index.html + "index.html", + "style.css", + "main.js" +]; + +self.addEventListener("install", e => e.waitUntil( + caches.open(PRECACHE) + .then(cache => cache.addAll(PRECACHE_URLS)) + .then(self.skipWaiting()))); + +self.addEventListener("activate", e => { + const currentCaches = [PRECACHE, RUNTIME]; + e.waitUntil( // Clean up old caches + caches.keys().then(cacheNames => + cacheNames.filter(cacheName => !currentCaches.includes(cacheName)) + ).then(cachesToDelete => Promise.all(cachesToDelete.map(cacheToDelete => + caches.delete(cacheToDelete))) + ).then(() => self.clients.claim()) + ); +}); + +self.addEventListener("fetch", e => { + if (e.request.url.startsWith(self.location.origin)) { + e.respondWith(caches.match(e.request).then(cachedResponse => + cachedResponse? cachedResponse + : caches.open(RUNTIME).then(cache => + fetch(e.request).then(res => + cache.put(e.request, res.clone()).then(() => res) + ) + ) + )); + } +}); -- cgit v1.2.3-70-g09d2