Restyle Tag Selector

* Render a colored dot for colored tags
* Improve spacing and positioning, especially on 2x screens
* Add scss map for tag colors in light/dark scheme
* Add support for compact/comfortable in tag selector
* Restyle filter box, add a placeholder and a new icon
This commit is contained in:
Tom Najdek 2023-10-18 14:16:08 +02:00 committed by Dan Stillman
parent ff115b0873
commit 9ff76d2dd9
21 changed files with 334 additions and 131 deletions

View file

@ -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 && <span className="menu-marker"/>
}
return this.props.isMenu && <IconDownChevron className="menu-marker"/>
return this.props.isMenu && <CSSIcon name="chevron-6" className="menu-marker icon-8"/>
}
get attributes() {

View file

@ -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}
/>
<div className="tag-selector-filter-container">
<Search
ref={this.props.searchBoxRef}
value={this.props.searchString}
onSearch={this.props.onSearch}
className="tag-selector-filter"
/>
<Button
icon={<IconTagSelectorMenu />}
title="zotero.toolbar.actions.label"
className="tag-selector-actions"
isMenu
onMouseDown={ev => this.props.onSettings(ev)}
/>
<div className="tag-selector-filter-pane">
<div className="tag-selector-filter-container">
<Search
ref={this.props.searchBoxRef}
value={this.props.searchString}
onSearch={this.props.onSearch}
className="tag-selector-filter"
data-l10n-id="tagselector-search"
/>
<Button
icon={<CSSIcon name="filter" className="icon-16" />}
title="zotero.toolbar.actions.label"
className="tag-selector-actions"
isMenu
onMouseDown={ev => this.props.onSettings(ev)}
/>
</div>
</div>
</div>
);
@ -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,

View file

@ -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 (
<div key={tag.name} {...props}>
{tag.name}
<span>{tag.name}</span>
</div>
);
}
@ -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
};
}

View file

@ -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 <TagSelector
tags={tags}
searchBoxRef={this.searchBoxRef}
@ -498,6 +535,8 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
width={this.state.width}
height={this.state.height}
fontSize={parseInt(this.state.fontSize.replace('px', ''))}
lineHeight={parseInt(this.state.lineHeight.replace('px', ''))}
uiDensity={Zotero.Prefs.get('uiDensity')}
/>;
}

View file

@ -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;
}
}

View file

@ -240,3 +240,6 @@ sidenav-related =
abstract-field =
.label = Add abstract…
tagselector-search =
.placeholder = Filter Tags

View file

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.99998 1.70711C1.37001 1.07714 1.81618 0 2.70708 0H14.2929C15.1838 0 15.6299 1.07714 15 1.70711L9.99998 6.70711V12.7071L6.99998 15.7071V6.70711L1.99998 1.70711ZM14.2929 1L2.70708 1L7.99998 6.29289V13.2929L8.99998 12.2929V6.29289L14.2929 1Z" fill="#FFFFFF8C" />
</svg>

After

Width:  |  Height:  |  Size: 423 B

View file

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.99998 1.70711C1.37001 1.07714 1.81618 0 2.70708 0H14.2929C15.1838 0 15.6299 1.07714 15 1.70711L9.99998 6.70711V12.7071L6.99998 15.7071V6.70711L1.99998 1.70711ZM14.2929 1L2.70708 1L7.99998 6.29289V13.2929L8.99998 12.2929V6.29289L14.2929 1Z" fill="#00000080" />
</svg>

After

Width:  |  Height:  |  Size: 423 B

View file

@ -0,0 +1,3 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.70711 2L1 2.70711L4 5.70711L7 2.70711L6.29289 2L4 4.29289L1.70711 2Z" fill="#FFFFFF8C"/>
</svg>

After

Width:  |  Height:  |  Size: 200 B

View file

@ -0,0 +1,3 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.70711 2L1 2.70711L4 5.70711L7 2.70711L6.29289 2L4 4.29289L1.70711 2Z" fill="#00000080"/>
</svg>

After

Width:  |  Height:  |  Size: 200 B

View file

@ -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,
);

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -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 {

View file

@ -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);
}
}
}

View file

@ -1,6 +1,5 @@
.search input {
-moz-appearance: searchfield;
height: 24px;
}
.search .search-cancel-button {

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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);
}
}