zotero/scss/elements/_quickSearchTextbox.scss
Dan Stillman 77a3a8815e
Some checks are pending
CI / Detect changes (push) Waiting to run
CI / Test () (push) Blocked by required conditions
CI / Test (macOS NFS) (push) Blocked by required conditions
CI / Test (Windows arm64) (push) Blocked by required conditions
CI / Test (Windows x64) (push) Blocked by required conditions
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
Add a query syntax to the quick search
Zotero.SearchQuery turns a query like `by:smith after:2020 tag:"to read"
crispr` or `creator is smith and (tag is foo or bar)` into a
Zotero.Search, matching whatever text is left over using the current
search mode. Anything that doesn't look like a clause is free text, so a
DOI or a title with a colon in it is matched literally.

The search box syntax-highlights the parts of recognized conditions and
offers autocomplete for condition names, for the values of conditions
that have a fixed set of them (like item type), and for tags and
creators from the selected libraries.
2026-08-20 16:09:20 -04:00

235 lines
6.3 KiB
SCSS

// | 6px padding | 16px icon width | 2px padding | 8px dropmarker width | 4px padding |
quick-search-textbox {
--search-textbox-width: 146px;
font-size: var(--zotero-font-size);
margin-right: 0;
width: var(--search-textbox-width);
height: 28px;
max-width: 300px;
flex-grow: 1;
// Let the wrapper shrink below its content width when the items pane is squeezed (e.g., by a
// wide item pane). Otherwise it keeps its intrinsic width and overflows to the right, pushing
// the trailing Advanced Search button out under the item pane where it's clipped.
#search-wrapper {
min-width: 0;
}
// While the Advanced Search indicator is shown, size this element to the indicator's content
// (full label + buttons) rather than the 146px quick-search width, and allow shrinking below
// it (min-width: 0) only when the toolbar overflows -- so the label stays full on a normal
// window and crops just enough on a narrow one, keeping the buttons to its right (collapse/
// close and the stacked item-pane toggle) unclipped. The normal search box keeps its default
// size (it isn't shown then).
&[advanced-search-open] {
width: auto;
min-width: 0;
// Take only the indicator's width (don't grow toward max-width), so the buttons sit right
// after the label and the toggle isn't pushed out; the toolbar's spacer absorbs the slack
flex-grow: 0;
// A XUL <deck> sizes to its largest panel and doesn't clamp the panel to the deck's
// width, so the indicator keeps its full width and overflows. Since only the indicator
// is shown while advanced search is open, lay the deck out as flex and let the indicator
// (and its label) shrink, hiding the inactive quick-search panel.
#search-deck {
min-width: 0;
display: flex;
}
#search-wrapper {
display: none;
}
#advanced-search-indicator {
flex: 1;
min-width: 0;
}
}
*[zoteroFontSize=small] {
font-size: 11px;
}
:is(search-textbox, query-textbox)::part(search-sign),
:is(search-textbox, query-textbox)::part(search-icon) {
@include svgicon-menu("magnifier", "universal", "16");
color: var(--fill-secondary);
// right: 4px gap + 2px padding + 8px dropmarker width + 4px padding
// left, top, and bottom: 5px padding (6px on Figma, including 1px search-textbox border)
// Use explicit left/right padding here because this element is flipped in RTL (see _search.scss)
padding: 5px 18px 5px 5px;
margin: 0;
}
:is(search-textbox, query-textbox)::part(search-input) {
padding: 0;
}
}
#zotero-tb-search {
height: 100%;
}
#zotero-tb-search-dropmarker {
position: relative;
// 6px padding + 16px icon width + 2px padding + 8px dropmarker width + 4px padding
width: 36px;
margin-inline-end: -36px;
z-index: 2;
}
#zotero-tb-search-menu-button {
width: 36px;
height: 28px;
min-height: 28px;
padding-block: 0;
// inline-start: 6px padding + 16px icon width + 2px padding - 1px outer border
padding-inline: 23px 4px !important;
margin: 0;
border: 0;
border-radius: 5px;
appearance: none;
min-width: 0;
cursor: default;
@include svgicon-menu("chevron-6", "universal", "8");
color: var(--fill-secondary);
background: transparent;
@include focus-ring;
.button-menu-dropmarker {
display: none; /* Hide automatic dropmarker */
}
}
#zotero-tb-search-textbox {
padding: 0;
padding-inline-end: 6px;
margin: 0;
position: relative;
inset-inline-start: 0;
width: var(--search-textbox-width);
height: 28px;
z-index: 1;
width: 100%;
// Keep input text and the clear icon out from under the Advanced Search button
&:has(~ #zotero-tb-search-advanced-button) {
padding-inline-end: 30px;
}
}
// Match the specificity of the #zotero-items-toolbar toolbarbutton rules
#zotero-tb-search #zotero-tb-search-advanced-button {
position: relative;
width: 28px;
height: 28px;
min-width: 0;
margin: 0;
margin-inline-start: -28px;
margin-inline-end: 2px;
padding: 0;
z-index: 2;
@include svgicon-menu("filter", "universal", "16");
color: var(--fill-secondary);
@include focus-ring;
// Show the hover effect on a chip around the icon, inset within the field,
// rather than on the whole button
&:hover, &:active {
background-color: transparent;
}
.toolbarbutton-icon {
width: 24px;
height: 24px;
// The glyph is weighted slightly to the right within the SVG, so shift it
// a pixel left to optically center it (physical sides -- doesn't flip in RTL)
padding: 5px 6px 5px 4px;
border-radius: 4px;
// The button is 4px wider than the chip and left-aligns it, which puts the
// focus ring off-center; shift the chip 2px to center it within the button
margin-inline-start: 2px;
}
&:hover .toolbarbutton-icon {
background-color: var(--fill-quinary);
}
&:active .toolbarbutton-icon {
background-color: var(--fill-quarternary);
}
}
#zotero-tb-search-spinner {
margin: 0 8px;
// make sure the spinner always occupies space
display: inline;
visibility: hidden;
}
#search-deck {
width: 100%;
}
#search-wrapper {
align-items: center;
}
#advanced-search-indicator {
gap: 8px;
align-items: center;
// Cover the inline-end toolbar padding and the existing bottom border
margin-inline-end: -$toolbar-padding-inline;
padding-inline: $toolbar-padding-inline;
margin-bottom: -1px;
background: var(--material-toolbar);
border-inline-start: var(--material-border);
// Prevent text from shifting when border shows after panel is collapsed
border-block: var(--material-border-transparent);
// This is styled like it's part of the Advanced Search panel, which can't drag the window,
// so match that behavior
-moz-window-dragging: no-drag;
& > label {
flex: 1;
// Let the label shrink and crop on a narrow window so the collapse/close buttons to its
// right stay visible
min-width: 0;
padding-inline: 4px;
font-weight: 700;
}
.zotero-clicky {
width: 28px;
height: 28px;
margin: 0;
padding: 4px;
}
.advanced-collapse-button {
@include svgicon-menu("minimize", "universal", "20");
}
.advanced-close-button {
@include svgicon-menu("x", "universal", "20");
// Inset to match the filter button's chip in the closed state (it sits 2px
// in from the field edge), so the edge doesn't shift when toggling between
// the search field and this header
margin-inline-end: 2px;
}
&[data-collapsed="true"] {
border-bottom: var(--material-border);
.advanced-collapse-button {
@include svgicon-menu("maximize", "universal", "20");
}
}
}