From a2f259d14cdbf0abe5799d56c6625a54732cd7f1 Mon Sep 17 00:00:00 2001 From: Abe Jellinek Date: Wed, 1 Nov 2023 08:00:21 -0400 Subject: [PATCH] Use item type CSS icons in more places .icon-item-type is now global, with extra styling to handle row selection when it's inside the item tree. getImageSrc() is still used for progress windows, which is probably OK for now because those don't stay on screen for very long. I've updated it to return SVGs based on the current UI color scheme. Other code uses treeitem-* images directly; getting rid of those references will cause a lot of conflicts and be a bit more involved than this initial pass, so I'll put that in a separate PR. --- chrome/content/zotero/components/icons.jsx | 39 ++++++++++- .../zotero/components/itemPane/notesList.jsx | 3 +- chrome/content/zotero/contextPane.js | 8 +-- chrome/content/zotero/elements/notesBox.js | 5 +- .../zotero/integration/addCitationDialog.js | 5 +- .../integration/editBibliographyDialog.js | 7 +- chrome/content/zotero/itemTree.jsx | 47 ++----------- .../content/zotero/xpcom/data/cachedTypes.js | 34 ++++----- chrome/content/zotero/xpcom/data/item.js | 35 +++++++--- .../zotero/xpcom/utilities_internal.js | 4 +- .../16/dark/attachment-epub-link.svg | 7 ++ .../16/dark/attachment-epub-link@2x.svg | 7 ++ .../16/light/attachment-epub-link.svg | 10 +++ .../16/light/attachment-epub-link@2x.svg | 10 +++ .../16/white/attachment-epub-link.svg | 13 ++++ .../16/white/attachment-epub-link@2x.svg | 13 ++++ .../28/dark/attachment-epub-link.svg | 14 ++++ .../28/light/attachment-epub-link.svg | 17 +++++ .../28/white/attachment-epub-link.svg | 7 ++ scss/components/_item-tree.scss | 69 +++++++++++-------- 20 files changed, 243 insertions(+), 111 deletions(-) create mode 100644 chrome/skin/default/zotero/item-type/16/dark/attachment-epub-link.svg create mode 100644 chrome/skin/default/zotero/item-type/16/dark/attachment-epub-link@2x.svg create mode 100644 chrome/skin/default/zotero/item-type/16/light/attachment-epub-link.svg create mode 100644 chrome/skin/default/zotero/item-type/16/light/attachment-epub-link@2x.svg create mode 100644 chrome/skin/default/zotero/item-type/16/white/attachment-epub-link.svg create mode 100644 chrome/skin/default/zotero/item-type/16/white/attachment-epub-link@2x.svg create mode 100644 chrome/skin/default/zotero/item-type/28/dark/attachment-epub-link.svg create mode 100644 chrome/skin/default/zotero/item-type/28/light/attachment-epub-link.svg create mode 100644 chrome/skin/default/zotero/item-type/28/white/attachment-epub-link.svg diff --git a/chrome/content/zotero/components/icons.jsx b/chrome/content/zotero/components/icons.jsx index c9ebc938ba..e1b996d3e3 100644 --- a/chrome/content/zotero/components/icons.jsx +++ b/chrome/content/zotero/components/icons.jsx @@ -20,7 +20,36 @@ Icon.propTypes = { style: object } -module.exports = { Icon } +const CSSIcon = (props) => { + props = Object.assign({}, props); + props.className = `icon icon-css icon-${props.name} ${props.className || ""}`; + delete props.name; + // Pass the props forward + return ; +}; + +CSSIcon.propTypes = { + children: element, + className: string, + name: string.isRequired, + style: object +}; + +const CSSItemTypeIcon = (props) => { + props = Object.assign({}, props); + let itemType = props.itemType; + delete props.itemType; + return ; +}; + +CSSItemTypeIcon.propTypes = { + children: element, + className: string, + itemType: string.isRequired, + style: object +}; + +module.exports = { Icon, CSSIcon, CSSItemTypeIcon }; function i(name, svgOrSrc, hasHiDPI = true) { @@ -231,4 +260,10 @@ module.exports.getCSSIcon = function (key) { } return cssIconsCache.get(key).cloneNode(true); -}; \ No newline at end of file +}; + +module.exports.getCSSItemTypeIcon = function (itemType) { + let icon = module.exports.getCSSIcon('icon-item-type'); + icon.dataset.itemType = itemType; + return icon; +}; diff --git a/chrome/content/zotero/components/itemPane/notesList.jsx b/chrome/content/zotero/components/itemPane/notesList.jsx index 98c9ce0007..ba6db84770 100644 --- a/chrome/content/zotero/components/itemPane/notesList.jsx +++ b/chrome/content/zotero/components/itemPane/notesList.jsx @@ -25,6 +25,7 @@ import React, { forwardRef, useImperativeHandle, useState, memo } from 'react'; import cx from 'classnames'; +import { CSSItemTypeIcon } from 'components/icons'; const MAX_UNEXPANDED_ALL_NOTES = 7; @@ -40,7 +41,7 @@ const NoteRow = memo(({ id, title, body, date, onClick, onKeyDown, onContextMenu
{ parentItemType ?
- + {parentTitle}
: null diff --git a/chrome/content/zotero/contextPane.js b/chrome/content/zotero/contextPane.js index dd3bed4348..4115d01466 100644 --- a/chrome/content/zotero/contextPane.js +++ b/chrome/content/zotero/contextPane.js @@ -28,6 +28,7 @@ var React = require('react'); var ReactDOM = require('react-dom'); var NotesList = require('components/itemPane/notesList').default; +var { getCSSItemTypeIcon } = require('components/icons'); var ZoteroContextPane = new function () { var _tabCover; @@ -850,13 +851,12 @@ var ZoteroContextPane = new function () { var parentItem = item.parentItem; if (parentItem) { var container = document.createElement('div'); - var img = document.createElement('img'); - img.src = Zotero.ItemTypes.getImageSrc(parentItem.itemType); - img.className = 'parent-item-type'; + var icon = getCSSItemTypeIcon(parentItem.getItemTypeIconName()); + icon.classList.add('parent-item-type'); var title = document.createElement('div'); title.append(parentItem.getDisplayTitle()); title.className = 'parent-title'; - container.append(img, title); + container.append(icon, title); parentTitleContainer.append(container); } _updateAddToNote(); diff --git a/chrome/content/zotero/elements/notesBox.js b/chrome/content/zotero/elements/notesBox.js index b69c1964db..1ce5ab1566 100644 --- a/chrome/content/zotero/elements/notesBox.js +++ b/chrome/content/zotero/elements/notesBox.js @@ -25,6 +25,8 @@ "use strict"; +import { getCSSItemTypeIcon } from 'components/icons'; + { class NotesBox extends XULElement { constructor() { @@ -123,8 +125,7 @@ let notes = Zotero.Items.get(this._item.getNotes()); for (let item of notes) { let id = item.id; - let icon = document.createElement("img"); - icon.src = item.getImageSrc(); + let icon = getCSSItemTypeIcon(item.getItemTypeIconName()); let label = document.createElement("label"); label.append(item.getDisplayTitle()); diff --git a/chrome/content/zotero/integration/addCitationDialog.js b/chrome/content/zotero/integration/addCitationDialog.js index 9c9f45b16e..3d06436ca3 100644 --- a/chrome/content/zotero/integration/addCitationDialog.js +++ b/chrome/content/zotero/integration/addCitationDialog.js @@ -23,6 +23,8 @@ ***** END LICENSE BLOCK ***** */ +import { getCSSItemTypeIcon } from 'components/icons'; + Components.utils.import("resource://gre/modules/Services.jsm"); var Zotero_Citation_Dialog = new function () { @@ -835,8 +837,7 @@ var Zotero_Citation_Dialog = new function () { } itemNode.setAttribute("value", itemDataID); - let image = document.createXULElement('image'); - image.src = item.getImageSrc(); + let image = getCSSItemTypeIcon(item.getItemTypeIconName()); itemNode.append(image); itemNode.setAttribute("class", "listitem-iconic"); itemNode.append(item.getDisplayTitle()); diff --git a/chrome/content/zotero/integration/editBibliographyDialog.js b/chrome/content/zotero/integration/editBibliographyDialog.js index 85a44f942d..94a8669e05 100644 --- a/chrome/content/zotero/integration/editBibliographyDialog.js +++ b/chrome/content/zotero/integration/editBibliographyDialog.js @@ -23,6 +23,8 @@ ***** END LICENSE BLOCK ***** */ +import { getCSSItemTypeIcon } from 'components/icons'; + var Zotero_Bibliography_Dialog = new function () { var bibEditInterface; var _lastSelectedItemID = false; @@ -325,8 +327,7 @@ var Zotero_Bibliography_Dialog = new function () { for(var i=0; i + + + + + + diff --git a/chrome/skin/default/zotero/item-type/16/dark/attachment-epub-link@2x.svg b/chrome/skin/default/zotero/item-type/16/dark/attachment-epub-link@2x.svg new file mode 100644 index 0000000000..29a3643416 --- /dev/null +++ b/chrome/skin/default/zotero/item-type/16/dark/attachment-epub-link@2x.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/chrome/skin/default/zotero/item-type/16/light/attachment-epub-link.svg b/chrome/skin/default/zotero/item-type/16/light/attachment-epub-link.svg new file mode 100644 index 0000000000..ab5f26e3ad --- /dev/null +++ b/chrome/skin/default/zotero/item-type/16/light/attachment-epub-link.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/chrome/skin/default/zotero/item-type/16/light/attachment-epub-link@2x.svg b/chrome/skin/default/zotero/item-type/16/light/attachment-epub-link@2x.svg new file mode 100644 index 0000000000..ab5f26e3ad --- /dev/null +++ b/chrome/skin/default/zotero/item-type/16/light/attachment-epub-link@2x.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/chrome/skin/default/zotero/item-type/16/white/attachment-epub-link.svg b/chrome/skin/default/zotero/item-type/16/white/attachment-epub-link.svg new file mode 100644 index 0000000000..465d186d8c --- /dev/null +++ b/chrome/skin/default/zotero/item-type/16/white/attachment-epub-link.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/chrome/skin/default/zotero/item-type/16/white/attachment-epub-link@2x.svg b/chrome/skin/default/zotero/item-type/16/white/attachment-epub-link@2x.svg new file mode 100644 index 0000000000..7d417b2458 --- /dev/null +++ b/chrome/skin/default/zotero/item-type/16/white/attachment-epub-link@2x.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/chrome/skin/default/zotero/item-type/28/dark/attachment-epub-link.svg b/chrome/skin/default/zotero/item-type/28/dark/attachment-epub-link.svg new file mode 100644 index 0000000000..107ee6fabc --- /dev/null +++ b/chrome/skin/default/zotero/item-type/28/dark/attachment-epub-link.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/chrome/skin/default/zotero/item-type/28/light/attachment-epub-link.svg b/chrome/skin/default/zotero/item-type/28/light/attachment-epub-link.svg new file mode 100644 index 0000000000..a301c33f38 --- /dev/null +++ b/chrome/skin/default/zotero/item-type/28/light/attachment-epub-link.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/chrome/skin/default/zotero/item-type/28/white/attachment-epub-link.svg b/chrome/skin/default/zotero/item-type/28/white/attachment-epub-link.svg new file mode 100644 index 0000000000..b556365e7a --- /dev/null +++ b/chrome/skin/default/zotero/item-type/28/white/attachment-epub-link.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/scss/components/_item-tree.scss b/scss/components/_item-tree.scss index f3af76c51e..cbe32de2df 100644 --- a/scss/components/_item-tree.scss +++ b/scss/components/_item-tree.scss @@ -48,10 +48,12 @@ .cell.numNotes { text-align: center; } +} - $itemTypesIcons: ( +$-itemTypesIcons: ( artwork, attachment-epub, + attachment-epub-link, attachment-file, // mapped to document below attachment-link, attachment-pdf-link, @@ -96,35 +98,46 @@ tv-broadcast, video-recording, webpage - ); - - $itemTypesMap: ( +); + +$-itemTypesMap: ( "attachment-file": "document" - ); - - - .virtualized-table .row { - .icon-item-type { - width: 16px; - height: 16px; +); + +.icon-item-type { + width: 16px; + height: 16px; +} + +// Due to quirks of the state() mixin, we need two sets of .icon-item-type rules: +// one when the icon is within a virtualized-table, and one when it isn't. We declare +// a mixin here to avoid duplication. + +@mixin -icon-item-type-rules($color) { + .icon-item-type { + // default icon, for known item types more specific selectors below will apply + @include svgicon("document", $color, "16", "item-type", true); + } + + @each $itemTypeIcon in $-itemTypesIcons { + $itemType: camelCase(str-replace(str-replace($itemTypeIcon, "pdf", "PDF"), "epub", "EPUB")); + + @if map.has-key($-itemTypesMap, $itemTypeIcon) { + $itemTypeIcon: map.get($-itemTypesMap, $itemTypeIcon); } - - @include focus-states using ($color) { - .icon-item-type { - // default icon, for known item types more specific selectors below will apply - @include svgicon("document", $color, "16", "item-type", true); - } - @each $itemTypeIcon in $itemTypesIcons { - $itemType: camelCase(str-replace(str-replace($itemTypeIcon, "pdf", "PDF"), "epub", "EPUB")); - - @if map.has-key($itemTypesMap, $itemTypeIcon) { - $itemTypeIcon: map.get($itemTypesMap, $itemTypeIcon); - } - - .icon-item-type[data-item-type=#{$itemType}] { - @include svgicon($itemTypeIcon, $color, "16", "item-type", true); - } - } + + .icon-item-type[data-item-type=#{$itemType}] { + @include svgicon($itemTypeIcon, $color, "16", "item-type", true); } } } + +@include focus-states using($color) { + @include -icon-item-type-rules($color); +} + +.virtualized-table .row { + @include focus-states using($color) { + @include -icon-item-type-rules($color); + } +}