From: Adam Dullage Date: Wed, 10 Aug 2022 20:22:53 +0000 (+0100) Subject: Implement NoteViewerEditor component X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=019ab4567b910ac1617484aef36fbcbfd18ae007;p=flatnotes.git Implement NoteViewerEditor component --- diff --git a/flatnotes/main.py b/flatnotes/main.py index f04fbeb..7877241 100644 --- a/flatnotes/main.py +++ b/flatnotes/main.py @@ -47,6 +47,7 @@ async def token(data: LoginModel): @app.get("/") @app.get("/login") @app.get("/search") +@app.get("/new") @app.get("/note/{title}") async def root(title: str = ""): with open("flatnotes/dist/index.html", "r", encoding="utf-8") as f: diff --git a/flatnotes/src/api.js b/flatnotes/src/api.js index 5006254..7f970de 100644 --- a/flatnotes/src/api.js +++ b/flatnotes/src/api.js @@ -1,7 +1,7 @@ -import axios from "axios"; - import * as constants from "./constants"; + import EventBus from "./eventBus"; +import axios from "axios"; const api = axios.create(); diff --git a/flatnotes/src/colours.scss b/flatnotes/src/colours.scss new file mode 100644 index 0000000..bf70512 --- /dev/null +++ b/flatnotes/src/colours.scss @@ -0,0 +1,7 @@ +$off-white: #f8f9fd70; +$form-control-border: #ced4da; +$drop-shadow: #0000000a; +$muted-text: #6c757d; +$text: #222222; +$button-background: #00000010; +$input-highlight: #bbcdff; diff --git a/flatnotes/src/components/App.js b/flatnotes/src/components/App.js index 6bdb1f9..27d9d42 100644 --- a/flatnotes/src/components/App.js +++ b/flatnotes/src/components/App.js @@ -1,31 +1,29 @@ -import { Editor } from "@toast-ui/vue-editor"; -import { Viewer } from "@toast-ui/vue-editor"; +import * as constants from "../constants"; +import * as helpers from "../helpers"; -import RecentlyModified from "./RecentlyModified"; +import EventBus from "../eventBus"; import LoadingIndicator from "./LoadingIndicator"; import Login from "./Login"; +import Logo from "./Logo"; +import Mousetrap from "mousetrap"; import NavBar from "./NavBar"; +import NoteViewerEditor from "./NoteViewerEditor"; +import RecentlyModified from "./RecentlyModified"; import SearchInput from "./SearchInput"; -import Logo from "./Logo" - +import { SearchResult } from "../classes"; 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 { name: "App", components: { - Viewer, - Editor, RecentlyModified, LoadingIndicator, Login, NavBar, SearchInput, Logo, + NoteViewerEditor, }, data: function() { @@ -41,6 +39,7 @@ export default { // Home Page if (basePath == "") { + this.updateDocumentTitle(); this.currentView = this.views.home; this.$nextTick(function() { this.focusSearchInput(); @@ -49,24 +48,30 @@ export default { // Search else if (basePath == constants.basePaths.search) { + this.updateDocumentTitle("Search"); this.searchTerm = helpers.getSearchParam(constants.params.searchTerm); this.getSearchResults(); this.currentView = this.views.search; } + // New Note + else if (basePath == constants.basePaths.new) { + this.updateDocumentTitle("New Note"); + this.currentView = this.views.note; + } + // Note else if (basePath == constants.basePaths.note) { - let noteTitle = path[2]; - this.loadNote(noteTitle); + this.updateDocumentTitle(); + this.noteTitle = path[2]; this.currentView = this.views.note; } // Login else if (basePath == constants.basePaths.login) { + this.updateDocumentTitle("Log In"); this.currentView = this.views.login; } - - this.updateDocumentTitle(); }, navigate: function(href, e) { @@ -83,20 +88,8 @@ export default { Object.assign(this.$data, constants.dataDefaults()); }, - 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"; + updateDocumentTitle: function(suffix) { + window.document.title = (suffix ? `${suffix} - ` : "") + "flatnotes"; }, logout: function() { @@ -131,261 +124,18 @@ export default { }); }, - getContentForEditor: function() { - let draftContent = localStorage.getItem(this.currentNote.title); - if (draftContent) { - if (confirm("Do you want to resume the saved draft?")) { - return draftContent; - } else { - localStorage.removeItem(this.currentNote.title); - } - } - return this.currentNote.content; - }, - - loadNote: function(title) { - let parent = this; - this.noteLoadFailed = false; - api - .get(`/api/notes/${title}`) - .then(function(response) { - parent.currentNote = new Note( - response.data.title, - response.data.lastModified, - response.data.content - ); - parent.updateDocumentTitle(); - }) - .catch(function(error) { - if (error.handled) { - return; - } else if ( - typeof error.response !== "undefined" && - error.response.status == 404 - ) { - parent.noteLoadFailedMessage = "Note not found 😞"; - parent.noteLoadFailed = true; - } else { - parent.unhandledServerErrorToast(); - parent.noteLoadFailed = true; - } - }); - }, - - toggleEditMode: function() { - let parent = this; - - // To Edit Mode - if (this.editMode == false) { - this.titleInput = this.currentNote.title; - let draftContent = localStorage.getItem(this.currentNote.title); - - if (draftContent) { - this.$bvModal - .msgBoxConfirm( - "There is an unsaved draft of this note stored in this browser. Do you want to resume the draft version or delete it?", - { - centered: true, - title: "Resume Draft?", - okTitle: "Resume Draft", - cancelTitle: "Delete Draft", - cancelVariant: "danger", - } - ) - .then(function(response) { - if (response == true) { - parent.initialContent = draftContent; - } else { - parent.initialContent = parent.currentNote.content; - localStorage.removeItem(parent.currentNote.title); - } - parent.editMode = !parent.editMode; - }); - } else { - this.initialContent = this.currentNote.content; - this.editMode = !this.editMode; - } - } - // To View Mode - else { - this.titleInput = null; - this.initialContent = null; - this.editMode = !this.editMode; - } - }, - newNote: function() { - this.currentNote = new Note(); - this.toggleEditMode(); - this.currentView = this.views.note; - }, - - getEditorContent: function() { - return this.$refs.toastUiEditor.invoke("getMarkdown"); - }, - - clearDraftSaveTimeout: function() { - if (this.draftSaveTimeout != null) { - clearTimeout(this.draftSaveTimeout); - } - }, - - startDraftSaveTimeout: function() { - this.clearDraftSaveTimeout(); - this.draftSaveTimeout = setTimeout(this.saveDraft, 1000); - }, - - saveDraft: function() { - localStorage.setItem(this.currentNote.title, this.getEditorContent()); - }, - - existingTitleToast: function() { - this.$bvToast.toast( - "A note with this title already exists. Please try again with a new title.", - { - title: "Duplicate ✘", - variant: "danger", - noCloseButton: true, - toaster: "b-toaster-bottom-right", - } - ); - }, - - saveNote: function() { - let parent = this; - let newContent = this.getEditorContent(); - - // Title Validation - if (typeof this.titleInput == "string") { - this.titleInput = this.titleInput.trim(); - } - if (!this.titleInput) { - this.$bvToast.toast("Cannot save note without a title ✘", { - variant: "danger", - noCloseButton: true, - toaster: "b-toaster-bottom-right", - }); - return; - } - - // New Note - if (this.currentNote.lastModified == null) { - api - .post(`/api/notes`, { - title: this.titleInput, - content: newContent, - }) - .then(this.saveNoteResponseHandler) - .catch(function(error) { - if (error.handled) { - return; - } else if ( - typeof error.response !== "undefined" && - error.response.status == 409 - ) { - parent.existingTitleToast(); - } else { - parent.unhandledServerErrorToast(); - } - }); - } - - // Modified Note - else if ( - newContent != this.currentNote.content || - this.titleInput != this.currentNote.title - ) { - api - .patch(`/api/notes/${this.currentNote.title}`, { - newTitle: this.titleInput, - newContent: newContent, - }) - .then(this.saveNoteResponseHandler) - .catch(function(error) { - if (error.handled) { - return; - } else if ( - typeof error.response !== "undefined" && - error.response.status == 409 - ) { - parent.existingTitleToast(); - } else { - parent.unhandledServerErrorToast(); - } - }); - } - - // No Change - else { - this.toggleEditMode(); - this.saveNoteToast(); - } - }, - - saveNoteResponseHandler: function(response) { - localStorage.removeItem(this.currentNote.title); - this.currentNote = new Note( - response.data.title, - response.data.lastModified, - response.data.content - ); - this.updateDocumentTitle(); - history.replaceState(null, "", this.currentNote.href); - this.toggleEditMode(); - this.saveNoteToast(); + this.navigate(`/${constants.basePaths.new}`); }, - saveNoteToast: function() { - this.$bvToast.toast("Note saved ✓", { + noteDeletedToast: function() { + this.$bvToast.toast("Note deleted ✓", { variant: "success", noCloseButton: true, toaster: "b-toaster-bottom-right", }); }, - cancelNote: function() { - localStorage.removeItem(this.currentNote.title); - if (this.currentNote.lastModified == null) { - // Cancelling a new note - this.currentNote = null; - this.currentView = this.views.home; - } - this.toggleEditMode(); - }, - - deleteNote: function() { - let parent = this; - this.$bvModal - .msgBoxConfirm( - `Are you sure you want to delete the note '${this.currentNote.title}'?`, - { - centered: true, - title: "Confirm Deletion", - okTitle: "Delete", - okVariant: "danger", - } - ) - .then(function(response) { - if (response == true) { - api - .delete(`/api/notes/${parent.currentNote.title}`) - .then(function() { - parent.navigate("/"); - parent.$bvToast.toast("Note deleted ✓", { - variant: "success", - noCloseButton: true, - toaster: "b-toaster-bottom-right", - }); - }) - .catch(function(error) { - if (!error.handled) { - parent.unhandledServerErrorToast(); - } - }); - } - }); - }, - focusSearchInput: function() { document.getElementById("search-input").focus(); }, @@ -399,44 +149,6 @@ export default { } }, - keyboardShortcuts: function(e) { - // If the user is focused on a text input or is editing a note, ignore. - if ( - !["e", "/"].includes(e.key) || - document.activeElement.type == "text" || - (this.currentView == this.views.note && this.editMode == true) - ) { - return; - } - - // 'e' to Edit - if ( - e.key == "e" && - this.currentView == this.views.note && - this.editMode == false - ) { - e.preventDefault(); - this.toggleEditMode(); - } - - // '/' to Search - if (e.key == "/") { - e.preventDefault(); - this.openSearch(); - } - - // 'CTRL + s' to Save - // else if ( - // e.key == "s" && - // e.ctrlKey == true && - // this.currentView == this.views.note && - // this.editMode == true - // ) { - // e.preventDefault(); - // this.saveNote(); - // } - }, - unhandledServerErrorToast: function() { this.$bvToast.toast( "Unknown error communicating with the server. Please try again.", @@ -451,9 +163,16 @@ export default { }, created: function() { + let parent = this; + EventBus.$on("navigate", this.navigate); EventBus.$on("unhandledServerError", this.unhandledServerErrorToast); - document.addEventListener("keydown", this.keyboardShortcuts); + EventBus.$on("updateDocumentTitle", this.updateDocumentTitle); + + Mousetrap.bind("/", function() { + parent.openSearch(); + return false; + }); let token = localStorage.getItem("token"); if (token != null) { diff --git a/flatnotes/src/components/App.vue b/flatnotes/src/components/App.vue index 4d98f90..47d9a0a 100644 --- a/flatnotes/src/components/App.vue +++ b/flatnotes/src/components/App.vue @@ -22,63 +22,9 @@ - -
- - - - - - - - - - - -
-
- -
- -
- -
- - -
-

{{ currentNote.title }}

- - - -
-
- -
- - -
- -
-
-
-
- - -
+ +
+ + +
diff --git a/flatnotes/src/components/Login.vue b/flatnotes/src/components/Login.vue index fbfd170..20201c6 100644 --- a/flatnotes/src/components/Login.vue +++ b/flatnotes/src/components/Login.vue @@ -62,11 +62,12 @@ diff --git a/flatnotes/src/components/RecentlyModified.vue b/flatnotes/src/components/RecentlyModified.vue index 6464ea2..a57b946 100644 --- a/flatnotes/src/components/RecentlyModified.vue +++ b/flatnotes/src/components/RecentlyModified.vue @@ -22,10 +22,10 @@