From: Adam Dullage Date: Thu, 17 Feb 2022 12:36:40 +0000 (+0000) Subject: Added Routing X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=120bd82e9571b5a3d72b74aa625b6d2f93c9f968;p=flatnotes.git Added Routing --- diff --git a/.gitignore b/.gitignore index 53dadd9..fb14dd3 100644 --- a/.gitignore +++ b/.gitignore @@ -248,3 +248,4 @@ dist # Custom .vscode/ data/ +notes/ diff --git a/README.md b/README.md index 8a82143..2c1d359 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,15 @@ This is what flatnotes aims to achieve. * [x] Password Authentication * [x] Ability to Create a Note * [x] Ability to Rename a Note +* [x] Routing +* [ ] Loading & Not Found Indicators +* [ ] Ability to Delete a Note +* [ ] / to search +* [ ] e to edit +* [ ] CTRL-S to save +* [ ] Drafts +* [ ] Image Embedding +* [ ] Index Page (alphabetically sorted note list) * [ ] Clean & Responsive UI * [ ] Public URL Sharing -* [ ] Image Embedding * [ ] Attachment Upload -* [ ] Ability to Delete a Note -* [ ] Error Handling diff --git a/flatnotes/main.py b/flatnotes/main.py index 4123faa..7d7ea21 100644 --- a/flatnotes/main.py +++ b/flatnotes/main.py @@ -45,7 +45,10 @@ async def token(data: LoginModel): @app.get("/") -async def root(): +@app.get("/login") +@app.get("/search") +@app.get("/note/{filename}") +async def root(filename: str = ""): with open("flatnotes/dist/index.html", "r", encoding="utf-8") as f: html = f.read() return HTMLResponse(content=html) diff --git a/flatnotes/src/api.js b/flatnotes/src/api.js index b1912cf..3b3c336 100644 --- a/flatnotes/src/api.js +++ b/flatnotes/src/api.js @@ -1,5 +1,5 @@ import axios from "axios"; -import EventBus from "./eventBus.js"; +import * as constants from "./constants"; const api = axios.create(); @@ -25,7 +25,12 @@ api.interceptors.response.use( typeof error.response !== "undefined" && error.response.status === 401 ) { - EventBus.$emit("logout"); + window.open( + `/${constants.basePaths.login}?${constants.params.redirect}=${encodeURI( + window.location.pathname + window.location.search + )}`, + "_self" + ); } return Promise.reject(error); } diff --git a/flatnotes/src/components/App.js b/flatnotes/src/components/App.js index 93264b4..393c7e1 100644 --- a/flatnotes/src/components/App.js +++ b/flatnotes/src/components/App.js @@ -4,8 +4,10 @@ import { Editor } from "@toast-ui/vue-editor"; import { Viewer } from "@toast-ui/vue-editor"; import api from "../api"; +import * as constants from "../constants"; import { Note, SearchResult } from "./classes"; import EventBus from "../eventBus"; +import * as helpers from "../helpers"; export default { components: { @@ -15,7 +17,13 @@ export default { data: function() { return { - loggedIn: false, + views: { + login: 0, + home: 1, + note: 2, + search: 3, + }, + currentView: 1, usernameInput: null, passwordInput: null, rememberMeInput: false, @@ -30,29 +38,6 @@ export default { }, computed: { - currentView: function() { - // 4 - Login - if (this.loggedIn == false) { - return 4; - } - // 3 - Edit Note - else if (this.currentNote && this.editMode) { - return 3; - } - // 2 - View Note - else if (this.currentNote) { - return 2; - } - // 1 - Search Results - else if (this.searchResults) { - return 1; - } - // 0 - Notes List - else { - return 0; - } - }, - notesByLastModifiedDesc: function() { return this.notes.sort(function(a, b) { return b.lastModified - a.lastModified; @@ -60,18 +45,55 @@ export default { }, }, - watch: { - searchTerm: function() { - this.clearSearchTimeout(); - if (this.searchTerm) { - this.startSearchTimeout(); - } else { - this.searchResults = null; + methods: { + route: function() { + let path = window.location.pathname.split("/"); + let basePath = path[1]; + + // Home Page + if (basePath == "") { + this.getNotes(); + this.currentView = this.views.home; + } + + // Search + else if (basePath == constants.basePaths.search) { + this.searchTerm = helpers.getSearchParam(constants.params.searchTerm); + this.getSearchResults(); + this.currentView = this.views.search; + } + + // Note + else if (basePath == constants.basePaths.note) { + let noteTitle = path[2]; + this.loadNote(noteTitle); + this.currentView = this.views.note; + } + + // Login + else if (basePath == constants.basePaths.login) { + this.currentView = this.views.login; } + + this.updateDocumentTitle(); + }, + + updateDocumentTitle: function() { + let pageTitleSuffix = null; + if (this.currentView == this.views.login) { + pageTitleSuffix = "Login"; + } else if (this.currentView == this.views.search) { + pageTitleSuffix = "Search"; + } else if ( + this.currentView == this.views.note && + this.currentNote != null + ) { + pageTitleSuffix = this.currentNote.title; + } + window.document.title = + (pageTitleSuffix ? `${pageTitleSuffix} - ` : "") + "flatnotes"; }, - }, - methods: { login: function() { let parent = this; api @@ -84,8 +106,8 @@ export default { if (parent.rememberMeInput == true) { localStorage.setItem("token", response.data.access_token); } - parent.loggedIn = true; - parent.getNotes(); + let redirectPath = helpers.getSearchParam(constants.params.redirect); + window.open(redirectPath || "/", "_self"); }) .finally(function() { parent.usernameInput = null; @@ -97,7 +119,7 @@ export default { logout: function() { sessionStorage.removeItem("token"); localStorage.removeItem("token"); - this.loggedIn = false; + window.open(`/${constants.basePaths.login}`, "_self"); }, getNotes: function() { @@ -110,61 +132,60 @@ export default { }); }, - clearSearchTimeout: function() { - if (this.searchTimeout != null) { - clearTimeout(this.searchTimeout); - } - }, - - startSearchTimeout: function() { - this.clearSearchTimeout(); - this.searchTimeout = setTimeout(this.search, 1000); + search: function() { + window.open( + `/${constants.basePaths.search}?${ + constants.params.searchTerm + }=${encodeURI(this.searchTerm)}`, + "_self" + ); }, - search: function() { - let parent = this; - this.clearSearchTimeout(); - if (this.searchTerm) { - api - .get("/api/search", { params: { term: this.searchTerm } }) - .then(function(response) { - parent.searchResults = []; - response.data.forEach(function(result) { - parent.searchResults.push( - new SearchResult( - result.filename, - result.lastModified, - result.titleHighlights, - result.contentHighlights - ) - ); - }); + getSearchResults: function() { + var parent = this; + api + .get("/api/search", { params: { term: this.searchTerm } }) + .then(function(response) { + parent.searchResults = []; + response.data.forEach(function(result) { + parent.searchResults.push( + new SearchResult( + result.filename, + result.lastModified, + result.titleHighlights, + result.contentHighlights + ) + ); }); - } + }); }, loadNote: function(filename) { let parent = this; - api.get(`/api/notes/${filename}`).then(function(response) { - parent.currentNote = response.data; - parent.newFilename = parent.currentNote.filename; - }); + api + .get(`/api/notes/${filename}.${constants.markdownExt}`) + .then(function(response) { + parent.currentNote = new Note( + response.data.filename, + response.data.lastModified, + response.data.content + ); + parent.newFilename = parent.currentNote.filename; + parent.updateDocumentTitle(); + }); + }, + + toggleEditMode: function() { + this.editMode = !this.editMode; }, newNote: function() { this.currentNote = new Note(); this.editMode = true; - }, - - unloadNote: function() { - this.currentNote = null; - this.newFilename = null; - this.editMode = false; - this.getNotes(); + this.currentView = this.views.note; }, saveNote: function() { - let parent = this; let newContent = this.$refs.toastUiEditor.invoke("getMarkdown"); // New Note @@ -174,11 +195,7 @@ export default { filename: this.newFilename, content: newContent, }) - .then(function(response) { - parent.currentNote = response.data; - parent.newFilename = parent.currentNote.filename; - parent.editMode = false; - }); + .then(this.saveNoteResponseHandler); } // Modified Note @@ -191,18 +208,26 @@ export default { newFilename: this.newFilename, newContent: newContent, }) - .then(function(response) { - parent.currentNote = response.data; - parent.newFilename = parent.currentNote.filename; - parent.editMode = false; - }); + .then(this.saveNoteResponseHandler); } // No Change else { - this.editMode = false; + this.toggleEditMode(); } }, + + saveNoteResponseHandler: function(response) { + this.currentNote = new Note( + response.data.filename, + response.data.lastModified, + response.data.content + ); + this.newFilename = this.currentNote.filename; + this.updateDocumentTitle(); + history.replaceState(null, "", this.currentNote.href); + this.toggleEditMode(); + }, }, created: function() { @@ -211,8 +236,8 @@ export default { let token = localStorage.getItem("token"); if (token != null) { sessionStorage.setItem("token", token); - this.loggedIn = true; - this.getNotes(); } + + this.route(); }, }; diff --git a/flatnotes/src/components/App.vue b/flatnotes/src/components/App.vue index 58fce64..b960d40 100644 --- a/flatnotes/src/components/App.vue +++ b/flatnotes/src/components/App.vue @@ -3,14 +3,53 @@
-

flatnotes

+

flatnotes

+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
- -
-
-
- - -
-
- - -
-
- - -
- -
-
+ +
+
+ +
+
- -
- -
+ +
+ +
+ +
- -
- - + +
+ + +
- -
- -
-
- -
-
- + +
-
+
- +

+
- -
- -
+ +
diff --git a/flatnotes/src/components/classes.js b/flatnotes/src/components/classes.js index 513fe23..d55e562 100644 --- a/flatnotes/src/components/classes.js +++ b/flatnotes/src/components/classes.js @@ -1,3 +1,5 @@ +import * as constants from "../constants"; + class Note { constructor(filename, lastModified, content) { this.filename = filename; @@ -8,6 +10,10 @@ class Note { get title() { return this.filename.slice(0, -3); } + + get href() { + return `/${constants.basePaths.note}/${this.title}` + } } class SearchResult extends Note { diff --git a/flatnotes/src/constants.js b/flatnotes/src/constants.js new file mode 100644 index 0000000..03a6d21 --- /dev/null +++ b/flatnotes/src/constants.js @@ -0,0 +1,7 @@ +export const markdownExt = "md"; + +// Base Paths +export const basePaths = { login: "login", note: "note", search: "search" }; + +// Params +export const params = { searchTerm: "term", redirect: "redirect" }; diff --git a/flatnotes/src/helpers.js b/flatnotes/src/helpers.js new file mode 100644 index 0000000..8e9bb7d --- /dev/null +++ b/flatnotes/src/helpers.js @@ -0,0 +1,4 @@ +export function getSearchParam(paramName) { + let urlSearchParams = new URLSearchParams(window.location.search); + return urlSearchParams.get(paramName); +} diff --git a/flatnotes/src/main.scss b/flatnotes/src/main.scss index a2185bc..55a0ac5 100644 --- a/flatnotes/src/main.scss +++ b/flatnotes/src/main.scss @@ -1,6 +1,10 @@ .clickable-link { - cursor: pointer; - &:hover { - font-weight: bold; - } + cursor: pointer; + &:hover { + font-weight: bold; + } + a { + text-decoration: none; + color: inherit; + } }