mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	grid view improvements, remembering grid/list status
This commit is contained in:
		| @@ -8,11 +8,20 @@ async function addLabel(noteId, name, value = "") { | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | async function setLabel(noteId, name, value = "") { | ||||||
|  |     await server.put(`notes/${noteId}/set-attribute`, { | ||||||
|  |         type: 'label', | ||||||
|  |         name: name, | ||||||
|  |         value: value | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
| async function removeAttributeById(noteId, attributeId) { | async function removeAttributeById(noteId, attributeId) { | ||||||
|     await server.remove(`notes/${noteId}/attributes/${attributeId}`); |     await server.remove(`notes/${noteId}/attributes/${attributeId}`); | ||||||
| } | } | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|     addLabel, |     addLabel, | ||||||
|  |     setLabel, | ||||||
|     removeAttributeById |     removeAttributeById | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,18 +12,23 @@ const TPL = ` | |||||||
|         height: 100%; |         height: 100%; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     .note-list.card-view .note-list-container { |     .note-list.grid-view .note-list-container { | ||||||
|         display: flex; |         display: flex; | ||||||
|  |         flex-wrap: wrap; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     .note-list.card-view .note-book-card { |     .note-list.grid-view .note-book-card { | ||||||
|         width: 300px; |         flex-basis: 300px; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     .note-list.card-view .note-expander { |     .note-list.grid-view .note-expander { | ||||||
|         display: none; |         display: none; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     .note-list.grid-view .note-book-card { | ||||||
|  |         max-height: 300px; | ||||||
|  |     } | ||||||
|  |      | ||||||
|     .note-book-card { |     .note-book-card { | ||||||
|         border-radius: 10px; |         border-radius: 10px; | ||||||
|         background-color: var(--accented-background-color); |         background-color: var(--accented-background-color); | ||||||
| @@ -33,10 +38,11 @@ const TPL = ` | |||||||
|         display: flex; |         display: flex; | ||||||
|         flex-direction: column; |         flex-direction: column; | ||||||
|         flex-shrink: 0; |         flex-shrink: 0; | ||||||
|  |         flex-grow: 1; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     .note-book-card .note-book-content { |     .note-book-card:not(.expanded) .note-book-content { | ||||||
|         display: none; |         display: none !important; | ||||||
|         padding: 10px |         padding: 10px | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @@ -57,6 +63,7 @@ const TPL = ` | |||||||
|         align-items: center; |         align-items: center; | ||||||
|         justify-content: center; |         justify-content: center; | ||||||
|         text-align: center; |         text-align: center; | ||||||
|  |         padding: 10px; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     .note-book-card.type-image .note-book-content img, .note-book-card.type-text .note-book-content img { |     .note-book-card.type-image .note-book-content img, .note-book-card.type-text .note-book-content img { | ||||||
| @@ -125,8 +132,14 @@ class NoteListRenderer { | |||||||
|         this.parentNote = parentNote; |         this.parentNote = parentNote; | ||||||
|         this.notes = notes; |         this.notes = notes; | ||||||
|         this.page = 1; |         this.page = 1; | ||||||
|         this.pageSize = 2; |         this.pageSize = 6; | ||||||
|         this.viewType = 'list'; |         this.viewType = parentNote.getLabelValue('viewType'); | ||||||
|  |  | ||||||
|  |         if (!['list', 'grid'].includes(this.viewType)) { | ||||||
|  |             this.viewType = 'list'; // default | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.$noteList.addClass(this.viewType + '-view'); | ||||||
|  |  | ||||||
|         this.$noteList.find('.list-view-button').on('click', () => this.toggleViewType('list')); |         this.$noteList.find('.list-view-button').on('click', () => this.toggleViewType('list')); | ||||||
|         this.$noteList.find('.grid-view-button').on('click', () => this.toggleViewType('grid')); |         this.$noteList.find('.grid-view-button').on('click', () => this.toggleViewType('grid')); | ||||||
| @@ -171,6 +184,8 @@ class NoteListRenderer { | |||||||
|             .removeClass('list-view') |             .removeClass('list-view') | ||||||
|             .addClass(this.viewType + '-view'); |             .addClass(this.viewType + '-view'); | ||||||
|  |  | ||||||
|  |         await attributeService.setLabel(this.parentNote.noteId, 'viewType', type); | ||||||
|  |  | ||||||
|         await this.renderList(); |         await this.renderList(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -202,8 +217,11 @@ class NoteListRenderer { | |||||||
|  |  | ||||||
|     renderPager() { |     renderPager() { | ||||||
|         const $pager = this.$noteList.find('.note-list-pager').empty(); |         const $pager = this.$noteList.find('.note-list-pager').empty(); | ||||||
|  |         const pageCount = Math.ceil(this.notes.length / this.pageSize); | ||||||
|  |  | ||||||
|         for (let i = 1; i <= Math.ceil(this.notes.length / this.pageSize); i++) { |         $pager.toggle(pageCount > 1); | ||||||
|  |  | ||||||
|  |         for (let i = 1; i <= pageCount; i++) { | ||||||
|             $pager.append( |             $pager.append( | ||||||
|                 i === this.page |                 i === this.page | ||||||
|                     ? $('<span>').text(i).css('text-decoration', 'underline').css('font-weight', "bold") |                     ? $('<span>').text(i).css('text-decoration', 'underline').css('font-weight', "bold") | ||||||
| @@ -228,6 +246,48 @@ class NoteListRenderer { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // TODO: we should also render (promoted) attributes | ||||||
|  |     async renderNote(note) { | ||||||
|  |         const notePath = /*this.notePath + '/' + */ note.noteId; | ||||||
|  |  | ||||||
|  |         const $expander = $('<span class="note-expander bx bx-chevron-right"></span>'); | ||||||
|  |  | ||||||
|  |         const $card = $('<div class="note-book-card">') | ||||||
|  |             .attr('data-note-id', note.noteId) | ||||||
|  |             .append( | ||||||
|  |                 $('<h5 class="note-book-title">') | ||||||
|  |                     .append($expander) | ||||||
|  |                     .append(await linkService.createNoteLink(notePath, {showTooltip: false})) | ||||||
|  |             ); | ||||||
|  |  | ||||||
|  |         $expander.on('click', () => this.toggleContent($card, note, !$card.hasClass("expanded"))); | ||||||
|  |  | ||||||
|  |         await this.toggleContent($card, note, this.parentNote.hasLabel('expanded')); | ||||||
|  |  | ||||||
|  |         return $card; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async toggleContent($card, note, expand) { | ||||||
|  |         if (this.viewType === 'list' && ((expand && $card.hasClass("expanded")) || (!expand && !$card.hasClass("expanded")))) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const $expander = $card.find('> .note-book-title .note-expander'); | ||||||
|  |  | ||||||
|  |         if (expand || this.viewType === 'grid') { | ||||||
|  |             $card.addClass("expanded"); | ||||||
|  |             $expander.addClass("bx-chevron-down").removeClass("bx-chevron-right"); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             $card.removeClass("expanded"); | ||||||
|  |             $expander.addClass("bx-chevron-right").removeClass("bx-chevron-down"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ((expand || this.viewType === 'grid') && $card.find('.note-book-content').length === 0) { | ||||||
|  |             $card.append(await this.renderNoteContent(note)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     async renderNoteContent(note) { |     async renderNoteContent(note) { | ||||||
|         const $content = $('<div class="note-book-content">'); |         const $content = $('<div class="note-book-content">'); | ||||||
|  |  | ||||||
| @@ -242,59 +302,19 @@ class NoteListRenderer { | |||||||
|             $content.append("rendering error"); |             $content.append("rendering error"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const imageLinks = note.getRelations('imageLink'); |         if (this.viewType === 'list') { | ||||||
|  |             const imageLinks = note.getRelations('imageLink'); | ||||||
|  |  | ||||||
|         const childNotes = (await note.getChildNotes()) |             const childNotes = (await note.getChildNotes()) | ||||||
|             .filter(childNote => !imageLinks.find(rel => rel.value === childNote.noteId)); |                 .filter(childNote => !imageLinks.find(rel => rel.value === childNote.noteId)); | ||||||
|  |  | ||||||
|         for (const childNote of childNotes) { |             for (const childNote of childNotes) { | ||||||
|             $content.append(await this.renderNote(childNote, false)); |                 $content.append(await this.renderNote(childNote)); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $content; |         return $content; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO: we should also render (promoted) attributes |  | ||||||
|     async renderNote(note, expand) { |  | ||||||
|         const notePath = /*this.notePath + '/' + */ note.noteId; |  | ||||||
|  |  | ||||||
|         const $expander = $('<span class="note-expander bx bx-chevron-right"></span>'); |  | ||||||
|  |  | ||||||
|         const $card = $('<div class="note-book-card">') |  | ||||||
|             .attr('data-note-id', note.noteId) |  | ||||||
|             .append( |  | ||||||
|                 $('<h5 class="note-book-title">') |  | ||||||
|                     .append($expander) |  | ||||||
|                     .append(await linkService.createNoteLink(notePath, {showTooltip: false})) |  | ||||||
|             ); |  | ||||||
|  |  | ||||||
|         $expander.on('click', () => toggleContent($card, note, !$card.hasClass("expanded"))); |  | ||||||
|  |  | ||||||
|         await this.toggleContent($card, note, expand); |  | ||||||
|  |  | ||||||
|         return $card; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async toggleContent($card, note, expand) { |  | ||||||
|         if (this.viewType === 'list' && ((expand && $card.hasClass("expanded")) || (!expand && !$card.hasClass("expanded")))) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         const $expander = $card.find('> .note-book-title .note-expander'); |  | ||||||
|  |  | ||||||
|         if (expand) { |  | ||||||
|             $card.addClass("expanded"); |  | ||||||
|             $expander.addClass("bx-chevron-down").removeClass("bx-chevron-right"); |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             $card.removeClass("expanded"); |  | ||||||
|             $expander.addClass("bx-chevron-right").removeClass("bx-chevron-down"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (expand && $card.find('.note-book-content').length === 0) { |  | ||||||
|             $card.append(await this.renderNoteContent(note)); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| export default NoteListRenderer; | export default NoteListRenderer; | ||||||
|   | |||||||
| @@ -62,13 +62,27 @@ function updateNoteAttribute(req) { | |||||||
|  |  | ||||||
|     attribute.save(); |     attribute.save(); | ||||||
|  |  | ||||||
|     console.log("Saving", attribute); |  | ||||||
|  |  | ||||||
|     return { |     return { | ||||||
|         attributeId: attribute.attributeId |         attributeId: attribute.attributeId | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function setNoteAttribute(req) { | ||||||
|  |     const noteId = req.params.noteId; | ||||||
|  |     const body = req.body; | ||||||
|  |  | ||||||
|  |     let attr = repository.getEntity(`SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ? AND type = ? AND name = ?`, [noteId, body.type, body.name]); | ||||||
|  |  | ||||||
|  |     if (attr) { | ||||||
|  |         attr.value = body.value; | ||||||
|  |     } else { | ||||||
|  |         attr = new Attribute(body); | ||||||
|  |         attr.noteId = noteId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     attr.save(); | ||||||
|  | } | ||||||
|  |  | ||||||
| function deleteNoteAttribute(req) { | function deleteNoteAttribute(req) { | ||||||
|     const noteId = req.params.noteId; |     const noteId = req.params.noteId; | ||||||
|     const attributeId = req.params.attributeId; |     const attributeId = req.params.attributeId; | ||||||
| @@ -200,6 +214,7 @@ function deleteRelation(req) { | |||||||
| module.exports = { | module.exports = { | ||||||
|     updateNoteAttributes, |     updateNoteAttributes, | ||||||
|     updateNoteAttribute, |     updateNoteAttribute, | ||||||
|  |     setNoteAttribute, | ||||||
|     deleteNoteAttribute, |     deleteNoteAttribute, | ||||||
|     getAttributeNames, |     getAttributeNames, | ||||||
|     getValuesForAttribute, |     getValuesForAttribute, | ||||||
|   | |||||||
| @@ -176,6 +176,7 @@ function register(app) { | |||||||
|     apiRoute(GET, '/api/notes/:noteId/attributes', attributesRoute.getEffectiveNoteAttributes); |     apiRoute(GET, '/api/notes/:noteId/attributes', attributesRoute.getEffectiveNoteAttributes); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes); |     apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/attribute', attributesRoute.updateNoteAttribute); |     apiRoute(PUT, '/api/notes/:noteId/attribute', attributesRoute.updateNoteAttribute); | ||||||
|  |     apiRoute(PUT, '/api/notes/:noteId/set-attribute', attributesRoute.setNoteAttribute); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/relations/:name/to/:targetNoteId', attributesRoute.createRelation); |     apiRoute(PUT, '/api/notes/:noteId/relations/:name/to/:targetNoteId', attributesRoute.createRelation); | ||||||
|     apiRoute(DELETE, '/api/notes/:noteId/relations/:name/to/:targetNoteId', attributesRoute.deleteRelation); |     apiRoute(DELETE, '/api/notes/:noteId/relations/:name/to/:targetNoteId', attributesRoute.deleteRelation); | ||||||
|     apiRoute(DELETE, '/api/notes/:noteId/attributes/:attributeId', attributesRoute.deleteNoteAttribute); |     apiRoute(DELETE, '/api/notes/:noteId/attributes/:attributeId', attributesRoute.deleteNoteAttribute); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user