From 99c166a1ac4a3ca54819f57ba0f26a174b09e851 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Thu, 13 May 2021 10:59:08 +1000 Subject: [PATCH] add new colour picker option --- extension/api.js | 31 ++++-- extension/dep/jscolor.min.js | 1 + extension/launcher.js | 5 + extension/repo/CHANGELOG.md | 1 - .../client.js | 1 - .../menu.css | 20 +++- .../menu.js | 100 ++++++++++++------ 7 files changed, 118 insertions(+), 41 deletions(-) create mode 100644 extension/dep/jscolor.min.js diff --git a/extension/api.js b/extension/api.js index ebfdfe9..fd14c5d 100644 --- a/extension/api.js +++ b/extension/api.js @@ -394,6 +394,9 @@ web.addTooltip = ($element, text) => { * @namespace fmt */ export const fmt = {}; +import './dep/jscolor.min.js'; +/** color picker with alpha channel using https://jscolor.com/ */ +fmt.JSColor = JSColor; import './dep/prism.js'; /** syntax highlighting using https://prismjs.com/ */ fmt.Prism = Prism; @@ -525,6 +528,18 @@ regexers.url = (str, err = () => {}) => { err(`invalid url ${str}`); return env.ERROR; }; +/** + * check for a valid color (https://regexr.com/39cgj) + * @param {string} str - the string to test + * @param {function} err - a callback to execute if the test fails + * @returns {boolean | env.ERROR} true or the env.ERROR constant + */ +regexers.color = (str, err = () => {}) => { + const match = str.match(/^(?:#|0x)(?:[a-f0-9]{3}|[a-f0-9]{6})\b|(?:rgb|hsl)a?\([^\)]*\)$/i); + if (match && match.length) return true; + err(`invalid color ${str}`); + return env.ERROR; +}; /** * an api for interacting with the enhancer's repository of mods @@ -704,6 +719,13 @@ registry.validate = async (mod, err, check) => { check('option.value', option.value, typeof option.value === 'number') ); break; + case 'color': + conditions.push( + check('option.value', option.value, typeof option.value === 'string').then( + (color) => (color === env.ERROR ? env.ERROR : regexers.color(color, err)) + ) + ); + break; case 'file': conditions.push( check( @@ -778,17 +800,14 @@ registry.defaults = async (id) => { for (const opt of mod.options) { switch (opt.type) { case 'toggle': + case 'text': + case 'number': + case 'color': defaults[opt.key] = opt.value; break; case 'select': defaults[opt.key] = opt.values[0]; break; - case 'text': - defaults[opt.key] = opt.value; - break; - case 'number': - defaults[opt.key] = opt.value; - break; case 'file': defaults[opt.key] = undefined; break; diff --git a/extension/dep/jscolor.min.js b/extension/dep/jscolor.min.js new file mode 100644 index 0000000..0677a02 --- /dev/null +++ b/extension/dep/jscolor.min.js @@ -0,0 +1 @@ +(function(global,factory){"use strict";if(typeof module==="object"&&typeof module.exports==="object"){module.exports=global.document?factory(global):function(win){if(!win.document){throw new Error("jscolor needs a window with document")}return factory(win)};return}factory(global)})(typeof window!=="undefined"?window:this,function(window){"use strict";var jscolor=function(){var jsc={initialized:false,instances:[],readyQueue:[],register:function(){if(typeof window!=="undefined"&&window.document){window.document.addEventListener("DOMContentLoaded",jsc.pub.init,false)}},installBySelector:function(selector,rootNode){rootNode=rootNode?jsc.node(rootNode):window.document;if(!rootNode){throw new Error("Missing root node")}var elms=rootNode.querySelectorAll(selector);var matchClass=new RegExp("(^|\\s)("+jsc.pub.lookupClass+")(\\s*(\\{[^}]*\\})|\\s|$)","i");for(var i=0;i-1},isButtonEmpty:function(el){switch(jsc.nodeName(el)){case"input":return!el.value||el.value.trim()==="";case"button":return el.textContent.trim()===""}return null},isPassiveEventSupported:function(){var supported=false;try{var opts=Object.defineProperty({},"passive",{get:function(){supported=true}});window.addEventListener("testPassive",null,opts);window.removeEventListener("testPassive",null,opts)}catch(e){}return supported}(),isColorAttrSupported:function(){var elm=window.document.createElement("input");if(elm.setAttribute){elm.setAttribute("type","color");if(elm.type.toLowerCase()=="color"){return true}}return false}(),dataProp:"_data_jscolor",setData:function(){var obj=arguments[0];if(arguments.length===3){var data=obj.hasOwnProperty(jsc.dataProp)?obj[jsc.dataProp]:obj[jsc.dataProp]={};var prop=arguments[1];var value=arguments[2];data[prop]=value;return true}else if(arguments.length===2&&typeof arguments[1]==="object"){var data=obj.hasOwnProperty(jsc.dataProp)?obj[jsc.dataProp]:obj[jsc.dataProp]={};var map=arguments[1];for(var prop in map){if(map.hasOwnProperty(prop)){data[prop]=map[prop]}}return true}throw new Error("Invalid arguments")},removeData:function(){var obj=arguments[0];if(!obj.hasOwnProperty(jsc.dataProp)){return true}for(var i=1;i=3&&(mR=par[0].match(re))&&(mG=par[1].match(re))&&(mB=par[2].match(re))){ret.format="rgb";ret.rgba=[parseFloat(mR[1])||0,parseFloat(mG[1])||0,parseFloat(mB[1])||0,null];if(par.length>=4&&(mA=par[3].match(re))){ret.format="rgba";ret.rgba[3]=parseFloat(mA[1])||0}return ret}}return false},parsePaletteValue:function(mixed){var vals=[];if(typeof mixed==="string"){mixed.replace(/#[0-9A-F]{3}([0-9A-F]{3})?|rgba?\(([^)]*)\)/gi,function(val){vals.push(val)})}else if(Array.isArray(mixed)){vals=mixed}var colors=[];for(var i=0;ivs[a]?-vp[a]+tp[a]+ts[a]/2>vs[a]/2&&tp[a]+ts[a]-ps[a]>=0?tp[a]+ts[a]-ps[a]:tp[a]:tp[a],-vp[b]+tp[b]+ts[b]+ps[b]-l+l*c>vs[b]?-vp[b]+tp[b]+ts[b]/2>vs[b]/2&&tp[b]+ts[b]-l-l*c>=0?tp[b]+ts[b]-l-l*c:tp[b]+ts[b]-l+l*c:tp[b]+ts[b]-l+l*c>=0?tp[b]+ts[b]-l+l*c:tp[b]+ts[b]-l-l*c]}var x=pp[a];var y=pp[b];var positionValue=thisObj.fixed?"fixed":"absolute";var contractShadow=(pp[0]+ps[0]>tp[0]||pp[0]0?Math.ceil(sampleCount/cols):0;cellW=Math.max(1,Math.floor((width-(cols-1)*thisObj.paletteSpacing)/cols));cellH=thisObj.paletteHeight?Math.min(thisObj.paletteHeight,cellW):cellW}if(rows){height=rows*cellH+(rows-1)*thisObj.paletteSpacing}return{cols:cols,rows:rows,cellW:cellW,cellH:cellH,width:width,height:height}},getControlPadding:function(thisObj){return Math.max(thisObj.padding/2,2*thisObj.pointerBorderWidth+thisObj.pointerThickness-thisObj.controlBorderWidth)},getPadYChannel:function(thisObj){switch(thisObj.mode.charAt(1).toLowerCase()){case"v":return"v";break}return"s"},getSliderChannel:function(thisObj){if(thisObj.mode.length>2){switch(thisObj.mode.charAt(2).toLowerCase()){case"s":return"s";break;case"v":return"v";break}}return null},triggerCallback:function(thisObj,prop){if(!thisObj[prop]){return}var callback=null;if(typeof thisObj[prop]==="string"){try{callback=new Function(thisObj[prop])}catch(e){console.error(e)}}else{callback=thisObj[prop]}if(callback){callback.call(thisObj)}},triggerGlobal:function(eventNames){var inst=jsc.getInstances();for(var i=0;i0){for(var y=0;y=2&&typeof arguments[0]==="string"){try{if(!setOption(arguments[0],arguments[1])){return false}}catch(e){console.warn(e);return false}this.redraw();this.exposeColor();return true}else if(arguments.length===1&&typeof arguments[0]==="object"){var opts=arguments[0];var success=true;for(var opt in opts){if(opts.hasOwnProperty(opt)){try{if(!setOption(opt,opts[opt])){success=false}}catch(e){console.warn(e);success=false}}}this.redraw();this.exposeColor();return success}throw new Error("Invalid arguments")};this.channel=function(name,value){if(typeof name!=="string"){throw new Error("Invalid value for channel name: "+name)}if(value===undefined){if(!this.channels.hasOwnProperty(name.toLowerCase())){console.warn("Getting unknown channel: "+name);return false}return this.channels[name.toLowerCase()]}else{var res=false;switch(name.toLowerCase()){case"r":res=this.fromRGBA(value,null,null,null);break;case"g":res=this.fromRGBA(null,value,null,null);break;case"b":res=this.fromRGBA(null,null,value,null);break;case"h":res=this.fromHSVA(value,null,null,null);break;case"s":res=this.fromHSVA(null,value,null,null);break;case"v":res=this.fromHSVA(null,null,value,null);break;case"a":res=this.fromHSVA(null,null,null,value);break;default:console.warn("Setting unknown channel: "+name);return false}if(res){this.redraw();return true}}return false};this.trigger=function(eventNames){var evs=jsc.strList(eventNames);for(var i=0;i255/2};this.hide=function(){if(isPickerOwner()){detachPicker()}};this.show=function(){drawPicker()};this.redraw=function(){if(isPickerOwner()){drawPicker()}};this.getFormat=function(){return this._currentFormat};this._setFormat=function(format){this._currentFormat=format.toLowerCase()};this.hasAlphaChannel=function(){if(this.alphaChannel==="auto"){return this.format.toLowerCase()==="any"||jsc.isAlphaFormat(this.getFormat())||this.alpha!==undefined||this.alphaElement!==undefined}return this.alphaChannel};this.processValueInput=function(str){if(!this.fromString(str)){this.exposeColor()}};this.processAlphaInput=function(str){if(!this.fromHSVA(null,null,null,parseFloat(str))){this.exposeColor()}};this.exposeColor=function(flags){var colorStr=this.toString();var fmt=this.getFormat();jsc.setDataAttr(this.targetElement,"current-color",colorStr);if(!(flags&jsc.flags.leaveValue)&&this.valueElement){if(fmt==="hex"||fmt==="hexa"){if(!this.uppercase){colorStr=colorStr.toLowerCase()}if(!this.hash){colorStr=colorStr.replace(/^#/,"")}}this.setValueElementValue(colorStr)}if(!(flags&jsc.flags.leaveAlpha)&&this.alphaElement){var alphaVal=Math.round(this.channels.a*100)/100;this.setAlphaElementValue(alphaVal)}if(!(flags&jsc.flags.leavePreview)&&this.previewElement){var previewPos=null;if(jsc.isTextInput(this.previewElement)||jsc.isButton(this.previewElement)&&!jsc.isButtonEmpty(this.previewElement)){previewPos=this.previewPosition}this.setPreviewElementBg(this.toRGBAString())}if(isPickerOwner()){redrawPad();redrawSld();redrawASld()}};this.setPreviewElementBg=function(color){if(!this.previewElement){return}var position=null;var width=null;if(jsc.isTextInput(this.previewElement)||jsc.isButton(this.previewElement)&&!jsc.isButtonEmpty(this.previewElement)){position=this.previewPosition;width=this.previewSize}var backgrounds=[];if(!color){backgrounds.push({image:"none",position:"left top",size:"auto",repeat:"no-repeat",origin:"padding-box"})}else{backgrounds.push({image:jsc.genColorPreviewGradient(color,position,width?width-jsc.pub.previewSeparator.length:null),position:"left top",size:"auto",repeat:position?"repeat-y":"repeat",origin:"padding-box"});var preview=jsc.genColorPreviewCanvas("rgba(0,0,0,0)",position?{left:"right",right:"left"}[position]:null,width,true);backgrounds.push({image:"url('"+preview.canvas.toDataURL()+"')",position:(position||"left")+" top",size:preview.width+"px "+preview.height+"px",repeat:position?"repeat-y":"repeat",origin:"padding-box"})}var bg={image:[],position:[],size:[],repeat:[],origin:[]};for(var i=0;i=0;i-=1){var pres=presetsArr[i];if(!pres){continue}if(!jsc.pub.presets.hasOwnProperty(pres)){console.warn("Unknown preset: %s",pres);continue}for(var opt in jsc.pub.presets[pres]){if(jsc.pub.presets[pres].hasOwnProperty(opt)){try{setOption(opt,jsc.pub.presets[pres][opt])}catch(e){console.warn(e)}}}}var nonProperties=["preset"];for(var opt in opts){if(opts.hasOwnProperty(opt)){if(nonProperties.indexOf(opt)===-1){try{setOption(opt,opts[opt])}catch(e){console.warn(e)}}}}if(this.container===undefined){this.container=window.document.body}else{this.container=jsc.node(this.container)}if(!this.container){throw new Error("Cannot instantiate color picker without a container element")}this.targetElement=jsc.node(targetElement);if(!this.targetElement){if(typeof targetElement==="string"&&/^[a-zA-Z][\w:.-]*$/.test(targetElement)){var possiblyId=targetElement;throw new Error("If '"+possiblyId+"' is supposed to be an ID, please use '#"+possiblyId+"' or any valid CSS selector.")}throw new Error("Cannot instantiate color picker without a target element")}if(this.targetElement.jscolor&&this.targetElement.jscolor instanceof jsc.pub){throw new Error("Color picker already installed on this element")}this.targetElement.jscolor=this;jsc.addClass(this.targetElement,jsc.pub.className);jsc.instances.push(this);if(jsc.isButton(this.targetElement)){if(this.targetElement.type.toLowerCase()!=="button"){this.targetElement.type="button"}if(jsc.isButtonEmpty(this.targetElement)){jsc.removeChildren(this.targetElement);this.targetElement.appendChild(window.document.createTextNode(" "));var compStyle=jsc.getCompStyle(this.targetElement);var currMinWidth=parseFloat(compStyle["min-width"])||0;if(currMinWidth-1){var color=jsc.parseColorString(initValue);this._currentFormat=color?color.format:"hex"}else{this._currentFormat=this.format.toLowerCase()}this.processValueInput(initValue);if(initAlpha!==undefined){this.processAlphaInput(initAlpha)}}};jsc.pub.className="jscolor";jsc.pub.activeClassName="jscolor-active";jsc.pub.looseJSON=true;jsc.pub.presets={};jsc.pub.presets["default"]={};jsc.pub.presets["light"]={backgroundColor:"rgba(255,255,255,1)",controlBorderColor:"rgba(187,187,187,1)",buttonColor:"rgba(0,0,0,1)"};jsc.pub.presets["dark"]={backgroundColor:"rgba(51,51,51,1)",controlBorderColor:"rgba(153,153,153,1)",buttonColor:"rgba(240,240,240,1)"};jsc.pub.presets["small"]={width:101,height:101,padding:10,sliderSize:14,paletteCols:8};jsc.pub.presets["medium"]={width:181,height:101,padding:12,sliderSize:16,paletteCols:10};jsc.pub.presets["large"]={width:271,height:151,padding:12,sliderSize:24,paletteCols:15};jsc.pub.presets["thin"]={borderWidth:1,controlBorderWidth:1,pointerBorderWidth:1};jsc.pub.presets["thick"]={borderWidth:2,controlBorderWidth:2,pointerBorderWidth:2};jsc.pub.sliderInnerSpace=3;jsc.pub.chessboardSize=8;jsc.pub.chessboardColor1="#666666";jsc.pub.chessboardColor2="#999999";jsc.pub.previewSeparator=["rgba(255,255,255,.65)","rgba(128,128,128,.65)"];jsc.pub.init=function(){if(jsc.initialized){return}window.document.addEventListener("mousedown",jsc.onDocumentMouseDown,false);window.document.addEventListener("keyup",jsc.onDocumentKeyUp,false);window.addEventListener("resize",jsc.onWindowResize,false);window.addEventListener("scroll",jsc.onWindowScroll,false);jsc.pub.install();jsc.initialized=true;while(jsc.readyQueue.length){var func=jsc.readyQueue.shift();func()}};jsc.pub.install=function(rootNode){var success=true;try{jsc.installBySelector("[data-jscolor]",rootNode)}catch(e){success=false;console.warn(e)}if(jsc.pub.lookupClass){try{jsc.installBySelector("input."+jsc.pub.lookupClass+", "+"button."+jsc.pub.lookupClass,rootNode)}catch(e){}}return success};jsc.pub.ready=function(func){if(typeof func!=="function"){console.warn("Passed value is not a function");return false}if(jsc.initialized){func()}else{jsc.readyQueue.push(func)}return true};jsc.pub.trigger=function(eventNames){var triggerNow=function(){jsc.triggerGlobal(eventNames)};if(jsc.initialized){triggerNow()}else{jsc.pub.ready(triggerNow)}};jsc.pub.hide=function(){if(jsc.picker&&jsc.picker.owner){jsc.picker.owner.hide()}};jsc.pub.chessboard=function(color){if(!color){color="rgba(0,0,0,0)"}var preview=jsc.genColorPreviewCanvas(color);return preview.canvas.toDataURL()};jsc.pub.background=function(color){var backgrounds=[];backgrounds.push(jsc.genColorPreviewGradient(color));var preview=jsc.genColorPreviewCanvas();backgrounds.push(["url('"+preview.canvas.toDataURL()+"')","left top","repeat"].join(" "));return backgrounds.join(", ")};jsc.pub.options={};jsc.pub.lookupClass="jscolor";jsc.pub.installByClassName=function(){console.error('jscolor.installByClassName() is DEPRECATED. Use data-jscolor="" attribute instead of a class name.'+jsc.docsRef);return false};jsc.register();return jsc.pub}();if(typeof window.jscolor==="undefined"){window.jscolor=window.JSColor=jscolor}return jscolor}); diff --git a/extension/launcher.js b/extension/launcher.js index d662247..1961b7c 100644 --- a/extension/launcher.js +++ b/extension/launcher.js @@ -16,5 +16,10 @@ import(chrome.runtime.getURL('api.js')).then(({ web, registry }) => { import(chrome.runtime.getURL(`repo/${mod._dir}/${script}`)); } } + const errors = await registry.errors(); + if (errors.length) { + console.log('notion-enhancer errors:'); + console.table(errors); + } }); }); diff --git a/extension/repo/CHANGELOG.md b/extension/repo/CHANGELOG.md index f67ac04..4a06892 100644 --- a/extension/repo/CHANGELOG.md +++ b/extension/repo/CHANGELOG.md @@ -14,7 +14,6 @@ - documentation e.g. \_file - complete/bugfix theming variables -- color pickers #### app-specific diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.js b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.js index df9b13d..6705055 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.js +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.js @@ -25,7 +25,6 @@ web.whenReady([sidebarSelector]).then(async () => { list: await fs.getJSON('https://notion-enhancer.github.io/notifications.json'), dismissed: await storage.get(_id, 'notifications', []), }; - console.log($enhancerSidebarElement); notifications.waiting = notifications.list.filter( ({ id }) => !notifications.dismissed.includes(id) ); diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css index 65f60c3..98f4498 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css @@ -250,6 +250,7 @@ main article img { .library--select_label, .library--text_label, .library--number_label, +.library--color_label, .library--file_label { margin: 0.6rem 0; display: block; @@ -260,6 +261,7 @@ main article img { .library--select_label *, .library--text_label *, .library--number_label *, +.library--color_label *, .library--file_label * { appearance: none; font-family: var(--theme--font_sans); @@ -282,6 +284,7 @@ label [data-icon='fa/solid/question-circle'] { .library--select_label > p, .library--text_label > p, .library--number_label > p, +.library--color_label > p, .library--file_label > p { margin: 0.6rem 0; } @@ -320,10 +323,11 @@ label [data-icon='fa/solid/question-circle'] { } .library--toggle_label:focus-within .library--toggle, .library--file_label:focus-within .library--file, +.library--color_label:focus-within .library--color, .library--select_label .library--select:focus-within { - outline: solid thin; + outline: -webkit-focus-ring-color auto 1px; } -.library--toggle_label input[type='checkbox'], +.library--toggle_label input, .library--file_label input { position: absolute; width: 1px; @@ -343,6 +347,7 @@ label [data-icon='fa/solid/question-circle'] { .library--text_label textarea, .library--number_label input, .library--select_label .library--select, +.library--color_label .library--color, .library--file_label .library--file { width: 100%; padding: 6px 8px; @@ -351,35 +356,44 @@ label [data-icon='fa/solid/question-circle'] { border: none; box-shadow: var(--theme--input-border) 0px 0px 0px 1px inset; } -.library--select_label .library--select select { +.library--select_label .library--select select, +.library--color_label .library--color input { outline: none; cursor: pointer; } +.library--color_label .library--color input { + border-radius: 0; +} .library--select_label .library--select select option { background: var(--theme--tag_select); } .library--select_label .library--select, +.library--color_label .library--color, .library--file_label .library--file { padding: 0; display: flex; cursor: pointer; } .library--select_label .library--select > :first-child, +.library--color_label .library--color > :first-child, .library--file_label .library--file > :first-child { display: flex; padding: 6px 8px; background: var(--theme--input-border); } .library--select_label .library--select > :first-child svg, +.library--color_label .library--color > :first-child svg, .library--file_label .library--file > :first-child svg { width: 0.9em; margin: auto 0; } .library--select_label .library--select > :first-child svg *, +.library--color_label .library--color > :first-child svg *, .library--file_label .library--file > :first-child svg * { color: var(--theme--input_icon); } .library--select_label .library--select > :last-child, +.library--color_label .library--color > :last-child, .library--file_label .library--file > :last-child { margin: auto 0; padding: 6px 8px; diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js index db00430..05f91a1 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js @@ -7,7 +7,7 @@ 'use strict'; const _id = 'a6621988-551d-495a-97d8-3c568bca2e9e'; -import { env, storage, web, fmt, fs, registry } from '../../api.js'; +import { env, storage, web, fmt, fs, registry, regexers } from '../../api.js'; for (const mod of await registry.get((mod) => registry.isEnabled(mod.id))) { for (const sheet of mod.css?.menu || []) { @@ -232,6 +232,46 @@ components.options = { if (tooltip) web.addTooltip(opt.querySelector('[data-tooltip]'), tooltip); return opt; }, + async color(id, { key, label, tooltip }) { + const state = await storage.get(id, key), + opt = web.createElement(web.html` + `); + const $fill = opt.querySelector('input'), + paintInput = () => { + $fill.style.background = picker.toBackground(); + $fill.style.color = picker.isLight() ? '#000' : '#fff'; + }, + picker = new fmt.JSColor($fill, { + value: state, + previewSize: 0, + borderRadius: 3, + borderColor: 'var(--theme--divider)', + controlBorderColor: 'var(--theme--divider)', + backgroundColor: 'var(--theme--page)', + onInput() { + paintInput(); + }, + onChange() { + paintInput(); + storage.set(id, key, this.toRGBAString()); + }, + }); + paintInput(); + opt.addEventListener('click', (event) => { + picker.show(); + }); + if (tooltip) web.addTooltip(opt.querySelector('[data-tooltip]'), tooltip); + return opt; + }, async file(id, { key, label, tooltip, extensions }) { const state = await storage.get(id, key), opt = web.createElement(web.html` @@ -295,15 +335,13 @@ const actionButtons = { _reloadTriggered: false, async reload($fragment = document) { let $reload = $fragment.querySelector('[data-reload]'); - if (!$reload) { + if (!$reload && this._reloadTriggered) { $reload = web.createElement(web.html` `); $reload.addEventListener('click', env.reloadTabs); - } - if (this._reloadTriggered) { $fragment.querySelector('.action--buttons').append($reload); await new Promise((res, rej) => requestAnimationFrame(res)); $reload.dataset.triggered = true; @@ -311,19 +349,19 @@ const actionButtons = { }, async clearFilters($fragment = document) { let $clearFilters = $fragment.querySelector('[data-clear-filters]'); - if (!$clearFilters) { - $clearFilters = web.createElement(web.html` - - - clear filters - `); - } const search = router.getSearch(); if (search.get('tag') || search.has('enabled') || search.has('disabled')) { - $fragment.querySelector('.action--buttons').append($clearFilters); - await new Promise((res, rej) => requestAnimationFrame(res)); - $clearFilters.dataset.triggered = true; - } else $clearFilters.remove(); + if (!$clearFilters) { + $clearFilters = web.createElement(web.html` + + + clear filters + `); + $fragment.querySelector('.action--buttons').append($clearFilters); + await new Promise((res, rej) => requestAnimationFrame(res)); + $clearFilters.dataset.triggered = true; + } + } else if ($clearFilters) $clearFilters.remove(); }, }; storage.addChangeListener(async (event) => { @@ -395,22 +433,24 @@ router.addView( .querySelector(`.action--buttons > [href="?view=library&${filter}"]`) .classList[active ? 'add' : 'remove']('action--active'); } - for (const card of document.querySelectorAll('main > .library--card')) { - const { tags } = (await registry.get()).find((mod) => mod.id === card.dataset.mod), - isEnabled = await registry.isEnabled(card.dataset.mod); - if ( - (search.has('tag') ? tags.includes(search.get('tag')) : true) && - (search.has('enabled') && search.has('disabled') - ? true - : search.has('enabled') - ? isEnabled - : search.has('disabled') - ? !isEnabled - : true) - ) { - card.style.display = ''; - } else card.style.display = 'none'; + const visible = new Set(); + for (const mod of await registry.get()) { + const isEnabled = await registry.isEnabled(mod.id), + filterConditions = + (search.has('tag') ? mod.tags.includes(search.get('tag')) : true) && + (search.has('enabled') && search.has('disabled') + ? true + : search.has('enabled') + ? isEnabled + : search.has('disabled') + ? !isEnabled + : true); + if (filterConditions) visible.add(mod.id); } + for (const card of document.querySelectorAll('main > .library--card')) + card.style.display = 'none'; + for (const card of document.querySelectorAll('main > .library--card')) + if (visible.has(card.dataset.mod)) card.style.display = ''; actionButtons.clearFilters(); } );