diff --git a/priv/static/js/jenot.js b/priv/static/js/jenot.js index ace87e9..9d9f5ce 100644 --- a/priv/static/js/jenot.js +++ b/priv/static/js/jenot.js @@ -9,6 +9,38 @@ import { } from "./notifications.js"; import "./components.js"; import { reminderLabel } from "./reminders.js"; +import { Router } from "./router.js"; + +// Cookie presence determines login state +const isLoggedIn = !!document.cookie + .split("; ") + .find((row) => row.startsWith("jenot_pub=")); + +// Notes storage configuration. +// The storage is a combination of IndexedDB + network sync. +// Network sync is only enabled is user is logged in. +const endpoint = isLoggedIn ? "/" : null; +const Notes = new SyncedNoteStore("jenot-app", endpoint); + +let view = "home"; + +const routes = [ + { + path: "index.html#home", + callback: () => { + view = "home"; + render(); + }, + }, + { + path: "index.html#reminders", + callback: () => { + view = "reminders"; + render(); + }, + }, + { path: "*", callback: (router) => router.redirect("index.html#home") }, +]; async function resetApp() { await window.navigator.serviceWorker @@ -24,16 +56,6 @@ document.querySelector("#reset-app").addEventListener("click", resetApp); const URL_PARAMS = new URLSearchParams(window.location.search); -// Cookie presence determines login state -const isLoggedIn = !!document.cookie - .split("; ") - .find((row) => row.startsWith("jenot_pub=")); - -// Notes storage configuration. -// The storage is a combination of IndexedDB + network sync. -// Network sync is only enabled is user is logged in. -const endpoint = isLoggedIn ? "/" : null; -const Notes = new SyncedNoteStore("jenot-app", endpoint); await Notes.init(); // Reset metadata to force full sync @@ -184,7 +206,16 @@ function notesEqual(note1, note2) { return note1.id === note2.id && note1.updated === note2.updated; } -async function render() { +async function renderReminders() { + const allNotes = await Notes.all(); + const reminderNotes = allNotes.filter((n) => n.reminder?.enabled); + const notes = filterNotes(reminderNotes).toSorted( + (a, b) => b.reminder.date - a.reminder.date, + ); + const notesContainer = document.querySelector("#reminders"); +} + +async function renderHome() { const allNotes = await Notes.all(); const notes = filterNotes(allNotes); const notesContainer = document.querySelector("#notes"); @@ -234,6 +265,19 @@ async function render() { notes.forEach((n) => (currentNotes[n.id] = structuredClone(n))); } +async function render() { + switch (view) { + case "home": + renderHome(); + break; + case "reminders": + renderReminders(); + break; + default: + renderError(); + } +} + function openModal(modal) { document.body.style.top = `-${window.scrollY}px`; document.body.style.position = "fixed"; @@ -309,3 +353,5 @@ function renderNote(note) { return container; } + +const router = Router.init(routes); diff --git a/priv/static/js/notes-view.js b/priv/static/js/notes-view.js new file mode 100644 index 0000000..545e5a0 --- /dev/null +++ b/priv/static/js/notes-view.js @@ -0,0 +1,7 @@ +export async function mount() { + +} + +export async function render() { + +} diff --git a/priv/static/js/reminders-view.js b/priv/static/js/reminders-view.js new file mode 100644 index 0000000..e69de29 diff --git a/priv/static/js/router.js b/priv/static/js/router.js new file mode 100644 index 0000000..e9b4ac3 --- /dev/null +++ b/priv/static/js/router.js @@ -0,0 +1,51 @@ +export class Router { + constructor(routes) { + this.routes = routes; + + window.addEventListener("popstate", () => { + this.loadInitialRoute(); + }); + } + + static init(routes) { + const router = new Router(routes); + router.loadInitialRoute(); + return router; + } + + loadRoute(path) { + const matchedRoute = this.#matchURLToRoute(path); + + if (!matchedRoute) { + throw new Error("Route not found!"); + } + + matchedRoute.callback(this); + } + + navigateTo(path) { + window.history.pushState({}, "", path); + this.loadRoute(path); + } + + redirect(path) { + this.loadRoute(path); + } + + #matchURLToRoute(path) { + const found = this.routes.find((router) => router.path === path); + + if (!found) { + return this.routes.find((router) => router.path === "*"); + } + + return found; + } + + loadInitialRoute() { + const pathParts = window.location.pathname.split("/"); + const path = pathParts.length > 1 ? pathParts[1] : ""; + + this.loadRoute(path); + } +} diff --git a/priv/static/style.css b/priv/static/style.css index 0a5fa89..7052032 100644 --- a/priv/static/style.css +++ b/priv/static/style.css @@ -53,6 +53,10 @@ dialog { max-height: 90vh; } +/* dialog[open] { */ +/* oversrcoll-behavior-y: contain; */ +/* } */ + ::backdrop { background: var(--backdrop-background); opacity: 0.75;