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
This commit is contained in:
Martynas Bagdonas 2021-02-25 09:31:28 +02:00 committed by Dan Stillman
parent 83109fc076
commit 7bdd34596d
6 changed files with 77 additions and 62 deletions

View file

@ -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 (
<div className="notes-list">
<section>
{!!currentChildNotes.length && <h2>{Zotero.getString('pane.context.itemNotes')}</h2>}
{currentChildNotes.map(note => <NoteRow key={note.id} {...note} onClick={() => onClick(note.id)}/>)}
</section>
<section>
{!!allNotes && <h2>{Zotero.getString('pane.context.allNotes')}</h2>}
{(!!childNotes.length || !searching) && <section>
<div className="header-row">
<h2>{Zotero.getString('pane.context.itemNotes')}</h2>
{!searching && <button onClick={onNewChild}>+</button>}
</div>
{!childNotes.length && !searching && <div className="empty-row">{Zotero.getString('pane.context.noNotes')}</div>}
{childNotes.map(note => <NoteRow key={note.id} {...note} onClick={() => onClick(note.id)}/>)}
</section>}
{(!!allNotes.length || !searching) && <section>
<div className="header-row">
<h2>{Zotero.getString('pane.context.allNotes')}</h2>
{!searching && <button onClick={onNewStandalone}>+</button>}
</div>
{!allNotes.length && !searching && <div className="empty-row">{Zotero.getString('pane.context.noNotes')}</div>}
{(expanded ? allNotes : allNotes.slice(0, MAX_ALL_NOTES)).map(note => <NoteRow key={note.id} {...note} onClick={() => onClick(note.id)}/>)}
{!expanded && allNotes.length > MAX_ALL_NOTES && <div className="more-row" onClick={handleClickMore}>{Zotero.getString('general.numMore', [allNotes.length - MAX_ALL_NOTES])}</div>}
</section>
</section>}
</div>
);
});

View file

@ -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,
() => {

View file

@ -632,13 +632,6 @@
<hbox id="zotero-context-pane-inner" flex="1" zotero-persist="height"/>
</vbox>
</box>
<popupset>
<menupopup id="context-pane-new-note-button-popup">
<menuitem id="context-pane-new-standalone-note" label="&zotero.toolbar.note.standalone;"/>
<menuitem id="context-pane-new-item-note" label="&zotero.toolbar.note.child;"/>
</menupopup>
</popupset>
</hbox>
<!-- Barrier to prevent tabbing into Zotero pane when busy -->

View file

@ -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

View file

@ -68,6 +68,7 @@
.zotero-context-notes-list {
padding-top: 5px;
background-color: #d2d8e2;
}
.zotero-context-pane-editor-parent-line > div {

View file

@ -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;