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:
parent
83109fc076
commit
7bdd34596d
6 changed files with 77 additions and 62 deletions
|
@ -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>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
() => {
|
||||
|
|
|
@ -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 -->
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
|
||||
.zotero-context-notes-list {
|
||||
padding-top: 5px;
|
||||
background-color: #d2d8e2;
|
||||
}
|
||||
|
||||
.zotero-context-pane-editor-parent-line > div {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue