diff --git a/chrome/content/zotero/components/button.jsx b/chrome/content/zotero/components/button.jsx
index ca4c6c9cab..b809299344 100644
--- a/chrome/content/zotero/components/button.jsx
+++ b/chrome/content/zotero/components/button.jsx
@@ -27,7 +27,7 @@
const React = require('react')
const { PureComponent, createElement: create } = React
-const { IconDownChevron } = require('./icons')
+const { CSSIcon } = require('./icons')
const cx = require('classnames')
const {
bool, element, func, node, number, oneOf, string
@@ -77,7 +77,7 @@ class Button extends PureComponent {
if (!Zotero.isNode && Zotero.isLinux) {
return this.props.isMenu &&
}
- return this.props.isMenu &&
+ return this.props.isMenu &&
}
get attributes() {
diff --git a/chrome/content/zotero/components/tagSelector.jsx b/chrome/content/zotero/components/tagSelector.jsx
index 774fe4874d..e98f43067f 100644
--- a/chrome/content/zotero/components/tagSelector.jsx
+++ b/chrome/content/zotero/components/tagSelector.jsx
@@ -29,7 +29,7 @@ const React = require('react');
const PropTypes = require('prop-types');
const TagList = require('./tagSelector/tagSelectorList');
const { Button } = require('./button');
-const { IconTagSelectorMenu } = require('./icons');
+const { CSSIcon } = require('./icons');
const Search = require('./search');
class TagSelector extends React.PureComponent {
@@ -46,21 +46,26 @@ class TagSelector extends React.PureComponent {
width={this.props.width}
height={this.props.height}
fontSize={this.props.fontSize}
+ lineHeight={this.props.lineHeight}
+ uiDensity={this.props.uiDensity}
/>
-
-
-
}
- title="zotero.toolbar.actions.label"
- className="tag-selector-actions"
- isMenu
- onMouseDown={ev => this.props.onSettings(ev)}
- />
+
+
+
+ }
+ title="zotero.toolbar.actions.label"
+ className="tag-selector-actions"
+ isMenu
+ onMouseDown={ev => this.props.onSettings(ev)}
+ />
+
);
@@ -88,6 +93,8 @@ TagSelector.propTypes = {
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
fontSize: PropTypes.number.isRequired,
+ lineHeight: PropTypes.number.isRequired,
+ uiDensity: PropTypes.string.isRequired,
// Search
searchBoxRef: PropTypes.object,
diff --git a/chrome/content/zotero/components/tagSelector/tagSelectorList.jsx b/chrome/content/zotero/components/tagSelector/tagSelectorList.jsx
index d5cf9e51ff..a5940d9175 100644
--- a/chrome/content/zotero/components/tagSelector/tagSelectorList.jsx
+++ b/chrome/content/zotero/components/tagSelector/tagSelectorList.jsx
@@ -26,21 +26,21 @@
const React = require('react');
const PropTypes = require('prop-types');
var { Collection } = require('react-virtualized');
+const { props } = require("bluebird");
// See also .tag-selector-item in _tag-selector.scss
-var filterBarHeight = 32;
-var tagPaddingTop = 4;
-var tagPaddingLeft = 2;
-var tagPaddingRight = 2;
-var tagPaddingBottom = 4;
-var tagSpaceBetweenX = 7;
+var filterBarHeight = 36;
+var tagPaddingLeft = 4;
+var tagPaddingRight = 4;
+var tagSpaceBetweenX = 2;
var tagSpaceBetweenY = 4;
-var panePaddingTop = 2;
-var panePaddingLeft = 2;
-var panePaddingRight = 25;
+var panePaddingTop = 8;
+var panePaddingLeft = 8;
+var panePaddingRight = 2; // + scrollbar width
//var panePaddingBottom = 2;
var minHorizontalPadding = panePaddingLeft + tagPaddingLeft + tagPaddingRight + panePaddingRight;
+
class TagList extends React.PureComponent {
constructor(props) {
super(props);
@@ -53,11 +53,13 @@ class TagList extends React.PureComponent {
// Redraw all tags on every refresh
if (this.collectionRef && this.collectionRef.current) {
// If width or height changed, recompute positions. It seems like this should happen
- // automatically, but it doesn't as of 9.21.0.
+ // automatically, but it doesn't as of 9.21.0. Also check for density change.
+
if (prevProps.height != this.props.height
|| prevProps.width != this.props.width
- || prevProps.fontSize != this.props.fontSize
- || prevProps.tags != this.props.tags) {
+ || prevProps.lineHeight != this.props.lineHeight
+ || prevProps.tags != this.props.tags
+ || prevProps.uiDensity !== this.props.uiDensity) {
this.collectionRef.current.recomputeCellSizesAndPositions();
}
// If dimensions didn't change, just redraw at current positions. Without this, clicking
@@ -94,8 +96,12 @@ class TagList extends React.PureComponent {
* Calculate the x,y coordinates of all tags
*/
updatePositions() {
- var tagMaxWidth = this.props.width - minHorizontalPadding;
- var rowHeight = tagPaddingTop + this.props.fontSize + tagPaddingBottom + tagSpaceBetweenY;
+ const tagPaddingTop = this.props.uiDensity === 'comfortable' ? 2 : 1;
+ const tagPaddingBottom = tagPaddingTop;
+ this.scrollbarWidth = Zotero.Utilities.Internal.getScrollbarWidth();
+
+ var tagMaxWidth = this.props.width - minHorizontalPadding - this.scrollbarWidth;
+ var rowHeight = tagPaddingTop + this.props.lineHeight + tagPaddingBottom + tagSpaceBetweenY;
var positions = [];
var row = 0;
let rowX = panePaddingLeft;
@@ -113,9 +119,11 @@ class TagList extends React.PureComponent {
shouldAddSeparator = true;
forceNewLine = true;
}
- let tagWidth = tagPaddingLeft + Math.min(tag.width, tagMaxWidth) + tagPaddingRight;
+ // size of the colored dot + space between the dot and the tag name always sums up to fontSize (e.g., 8px + 3px at 11px fontSize)
+ const tagColorWidth = (tag.color && !Zotero.Utilities.Internal.isOnlyEmoji(tag.name)) ? this.props.fontSize : 0;
+ let tagWidth = tagPaddingLeft + Math.min(tag.width, tagMaxWidth) + tagPaddingRight + tagColorWidth;
// If first row or cell fits, add to current row
- if (!forceNewLine && (i == 0 || ((rowX + tagWidth) < (this.props.width - panePaddingLeft - panePaddingRight)))) {
+ if (!forceNewLine && (i == 0 || ((rowX + tagWidth) < (this.props.width - panePaddingRight - this.scrollbarWidth)))) {
positions[i] = [rowX, panePaddingTop + (row * rowHeight)];
}
// Otherwise, start new row
@@ -135,10 +143,10 @@ class TagList extends React.PureComponent {
}
cellSizeAndPositionGetter = ({ index }) => {
- var tagMaxWidth = this.props.width - minHorizontalPadding;
+ var tagMaxWidth = this.props.width - minHorizontalPadding - this.scrollbarWidth;
return {
width: Math.min(this.props.tags[index].width, tagMaxWidth),
- height: this.props.fontSize,
+ height: this.props.lineHeight,
x: this.positions[index][0],
y: this.positions[index][1]
};
@@ -149,7 +157,7 @@ class TagList extends React.PureComponent {
const { onDragOver, onDragExit, onDrop } = this.props.dragObserver;
- var className = 'tag-selector-item zotero-clicky';
+ var className = 'tag-selector-item';
if (tag.selected) {
className += ' selected';
}
@@ -159,6 +167,9 @@ class TagList extends React.PureComponent {
if (tag.disabled) {
className += ' disabled';
}
+ if (Zotero.Utilities.Internal.isOnlyEmoji(tag.name)) {
+ className += ' emoji';
+ }
let props = {
className,
@@ -176,7 +187,7 @@ class TagList extends React.PureComponent {
// Don't specify explicit width unless we're truncating, because for some reason the width
// from canvas can sometimes be slightly smaller than the actual width, resulting in an
// unnecessary ellipsis.
- var tagMaxWidth = this.props.width - minHorizontalPadding;
+ var tagMaxWidth = this.props.width - minHorizontalPadding - this.scrollbarWidth;
if (props.style.width < tagMaxWidth) {
delete props.style.width;
}
@@ -190,11 +201,12 @@ class TagList extends React.PureComponent {
if (tag.color) {
props.style.color = tag.color;
+ props['data-color'] = tag.color.toLowerCase();
}
return (
- {tag.name}
+ {tag.name}
);
}
@@ -265,6 +277,8 @@ class TagList extends React.PureComponent {
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
fontSize: PropTypes.number.isRequired,
+ lineHeight: PropTypes.number.isRequired,
+ uiDensity: PropTypes.string.isRequired
};
}
diff --git a/chrome/content/zotero/containers/tagSelectorContainer.jsx b/chrome/content/zotero/containers/tagSelectorContainer.jsx
index a7e529ac5c..1a443dd974 100644
--- a/chrome/content/zotero/containers/tagSelectorContainer.jsx
+++ b/chrome/content/zotero/containers/tagSelectorContainer.jsx
@@ -42,6 +42,9 @@ const defaults = {
};
const { Cc, Ci } = require('chrome');
+// first n tags will be measured using DOM method for more accurate measurment (at the cost of performance)
+const FORCE_DOM_TAGS_FOR_COUNT = 200;
+
Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
constructor(props) {
super(props);
@@ -50,7 +53,10 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
['collection-item', 'item', 'item-tag', 'tag', 'setting'],
'tagSelector'
);
- this._prefObserverID = Zotero.Prefs.registerObserver('fontSize', this.handleFontChange.bind(this));
+ this._prefObserverID = Zotero.Prefs.registerObserver('fontSize', this.handleUIPropertiesChange.bind(this));
+ this._prefObserverID = Zotero.Prefs.registerObserver('uiDensity', this.handleUIPropertiesChange.bind(this));
+ this._mediaQueryList = window.matchMedia("(min-resolution: 1.5dppx)");
+ this._mediaQueryList.addEventListener("change", this.handleUIPropertiesChange.bind(this));
this.tagListRef = React.createRef();
this.searchBoxRef = React.createRef();
@@ -66,7 +72,8 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
this.state = {
...defaults,
...this.getContainerDimensions(),
- ...this.getFontInfo()
+ ...this.getFontInfo(),
+ isHighDensity: this._mediaQueryList.matches
};
}
@@ -357,6 +364,7 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
container.appendChild(elem);
var style = window.getComputedStyle(elem);
var props = {
+ lineHeight: style.getPropertyValue('line-height'),
fontSize: style.getPropertyValue('font-size'),
fontFamily: style.getPropertyValue('font-family')
};
@@ -365,36 +373,61 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
}
/**
- * Recompute tag widths based on the current font settings
+ * Recompute tag widths when either font, UI density or pixel density changes
*/
- handleFontChange() {
+ handleUIPropertiesChange(ev) {
this.widths.clear();
this.widthsBold.clear();
+ const isHighDensity = ev.target instanceof MediaQueryList ? ev.matches : this.state.isHighDensity;
this.setState({
- ...this.getFontInfo()
+ ...this.getFontInfo(),
+ uiDensity: Zotero.Prefs.get('uiDensity'),
+ isHighDensity
});
}
/**
* Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
+ * Except for emoji tags, where, on high-density screens, we use actual DOM element for more accurate
+ * measurement (which is 4-5x slower) because canvas method can be off by enough to cause visible artifacts.
+ * It's possible to force use of DOM method for other tags using forceUseDOM parameter.
*
* @param {String} text The text to be rendered.
* @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
+ * @param {String} forceUseDOM Force use of DOM method for measuring text width
*
* @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
*/
- getTextWidth(text, font) {
- // re-use canvas object for better performance
- var canvas = this.canvas || (this.canvas = document.createElement("canvas"));
- var context = canvas.getContext("2d");
- context.font = font;
- // Add a little more to make sure we don't crop
- var metrics = context.measureText(text);
- return Math.ceil(metrics.width);
+ getTextWidth(text, font, forceUseDOM = false) {
+ let width;
+ const useDOM = forceUseDOM || (this.state.isHighDensity && Zotero.Utilities.Internal.includesEmoji(text));
+ if (useDOM) {
+ if (!this.divMeasure) {
+ this.divMeasure = document.createElement('div');
+ this.divMeasure.style.position = 'absolute';
+ this.divMeasure.style.top = '-9999px';
+ this.divMeasure.whiteSpace = 'nowrap';
+ document.querySelector('#zotero-tag-selector').appendChild(this.divMeasure);
+ }
+
+ this.divMeasure.style.font = font;
+ this.divMeasure.textContent = text;
+ width = this.divMeasure.clientWidth;
+ this.divMeasure.textContent = '';
+ }
+ else {
+ // re-use canvas object for better performance
+ var canvas = this.canvas || (this.canvas = document.createElement("canvas"));
+ var context = canvas.getContext("2d");
+ context.font = font;
+ var metrics = context.measureText(text);
+ width = metrics.width;
+ }
+
+ return width;
}
- getWidth(name) {
- var num = 0;
+ getWidth(name, forceUseDOM = false) {
var font = this.state.fontSize + ' ' + this.state.fontFamily;
// Colored tags are shown in bold, which results in a different width
var fontBold = 'bold ' + font;
@@ -402,8 +435,8 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
let widths = hasColor ? this.widthsBold : this.widths;
let width = widths.get(name);
if (width === undefined) {
- width = this.getTextWidth(name, hasColor ? fontBold : font);
- //Zotero.debug(`Calculated ${hasColor ? 'bold ' : ''}width of ${width} for tag '${name}'`);
+ width = this.getTextWidth(name, hasColor ? fontBold : font, forceUseDOM);
+ // Zotero.debug(`Calculated ${hasColor ? 'bold ' : ''}width of ${width} for tag '${name}' using ${forceUseDOM ? 'DOM' : 'hybrid'} method`);
widths.set(name, width);
}
return width;
@@ -460,7 +493,7 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
// Prepare tag objects for list component
//var d = new Date();
var inTagColors = true;
- tags = tags.map((tag) => {
+ tags = tags.map((tag, i) => {
let name = tag.tag;
tag = {
name,
@@ -480,10 +513,14 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
if ((this.displayAllTags || inTagColors) && !this.state.scope.has(name)) {
tag.disabled = true;
}
- tag.width = this.getWidth(name);
+ const forceUseDOM = this.state.isHighDensity && i < FORCE_DOM_TAGS_FOR_COUNT;
+ tag.width = this.getWidth(name, forceUseDOM);
return tag;
});
- //Zotero.debug(`Prepared tags in ${new Date() - d} ms`);
+ // clean up divMeasure, which might have been used for measuring emoji tags
+ this.divMeasure?.parentNode?.removeChild?.(this.divMeasure);
+ this.divMeasure = null;
+ // Zotero.debug(`Prepared ${tags.length} tags in ${new Date() - d} ms`);
return ;
}
diff --git a/chrome/content/zotero/xpcom/utilities_internal.js b/chrome/content/zotero/xpcom/utilities_internal.js
index 32d8a5ffbc..1705a2f8e2 100644
--- a/chrome/content/zotero/xpcom/utilities_internal.js
+++ b/chrome/content/zotero/xpcom/utilities_internal.js
@@ -416,6 +416,12 @@ Zotero.Utilities.Internal = {
const re = /\p{Extended_Pictographic}|\u200D|\uFE0F/gu;
return !str.replace(re, '');
},
+
+ includesEmoji: function (str) {
+ // Remove emoji, Zero Width Joiner, and Variation Selector-16 and compare lengths
+ const re = /\p{Extended_Pictographic}|\u200D|\uFE0F/gu;
+ return str.replace(re, '').length !== str.length;
+ },
/**
* Display a prompt from an error with custom buttons and a callback
@@ -2304,6 +2310,21 @@ Zotero.Utilities.Internal = {
}
return false;
+ },
+
+ getScrollbarWidth() {
+ let document = Zotero.getMainWindow().document;
+ let scrollDiv = document.createElement('div');
+ scrollDiv.style.position = 'absolute';
+ scrollDiv.style.top = '-9999px';
+ scrollDiv.style.width = '50px';
+ scrollDiv.style.height = '50px';
+ scrollDiv.style.overflow = 'scroll';
+ document.documentElement.appendChild(scrollDiv);
+ const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
+ document.documentElement.removeChild(scrollDiv);
+
+ return scrollbarWidth;
}
}
diff --git a/chrome/locale/en-US/zotero/zotero.ftl b/chrome/locale/en-US/zotero/zotero.ftl
index b635392579..dc93261945 100644
--- a/chrome/locale/en-US/zotero/zotero.ftl
+++ b/chrome/locale/en-US/zotero/zotero.ftl
@@ -240,3 +240,6 @@ sidenav-related =
abstract-field =
.label = Add abstract…
+
+tagselector-search =
+ .placeholder = Filter Tags
\ No newline at end of file
diff --git a/chrome/skin/default/zotero/16/dark/filter.svg b/chrome/skin/default/zotero/16/dark/filter.svg
new file mode 100644
index 0000000000..fcb63ce855
--- /dev/null
+++ b/chrome/skin/default/zotero/16/dark/filter.svg
@@ -0,0 +1,4 @@
+
diff --git a/chrome/skin/default/zotero/16/light/filter.svg b/chrome/skin/default/zotero/16/light/filter.svg
new file mode 100644
index 0000000000..b1f35f8255
--- /dev/null
+++ b/chrome/skin/default/zotero/16/light/filter.svg
@@ -0,0 +1,4 @@
+
diff --git a/chrome/skin/default/zotero/8/dark/chevron-6.svg b/chrome/skin/default/zotero/8/dark/chevron-6.svg
new file mode 100644
index 0000000000..378c49cc9e
--- /dev/null
+++ b/chrome/skin/default/zotero/8/dark/chevron-6.svg
@@ -0,0 +1,3 @@
+
diff --git a/chrome/skin/default/zotero/8/light/chevron-6.svg b/chrome/skin/default/zotero/8/light/chevron-6.svg
new file mode 100644
index 0000000000..bde2fd825a
--- /dev/null
+++ b/chrome/skin/default/zotero/8/light/chevron-6.svg
@@ -0,0 +1,3 @@
+
diff --git a/scss/abstracts/_variables.scss b/scss/abstracts/_variables.scss
index 9c7f722f45..cf8f10ad8b 100644
--- a/scss/abstracts/_variables.scss
+++ b/scss/abstracts/_variables.scss
@@ -88,3 +88,15 @@ $item-pane-sections: (
"tags": var(--accent-orange),
"related": var(--accent-wood),
);
+
+$tagColorsLookup: (
+ '#ff6666': --tag-red,
+ '#ff8c19': --tag-orange,
+ '#999999': --tag-gray,
+ '#5fb236': --tag-green,
+ '#009980': --tag-teal,
+ '#2ea8e5': --tag-blue,
+ '#576dd9': --tag-indigo,
+ '#a28ae5': --tag-purple,
+ '#a6507b': --tag-plum,
+);
diff --git a/scss/base/_base.scss b/scss/base/_base.scss
index f8a330e4af..2784558c89 100644
--- a/scss/base/_base.scss
+++ b/scss/base/_base.scss
@@ -8,7 +8,7 @@
font-style: normal;
}
-#zotero-collections-pane {
+#zotero-collections-pane, #zotero-item-pane {
background: var(--material-sidepane);
}
@@ -18,4 +18,4 @@
height: 150px;
width: 290px;
background: var(--material-background);
-}
\ No newline at end of file
+}
diff --git a/scss/components/_button.scss b/scss/components/_button.scss
index 21efff6e82..bc3a42e70d 100644
--- a/scss/components/_button.scss
+++ b/scss/components/_button.scss
@@ -3,37 +3,31 @@
// --------------------------------------------------
.btn {
- font: {
- family: inherit;
- size: inherit;
- }
- line-height: inherit;
- color: inherit;
- text-align: center;
- -moz-appearance: toolbarbutton;
+ font: {
+ family: inherit;
+ size: inherit;
+ }
+ line-height: inherit;
+ color: inherit;
+ text-align: center;
+ -moz-appearance: toolbarbutton;
- &[disabled],
- &.disabled {
- opacity: $btn-disabled-opacity;
- }
+ &[disabled],
+ &.disabled {
+ opacity: $btn-disabled-opacity;
+ }
}
.btn-icon {
- .icon {
- &:first-child {
- margin-left: -5px;
- }
- &:last-child {
- margin-right: -5px;
- }
- svg, img {
- vertical-align: middle;
- }
- }
- span.menu-marker {
- -moz-appearance: toolbarbutton-dropdown;
- display: inline-block;
- margin-right: -5px;
- }
+ .icon {
+ svg, img {
+ vertical-align: middle;
+ }
+ }
+ span.menu-marker {
+ -moz-appearance: toolbarbutton-dropdown;
+ display: inline-block;
+ margin-left: 4px;
+ }
}
diff --git a/scss/components/_icons.scss b/scss/components/_icons.scss
index fb9b5a98df..21dd3fcf74 100644
--- a/scss/components/_icons.scss
+++ b/scss/components/_icons.scss
@@ -1,26 +1,49 @@
.icon > svg, .icon > img {
- width: 16px;
+ width: 16px;
}
.icon-bg {
- width: 16px;
- height: 16px;
- display: inline-block;
- background-repeat: no-repeat;
- background-size: contain;
- background-position: center;
- vertical-align: middle;
+ width: 16px;
+ height: 16px;
+ display: inline-block;
+ background-repeat: no-repeat;
+ background-size: contain;
+ background-position: center;
+ vertical-align: middle;
}
.icon-css {
- display: inline-block;
- vertical-align: middle;
+ display: inline-block;
+ vertical-align: middle;
}
.icon.icon-downchevron {
- width: 7px !important;
+ width: 7px !important;
}
.icon {
- -moz-appearance: none !important;
+ -moz-appearance: none !important;
}
+
+.icon-16 {
+ width: 16px;
+ height: 16px;
+}
+
+.icon-8 {
+ width: 8px;
+ height: 8px;
+}
+
+$-icons: (
+ filter: 16,
+ chevron-6: 8
+);
+
+@each $icon, $size in $-icons {
+ .icon-#{$icon} {
+ @include color-scheme using($color) {
+ @include svgicon($icon, $color, $size);
+ }
+ }
+}
\ No newline at end of file
diff --git a/scss/components/_mainWindow.scss b/scss/components/_mainWindow.scss
index db50bfb822..252a56520a 100644
--- a/scss/components/_mainWindow.scss
+++ b/scss/components/_mainWindow.scss
@@ -133,14 +133,13 @@
#tab-bar-container .tab.selected {
background: var(--material-tabbar)
}
-
+
.zotero-toolbar {
-moz-appearance: none;
+ }
+
+ #zotero-layout-switcher .zotero-toolbar {
background: var(--material-tabbar);
border-bottom: var(--material-panedivider);
}
-
- #zotero-collections-tree > div, #zotero-item-pane {
- background: var(--material-sidepane);
- }
}
diff --git a/scss/components/_search.scss b/scss/components/_search.scss
index cc372840a2..aaf69b8824 100644
--- a/scss/components/_search.scss
+++ b/scss/components/_search.scss
@@ -4,10 +4,25 @@
}
.search input {
+ background: var(--material-background);
+ border-radius: 5px;
+ border: var(--material-border-quinary);
+ color: var(--fill-primary);
flex: 1 0;
- font-size: 1em;
+ margin: 6px 4px;
min-width: 40px;
- padding-left: 4px;
+ padding: 3px 7px;
+
+ &::placeholder {
+ color: var(--fill-tertiary);
+ opacity: 1.0;
+ }
+
+ &:focus {
+ outline: none;
+ border-color: SelectedItem;
+ box-shadow: 0 0 0 2px SelectedItem;
+ }
}
.search .search-cancel-button {
diff --git a/scss/components/_tagSelector.scss b/scss/components/_tagSelector.scss
index 9d3c86f827..83b3af4251 100644
--- a/scss/components/_tagSelector.scss
+++ b/scss/components/_tagSelector.scss
@@ -28,7 +28,6 @@
display: flex;
overflow: hidden;
height: 100px;
- background: var(--material-sidepane);
}
.tag-selector-list-container > div {
@@ -43,18 +42,22 @@
}
.tag-selector-list {
- list-style: none;
display: inline-block;
+ list-style: none;
margin: 0;
padding: 0;
+ scrollbar-color: var(--color-scrollbar) var(--color-scrollbar-background);
+}
+
+.tag-selector-filter-pane {
+ padding: 0 8px 0;
}
.tag-selector-filter-container {
- height: 30px;
- flex: 0 0 1em;
+ border-top: var(--material-panedivider);
display: flex;
flex-direction: row;
- padding: 0.125em 0 0.125em 0.5em;
+ flex: 0 0 1em;
}
.tag-selector-filter-container .search {
@@ -63,21 +66,79 @@
}
.tag-selector-actions {
- flex: 0 1;
- display: block;
- white-space: nowrap;
+ align-self: center;
background-color: inherit;
+ border: 0;
+ display: block;
+ flex: 0 1;
+ padding: 3px 4px;
+ white-space: nowrap;
}
.tag-selector-item {
+ border-radius: 4px;
cursor: pointer;
+ font-size: 0.916666667em;
+ line-height: 1.272727273;
overflow: hidden;
+ padding: 1px 4px;
text-overflow: ellipsis;
white-space: pre;
- padding: 1px 4px 3px; // See also TagSelectorList.jsx
+
+ @include comfortable {
+ padding: 2px 4px;
+ }
+
+ &:hover {
+ background-color: var(--fill-quinary);
+ }
+
+ &.selected {
+ background-color: var(--fill-secondary);
+
+ &:hover {
+ opacity: .75;
+ }
+ }
&.colored {
font-weight: bold;
+
+ &.selected {
+ background-color: currentcolor;
+
+ @each $colorHex, $colorVar in $tagColorsLookup {
+ @include state('.tag-selector-item[data-color="#{$colorHex}"]') {
+ background-color: var($colorVar);
+ }
+ }
+ }
+
+ &:not(.emoji) {
+ &::before {
+ content: " ";
+ display: inline-block;
+ width: 0.636363636em; // 7px (+ 1px border = 8px)
+ height: 0.636363636em;
+ margin-right: .272727273em;
+ border-radius: 50%;
+ background-color: currentcolor; // fallback for non-standard colors
+ vertical-align: -0.363636364em; // -4px
+ border: var(--material-border-transparent);
+
+ @include state('.tag-selector-item.selected') {
+ border-color: var(--color-background);
+ }
+ }
+
+ @each $colorHex, $colorVar in $tagColorsLookup {
+ @include state('.tag-selector-item[data-color="#{$colorHex}"]') {
+ &::before {
+ background-color: var($colorVar);
+ }
+ }
+ }
+ }
}
&.disabled {
@@ -89,4 +150,12 @@
color: var(--color-background);
background-color: var(--fill-secondary);
}
+
+ span {
+ color: var(--fill-primary);
+
+ @include state('.tag-selector-item.selected') {
+ color: var(--color-background);
+ }
+ }
}
diff --git a/scss/mac/_search.scss b/scss/mac/_search.scss
index 8680b81d2a..78a6732df6 100644
--- a/scss/mac/_search.scss
+++ b/scss/mac/_search.scss
@@ -1,6 +1,5 @@
.search input {
-moz-appearance: searchfield;
- height: 24px;
}
.search .search-cancel-button {
diff --git a/scss/mac/_tag-selector.scss b/scss/mac/_tag-selector.scss
index 491d4d8a7a..25d00965b1 100644
--- a/scss/mac/_tag-selector.scss
+++ b/scss/mac/_tag-selector.scss
@@ -2,18 +2,4 @@
// Tag selector
// --------------------------------------------------
-.tag-selector-filter-container {
- padding: 0.25em 0 0.25em 0.5em;
- border-top: var(--material-panedivider);
-}
-.tag-selector-item {
- padding-bottom: .3em;
-}
-
-.tag-selector-actions {
- flex: none;
- border: 0;
- margin-right: 3px;
- padding: 1px 6px 0;
-}
diff --git a/scss/themes/_dark.scss b/scss/themes/_dark.scss
index b59bc77193..9b1449822c 100644
--- a/scss/themes/_dark.scss
+++ b/scss/themes/_dark.scss
@@ -31,6 +31,9 @@
--color-sidepane: #303030;
--color-tabbar: #1e1e1e;
--color-toolbar: #272727;
+ --color-scrollbar: rgb(117, 117, 117);
+ --color-scrollbar-hover: rgb(158, 158, 158);
+ --color-scrollbar-background: transparent;
--tag-blue: #55a6dfd9;
--tag-gray: #aaac;
--tag-green: #74b04ad9;
@@ -59,5 +62,6 @@
--material-border: 1px solid var(--color-border);
--material-border50: 1px solid var(--color-border50);
--material-panedivider: 1px solid var(--color-panedivider);
+ --material-border-quinary: 1px solid var(--fill-quinary);
}
}
\ No newline at end of file
diff --git a/scss/themes/_light.scss b/scss/themes/_light.scss
index b618df29c5..13810c4b3e 100644
--- a/scss/themes/_light.scss
+++ b/scss/themes/_light.scss
@@ -31,6 +31,9 @@
--color-sidepane: #f2f2f2;
--color-tabbar: #f2f2f2;
--color-toolbar: #f9f9f9;
+ --color-scrollbar: rgb(194, 194, 194);
+ --color-scrollbar-hover: rgb(125, 125, 125);
+ --color-scrollbar-background: transparent;
--tag-blue: #55a6df;
--tag-gray: #aaa;
--tag-green: #74b04a;
@@ -59,5 +62,6 @@
--material-border: 1px solid var(--color-border);
--material-border50: 1px solid var(--color-border50);
--material-panedivider: 1px solid var(--color-panedivider);
+ --material-border-quinary: 1px solid var(--fill-quinary);
}
}