From 7bdd34596deb6c9bc7ea1f15eabaa88eef689040 Mon Sep 17 00:00:00 2001 From: Martynas Bagdonas Date: Thu, 25 Feb 2021 09:31:28 +0200 Subject: [PATCH] Improve notes list UI: - Always show both sections - Do not show empty sections when searching - Collapse notes list when all tabs are closed - Work around search input to take full width without breaking its stuff --- .../zotero/components/itemPane/notesList.jsx | 29 ++++++--- chrome/content/zotero/contextPane.js | 63 +++++++------------ chrome/content/zotero/zoteroPane.xul | 7 --- chrome/locale/en-US/zotero/zotero.properties | 1 + chrome/skin/default/zotero/contextPane.css | 1 + scss/components/_notesList.scss | 38 +++++++++-- 6 files changed, 77 insertions(+), 62 deletions(-) diff --git a/chrome/content/zotero/components/itemPane/notesList.jsx b/chrome/content/zotero/components/itemPane/notesList.jsx index 8edb760d53..a3e26210a9 100644 --- a/chrome/content/zotero/components/itemPane/notesList.jsx +++ b/chrome/content/zotero/components/itemPane/notesList.jsx @@ -51,28 +51,37 @@ const NoteRow = ({ title, body, date, onClick, parentItemType, parentTitle }) => ); }; -const NotesList = forwardRef(({ onClick }, ref) => { +const NotesList = forwardRef(({ onClick, onNewChild, onNewStandalone }, ref) => { const [notes, setNotes] = useState([]); const [expanded, setExpanded] = useState(false); - useImperativeHandle(ref, () => ({ setNotes, setExpanded })); + const [searching, setSearching] = useState(false); + useImperativeHandle(ref, () => ({ setNotes, setExpanded, setSearching })); function handleClickMore() { setExpanded(true); } - let currentChildNotes = notes.filter(x => x.isCurrentChild); + let childNotes = notes.filter(x => x.isCurrentChild); let allNotes = notes.filter(x => !x.isCurrentChild); return (
-
- {!!currentChildNotes.length &&

{Zotero.getString('pane.context.itemNotes')}

} - {currentChildNotes.map(note => onClick(note.id)}/>)} -
-
- {!!allNotes &&

{Zotero.getString('pane.context.allNotes')}

} + {(!!childNotes.length || !searching) &&
+
+

{Zotero.getString('pane.context.itemNotes')}

+ {!searching && } +
+ {!childNotes.length && !searching &&
{Zotero.getString('pane.context.noNotes')}
} + {childNotes.map(note => onClick(note.id)}/>)} +
} + {(!!allNotes.length || !searching) &&
+
+

{Zotero.getString('pane.context.allNotes')}

+ {!searching && } +
+ {!allNotes.length && !searching &&
{Zotero.getString('pane.context.noNotes')}
} {(expanded ? allNotes : allNotes.slice(0, MAX_ALL_NOTES)).map(note => onClick(note.id)}/>)} {!expanded && allNotes.length > MAX_ALL_NOTES &&
{Zotero.getString('general.numMore', [allNotes.length - MAX_ALL_NOTES])}
} -
+
}
); }); diff --git a/chrome/content/zotero/contextPane.js b/chrome/content/zotero/contextPane.js index 68f33a7d44..934cb21a42 100644 --- a/chrome/content/zotero/contextPane.js +++ b/chrome/content/zotero/contextPane.js @@ -150,6 +150,9 @@ var ZoteroContextPane = new function () { } else if (action == 'close') { _removeItemContext(ids[0]); + if (Zotero_Tabs.deck.children.length == 1) { + _notesContexts.forEach(x => x.notesListRef.current.setExpanded(false)); + } } else if (action == 'select') { if (Zotero_Tabs.selectedIndex == 0) { @@ -405,29 +408,8 @@ var ZoteroContextPane = new function () { var head = document.createElement('hbox'); head.style.display = 'flex'; - var label = document.createElement('label'); - var button = document.createElement('button'); - button.setAttribute('label', Zotero.Intl.strings['zotero.toolbar.newNote']); - - // Create standalone or child note on menuitem click - document.getElementById('context-pane-new-note-button-popup').onclick = function (event) { - var parentID = null; - switch (event.originalTarget.id) { - case 'context-pane-new-standalone-note': - break; - - case 'context-pane-new-item-note': - var parentItem = _getCurrentParentItem(); - if (!parentItem) { - return; - } - parentID = parentItem.id; - break; - - default: - return; - } - + + function _createNote(parentID) { contextNode.setAttribute('selectedIndex', 1); var item = new Zotero.Item('note'); item.libraryID = libraryID; @@ -439,28 +421,21 @@ var ZoteroContextPane = new function () { editor.parentItem = null; editor.focus(); _updateAddToNote(); - }; - - button.addEventListener('mousedown', (event) => { - var popup = document.getElementById('context-pane-new-note-button-popup'); - popup.openPopup(event.target, 'after_end'); - }); + } - var vbox1 = document.createElement('vbox'); - vbox1.append(label, button); - - var vbox2 = document.createElement('vbox'); - vbox2.style.flex = '1'; + var vbox = document.createElement('vbox'); + vbox.style.flex = '1'; var input = document.createElement('textbox'); + input.style.width = 'calc(100% - 8px)'; input.setAttribute('type', 'search'); input.setAttribute('timeout', '250'); input.addEventListener('command', () => { notesListRef.current.setExpanded(false); _updateNotesList(); }); - vbox2.append(input); + vbox.append(input); - head.append(vbox2, vbox1); + head.append(vbox); var listBox = document.createElement('vbox'); listBox.style.display = 'flex'; @@ -474,12 +449,12 @@ var ZoteroContextPane = new function () { var notesListRef = React.createRef(); async function _updateNotesList(useCached) { + var query = input.value; var notes; if (useCached && context.cachedNotes.length) { notes = context.cachedNotes; } else { - var query = input.value; await Zotero.Schema.schemaUpdatePromise; var s = new Zotero.Search(); s.addCondition('libraryID', 'is', libraryID); @@ -523,19 +498,18 @@ var ZoteroContextPane = new function () { } var readerParentItem = _getCurrentParentItem(); + notesListRef.current.setSearching(query.length); notesListRef.current.setNotes(notes.map(note => ({ ...note, isCurrentChild: readerParentItem && note.parentID == readerParentItem.id }))); - - var c = notes.length; - label.value = Zotero.getString('pane.item.notes.count', c, c); } var context = { libraryID, node: contextNode, editor, + notesListRef, cachedNotes: [], update: Zotero.Utilities.throttle(_updateNotesList, 1000, { leading: false }), updateFromCache: () => _updateNotesList(true) @@ -547,6 +521,15 @@ var ZoteroContextPane = new function () { onClick={(id) => { _setPinnedNote(libraryID, id); }} + onNewChild={() => { + var parentItem = _getCurrentParentItem(); + if (parentItem) { + _createNote(parentItem.id); + } + }} + onNewStandalone={() => { + _createNote(); + }} />, listInner, () => { diff --git a/chrome/content/zotero/zoteroPane.xul b/chrome/content/zotero/zoteroPane.xul index e18f392a64..58f5a2b603 100644 --- a/chrome/content/zotero/zoteroPane.xul +++ b/chrome/content/zotero/zoteroPane.xul @@ -632,13 +632,6 @@ - - - - - - - diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index 113f817555..c38b2a15e7 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -402,6 +402,7 @@ pane.item.parentItem = Parent Item: pane.context.noParent = No parent item pane.context.itemNotes = Item Notes pane.context.allNotes = All Notes +pane.context.noNotes = No notes noteEditor.editNote = Edit Note diff --git a/chrome/skin/default/zotero/contextPane.css b/chrome/skin/default/zotero/contextPane.css index 16ad9e2d3e..d7bcd5f787 100644 --- a/chrome/skin/default/zotero/contextPane.css +++ b/chrome/skin/default/zotero/contextPane.css @@ -68,6 +68,7 @@ .zotero-context-notes-list { padding-top: 5px; + background-color: #d2d8e2; } .zotero-context-pane-editor-parent-line > div { diff --git a/scss/components/_notesList.scss b/scss/components/_notesList.scss index a01f30cd40..116575fc3f 100644 --- a/scss/components/_notesList.scss +++ b/scss/components/_notesList.scss @@ -13,14 +13,42 @@ height: 0; flex-grow: 1; padding-top: 2px; - - &> section > h2 { - font-weight: bold; - margin: 7px 8px 3px; - font-size: 13px; + + & > section { + margin: 5px 0; } } +.header-row { + margin: 0 7px; + display: flex; + justify-content: space-between; + height: 24px; + + h2 { + font-weight: bold; + margin: 0; + font-size: 13px; + align-self: center; + } + + button { + height: 24px; + // Necessary on linux to horizontaly center text + line-height: 0; + } +} + +.empty-row { + border: 1px solid #bcc4d2; + border-radius: 5px; + margin: 4px 7px; + background-color: $shade-2; + text-align: center; + padding: 5px; + opacity: 0.5; +} + .note-row { border: 1px solid #bcc4d2; border-radius: 5px;