diff --git a/src/public/javascripts/services/note_detail_book.js b/src/public/javascripts/services/note_detail_book.js index 6af05e004..98f07846a 100644 --- a/src/public/javascripts/services/note_detail_book.js +++ b/src/public/javascripts/services/note_detail_book.js @@ -1,6 +1,18 @@ -import bundleService from "./bundle.js"; import server from "./server.js"; import linkService from "./link.js"; +import utils from "./utils.js"; + +const MIN_ZOOM_LEVEL = 1; +const MAX_ZOOM_LEVEL = 6; + +const ZOOMS = { + 1: 100, + 2: 49, + 3: 32, + 4: 24, + 5: 19, + 6: 16 +}; class NoteDetailBook { /** @@ -9,14 +21,32 @@ class NoteDetailBook { constructor(ctx) { this.ctx = ctx; this.$component = ctx.$tabContent.find('.note-detail-book'); + this.$content = this.$component.find('.note-detail-book-content'); + this.$zoomInButton = this.$component.find('.book-zoom-in'); + this.$zoomOutButton = this.$component.find('.book-zoom-out'); + this.setZoom(1); + + this.$zoomInButton.click(() => this.setZoom(this.zoomLevel - 1)); + this.$zoomOutButton.click(() => this.setZoom(this.zoomLevel + 1)); + } + + setZoom(zoomLevel) { + this.zoomLevel = zoomLevel; + + this.$zoomInButton.prop("disabled", zoomLevel === MIN_ZOOM_LEVEL); + this.$zoomOutButton.prop("disabled", zoomLevel === MAX_ZOOM_LEVEL); + + this.$content.find('.note-book').css("flex-basis", ZOOMS[zoomLevel] + "%"); } async render() { - this.$component.empty(); + this.$content.empty(); for (const childNote of await this.ctx.note.getChildNotes()) { - this.$component.append( + this.$content.append( $('
') + .css("flex-basis", ZOOMS[this.zoomLevel] + "%") + .addClass("type-" + childNote.type) .append($('
').append(await linkService.createNoteLink(childNote.noteId, null, false))) .append($('
').append(await this.getNoteContent(childNote))) ); @@ -48,6 +78,35 @@ class NoteDetailBook { else if (note.type === 'image') { return $("").attr("src", `api/images/${note.noteId}/${note.title}`); } + else if (note.type === 'file') { + function getFileUrl() { + // electron needs absolute URL so we extract current host, port, protocol + return utils.getHost() + "/api/notes/" + note.noteId + "/download"; + } + + const $downloadButton = $(''); + const $openButton = $(''); + + $downloadButton.click(() => utils.download(getFileUrl())); + $openButton.click(() => { + if (utils.isElectron()) { + const open = require("open"); + + open(getFileUrl()); + } + else { + window.location.href = getFileUrl(); + } + }); + + // open doesn't work for protected notes since it works through browser which isn't in protected session + $openButton.toggle(!note.isProtected); + + return $('
') + .append($downloadButton) + .append('   ') + .append($openButton); + } else { return "Content of this note cannot be displayed in the book format"; } @@ -64,7 +123,7 @@ class NoteDetailBook { onNoteChange() {} cleanup() { - this.$component.empty(); + this.$content.empty(); } scrollToTop() { diff --git a/src/public/stylesheets/relation_map.css b/src/public/stylesheets/relation_map.css index c315bcea2..75f0fb118 100644 --- a/src/public/stylesheets/relation_map.css +++ b/src/public/stylesheets/relation_map.css @@ -75,9 +75,4 @@ .note-detail-relation-map .ui-contextmenu { z-index: 100; -} - -.note-detail-relation-map .floating-button { - position: absolute !important; - z-index: 100; } \ No newline at end of file diff --git a/src/public/stylesheets/style.css b/src/public/stylesheets/style.css index b4a74dbce..ed670e122 100644 --- a/src/public/stylesheets/style.css +++ b/src/public/stylesheets/style.css @@ -819,10 +819,41 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href padding: 0.7rem 1rem !important; /* make modal header padding slightly smaller */ } +.floating-button { + position: absolute !important; + z-index: 100; +} + +.note-detail-book-content { + display: flex; + flex-wrap: wrap; + overflow: auto; + align-content: start; +} + .note-book { border-radius: 10px; background-color: var(--accented-background-color); padding: 15px; margin: 10px; margin-left: 0; + max-height: 300px; + overflow: hidden; + display: flex; + flex-direction: column; + flex-shrink: 0; +} + +.note-book.type-image .note-book-content, .note-book.type-file .note-book-content { + display: flex; + align-items: center; + justify-content: center; +} + +.note-book-title { + flex-grow: 0; +} + +.note-book-content { + flex-grow: 1; } \ No newline at end of file diff --git a/src/public/stylesheets/themes.css b/src/public/stylesheets/themes.css index 875ae7b90..0557e8b55 100644 --- a/src/public/stylesheets/themes.css +++ b/src/public/stylesheets/themes.css @@ -9,7 +9,7 @@ --main-background-color: white; --main-text-color: black; --main-border-color: #ccc; - --accented-background-color: #eee; + --accented-background-color: #f5f5f5; --more-accented-background-color: #ccc; --header-background-color: #f8f8f8; --button-background-color: #eee; diff --git a/src/services/import/mime.js b/src/services/import/mime.js index 485c0cbee..3266b5a1e 100644 --- a/src/services/import/mime.js +++ b/src/services/import/mime.js @@ -79,7 +79,7 @@ function getMime(fileName) { } function getType(importContext, mime) { - mime = mime.toLowerCase(); + mime = mime ? mime.toLowerCase() : ''; if (importContext.textImportedAsText && (mime === 'text/html' || ['text/markdown', 'text/x-markdown'].includes(mime))) { return 'text'; @@ -96,7 +96,7 @@ function getType(importContext, mime) { } function normalizeMimeType(mime) { - mime = mime.toLowerCase(); + mime = mime ? mime.toLowerCase() : ''; if (!(mime in CODE_MIME_TYPES) || CODE_MIME_TYPES[mime] === true) { return mime; diff --git a/src/views/details/book.ejs b/src/views/details/book.ejs index 711b42625..35169052b 100644 --- a/src/views/details/book.ejs +++ b/src/views/details/book.ejs @@ -1 +1,13 @@ -
\ No newline at end of file +
+
+ + + +
+ +
+
\ No newline at end of file