Filter Minimized Window UI Done

This commit is contained in:
SwingTheVine 2026-02-28 17:36:27 -05:00
parent a20adef713
commit 0f34b78279
12 changed files with 346 additions and 108 deletions

View file

@ -277,6 +277,12 @@ input[type=file] {
font-size: 1.6em;
font-family: monospace;
}
.bm-container {
margin: 0.25em 0;
}
.bm-windowed h1 {
font-size: 1em;
}
/* src/WindowFilter.css */
#bm-window-filter p svg {
@ -349,6 +355,33 @@ input[type=file] {
#bm-window-filter .bm-filter-color.bm-color-hide {
display: none;
}
.bm-windowed .bm-filter-flex {
flex-direction: column;
gap: 0.25em;
}
.bm-windowed .bm-filter-color {
width: auto;
margin: 0;
padding: 0;
}
.bm-windowed .bm-filter-container-rgb {
display: flex;
width: 100%;
gap: 0.5ch;
align-items: center;
padding: 0.1em 0.5ch;
border: none;
border-radius: 1em;
}
#bm-window-filter.bm-windowed .bm-filter-container-rgb button {
padding: 0.5em 0.25ch;
}
.bm-windowed .bm-filter-container-rgb svg {
width: 3ch;
}
.bm-windowed .bm-filter-color h2 {
font-size: 0.75em;
}
/* src/WindowWizard.css */
#bm-wizard-tlist {

View file

@ -2,7 +2,7 @@
// @name Blue Marble
// @name:en Blue Marble
// @namespace https://github.com/SwingTheVine/
// @version 0.90.38
// @version 0.90.59
// @description A userscript to enhance the user experience on Wplace.live. This includes, but is not limited to: uploading images to display locally on a canvas, adding a button to move the Wplace color palette menu, and other QoL features.
// @description:en A userscript to enhance the user experience on Wplace.live. This includes, but is not limited to: uploading images to display locally on a canvas, adding a button to move the Wplace color palette menu, and other QoL features.
// @author SwingTheVine
@ -2775,7 +2775,7 @@ Did you try clicking the canvas first?`);
this.updateInnerHTML("#bm-filter-tot-remaining", `<b>Remaining:</b> ${localizeNumber((this.allPixelsTotal || 0) - (this.allPixelsCorrectTotal || 0))} (${localizePercent(((this.allPixelsTotal || 0) - (this.allPixelsCorrectTotal || 0)) / (this.allPixelsTotal || 1))})`);
this.updateInnerHTML("#bm-filter-tot-completed", `<b>Completed at:</b> <time datetime="${this.timeRemaining.toISOString().replace(/\.\d{3}Z$/, "Z")}">${this.timeRemainingLocalized}</time>`);
__privateMethod(this, _WindowFilter_instances, buildColorList_fn).call(this, scrollableContainer);
__privateMethod(this, _WindowFilter_instances, sortColorList_fn).call(this, "id", "ascending", false);
__privateMethod(this, _WindowFilter_instances, sortColorList_fn).call(this, this.sortPrimary, this.sortSecondary, this.showUnused);
}
/** Spawns a windowed Color Filter window.
* If another color filter window already exists, we DON'T spawn another!
@ -2792,10 +2792,10 @@ Did you try clicking the canvas first?`);
button.ontouchend = () => {
button.click();
};
}).buildElement().addDiv().buildElement().addDiv({ "class": "bm-flex-center" }).addButton({ "class": "bm-button-circle", "textContent": "\u{1F5D7}", "aria-label": 'Switch to windowed mode for "Color Filter"' }, (instance, button) => {
}).buildElement().addDiv().buildElement().addDiv({ "class": "bm-flex-center" }).addButton({ "class": "bm-button-circle", "textContent": "\u{1F5D6}", "aria-label": 'Switch to fullscreen mode for "Color Filter"' }, (instance, button) => {
button.onclick = () => {
document.querySelector(`#${this.windowID}`)?.remove();
this.buildWindowed();
this.buildWindow();
};
button.ontouchend = () => {
button.click();
@ -2807,7 +2807,19 @@ Did you try clicking the canvas first?`);
button.ontouchend = () => {
button.click();
};
}).buildElement().buildElement().buildElement().buildElement().buildOverlay(this.windowParent);
}).buildElement().buildElement().buildElement().addDiv({ "class": "bm-window-content" }).addDiv({ "class": "bm-container bm-center-vertically" }).addHeader(1, { "textContent": "Color Filter" }).buildElement().buildElement().addHr().buildElement().addDiv({ "class": "bm-container bm-flex-between bm-center-vertically", "style": "gap: 1.5ch;" }).addButton({ "textContent": "None" }, (instance, button) => {
button.onclick = () => __privateMethod(this, _WindowFilter_instances, selectColorList_fn).call(this, false);
}).buildElement().addButton({ "textContent": "Refresh" }, (instance, button) => {
button.onclick = () => {
};
}).buildElement().addButton({ "textContent": "All" }, (instance, button) => {
button.onclick = () => __privateMethod(this, _WindowFilter_instances, selectColorList_fn).call(this, true);
}).buildElement().buildElement().addDiv({ "class": "bm-container bm-scrollable" }).buildElement().buildElement().buildElement().buildOverlay(this.windowParent);
this.handleDrag(`#${this.windowID}.bm-window`, `#${this.windowID} .bm-dragbar`);
const scrollableContainer = document.querySelector(`#${this.windowID} .bm-container.bm-scrollable`);
__privateMethod(this, _WindowFilter_instances, calculatePixelStatistics_fn).call(this);
__privateMethod(this, _WindowFilter_instances, buildColorList_fn).call(this, scrollableContainer);
__privateMethod(this, _WindowFilter_instances, sortColorList_fn).call(this, this.sortPrimary, this.sortSecondary, this.showUnused);
}
};
_WindowFilter_instances = new WeakSet();
@ -2816,6 +2828,8 @@ Did you try clicking the canvas first?`);
* @since 0.88.222
*/
buildColorList_fn = function(parentElement) {
const isWindowedMode = parentElement.closest(`#${this.windowID}`)?.classList.contains("bm-windowed");
console.log(`Is Windowed Mode: ${isWindowedMode}`);
const colorList = new Overlay(this.name, this.version);
colorList.addDiv({ "class": "bm-filter-flex" });
for (const color of this.palette) {
@ -2841,45 +2855,89 @@ Did you try clicking the canvas first?`);
}
const colorIncorrect = parseInt(colorTotal) - parseInt(colorCorrect);
const isColorHidden = !!(this.templateManager.shouldFilterColor.get(color.id) || false);
colorList.addDiv({
"class": "bm-container bm-filter-color bm-flex-between",
"data-id": color.id,
"data-name": color.name,
"data-premium": +color.premium,
"data-correct": !Number.isNaN(parseInt(colorCorrect)) ? colorCorrect : "0",
"data-total": colorTotal,
"data-percent": colorPercent.slice(-1) == "%" ? colorPercent.slice(0, -1) : "0",
"data-incorrect": colorIncorrect || 0
}).addDiv({ "class": "bm-flex-center", "style": "flex-direction: column;" }).addDiv({ "class": "bm-filter-container-rgb", "style": `background-color: rgb(${color.rgb?.map((channel) => Number(channel) || 0).join(",")});` }).addButton(
{
"class": "bm-button-trans " + bgEffectForButtons,
"data-state": isColorHidden ? "hidden" : "shown",
"aria-label": isColorHidden ? `Show the color ${color.name || ""} on templates.` : `Hide the color ${color.name || ""} on templates.`,
"innerHTML": isColorHidden ? this.eyeClosed.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`) : this.eyeOpen.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`)
},
(instance, button) => {
button.onclick = () => {
button.style.textDecoration = "none";
button.disabled = true;
if (button.dataset["state"] == "shown") {
button.innerHTML = this.eyeClosed.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset["state"] = "hidden";
button.ariaLabel = `Show the color ${color.name || ""} on templates.`;
this.templateManager.shouldFilterColor.set(color.id, true);
} else {
button.innerHTML = this.eyeOpen.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset["state"] = "shown";
button.ariaLabel = `Hide the color ${color.name || ""} on templates.`;
this.templateManager.shouldFilterColor.delete(color.id);
if (isWindowedMode) {
const styleBackgroundStar = `background-size: auto 100%; background-repeat: repeat-x; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><path d='M50,5L79,91L2,39L98,39L21,91' fill='${textColorForPaletteColorBackground}' fill-opacity='.1'/></svg>");`;
colorList.addDiv({
"class": "bm-container bm-filter-color bm-flex-between",
// Dataset
"data-id": color.id,
"data-name": color.name,
"data-premium": +color.premium,
"data-correct": !Number.isNaN(parseInt(colorCorrect)) ? colorCorrect : "0",
"data-total": colorTotal,
"data-percent": colorPercent.slice(-1) == "%" ? colorPercent.slice(0, -1) : "0",
"data-incorrect": colorIncorrect || 0
}).addDiv({ "class": "bm-filter-container-rgb", "style": `background-color: rgb(${color.rgb?.map((channel) => Number(channel) || 0).join(",")});${color.premium ? styleBackgroundStar : ""}` }).addButton(
{
"class": "bm-button-trans " + bgEffectForButtons,
"data-state": isColorHidden ? "hidden" : "shown",
"aria-label": isColorHidden ? `Show the color ${color.name || ""} on templates.` : `Hide the color ${color.name || ""} on templates.`,
"innerHTML": isColorHidden ? this.eyeClosed.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`) : this.eyeOpen.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`)
},
(instance, button) => {
button.onclick = () => {
button.style.textDecoration = "none";
button.disabled = true;
if (button.dataset["state"] == "shown") {
button.innerHTML = this.eyeClosed.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset["state"] = "hidden";
button.ariaLabel = `Show the color ${color.name || ""} on templates.`;
this.templateManager.shouldFilterColor.set(color.id, true);
} else {
button.innerHTML = this.eyeOpen.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset["state"] = "shown";
button.ariaLabel = `Hide the color ${color.name || ""} on templates.`;
this.templateManager.shouldFilterColor.delete(color.id);
}
button.disabled = false;
button.style.textDecoration = "";
};
if (!color.id) {
button.disabled = true;
}
button.disabled = false;
button.style.textDecoration = "";
};
if (!color.id) {
button.disabled = true;
}
}
).buildElement().buildElement().addSmall({ "textContent": color.id == -2 ? "???????" : colorValueHex }).buildElement().buildElement().addDiv({ "class": "bm-flex-between" }).addHeader(2, { "textContent": (color.premium ? "\u2605 " : "") + color.name }).buildElement().addDiv({ "class": "bm-flex-between", "style": "gap: 1.5ch;" }).addSmall({ "textContent": `#${color.id}` }).buildElement().addSmall({ "textContent": `${colorCorrectLocalized} / ${colorTotalLocalized}` }).buildElement().buildElement().addP({ "textContent": `${typeof colorIncorrect == "number" && !isNaN(colorIncorrect) ? colorIncorrect : "???"} incorrect pixels. Completed: ${colorPercent}` }).buildElement().buildElement().buildElement();
).buildElement().addSmall({ "textContent": `#${color.id.toString().padStart(2, 0)}`, "style": `color: ${color.id == -1 || color.id == 0 ? "white" : textColorForPaletteColorBackground}` }).buildElement().addHeader(2, { "textContent": color.name, "style": `color: ${color.id == -1 || color.id == 0 ? "white" : textColorForPaletteColorBackground}` }).buildElement().addSmall({ "textContent": `${colorCorrectLocalized} / ${colorTotalLocalized}`, "style": `color: ${color.id == -1 || color.id == 0 ? "white" : textColorForPaletteColorBackground}; flex: 1 1 auto; text-align: right;` }).buildElement().buildElement().buildElement();
} else {
colorList.addDiv({
"class": "bm-container bm-filter-color bm-flex-between",
"data-id": color.id,
"data-name": color.name,
"data-premium": +color.premium,
"data-correct": !Number.isNaN(parseInt(colorCorrect)) ? colorCorrect : "0",
"data-total": colorTotal,
"data-percent": colorPercent.slice(-1) == "%" ? colorPercent.slice(0, -1) : "0",
"data-incorrect": colorIncorrect || 0
}).addDiv({ "class": "bm-flex-center", "style": "flex-direction: column;" }).addDiv({ "class": "bm-filter-container-rgb", "style": `background-color: rgb(${color.rgb?.map((channel) => Number(channel) || 0).join(",")});` }).addButton(
{
"class": "bm-button-trans " + bgEffectForButtons,
"data-state": isColorHidden ? "hidden" : "shown",
"aria-label": isColorHidden ? `Show the color ${color.name || ""} on templates.` : `Hide the color ${color.name || ""} on templates.`,
"innerHTML": isColorHidden ? this.eyeClosed.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`) : this.eyeOpen.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`)
},
(instance, button) => {
button.onclick = () => {
button.style.textDecoration = "none";
button.disabled = true;
if (button.dataset["state"] == "shown") {
button.innerHTML = this.eyeClosed.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset["state"] = "hidden";
button.ariaLabel = `Show the color ${color.name || ""} on templates.`;
this.templateManager.shouldFilterColor.set(color.id, true);
} else {
button.innerHTML = this.eyeOpen.replace("<svg", `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset["state"] = "shown";
button.ariaLabel = `Hide the color ${color.name || ""} on templates.`;
this.templateManager.shouldFilterColor.delete(color.id);
}
button.disabled = false;
button.style.textDecoration = "";
};
if (!color.id) {
button.disabled = true;
}
}
).buildElement().buildElement().addSmall({ "textContent": color.id == -2 ? "???????" : colorValueHex }).buildElement().buildElement().addDiv({ "class": "bm-flex-between" }).addHeader(2, { "textContent": (color.premium ? "\u2605 " : "") + color.name }).buildElement().addDiv({ "class": "bm-flex-between", "style": "gap: 1.5ch;" }).addSmall({ "textContent": `#${color.id.toString().padStart(2, 0)}` }).buildElement().addSmall({ "textContent": `${colorCorrectLocalized} / ${colorTotalLocalized}` }).buildElement().buildElement().addP({ "textContent": `${typeof colorIncorrect == "number" && !isNaN(colorIncorrect) ? colorIncorrect : "???"} incorrect pixels. Completed: ${colorPercent}` }).buildElement().buildElement().buildElement();
}
}
colorList.buildOverlay(parentElement);
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -51,7 +51,7 @@
<a href="https://discord.gg/tpeBPy46hf" target="_blank" rel="noopener noreferrer"><img alt="Contact Me" src="https://img.shields.io/badge/Contact_Me-gray?style=flat&logo=Discord&logoColor=white&logoSize=auto&labelColor=cornflowerblue"></a>
<a href="https://bluemarble.lol/" target="_blank" rel="noopener noreferrer"><img alt="Blue Marble Website" src="https://img.shields.io/badge/Blue_Marble_Website-crqch-blue?style=flat&logo=globe&logoColor=white"></a>
<a href="" target="_blank" rel="noopener noreferrer"><img alt="WakaTime" src="https://img.shields.io/badge/Coding_Time-212hrs_17mins-blue?style=flat&logo=wakatime&logoColor=black&logoSize=auto&labelColor=white"></a>
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-1077-black?style=flat"></a>
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-1098-black?style=flat"></a>
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Lines of Code" src="https://img.shields.io/badge/Lines_Of_Code-5908-blue?style=flat"></a>
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Comments" src="https://img.shields.io/badge/Lines_Of_Comments-5160-blue?style=flat"></a>
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Compression" src="https://img.shields.io/badge/Compression-73.34%25-blue"></a>

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "wplace-bluemarble",
"version": "0.90.38",
"version": "0.90.59",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "wplace-bluemarble",
"version": "0.90.38",
"version": "0.90.59",
"devDependencies": {
"esbuild": "^0.25.0",
"jsdoc": "^4.0.5",

View file

@ -1,6 +1,6 @@
{
"name": "wplace-bluemarble",
"version": "0.90.38",
"version": "0.90.59",
"type": "module",
"homepage": "https://bluemarble.lol/",
"repository": {

View file

@ -2,7 +2,7 @@
// @name Blue Marble
// @name:en Blue Marble
// @namespace https://github.com/SwingTheVine/
// @version 0.90.38
// @version 0.90.59
// @description A userscript to enhance the user experience on Wplace.live. This includes, but is not limited to: uploading images to display locally on a canvas, adding a button to move the Wplace color palette menu, and other QoL features.
// @description:en A userscript to enhance the user experience on Wplace.live. This includes, but is not limited to: uploading images to display locally on a canvas, adding a button to move the Wplace color palette menu, and other QoL features.
// @author SwingTheVine

View file

@ -94,4 +94,45 @@
/* Filter window hide unused colors */
#bm-window-filter .bm-filter-color.bm-color-hide {
display: none;
}
/* WINDOWED MODE */
/* Filter flex in windowed mode */
.bm-windowed .bm-filter-flex {
flex-direction: column;
gap: 0.25em;
}
/* Filter color in windowed mode */
.bm-windowed .bm-filter-color {
width: auto;
margin: 0;
padding: 0;
}
/* Filter window container for RGB color display in windowed mode */
.bm-windowed .bm-filter-container-rgb {
display: flex;
width: 100%;
gap: 0.5ch;
align-items: center;
padding: 0.1em 0.5ch;
border: none;
border-radius: 1em;
}
/* Filter window hide color button */
#bm-window-filter.bm-windowed .bm-filter-container-rgb button {
padding: 0.5em 0.25ch;
}
/* Filter window hide color button SVG in windowed mode */
.bm-windowed .bm-filter-container-rgb svg {
width: 3ch;
}
/* Filter window header 2 in windowed mode */
.bm-windowed .bm-filter-color h2 {
font-size: 0.75em;
}

View file

@ -173,6 +173,8 @@ export default class WindowFilter extends Overlay {
// Obtains the scrollable container to put the color filter in
const scrollableContainer = document.querySelector(`#${this.windowID} .bm-container.bm-scrollable`);
// Calculates the pixel statistics
// E.g. correct pixels per color
this.#calculatePixelStatistics();
// Displays some template statistics to the user
@ -184,7 +186,7 @@ export default class WindowFilter extends Overlay {
// These run when the user opens the Color Filter window
this.#buildColorList(scrollableContainer);
this.#sortColorList('id', 'ascending', false);
this.#sortColorList(this.sortPrimary, this.sortSecondary, this.showUnused);
}
/** Spawns a windowed Color Filter window.
@ -209,10 +211,10 @@ export default class WindowFilter extends Overlay {
}).buildElement()
.addDiv().buildElement() // Contains the minimized h1 element
.addDiv({'class': 'bm-flex-center'})
.addButton({'class': 'bm-button-circle', 'textContent': '🗗', 'aria-label': 'Switch to windowed mode for "Color Filter"'}, (instance, button) => {
.addButton({'class': 'bm-button-circle', 'textContent': '🗖', 'aria-label': 'Switch to fullscreen mode for "Color Filter"'}, (instance, button) => {
button.onclick = () => {
document.querySelector(`#${this.windowID}`)?.remove();
this.buildWindowed();
this.buildWindow();
};
button.ontouchend = () => {button.click();}; // Needed only to negate weird interaction with dragbar
}).buildElement()
@ -223,9 +225,40 @@ export default class WindowFilter extends Overlay {
.buildElement()
.buildElement()
.addDiv({'class': 'bm-window-content'})
.addDiv({'class': 'bm-container bm-center-vertically'})
.addHeader(1, {'textContent': 'Color Filter'}).buildElement()
.buildElement()
.addHr().buildElement()
.addDiv({'class': 'bm-container bm-flex-between bm-center-vertically', 'style': 'gap: 1.5ch;'})
.addButton({'textContent': 'None'}, (instance, button) => {
button.onclick = () => this.#selectColorList(false);
}).buildElement()
.addButton({'textContent': 'Refresh'}, (instance, button) => {
button.onclick = () => {};
}).buildElement()
.addButton({'textContent': 'All'}, (instance, button) => {
button.onclick = () => this.#selectColorList(true);
}).buildElement()
.buildElement()
.addDiv({'class': 'bm-container bm-scrollable'})
// Color list will appear here
.buildElement()
.buildElement()
.buildElement().buildOverlay(this.windowParent);
// Creates dragging capability on the drag bar for dragging the window
this.handleDrag(`#${this.windowID}.bm-window`, `#${this.windowID} .bm-dragbar`);
// Obtains the scrollable container to put the color filter in
const scrollableContainer = document.querySelector(`#${this.windowID} .bm-container.bm-scrollable`);
// Calculates the pixel statistics
// E.g. correct pixels per color
this.#calculatePixelStatistics();
// These run when the user opens the Color Filter window
this.#buildColorList(scrollableContainer);
this.#sortColorList(this.sortPrimary, this.sortSecondary, this.showUnused);
}
/** Creates the color list container.
@ -234,6 +267,12 @@ export default class WindowFilter extends Overlay {
*/
#buildColorList(parentElement) {
// Figures out if this window is fullscreen or windowed mode
const isWindowedMode = parentElement.closest(`#${this.windowID}`)?.classList.contains('bm-windowed');
// Note: `undefined` is expected to behave as if `false`
console.log(`Is Windowed Mode: ${isWindowedMode}`);
const colorList = new Overlay(this.name, this.version);
colorList.addDiv({'class': 'bm-filter-flex'})
// We leave it open so we can add children to the grid
@ -292,60 +331,115 @@ export default class WindowFilter extends Overlay {
const isColorHidden = !!(this.templateManager.shouldFilterColor.get(color.id) || false);
// Construct the DOM tree for color in color list
colorList.addDiv({'class': 'bm-container bm-filter-color bm-flex-between',
'data-id': color.id,
'data-name': color.name,
'data-premium': +color.premium,
'data-correct': !Number.isNaN(parseInt(colorCorrect)) ? colorCorrect : '0',
'data-total': colorTotal,
'data-percent': (colorPercent.slice(-1) == '%') ? colorPercent.slice(0, -1) : '0',
'data-incorrect': colorIncorrect || 0
})
.addDiv({'class': 'bm-flex-center', 'style': 'flex-direction: column;'})
.addDiv({'class': 'bm-filter-container-rgb', 'style': `background-color: rgb(${color.rgb?.map(channel => Number(channel) || 0).join(',')});`})
.addButton({
'class': 'bm-button-trans ' + bgEffectForButtons,
'data-state': isColorHidden ? 'hidden' : 'shown',
'aria-label': isColorHidden ? `Show the color ${color.name || ''} on templates.` : `Hide the color ${color.name || ''} on templates.`,
'innerHTML': isColorHidden ? this.eyeClosed.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`) : this.eyeOpen.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`)},
(instance, button) => {
// Add the color to the color list DOM
if (isWindowedMode) {
// When the button is clicked
button.onclick = () => {
button.style.textDecoration = 'none';
button.disabled = true;
if (button.dataset['state'] == 'shown') {
button.innerHTML = this.eyeClosed.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset['state'] = 'hidden';
button.ariaLabel = `Show the color ${color.name || ''} on templates.`;
this.templateManager.shouldFilterColor.set(color.id, true);
} else {
button.innerHTML = this.eyeOpen.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset['state'] = 'shown';
button.ariaLabel = `Hide the color ${color.name || ''} on templates.`;
this.templateManager.shouldFilterColor.delete(color.id);
// The star pattern for premium colors
const styleBackgroundStar = `background-size: auto 100%; background-repeat: repeat-x; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><path d='M50,5L79,91L2,39L98,39L21,91' fill='${textColorForPaletteColorBackground}' fill-opacity='.1'/></svg>");`;
// Add windowed mode color DOM to color list
colorList.addDiv({'class': 'bm-container bm-filter-color bm-flex-between',
// Dataset
'data-id': color.id,
'data-name': color.name,
'data-premium': +color.premium,
'data-correct': !Number.isNaN(parseInt(colorCorrect)) ? colorCorrect : '0',
'data-total': colorTotal,
'data-percent': (colorPercent.slice(-1) == '%') ? colorPercent.slice(0, -1) : '0',
'data-incorrect': colorIncorrect || 0
}).addDiv({'class': 'bm-filter-container-rgb', 'style': `background-color: rgb(${color.rgb?.map(channel => Number(channel) || 0).join(',')});${color.premium ? styleBackgroundStar : ''}`})
.addButton({
'class': 'bm-button-trans ' + bgEffectForButtons,
'data-state': isColorHidden ? 'hidden' : 'shown',
'aria-label': isColorHidden ? `Show the color ${color.name || ''} on templates.` : `Hide the color ${color.name || ''} on templates.`,
'innerHTML': isColorHidden ? this.eyeClosed.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`) : this.eyeOpen.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`)},
(instance, button) => {
// When the button is clicked
button.onclick = () => {
button.style.textDecoration = 'none';
button.disabled = true;
if (button.dataset['state'] == 'shown') {
button.innerHTML = this.eyeClosed.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset['state'] = 'hidden';
button.ariaLabel = `Show the color ${color.name || ''} on templates.`;
this.templateManager.shouldFilterColor.set(color.id, true);
} else {
button.innerHTML = this.eyeOpen.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset['state'] = 'shown';
button.ariaLabel = `Hide the color ${color.name || ''} on templates.`;
this.templateManager.shouldFilterColor.delete(color.id);
}
button.disabled = false;
button.style.textDecoration = '';
}
button.disabled = false;
button.style.textDecoration = '';
}
// Disables the "hide color" button if the color is "Transparent" (or no ID exists)
if (!color.id) {button.disabled = true;}
}
).buildElement()
.buildElement()
.addSmall({'textContent': (color.id == -2) ? '???????' : colorValueHex}).buildElement()
.buildElement()
.addDiv({'class': 'bm-flex-between'})
.addHeader(2, {'textContent': (color.premium ? '★ ' : '') + color.name}).buildElement()
.addDiv({'class': 'bm-flex-between', 'style': 'gap: 1.5ch;'})
.addSmall({'textContent': `#${color.id}`}).buildElement()
.addSmall({'textContent': `${colorCorrectLocalized} / ${colorTotalLocalized}`}).buildElement()
.buildElement()
.addP({'textContent': `${((typeof colorIncorrect == 'number') && !isNaN(colorIncorrect)) ? colorIncorrect : '???'} incorrect pixels. Completed: ${colorPercent}`}).buildElement()
.buildElement()
.buildElement()
// Disables the "hide color" button if the color is "Transparent" (or no ID exists)
if (!color.id) {button.disabled = true;}
}
).buildElement()
.addSmall({'textContent': `#${color.id.toString().padStart(2, 0)}`, 'style': `color: ${((color.id == -1) || (color.id == 0)) ? 'white' : textColorForPaletteColorBackground}`}).buildElement()
.addHeader(2, {'textContent': color.name, 'style': `color: ${((color.id == -1) || (color.id == 0)) ? 'white' : textColorForPaletteColorBackground}`}).buildElement()
.addSmall({'textContent': `${colorCorrectLocalized} / ${colorTotalLocalized}`, 'style': `color: ${((color.id == -1) || (color.id == 0)) ? 'white' : textColorForPaletteColorBackground}; flex: 1 1 auto; text-align: right;`}).buildElement()
.buildElement()
.buildElement();
} else {
// Else we are in fullscreen mode.
// Add fullscreen mode color DOM to color list
colorList.addDiv({'class': 'bm-container bm-filter-color bm-flex-between',
'data-id': color.id,
'data-name': color.name,
'data-premium': +color.premium,
'data-correct': !Number.isNaN(parseInt(colorCorrect)) ? colorCorrect : '0',
'data-total': colorTotal,
'data-percent': (colorPercent.slice(-1) == '%') ? colorPercent.slice(0, -1) : '0',
'data-incorrect': colorIncorrect || 0
}).addDiv({'class': 'bm-flex-center', 'style': 'flex-direction: column;'})
.addDiv({'class': 'bm-filter-container-rgb', 'style': `background-color: rgb(${color.rgb?.map(channel => Number(channel) || 0).join(',')});`})
.addButton({
'class': 'bm-button-trans ' + bgEffectForButtons,
'data-state': isColorHidden ? 'hidden' : 'shown',
'aria-label': isColorHidden ? `Show the color ${color.name || ''} on templates.` : `Hide the color ${color.name || ''} on templates.`,
'innerHTML': isColorHidden ? this.eyeClosed.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`) : this.eyeOpen.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`)},
(instance, button) => {
// When the button is clicked
button.onclick = () => {
button.style.textDecoration = 'none';
button.disabled = true;
if (button.dataset['state'] == 'shown') {
button.innerHTML = this.eyeClosed.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset['state'] = 'hidden';
button.ariaLabel = `Show the color ${color.name || ''} on templates.`;
this.templateManager.shouldFilterColor.set(color.id, true);
} else {
button.innerHTML = this.eyeOpen.replace('<svg', `<svg fill="${textColorForPaletteColorBackground}"`);
button.dataset['state'] = 'shown';
button.ariaLabel = `Hide the color ${color.name || ''} on templates.`;
this.templateManager.shouldFilterColor.delete(color.id);
}
button.disabled = false;
button.style.textDecoration = '';
}
// Disables the "hide color" button if the color is "Transparent" (or no ID exists)
if (!color.id) {button.disabled = true;}
}
).buildElement()
.buildElement()
.addSmall({'textContent': (color.id == -2) ? '???????' : colorValueHex}).buildElement()
.buildElement()
.addDiv({'class': 'bm-flex-between'})
.addHeader(2, {'textContent': (color.premium ? '★ ' : '') + color.name}).buildElement()
.addDiv({'class': 'bm-flex-between', 'style': 'gap: 1.5ch;'})
.addSmall({'textContent': `#${color.id.toString().padStart(2, 0)}`}).buildElement()
.addSmall({'textContent': `${colorCorrectLocalized} / ${colorTotalLocalized}`}).buildElement()
.buildElement()
.addP({'textContent': `${((typeof colorIncorrect == 'number') && !isNaN(colorIncorrect)) ? colorIncorrect : '???'} incorrect pixels. Completed: ${colorPercent}`}).buildElement()
.buildElement()
.buildElement();
}
}
// Adds the colors to the color container in the filter window

View file

@ -338,4 +338,16 @@ input[type="file"] {
line-height: 1 !important;
font-size: 1.6em;
font-family: monospace;
}
}
/* WINDOWED MODE */
/* Containers for "sections" of elements in windowed mode */
.bm-container {
margin: 0.25em 0;
}
/* Header 1 in windowed mode */
.bm-windowed h1 {
font-size: 1em;
}