Fix item pane header (#4159)

* Improve feed item pane header (fixes #4141)
* Show item pane custom head when headerMode is none (fixes #4116)
* fx115: Fix button style on windows (fixes #4120)
* Move split-menu-button styles to SCSS
This commit is contained in:
windingwind 2024-06-04 14:14:20 +08:00 committed by GitHub
parent 845f11b1da
commit a6076ce76c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 214 additions and 103 deletions

View file

@ -338,6 +338,7 @@
let toggleReadButton = doc.createXULElement("button"); let toggleReadButton = doc.createXULElement("button");
toggleReadButton.classList.add("feed-item-toggleRead-button"); toggleReadButton.classList.add("feed-item-toggleRead-button");
toggleReadButton.classList.add("no-shrink-button");
toggleReadButton.addEventListener("command", () => { toggleReadButton.addEventListener("command", () => {
ZoteroPane.toggleSelectedItemsRead(); ZoteroPane.toggleSelectedItemsRead();
}); });
@ -447,6 +448,12 @@
+ key + ')'; + key + ')';
elem.title = tooltip; elem.title = tooltip;
elem.image = this._translationTarget.treeViewImage; elem.image = this._translationTarget.treeViewImage;
// Set button width to take up the free width when the text is too long
// to prevent another button from growing
// 6px button padding + 16px icon + 4 px gap + ${textWidth} + 6px gap
// + 1px separator + 6px gap + 8px dropdown arrow + 6px button padding
elem.style.flexBasis = `${elem.querySelector(`[anonid="button-text"]`).scrollWidth + 53}px`;
} }
setTranslationTarget(translationTarget) { setTranslationTarget(translationTarget) {

View file

@ -30,14 +30,20 @@
class ItemPaneHeader extends ItemPaneSectionElementBase { class ItemPaneHeader extends ItemPaneSectionElementBase {
content = MozXULElement.parseXULToFragment(` content = MozXULElement.parseXULToFragment(`
<html:div class="title"> <html:div class="head-container">
<editable-text /> <html:div class="title-head">
<html:div class="title">
<editable-text />
</html:div>
<html:div class="creator-year"></html:div>
<html:div class="bib-entry"></html:div>
</html:div>
<html:div class="custom-head"></html:div>
</html:div> </html:div>
<html:div class="creator-year" />
<html:div class="bib-entry" />
<popupset> <popupset>
<menupopup class="secondary-popup"> <menupopup class="secondary-popup">
<menuitem data-l10n-id="text-action-copy" /> <menuitem data-l10n-id="text-action-copy" />
@ -47,8 +53,6 @@
</menu> </menu>
</menupopup> </menupopup>
</popupset> </popupset>
<html:div class="custom-head"/>
`, ['chrome://zotero/locale/zotero.dtd']); `, ['chrome://zotero/locale/zotero.dtd']);
_item = null; _item = null;
@ -68,8 +72,6 @@
this._notifierID = Zotero.Notifier.registerObserver(this, ['item'], 'paneHeader'); this._notifierID = Zotero.Notifier.registerObserver(this, ['item'], 'paneHeader');
this._prefsObserverIDs = [ this._prefsObserverIDs = [
Zotero.Prefs.registerObserver('itemPaneHeader', () => { Zotero.Prefs.registerObserver('itemPaneHeader', () => {
// TEMP?: _forceRenderAll() doesn't do anything if the section is hidden, so un-hide first
this.hidden = false;
this._forceRenderAll(); this._forceRenderAll();
}), }),
Zotero.Prefs.registerObserver('itemPaneHeader.bibEntry.style', () => this._forceRenderAll()), Zotero.Prefs.registerObserver('itemPaneHeader.bibEntry.style', () => this._forceRenderAll()),
@ -196,15 +198,16 @@
headerMode = 'title'; headerMode = 'title';
} }
if (headerMode === 'none') {
this.hidden = true;
return;
}
this.hidden = false;
this.title.hidden = true; this.title.hidden = true;
this.creatorYear.hidden = true; this.creatorYear.hidden = true;
this.bibEntry.hidden = true; this.bibEntry.hidden = true;
if (headerMode === 'none') {
this.classList.add('no-title-head');
return;
}
this.classList.remove('no-title-head');
if (headerMode === 'bibEntry') { if (headerMode === 'bibEntry') {
if (!Zotero.Styles.initialized()) { if (!Zotero.Styles.initialized()) {
@ -379,6 +382,7 @@
doc: document, doc: document,
append, append,
}); });
this.classList.toggle('has-custom-head', customHead.innerHTML);
} }
} }
customElements.define("item-pane-header", ItemPaneHeader); customElements.define("item-pane-header", ItemPaneHeader);

View file

@ -411,45 +411,3 @@ TODO: Replace with SVG
background-color: Highlight; background-color: Highlight;
color: HighlightText; color: HighlightText;
} }
.split-menu-button {
display: flex;
align-items: center;
padding-right: 0;
}
.split-menu-button [anonid="button-image-and-text-box"] {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.split-menu-button [anonid="button-image"] {
width: 16px;
height: 16px;
flex-shrink: 0;
margin-inline-end: 8px;
}
.split-menu-button [anonid="button-text"] {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.split-menu-button [anonid="dropmarker-box"] {
display: flex;
align-items: center;
overflow: hidden;
}
.split-menu-button [anonid="dropmarker-separator"] {
height: calc(100% - 5px);
border-inline-start: 1px solid #aaa;
margin: 0 2px 0 4px;
}
.split-menu-button .split-menu-button-dropmarker {
margin-inline: 5px;
}

View file

@ -79,6 +79,7 @@
@import "elements/quickSearchTextbox"; @import "elements/quickSearchTextbox";
@import "elements/richlistCheckbox"; @import "elements/richlistCheckbox";
@import "elements/styleConfigurator"; @import "elements/styleConfigurator";
@import "elements/splitMenuButton";
@import "elements/tagsBox"; @import "elements/tagsBox";
@import "elements/zoteroSearch"; @import "elements/zoteroSearch";
@import "elements/itemPaneHeader"; @import "elements/itemPaneHeader";

View file

@ -62,3 +62,7 @@
{ {
margin-left: 5px; margin-left: 5px;
} }
.feed-item-addTo-button {
--split-button-icon-color: var(--accent-blue);
}

View file

@ -6,7 +6,7 @@ item-message-pane {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-self: stretch; align-self: stretch;
gap: 6px; gap: 8px;
padding: 6px 8px; padding: 6px 8px;
background: var(--material-toolbar); background: var(--material-toolbar);
border-bottom: var(--material-panedivider); border-bottom: var(--material-panedivider);

View file

@ -11,49 +11,118 @@ item-pane-header {
overflow-y: auto; overflow-y: auto;
scrollbar-color: var(--color-scrollbar) var(--color-scrollbar-background); scrollbar-color: var(--color-scrollbar) var(--color-scrollbar-background);
.title { .head-container {
margin-top: calc(0px - var(--editable-text-padding-block));
flex: 1 1 0;
font-weight: 600;
line-height: 1.333;
editable-text {
flex: 1;
}
}
.creator-year {
color: var(--fill-secondary);
}
.bib-entry {
line-height: 1.5;
&.loading {
color: var(--fill-secondary);
}
}
.creator-year, .bib-entry {
// Set padding to match editable-text in tight mode, plus 1px for border
padding-inline: calc(var(--editable-text-tight-padding-inline) + 1px);
overflow-wrap: anywhere;
}
.custom-head {
display: flex; display: flex;
flex-direction: row; flex-direction: column;
align-self: stretch; align-items: center;
gap: 6px; justify-content: space-between;
&:empty { @include compact {
display: none; gap: 4px;
} }
button { @include comfortable {
height: 26px; gap: 8px;
margin: 0; }
flex-grow: 1;
.title-head {
align-self: stretch;
.title {
margin-top: calc(0px - var(--editable-text-padding-block));
flex: 1 1 0;
font-weight: 600;
line-height: 1.333;
editable-text {
flex: 1;
}
}
.creator-year {
color: var(--fill-secondary);
}
.bib-entry {
line-height: 1.5;
&.loading {
color: var(--fill-secondary);
}
}
.creator-year, .bib-entry {
// Set padding to match editable-text in tight mode, plus 1px for border
padding-inline: calc(var(--editable-text-tight-padding-inline) + 1px);
overflow-wrap: anywhere;
}
}
.custom-head {
display: flex;
flex-direction: row;
align-self: stretch;
gap: 8px;
@media (-moz-platform: macos) {
// The extent of the button is about 2px wider than its optical width
// need to compensate for that
gap: 4px;
}
&:empty {
display: none;
}
button {
// Allow the button to grow/shrink to fit the container
width: 0;
margin: 0;
flex-grow: 1;
padding: 2px 6px;
@media (-moz-platform: macos) {
height: 24px;
padding: 3px 0px 1px 0px;
&:is(.split-menu-button) {
padding: 3px 2px 1px 3px;
}
}
.button-text {
width: 0;
flex-grow: 1;
justify-content: center;
&::before {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
&:is(.no-shrink-button) {
width: auto;
flex-shrink: 0;
.button-text {
width: auto;
}
}
}
}
}
&.no-title-head {
&:not(.has-custom-head) {
padding: 0;
border: none;
}
.title-head {
display: none;
} }
} }
} }

View file

@ -5,7 +5,7 @@ note-editor {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-self: stretch; align-self: stretch;
gap: 6px; gap: 8px;
padding: 6px 8px; padding: 6px 8px;
background: var(--material-toolbar); background: var(--material-toolbar);
border-bottom: var(--material-panedivider); border-bottom: var(--material-panedivider);

View file

@ -0,0 +1,50 @@
.split-menu-button {
display: flex;
align-items: center;
padding-right: 0;
gap: 6px;
& [anonid="button-image-and-text-box"] {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
// Allow the button to grow/shrink to fit the container
width: 0;
}
& [anonid="button-image"] {
width: 16px;
height: 16px;
flex-shrink: 0;
margin-inline-end: 4px;
color: var(--split-button-icon-color);
fill: currentColor;
-moz-context-properties: fill,fill-opacity;
}
& [anonid="button-text"] {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
& [anonid="dropmarker-box"] {
display: flex;
align-items: center;
overflow: hidden;
}
& [anonid="dropmarker-separator"] {
height: calc(100% - 2px);
border-inline-start: 1px solid var(--fill-quinary);
}
& .split-menu-button-dropmarker {
padding: 0;
margin: 0;
color: var(--fill-secondary);
fill: currentColor;
-moz-context-properties: fill,fill-opacity;
}
}

View file

@ -12,6 +12,8 @@ menupopup {
margin-left: 4px; margin-left: 4px;
margin-right: 4px; margin-right: 4px;
border-radius: 4px; border-radius: 4px;
fill: currentColor;
-moz-context-properties: fill,fill-opacity;
&[_moz-menuactive="true"] { &[_moz-menuactive="true"] {
background: var(--fill-quinary); background: var(--fill-quinary);
} }

View file

@ -1,13 +1,13 @@
@mixin windows-form-element-base { @mixin windows-form-element-base {
appearance: none; appearance: none;
padding: 0; padding: 0;
border: solid 1px transparent; border: 1px solid transparent !important;
border-radius: 3px; border-radius: 3px;
background-origin: border-box; background-origin: border-box;
background-clip: padding-box, padding-box, border-box; background-clip: padding-box, padding-box, border-box;
// Overwrite default background color // Overwrite default background color
background-color: unset; background-color: unset !important;
// Simulate linear-gradient border with border-radius using background-image // Simulate linear-gradient border with border-radius using background-image
@include light-dark(--color-form-element-background, var(--color-background70), var(--fill-quinary)); @include light-dark(--color-form-element-background, var(--color-background70), var(--fill-quinary));

View file

@ -66,7 +66,23 @@ describe("Item pane", function () {
it("should be hidden when set to None mode", async function () { it("should be hidden when set to None mode", async function () {
Zotero.Prefs.set('itemPaneHeader', 'none'); Zotero.Prefs.set('itemPaneHeader', 'none');
await createDataObject('item', itemData); await createDataObject('item', itemData);
assert.isTrue(doc.querySelector('item-pane-header').hidden); assert.equal(doc.querySelector('item-pane-header').clientHeight, 0);
});
it("should show custom header elements when set to None mode", async function () {
Zotero.Prefs.set('itemPaneHeader', 'none');
// Use feed item toggle button as an example
let feed = await createFeed();
await selectLibrary(win, feed.libraryID);
await waitForItemsLoad(win);
var item = await createDataObject('feedItem', { libraryID: feed.libraryID });
await ZoteroPane.selectItem(item.id);
let feedButton = ZoteroPane.itemPane._itemDetails.querySelector('.feed-item-toggleRead-button');
assert.exists(feedButton);
await selectLibrary(win);
}); });
it("should show title when set to Title mode", async function () { it("should show title when set to Title mode", async function () {