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 [notes, setNotes] = useState([]);
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
useImperativeHandle(ref, () => ({ setNotes, setExpanded }));
|
const [searching, setSearching] = useState(false);
|
||||||
|
useImperativeHandle(ref, () => ({ setNotes, setExpanded, setSearching }));
|
||||||
|
|
||||||
function handleClickMore() {
|
function handleClickMore() {
|
||||||
setExpanded(true);
|
setExpanded(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentChildNotes = notes.filter(x => x.isCurrentChild);
|
let childNotes = notes.filter(x => x.isCurrentChild);
|
||||||
let allNotes = notes.filter(x => !x.isCurrentChild);
|
let allNotes = notes.filter(x => !x.isCurrentChild);
|
||||||
return (
|
return (
|
||||||
<div className="notes-list">
|
<div className="notes-list">
|
||||||
<section>
|
{(!!childNotes.length || !searching) && <section>
|
||||||
{!!currentChildNotes.length && <h2>{Zotero.getString('pane.context.itemNotes')}</h2>}
|
<div className="header-row">
|
||||||
{currentChildNotes.map(note => <NoteRow key={note.id} {...note} onClick={() => onClick(note.id)}/>)}
|
<h2>{Zotero.getString('pane.context.itemNotes')}</h2>
|
||||||
</section>
|
{!searching && <button onClick={onNewChild}>+</button>}
|
||||||
<section>
|
</div>
|
||||||
{!!allNotes && <h2>{Zotero.getString('pane.context.allNotes')}</h2>}
|
{!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 : 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>}
|
{!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>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -150,6 +150,9 @@ var ZoteroContextPane = new function () {
|
||||||
}
|
}
|
||||||
else if (action == 'close') {
|
else if (action == 'close') {
|
||||||
_removeItemContext(ids[0]);
|
_removeItemContext(ids[0]);
|
||||||
|
if (Zotero_Tabs.deck.children.length == 1) {
|
||||||
|
_notesContexts.forEach(x => x.notesListRef.current.setExpanded(false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (action == 'select') {
|
else if (action == 'select') {
|
||||||
if (Zotero_Tabs.selectedIndex == 0) {
|
if (Zotero_Tabs.selectedIndex == 0) {
|
||||||
|
@ -405,29 +408,8 @@ var ZoteroContextPane = new function () {
|
||||||
var head = document.createElement('hbox');
|
var head = document.createElement('hbox');
|
||||||
head.style.display = 'flex';
|
head.style.display = 'flex';
|
||||||
|
|
||||||
var label = document.createElement('label');
|
|
||||||
var button = document.createElement('button');
|
function _createNote(parentID) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
contextNode.setAttribute('selectedIndex', 1);
|
contextNode.setAttribute('selectedIndex', 1);
|
||||||
var item = new Zotero.Item('note');
|
var item = new Zotero.Item('note');
|
||||||
item.libraryID = libraryID;
|
item.libraryID = libraryID;
|
||||||
|
@ -439,28 +421,21 @@ var ZoteroContextPane = new function () {
|
||||||
editor.parentItem = null;
|
editor.parentItem = null;
|
||||||
editor.focus();
|
editor.focus();
|
||||||
_updateAddToNote();
|
_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');
|
var vbox = document.createElement('vbox');
|
||||||
vbox1.append(label, button);
|
vbox.style.flex = '1';
|
||||||
|
|
||||||
var vbox2 = document.createElement('vbox');
|
|
||||||
vbox2.style.flex = '1';
|
|
||||||
var input = document.createElement('textbox');
|
var input = document.createElement('textbox');
|
||||||
|
input.style.width = 'calc(100% - 8px)';
|
||||||
input.setAttribute('type', 'search');
|
input.setAttribute('type', 'search');
|
||||||
input.setAttribute('timeout', '250');
|
input.setAttribute('timeout', '250');
|
||||||
input.addEventListener('command', () => {
|
input.addEventListener('command', () => {
|
||||||
notesListRef.current.setExpanded(false);
|
notesListRef.current.setExpanded(false);
|
||||||
_updateNotesList();
|
_updateNotesList();
|
||||||
});
|
});
|
||||||
vbox2.append(input);
|
vbox.append(input);
|
||||||
|
|
||||||
head.append(vbox2, vbox1);
|
head.append(vbox);
|
||||||
|
|
||||||
var listBox = document.createElement('vbox');
|
var listBox = document.createElement('vbox');
|
||||||
listBox.style.display = 'flex';
|
listBox.style.display = 'flex';
|
||||||
|
@ -474,12 +449,12 @@ var ZoteroContextPane = new function () {
|
||||||
var notesListRef = React.createRef();
|
var notesListRef = React.createRef();
|
||||||
|
|
||||||
async function _updateNotesList(useCached) {
|
async function _updateNotesList(useCached) {
|
||||||
|
var query = input.value;
|
||||||
var notes;
|
var notes;
|
||||||
if (useCached && context.cachedNotes.length) {
|
if (useCached && context.cachedNotes.length) {
|
||||||
notes = context.cachedNotes;
|
notes = context.cachedNotes;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var query = input.value;
|
|
||||||
await Zotero.Schema.schemaUpdatePromise;
|
await Zotero.Schema.schemaUpdatePromise;
|
||||||
var s = new Zotero.Search();
|
var s = new Zotero.Search();
|
||||||
s.addCondition('libraryID', 'is', libraryID);
|
s.addCondition('libraryID', 'is', libraryID);
|
||||||
|
@ -523,19 +498,18 @@ var ZoteroContextPane = new function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
var readerParentItem = _getCurrentParentItem();
|
var readerParentItem = _getCurrentParentItem();
|
||||||
|
notesListRef.current.setSearching(query.length);
|
||||||
notesListRef.current.setNotes(notes.map(note => ({
|
notesListRef.current.setNotes(notes.map(note => ({
|
||||||
...note,
|
...note,
|
||||||
isCurrentChild: readerParentItem && note.parentID == readerParentItem.id
|
isCurrentChild: readerParentItem && note.parentID == readerParentItem.id
|
||||||
})));
|
})));
|
||||||
|
|
||||||
var c = notes.length;
|
|
||||||
label.value = Zotero.getString('pane.item.notes.count', c, c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var context = {
|
var context = {
|
||||||
libraryID,
|
libraryID,
|
||||||
node: contextNode,
|
node: contextNode,
|
||||||
editor,
|
editor,
|
||||||
|
notesListRef,
|
||||||
cachedNotes: [],
|
cachedNotes: [],
|
||||||
update: Zotero.Utilities.throttle(_updateNotesList, 1000, { leading: false }),
|
update: Zotero.Utilities.throttle(_updateNotesList, 1000, { leading: false }),
|
||||||
updateFromCache: () => _updateNotesList(true)
|
updateFromCache: () => _updateNotesList(true)
|
||||||
|
@ -547,6 +521,15 @@ var ZoteroContextPane = new function () {
|
||||||
onClick={(id) => {
|
onClick={(id) => {
|
||||||
_setPinnedNote(libraryID, id);
|
_setPinnedNote(libraryID, id);
|
||||||
}}
|
}}
|
||||||
|
onNewChild={() => {
|
||||||
|
var parentItem = _getCurrentParentItem();
|
||||||
|
if (parentItem) {
|
||||||
|
_createNote(parentItem.id);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onNewStandalone={() => {
|
||||||
|
_createNote();
|
||||||
|
}}
|
||||||
/>,
|
/>,
|
||||||
listInner,
|
listInner,
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -632,13 +632,6 @@
|
||||||
<hbox id="zotero-context-pane-inner" flex="1" zotero-persist="height"/>
|
<hbox id="zotero-context-pane-inner" flex="1" zotero-persist="height"/>
|
||||||
</vbox>
|
</vbox>
|
||||||
</box>
|
</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>
|
</hbox>
|
||||||
|
|
||||||
<!-- Barrier to prevent tabbing into Zotero pane when busy -->
|
<!-- 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.noParent = No parent item
|
||||||
pane.context.itemNotes = Item Notes
|
pane.context.itemNotes = Item Notes
|
||||||
pane.context.allNotes = All Notes
|
pane.context.allNotes = All Notes
|
||||||
|
pane.context.noNotes = No notes
|
||||||
|
|
||||||
noteEditor.editNote = Edit Note
|
noteEditor.editNote = Edit Note
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
|
|
||||||
.zotero-context-notes-list {
|
.zotero-context-notes-list {
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
|
background-color: #d2d8e2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.zotero-context-pane-editor-parent-line > div {
|
.zotero-context-pane-editor-parent-line > div {
|
||||||
|
|
|
@ -13,14 +13,42 @@
|
||||||
height: 0;
|
height: 0;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
|
|
||||||
&> section > h2 {
|
& > section {
|
||||||
font-weight: bold;
|
margin: 5px 0;
|
||||||
margin: 7px 8px 3px;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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 {
|
.note-row {
|
||||||
border: 1px solid #bcc4d2;
|
border: 1px solid #bcc4d2;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|
Loading…
Reference in a new issue