From 89b57fe0ca2a7e9fd59c2e44862aff55322db434 Mon Sep 17 00:00:00 2001 From: "Martin, Alexander Scott" Date: Thu, 29 May 2025 16:31:54 -0400 Subject: [PATCH 01/13] init- mostly complete --- tdx-enhanced.js | 2023 +++++++++++++++++++++++++++++++---------------- 1 file changed, 1322 insertions(+), 701 deletions(-) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index ca10fe2..04919ce 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -1,21 +1,26 @@ // ==UserScript== // @name tdx-enhanced -// @namespace ecn -// @version 2025-02-05-01 +// @namespace purdue-it +// @version 2025-05-29-558 // @description enhanced tdx coloring & formatting. follows system color scheme. // @author Purdue STEM IT - it@purdue.edu -// @match https://service.purdue.edu/TDNext/* -// @match https://service.purdue.edu/TDWebApi/* +// @match https://service.purdue.edu/TDWorkManagement* +// @match https://service.purdue.edu/TDNext* +// @match https://service.purdue.edu/TDWebApi* +// @match https://purdue.teamdynamixpreview.com/TDWorkManagement* +// @match https://purdue.teamdynamixpreview.com/TDNext* // @require https://momentjs.com/downloads/moment.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.6.0/tinycolor.min.js -// @downloadURL https://raw.github.itap.purdue.edu/ECN/tdx-userscript/main/tdx-enhanced.js -// @updateURL https://raw.github.itap.purdue.edu/ECN/tdx-userscript/main/tdx-enhanced.js -// @grant GM.addStyle +// @grant GM_getResourceText +// @grant GM_addStyle // @run-at document-end // ==/UserScript== (function() { 'use strict'; + + const primaryTitle = "Purdue University IT" + /* QUEUE COLORS */ //from main webqueue script @@ -80,7 +85,7 @@ /* BEGIN FUNCTIONS */ function updateHeading(mutation,numItems,totalItems) { - let headings = mutation.querySelectorAll(".panel-title") + let headings = mutation.querySelectorAll(".tdx-control-bar__title") for (const heading of headings) { //color the header if queue name is found @@ -90,64 +95,24 @@ let parent = heading.parentElement - //console.log("HEADING:",headingTxt) - - for (const qK of Object.keys(colorsByQueue)) { - let q = colorsByQueue[qK] - if (headingFirst == qK) { - //console.log("Match:",parent) - heading.style.color = q.txt - parent.style.backgroundColor = q.bg - } - handleHighlight("report",headingTxt,heading.parentElement) - - //try embedding - if (headingTxt.startsWith("{")) { - try { - let embedData = JSON.parse(headingTxt) - - let title = document.createElement("h4") - title.classList = heading.classList - title.innerText = embedData.name - let moduleBody = heading.parentNode.parentNode.querySelector(".ModuleContent") - let embed = document.createElement("iframe") - embed.classList = "customEmbed" - embed.src = embedData.url - heading.replaceWith(title) - moduleBody.replaceWith(embed) - } catch { - } + handleHighlight("report",headingTxt,heading) + + //try embedding + if (headingTxt.startsWith("{")) { + try { + let embedData = JSON.parse(headingTxt) + + let title = document.createElement("h4") + title.classList = heading.classList + title.innerText = embedData.name + let moduleBody = heading.parentNode.parentNode.querySelector(".ModuleContent") + let embed = document.createElement("iframe") + embed.classList = "customEmbed" + embed.src = embedData.url + heading.replaceWith(title) + moduleBody.replaceWith(embed) + } catch { } - - } - - //append number of items to title - //let parentDiv = document.createElement("div") - - //let header = document.createElement("h4") - //header.innerText = headingTxt - - var countSpan = heading.querySelector(".subtitle") - - if (!countSpan) { - countSpan = document.createElement("span") - //countSpan.innerText = `${numItems} items` - countSpan.classList.add("subtitle") - - heading.innerText = headingTxt - heading.appendChild(countSpan) - } - - var countTxt = null - - if (totalItems) { - countTxt = `${numItems} of ${totalItems} ${totalItems == 1 ? 'item' : 'items'}` - } else if (numItems) { - countTxt = `${numItems} ${numItems == 1 ? 'item' : 'items'}` - } - - if (countTxt) { - countSpan.innerText = countTxt } } } @@ -156,7 +121,7 @@ let qBlock = document.querySelector("#ctlAttribute2285") //ticket or task - let header = document.getElementById("thTicket_spnTitle") || document.querySelector("#upTaskHeader>h1") + let header = document.getElementById("thTicket_spnTitle") || document.querySelector("#upTaskHeader>div>h1") //find calendar inputs when editing tickets/tasks //let calendars = document.querySelectorAll("input.hasDatepicker") @@ -318,6 +283,8 @@ feedItems = document.querySelectorAll("#ttDescription") } + //console.log("Feed items:",feedItems) + if (feedItems) { for (const feedItem of feedItems) { [...feedItem.querySelectorAll("*[style*='color']")].forEach(feedElement=>{ @@ -360,7 +327,15 @@ } function parseOtherElements() { - let path = document.location.pathname + let path = document.location.pathname; + + //inject styles into search bar + [...document.querySelectorAll("#globalSearchBar, #input_ticketSearch33, .tdx-leftnav__filter-bar")].forEach(searchBar=>{ + let shadow = searchBar.shadowRoot + if (shadow) { + injectOtherStyles(shadow) + } + }) let desktopLayout = settings('get','layout') let desktop = document.querySelector("#divContent") @@ -412,10 +387,10 @@ return (Number(`0x1${hex}`) ^ 0xFFFFFF).toString(16).substr(1).toUpperCase() } - function parseTable(mutation) { - let t = mutation.target; - //console.error("BEGIN MUTATION") - let table = t.querySelector("table.report-viewer") + function parseTable(element) { + //let t = mutation.target; + //console.error("BEGIN MUTATION",t) + let table = element.querySelector("table") let items = []; var numItems = null @@ -427,10 +402,12 @@ //get headers of the tables [...table.querySelectorAll("th")].forEach((header)=>{ - var txt = header.querySelector("a") - txt = txt.dataset.sort - txt = txt.split(" ")[0] - headers.push(txt) + var txt = header.querySelector("span") + //txt = txt.dataset.sort + //txt = txt.split(" ")[0] + if (txt) { + headers.push(txt.textContent) + } //console.log("i:",header.cellIndex,txt) }); @@ -441,13 +418,16 @@ //console.log("row:",row); let item = {}; //parse each cell - [...row.querySelectorAll("td")].forEach((cell)=>{ - let i = cell.cellIndex; + let i = 0; + [...row.querySelectorAll("td:not(:has(input))")].forEach((cell)=>{ + //let i = cell.cellIndex; //can't use cellindex if there's a checkbox in the table let txt = cell.textContent; + txt = txt.trim() //console.log("Cell:",i,cell); item[headers[i]] = {txt:txt,cell:cell} + i++ }) item.row = row @@ -462,18 +442,20 @@ numItems = items.length //totalItems = null + /* let pagination = t.querySelector(".pull-right .bootstrap-pagination-label") if (pagination) { let pTxt = pagination.innerText pTxt = pTxt.split(" ")[0] totalItems = pTxt } + */ //console.log("Items:",items) } - updateHeading(t.parentElement,numItems,totalItems) + updateHeading(element,numItems,totalItems) } function createHighlightBubble(element,bgColor,txtColor) { @@ -499,10 +481,12 @@ //modify/color the cells function parseItem(item) { + //console.log("Parse item:",item) + //color queue names - if ('2285' in item) { - let qCell = item["2285"].cell - let qTxt = item["2285"].txt.toLowerCase() + if ('STEM Support' in item) { + let qCell = item["STEM Support"].cell + let qTxt = item["STEM Support"].txt.toLowerCase() if (qTxt in colorsByQueue) { let q = colorsByQueue[qTxt] @@ -511,7 +495,7 @@ } //change date modified - let relativeDates = ['LastModifiedDate','ModifiedDate','CreatedDate'] + let relativeDates = ['Modified','Created'] for (const dType of relativeDates) { if (dType in item) { let dTxt = item[dType].txt @@ -521,14 +505,14 @@ let dTxtNew = date.fromNow() if (dTxtNew == "Invalid date") { - console.warn("Failed date:",dTxt,item) + //console.warn("Failed date:",dTxt,item) } else { dCell.innerText = dTxtNew } } } - let detailedDates = ['DueDate','StartDate'] + let detailedDates = ['Date Due','Due','Created','Start'] for (const dType of detailedDates) { if (dType in item) { let dTxt = item[dType].txt @@ -538,7 +522,7 @@ let dTxtNew = date.calendar() if (dTxtNew == "Invalid date") { - console.warn("Failed date:",dTxt,item) + //console.warn("Failed date:",dTxt,item) } else { dCell.innerText = dTxtNew } @@ -546,7 +530,7 @@ } //highlight modified/age red - let modifiedDates = ['LastModifiedDate','ModifiedDate'] + let modifiedDates = ['Modified'] for (const dType of modifiedDates) { if (dType in item) { let modDate = item[dType] @@ -566,10 +550,10 @@ } //find user replies & last modified by internal - if ('CustomerName' in item && 'LastModifiedByFullName' in item && 'ResponsibleFullName' in item) { - let fromUser = item.CustomerName - let lastModified = item.LastModifiedByFullName - let assignedTo = item.ResponsibleFullName + if ('Requestor' in item && 'Modified By' in item && 'Prim Resp' in item) { + let fromUser = item["Requestor"] + let lastModified = item["Modified By"] + let assignedTo = item["Prim Resp"] //reply from user if (fromUser.txt == lastModified.txt && fromUser.txt != assignedTo.txt && assignedTo.txt != "Unassigned") { @@ -579,7 +563,7 @@ //modified by internal if (lastModified.txt != fromUser.txt && lastModified.txt != assignedTo.txt) { - let cell = item.LastModifiedByFullName.cell + let cell = lastModified.cell //cell.style.backgroundColor = "var(--col-modified)" handleHighlight("userModified",null,cell) } @@ -650,6 +634,8 @@ } } else { + return + //leave default link.onclick = (event)=>{ event.preventDefault() var params @@ -729,6 +715,7 @@ if (type=="report" && customType=="report") { if (customHighlight.value==txt) { + element.classList.add("reportTitle") style = customHighlight.style } } @@ -776,9 +763,21 @@ } function injectOtherStyles(element) { + + let s = document.createElement("style") + s.id = "customStyles" + s.innerText = customStyles + //find iframes - likely text editors if (element.tagName == "IFRAME") { - let frame = element.contentWindow.document + let frame = element.contentWindow.document; + + //attempt color coded tables on non-desktop pages + let tables = frame.querySelectorAll("table"); + [...tables].forEach(table=>{ + console.log("Table in frame:",table,table.parentElement) + parseTable(table.parentElement) + }) //console.log("Found iFrame:",frame) @@ -787,27 +786,35 @@ let head = frame.querySelector("head") let html = frame.querySelector("html") html.classList.add(settings("get","colorMode")) - let s = document.createElement("style") - s.id = "customStyles" - s.innerText = customStyles - head.appendChild(s) } + } else { + if (!element.querySelector("#customStyles")) { + element.appendChild(s) + } } -} + } //setup observer to watch report/table changes/refreshes let observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { let t = mutation.target - //console.log("Mutation:",mutation) - if (t.classList.contains("ModuleContent")) { - parseTable(mutation) + //console.error("Mutation:",t) + if (t.querySelector("div > table")) { + //let table = t.firstElementChild.querySelector("table") + //console.log("Matched table",t) + parseTable(t) } //parse the feed if it updates if (t.classList.contains("feed")) { parseTicket(mutation.addedNodes) + } else if (t.classList.contains("feed-body")) { + parseTicket(t.querySelectorAll(".feed-reply")) + } + + if (t.id=="tdx-workmgmt-container-collection") { + parseOtherElements() } //search whole document, frames may reset when reopened @@ -831,9 +838,9 @@ } async function changeTitle() { - let title = document.querySelector(".organization-link a") + let title = document.querySelector(".tdx-headerbar-headline a") if (title) { - title.innerText = "Purdue University - STEM" + title.innerText = primaryTitle } await injectToolbar() @@ -914,62 +921,12 @@ } - /* - function getColorMode() { - let localScheme = localStorage.getItem("styles") - let autoScheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? "darkMode" : "lightMode" - let scheme - - if (localScheme == "auto") { - scheme = autoScheme - } else if (!localScheme) { - localScheme = autoScheme == "darkMode" ? "lightMode" : "darkMode" - } else { - scheme = localScheme - } - - return scheme - } - - function checkColorMode() { - let localScheme = localStorage.getItem("styles") - let autoScheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? "darkMode" : "lightMode" - - let colors = localStorage.getItem("colors") - if (colors) { - console.log("Setting color from init") - setColors(colors) - } - - let primaryColor = document.querySelector("#primaryColor") - if (primaryColor) { - primaryColor.value = colors - } - - if (localScheme != autoScheme && localScheme != "auto") { - setColorMode(localScheme) - } else { - setColorMode(autoScheme,false) - } - - addEventListener("storage", (event) => { - //console.log("Storage event:",event) - if (event.key == "styles") { - setColorMode(event.newValue,false) - } else if (event.key == "colors") { - setColors(event.newValue) - } - }); - } - */ - - async function injectToolbar() { - let iconBar = document.querySelector(".tdbar-settings .pull-right") + let iconBar = document.querySelector("#globalSearchBar") let statusHTML = `
- +
+ +
` let settingsHTML = `
-

Layout

-
@@ -1162,13 +1144,15 @@ } console.log("Apply setting:",setting,value) - if (form) { - let elements = form.elements - form[setting].value = value - if (form[setting].type=="checkbox") { - form[setting].checked = value=="enabled" ? true : false + try { + if (form) { + let elements = form.elements + form[setting].value = value + if (form[setting].type=="checkbox") { + form[setting].checked = value=="enabled" ? true : false + } } - } + } catch {} } if ('colorMode' in data) { @@ -2385,6 +2369,17 @@ span.input-group-btn .btn-default { border-color: var(--col-300); } +.tdx-tile-list__item-container, +.tdx-tile-list__item-container:visited { + background-color: var(--col-100) !important; + color: var(--col-400) !important; +} + +.tdx-tile-list__item-container:hover, .tdx-tile-list__item-container:focus { + background-color: var(--col-400) !important; + color: var(--col-100) !important; +} + .btn-primary { background-color: var(--col-600); color: var(--txt-5); From 3b7c1c8980a2864be44eff5fa38f71fb87fa001a Mon Sep 17 00:00:00 2001 From: ejunga Date: Fri, 30 May 2025 09:08:09 -0400 Subject: [PATCH 03/13] Fix table colors in light mode --- tdx-enhanced.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index feee009..70b3ddf 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -2613,9 +2613,12 @@ thead, tbody, tfoot, tr, td, th { background-color: var(--bg-1); /* can change to 0 for non-striped rows */ } -td.k-table-td, -.k-grid .k-grid-header .k-table-th, .k-table-tbody .k-group-cell { - background-color: var(--bg-0); +td.k-table-td { + background-color: var(--bg-1); +} + +tr.k-alt td.k-table-td { + background-color: var(--bg-0) } .k-table-th { @@ -2626,7 +2629,7 @@ td.k-table-td, color: var(--txt-4) !important; } -td.k-table-td, .k-grid .k-grid-header .k-table-th, .k-table-tbody .k-group-cell { +.k-grid .k-grid-header .k-table-th, .k-table-tbody .k-group-cell { background-color: unset; } From 311a9f9321e89187fa25b0de4c59785d24fb786b Mon Sep 17 00:00:00 2001 From: ejunga Date: Fri, 30 May 2025 15:19:46 -0400 Subject: [PATCH 04/13] Implement informational colors in light mode --- tdx-enhanced.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index 70b3ddf..205f6ad 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -1275,6 +1275,11 @@ --dark-col-blue: #32577a; --dark-col-yellow: #654a24; + --light-col-green: #e3fcea; + --light-col-red: #ff6190; + --light-col-blue: #e1f5fc; + --light-col-yellow: #ffefd8; + /* Original TDX blue */ --dark-blue-accent: #4c778d; --light-blue-accent: #4b3bb9; @@ -1476,10 +1481,10 @@ --col-500: var(--light-col-500); --col-600: var(--light-col-600); --col-700: var(--light-col-700); - --col-red: var(--dark-col-red); - --col-green: var(--null); - --col-blue: var(--null); - --col-yellow: var(--null); + --col-red: var(--light-col-red); + --col-green: var(--light-col-green); + --col-blue: var(--light-col-blue); + --col-yellow: var(--light-col-yellow); --col-link: var(--light-col-link); --txt-0: var(--light-txt-0); --txt-1: var(--light-txt-1); @@ -2804,7 +2809,7 @@ nav#divTabHeader, } .alert-info, div.alert-info { - color: var(--txt-5) !important; + color: var(--txt-1) !important; background-color: var(--col-blue) !important; } From 9cd37d04808ac4fa987aaf3b1cbae9a2d60e4ddc Mon Sep 17 00:00:00 2001 From: "Martin, Alexander Scott" Date: Fri, 30 May 2025 15:41:45 -0400 Subject: [PATCH 05/13] support for custom element styling + other coloring --- tdx-enhanced.js | 541 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 516 insertions(+), 25 deletions(-) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index 70b3ddf..ee19568 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -1,7 +1,7 @@ // ==UserScript== // @name tdx-enhanced // @namespace purdue-it -// @version 2025-05-29-570 +// @version 2025-05-29-600 // @description enhanced tdx coloring & formatting. follows system color scheme. // @author Purdue STEM IT - it@purdue.edu // @match https://service.purdue.edu/TDWorkManagement* @@ -84,6 +84,351 @@ /* BEGIN FUNCTIONS */ + //better solution + //start + + class Color { + constructor(r, g, b) { + this.set(r, g, b); + } + + toString() { + return `rgb(${Math.round( + this.r + )}, ${Math.round(this.g)}, ${Math.round(this.b)})`; + } + + set(r, g, b) { + this.r = this.clamp(r); + this.g = this.clamp(g); + this.b = this.clamp(b); + } + + hueRotate(angle = 0) { + angle = (angle / 180) * Math.PI; + const sin = Math.sin(angle); + const cos = Math.cos(angle); + + this.multiply([ + 0.213 + cos * 0.787 - sin * 0.213, + 0.715 - cos * 0.715 - sin * 0.715, + 0.072 - cos * 0.072 + sin * 0.928, + 0.213 - cos * 0.213 + sin * 0.143, + 0.715 + cos * 0.285 + sin * 0.14, + 0.072 - cos * 0.072 - sin * 0.283, + 0.213 - cos * 0.213 - sin * 0.787, + 0.715 - cos * 0.715 + sin * 0.715, + 0.072 + cos * 0.928 + sin * 0.072 + ]); + } + + grayscale(value = 1) { + this.multiply([ + 0.2126 + 0.7874 * (1 - value), + 0.7152 - 0.7152 * (1 - value), + 0.0722 - 0.0722 * (1 - value), + 0.2126 - 0.2126 * (1 - value), + 0.7152 + 0.2848 * (1 - value), + 0.0722 - 0.0722 * (1 - value), + 0.2126 - 0.2126 * (1 - value), + 0.7152 - 0.7152 * (1 - value), + 0.0722 + 0.9278 * (1 - value) + ]); + } + + sepia(value = 1) { + this.multiply([ + 0.393 + 0.607 * (1 - value), + 0.769 - 0.769 * (1 - value), + 0.189 - 0.189 * (1 - value), + 0.349 - 0.349 * (1 - value), + 0.686 + 0.314 * (1 - value), + 0.168 - 0.168 * (1 - value), + 0.272 - 0.272 * (1 - value), + 0.534 - 0.534 * (1 - value), + 0.131 + 0.869 * (1 - value) + ]); + } + + saturate(value = 1) { + this.multiply([ + 0.213 + 0.787 * value, + 0.715 - 0.715 * value, + 0.072 - 0.072 * value, + 0.213 - 0.213 * value, + 0.715 + 0.285 * value, + 0.072 - 0.072 * value, + 0.213 - 0.213 * value, + 0.715 - 0.715 * value, + 0.072 + 0.928 * value + ]); + } + + multiply(matrix) { + const newR = this.clamp( + this.r * matrix[0] + this.g * matrix[1] + this.b * matrix[2] + ); + const newG = this.clamp( + this.r * matrix[3] + this.g * matrix[4] + this.b * matrix[5] + ); + const newB = this.clamp( + this.r * matrix[6] + this.g * matrix[7] + this.b * matrix[8] + ); + this.r = newR; + this.g = newG; + this.b = newB; + } + + brightness(value = 1) { + this.linear(value); + } + contrast(value = 1) { + this.linear(value, -(0.5 * value) + 0.5); + } + + linear(slope = 1, intercept = 0) { + this.r = this.clamp(this.r * slope + intercept * 255); + this.g = this.clamp(this.g * slope + intercept * 255); + this.b = this.clamp(this.b * slope + intercept * 255); + } + + invert(value = 1) { + this.r = this.clamp((value + (this.r / 255) * (1 - 2 * value)) * 255); + this.g = this.clamp((value + (this.g / 255) * (1 - 2 * value)) * 255); + this.b = this.clamp((value + (this.b / 255) * (1 - 2 * value)) * 255); + } + + hsl() { + // Code taken from https://stackoverflow.com/a/9493060/2688027, licensed under CC BY-SA. + const r = this.r / 255; + const g = this.g / 255; + const b = this.b / 255; + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + let h, + s, + l = (max + min) / 2; + + if (max === min) { + h = s = 0; + } else { + const d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + + case g: + h = (b - r) / d + 2; + break; + + case b: + h = (r - g) / d + 4; + break; + } + h /= 6; + } + + return { + h: h * 100, + s: s * 100, + l: l * 100 + }; + } + + clamp(value) { + if (value > 255) { + value = 255; + } else if (value < 0) { + value = 0; + } + return value; + } + } + + class Solver { + constructor(target, baseColor) { + this.target = target; + this.targetHSL = target.hsl(); + this.reusedColor = new Color(0, 0, 0); + } + + solve() { + const result = this.solveNarrow(this.solveWide()); + return { + values: result.values, + loss: result.loss, + filter: this.css(result.values) + }; + } + + solveWide() { + const A = 5; + const c = 15; + const a = [60, 180, 18000, 600, 1.2, 1.2]; + + let best = { loss: Infinity }; + for (let i = 0; best.loss > 25 && i < 3; i++) { + const initial = [50, 20, 3750, 50, 100, 100]; + const result = this.spsa(A, a, c, initial, 1000); + if (result.loss < best.loss) { + best = result; + } + } + return best; + } + + solveNarrow(wide) { + const A = wide.loss; + const c = 2; + const A1 = A + 1; + const a = [0.25 * A1, 0.25 * A1, A1, 0.25 * A1, 0.2 * A1, 0.2 * A1]; + return this.spsa(A, a, c, wide.values, 500); + } + + spsa(A, a, c, values, iters) { + const alpha = 1; + const gamma = 0.16666666666666666; + + let best = null; + let bestLoss = Infinity; + const deltas = new Array(6); + const highArgs = new Array(6); + const lowArgs = new Array(6); + + for (let k = 0; k < iters; k++) { + const ck = c / Math.pow(k + 1, gamma); + for (let i = 0; i < 6; i++) { + deltas[i] = Math.random() > 0.5 ? 1 : -1; + highArgs[i] = values[i] + ck * deltas[i]; + lowArgs[i] = values[i] - ck * deltas[i]; + } + + const lossDiff = this.loss(highArgs) - this.loss(lowArgs); + + for (let i = 0; i < 6; i++) { + const g = (lossDiff / (2 * ck)) * deltas[i]; + const ak = a[i] / Math.pow(A + k + 1, alpha); + values[i] = fix(values[i] - ak * g, i); + } + + const loss = this.loss(values); + if (loss < bestLoss) { + best = values.slice(0); + bestLoss = loss; + } + } + return { values: best, loss: bestLoss }; + + function fix(value, idx) { + let max = 100; + if (idx === 2 /* saturate */) { + max = 7500; + } else if (idx === 4 /* brightness */ || idx === 5 /* contrast */) { + max = 200; + } + + if (idx === 3 /* hue-rotate */) { + if (value > max) { + value %= max; + } else if (value < 0) { + value = max + (value % max); + } + } else if (value < 0) { + value = 0; + } else if (value > max) { + value = max; + } + return value; + } + } + + loss(filters) { + // Argument is array of percentages. + const color = this.reusedColor; + color.set(0, 0, 0); + + color.invert(filters[0] / 100); + color.sepia(filters[1] / 100); + color.saturate(filters[2] / 100); + color.hueRotate(filters[3] * 3.6); + color.brightness(filters[4] / 100); + color.contrast(filters[5] / 100); + + const colorHSL = color.hsl(); + return ( + Math.abs(color.r - this.target.r) + + Math.abs(color.g - this.target.g) + + Math.abs(color.b - this.target.b) + + Math.abs(colorHSL.h - this.targetHSL.h) + + Math.abs(colorHSL.s - this.targetHSL.s) + + Math.abs(colorHSL.l - this.targetHSL.l) + ); + } + + css(filters) { + function fmt(idx, multiplier = 1) { + return Math.round(filters[idx] * multiplier); + } + + return { + invert: `${fmt(0)}%`, + sepia: `${fmt(1)}%`, + saturate: `${fmt(2)}%`, + hue_rotate: `${fmt(3, 3.6)}deg`, + brightness: `${fmt(4)}%`, + contrast: `${fmt(5)}%` + } + + //return `filter: invert(${fmt( + // 0 + //)}%) sepia(${fmt(1)}%) saturate(${fmt(2)}%) hue-rotate(${fmt(3, 3.6)}deg) brightness(${fmt(4)}%) contrast(${fmt(5)}%);`; + } + } + + function hexToRgb(hex) { + // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") + const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + hex = hex.replace(shorthandRegex, (m, r, g, b) => { + return r + r + g + g + b + b; + }); + + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result + ? [ + parseInt(result[1], 16), + parseInt(result[2], 16), + parseInt(result[3], 16) + ] + : null; + } + + function getFilterForColor(rgbColor) { + let bestResult = null; + let iterationCount = 0; // Initialize a counter for iterations + + for (let i = 0; i < 200; i++) { + iterationCount++; // Increment the counter for each iteration + const color = new Color(rgbColor[0], rgbColor[1], rgbColor[2]); + const solver = new Solver(color); + const result = solver.solve(); + + if (!bestResult || result.loss < bestResult.loss) { + bestResult = result; + if (bestResult.loss <= 0.01) { + // exit early if good result is found + break; + } + } + } + + console.log("Total iterations: ", iterationCount); // Log the total iterations + return bestResult; + } + + //end + function updateHeading(mutation) { let headings = mutation.querySelectorAll(".tdx-control-bar__title") @@ -330,10 +675,21 @@ let path = document.location.pathname; //inject styles into search bar - [...document.querySelectorAll("#globalSearchBar, #input_ticketSearch33, .tdx-leftnav__filter-bar")].forEach(searchBar=>{ + [...document.querySelectorAll("tdx-search-bar")].forEach(searchBar=>{ + //console.log("SEARCH BAR:",searchBar) let shadow = searchBar.shadowRoot if (shadow) { - injectOtherStyles(shadow) + + injectOtherStyles(shadow); + + //check nested shadows + [...shadow.querySelectorAll("tdx-close-x")].forEach(nested=>{ + let nestedShadow = nested.shadowRoot + //console.log("NESTED:",nestedShadow) + if (nestedShadow) { + injectOtherStyles(nestedShadow) + } + }) } }) @@ -755,10 +1111,10 @@ let frame = element.contentWindow.document; //attempt color coded tables on non-desktop pages - let tables = frame.querySelectorAll("table"); + /*let tables = frame.querySelectorAll("table"); [...tables].forEach(table=>{ parseTable(table.parentElement) - }) + })*/ //console.log("Found iFrame:",frame) @@ -771,6 +1127,7 @@ } } else { if (!element.querySelector("#customStyles")) { + setCssFilters(s) element.appendChild(s) } } @@ -862,12 +1219,38 @@ let bg = `var(--${col}-${value}-bg)` style.setProperty(`--${col}-col-primary`, accent) style.setProperty(`--${col}-bg-primary`, `var(--${col}-bg-default)`) + } + break } } } + function setCssFilters(element=null) { + let style = element ? element.style : document.documentElement.style + //quick test for filter generation + let mode = getColorMode().split("Mode")[0] + let priCol = window.getComputedStyle(document.body).getPropertyValue("--dark-col-primary") + let rgb = hexToRgb(priCol) + //let filters = getFilterForColor(rgb) + + const color = new Color(rgb[0], rgb[1], rgb[2]); + const solver = new Solver(color); + const result = solver.solve(); + let filters = result.filter + + console.log("STYLES:",priCol) + console.log("FILTERS:",priCol,rgb,filters) + + style.setProperty("--filter-brightness",filters.brightness) + style.setProperty("--filter-contrast",filters.contrast) + style.setProperty("--filter-hue-rotate",filters.hue_rotate) + style.setProperty("--filter-invert",filters.invert) + style.setProperty("--filter-saturate",filters.saturate) + style.setProperty("--filter-sepia",filters.sepia) +} + /* function toggleColorMode() { let mode = getColorMode() == "darkMode" ? "lightMode" : "darkMode" @@ -1195,6 +1578,7 @@ console.log("Settings update!",data) localStorage.setItem("userSettings",JSON.stringify(data)) settings("apply") + setCssFilters() } } } @@ -1240,7 +1624,6 @@ settings("apply") parseTicket() checkPath() - parseOtherElements() addEventListener("storage", (event) => { //console.log("Storage event:",event) @@ -1282,6 +1665,13 @@ --dark-green-accent: #559170; --light-green-accent: var(--dark-green-accent); + --filter-invert: 0; + --filter-sepia: 0; + --filter-saturate: 0; + --filter-hue-rotate: 0; + --filter-brightness: 0; + --filter-contrast: 0; + --dark-bg-0: color-mix(in srgb,var(--dark-bg-primary),#fff 5%); --dark-bg-1: color-mix(in srgb,var(--dark-bg-primary),#fff 12%); --dark-bg-2: color-mix(in srgb,var(--dark-bg-primary),#fff 20%); @@ -1378,6 +1768,8 @@ --col-modified: var(--dark-col-modified); --shadow-1: var(--light-shadow-1); --shadow-2: var(--light-shadow-2); + --filter-brightness: var(--light-filter-brightness); + --filter-invert: var(--light-filter-invert); } } @@ -1419,6 +1811,8 @@ --col-modified: var(--dark-col-modified); --shadow-1: var(--dark-shadow-1); --shadow-2: var(--dark-shadow-2); + --filter-brightness: var(--dark-filter-brightness); + --filter-invert: var(--dark-filter-invert); } } @@ -1459,6 +1853,8 @@ --col-modified: var(--dark-col-modified); --shadow-1: var(--dark-shadow-1); --shadow-2: var(--dark-shadow-2); + --filter-brightness: var(--dark-filter-brightness); + --filter-invert: var(--dark-filter-invert); } :root.lightMode { @@ -1498,6 +1894,8 @@ --col-modified: var(--dark-col-modified); --shadow-1: var(--light-shadow-1); --shadow-2: var(--light-shadow-2); + --filter-brightness: var(--light-filter-brightness); + --filter-invert: var(--light-filter-invert); } /* Body */ @@ -1526,7 +1924,17 @@ body { } .tdx-overlay { - background-color: var(--bg-5) !important; + background-color: color-mix(in srgb,var(--col-400),#00000000 25%) !important; +} + +.tdx-overlay__item { + background-color: var(--bg-0) !important; + color: var(--col-400) !important; +} + +.tdx-overlay__item:hover, .tdx-overlay__item:focus-visible { + background-color: var(--col-400) !important; + color: var(--col-100) !important; } .tdx-navigation-tab-bar { @@ -1724,6 +2132,14 @@ h1, h2, h3, h4, h5 { background-color: var(--col-200) !important; } +.tdx-navigation-tabs__home-tab:hover { + background-color: var(--col-200) !important; +} + +.tdx-navigation-tabs__home-tab--active:hover { + background-color: var(--bg-0) !important; +} + .tdx-dropdown--headline { color: var(--txt-1) !important; } @@ -1784,6 +2200,10 @@ h1, h2, h3, h4, h5 { color: var(--txt-1) !important; } +.tdx-dropdown--dark:hover, .tdx-dropdown--dark:focus-visible { + background-color: var(--col-300) !important; +} + .tdx-searchbar__textbox:not(.tdx-searchbar__textbox--dark) { background-color: var(--bg-0) !important; color: var(--txt-1) !important; @@ -1793,8 +2213,17 @@ h1, h2, h3, h4, h5 { background-color: var(--col-200) !important; } +.tdx-searchbar__textbox:focus, .tdx-searchbar__textbox:active, .tdx-searchbar__textbox:focus-within { + border-color: var(--col-400) !important; +} + .tdx-searchbar__textbox::placeholder { - color: var(--txt-4) !important; + color: var(--col-400) !important; +} + +.tdx-searchbar__textbox--dark:hover:not(:focus)::placeholder, .tdx-searchbar:hover .tdx-searchbar__textbox--dark:not(:focus)::placeholder, +.tdx-searchbar__textbox:hover:not(:focus)::placeholder, .tdx-searchbar:hover .tdx-searchbar__textbox:not(:focus)::placeholder { + color: var(--col-400) !important; } input[type=checkbox], input[type=radio] { @@ -2615,7 +3044,7 @@ thead, tbody, tfoot, tr, td, th { td.k-table-td { background-color: var(--bg-1); -} +} tr.k-alt td.k-table-td { background-color: var(--bg-0) @@ -2645,21 +3074,26 @@ tr.k-alt td.k-table-td { background-color: var(--bg-0) !important; } -.k-pager-md .k-pager-numbers-wrap .k-button.k-pager-nav { - background-color: var(--bg-2) !important; -} - -.k-pager-md .k-pager-numbers-wrap .k-button.k-pager-nav { +button.k-pager-nav.k-button.k-button-flat.k-button-flat-base.k-icon-button.k-button-md { background-color: var(--bg-0) !important; - color: var(--bg-3) !important; + color: var(--col-400) !important; } .k-pager-md .k-pager-numbers-wrap .k-button.k-pager-nav.k-disabled, button.k-pager-nav.k-button.k-button-flat.k-button-flat-base.k-icon-button.k-pager-last.k-button-md { background-color: var(--bg-0) !important; + color: var(--col-400) !important; +} + +button.k-pager-nav.k-button.k-button-flat.k-button-flat-base.k-icon-button.k-pager-last.k-button-md.k-disabled, +button.k-pager-nav.k-button.k-button-flat.k-button-flat-base.k-icon-button.k-button-md.k-disabled { color: var(--bg-2) !important; } +.k-pager-md .k-pager-numbers-wrap .k-button.k-pager-nav:hover { + color: var(--col-600) !important; +} + #lookupIframeWrapper { background-color: var(--bg-0); } @@ -2686,12 +3120,25 @@ button.k-pager-nav.k-button.k-button-flat.k-button-flat-base.k-icon-button.k-pag } button.k-button.k-button-md.k-button-flat.k-button-flat-primary.k-selected { - background-color: var(--col-300) !important; + background-color: var(--col-100) !important; } button.k-selected { background-color: var(--col-1) !important; - color: var(--txt-1) !important; + color: var(--col-400) !important; +} + +.k-pager-md .k-pager-numbers-wrap .k-button { + color: var(--col-400) !important; +} + +button.k-button.k-button-md.k-button-flat.k-button-flat-primary:hover { + color: var(--col-500); + background-color: var(--col-100)!important; +} + +.k-pager-md .k-pager-numbers-wrap .k-button.k-pager-nav { + background-color: var(--bg-0) !important; } .tdx-pagination-bar { @@ -3111,10 +3558,6 @@ select.cke_dialog_ui_input_select { color: var(--col-500); } -.tdx-icon--home-on { - filter: grayscale(1) brightness(3); -} - .tdx-lookup-button-group a, .tdx-lookup-button-group button, .input-btn-group a, .input-btn-group button, div.select2-container.select2-allowclear .select2-choice abbr { color: var(--col-400); @@ -3124,15 +3567,22 @@ div.select2-container.select2-allowclear .select2-choice abbr { color: var(--col-500); } -.tdx-icon--filter-purple { - filter: brightness(5) !important; - color: var(--txt-1); +.tdx-icon__encircled--active { + background-color: var(--col-200) !important; +} + +.tdx-icon__encircled--active:hover { + background-color: var(--col-300) !important; } -.tdx-icon__encircled { +.tdx-icon__encircled:not(.tdx-icon__encircled--active) { background-color: var(--bg-0) !important; } +.tdx-icon__encircled:not(.tdx-icon__encircled--active):hover { + background-color: var(--col-200) !important; +} + .tdx-user-icon, .tdx-multiuser-icon { background-color: var(--col-0) !important; color: var(--txt-5) !important; @@ -3154,9 +3604,50 @@ div.select2-container.select2-allowclear .select2-choice abbr { color: var(--col-500) !important; } +.k-table-th[data-role=columnsorter] .k-link:not(:has(>.k-sort-icon)):after { + color: var(--col-400) !important; +} + +.k-table-th[data-role=columnsorter] .k-link:not(:has(>.k-sort-icon)):hover:after { + color: var(--col-500) !important; +} + +/* Icons + Filters */ +.tdx-dropdown__menu-icon, +.tdx-dropdown--headline:after, +.tdx-dropdown:after, +.tdx-icon--search, +.tdx-icon { + filter: brightness(0) invert(var(--filter-invert)) sepia(var(--filter-sepia)) saturate(var(--filter-saturate)) hue-rotate(var(--filter-hue-rotate)) brightness(var(--filter-brightness)) contrast(var(--filter-contrast)); +} + +/* Same but with !important */ +.tdx-icon__encircled--active .tdx-icon, +.tdx-icon--filter-purple, +.tdx-navigation-tabs__tab--active .tdx-close-x, +.tdx-icon--new-browser, +.tdx-close-x, button.tdx-close-x, +.tdx-action-menu__item--primary:after, +.tdx-action-menu-dropdown:after, +.tdx-icon.tdx-icon--hover-darken, .tdx-icon--hover-darken>.tdx-icon +{ + filter: brightness(0) invert(var(--filter-invert)) sepia(var(--filter-sepia)) saturate(var(--filter-saturate)) hue-rotate(var(--filter-hue-rotate)) brightness(var(--filter-brightness)) contrast(var(--filter-contrast)) !important; +} + +/* Hover + !important */ +.tdx-icon__encircled:hover .tdx-icon, +.tdx-close-x:hover, button.tdx-close-x:hover, +.tdx-icon.tdx-icon--hover-darken:hover, .tdx-icon.tdx-icon--hover-darken:focus, .tdx-icon--hover-darken>.tdx-icon:hover, .tdx-icon--hover-darken>.tdx-icon:focus, +.tdx-leftnav__item-expander:hover .tdx-icon, .tdx-leftnav__item-expander:focus .tdx-icon +{ + filter: brightness(0) invert(var(--filter-invert)) sepia(var(--filter-sepia)) saturate(var(--filter-saturate)) hue-rotate(var(--filter-hue-rotate)) brightness(var(--filter-brightness)) contrast(var(--filter-contrast)) brightness(125%) !important; +} + ` //const customStyles = GM_getResourceText("IMPORTED_CSS"); GM_addStyle(customStyles); + setCssFilters() + parseOtherElements() })(); \ No newline at end of file From 5ba207a7f79502e0d04ceac2987faff729c0295e Mon Sep 17 00:00:00 2001 From: "Martin, Alexander Scott" Date: Fri, 30 May 2025 16:14:20 -0400 Subject: [PATCH 06/13] few more color changes + x icons --- tdx-enhanced.js | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index ee19568..da94120 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -1,7 +1,7 @@ // ==UserScript== // @name tdx-enhanced // @namespace purdue-it -// @version 2025-05-29-600 +// @version 2025-05-29-610 // @description enhanced tdx coloring & formatting. follows system color scheme. // @author Purdue STEM IT - it@purdue.edu // @match https://service.purdue.edu/TDWorkManagement* @@ -84,8 +84,8 @@ /* BEGIN FUNCTIONS */ - //better solution - //start + //color manipulation via css filters: https://github.com/angel-rs/css-color-filter-generator + //modified to return an object instead of filter string class Color { constructor(r, g, b) { @@ -372,6 +372,7 @@ return Math.round(filters[idx] * multiplier); } + //modified here return { invert: `${fmt(0)}%`, sepia: `${fmt(1)}%`, @@ -427,7 +428,7 @@ return bestResult; } - //end + //end color manipulation function updateHeading(mutation) { let headings = mutation.querySelectorAll(".tdx-control-bar__title") @@ -675,7 +676,7 @@ let path = document.location.pathname; //inject styles into search bar - [...document.querySelectorAll("tdx-search-bar")].forEach(searchBar=>{ + [...document.querySelectorAll("tdx-search-bar, .js_sidePanelX")].forEach(searchBar=>{ //console.log("SEARCH BAR:",searchBar) let shadow = searchBar.shadowRoot if (shadow) { @@ -2562,6 +2563,10 @@ a:visited, color: var(--col-400); } +a.disabledLink { + color: var(--txt-1) !important; +} + .k-grid a.tdx-link { color: var(--col-400) !important; } @@ -3332,6 +3337,14 @@ div.btn-group.open>.dropdown-toggle.btn-primary, .open>.dropdown-toggle.btn-prim background-color: var(--col-red); } +[class^=fa-].red, [class^=fa-].red:hover { + color: var(--col-red) !important; +} + +[class^=fa-].green, [class^=fa-].green:hover { + color: var(--col-green) !important; +} + .red-bg, .status.red, .status-danger, .pri-hi { background-color: var(--col-red) !important; @@ -3616,8 +3629,8 @@ div.select2-container.select2-allowclear .select2-choice abbr { .tdx-dropdown__menu-icon, .tdx-dropdown--headline:after, .tdx-dropdown:after, -.tdx-icon--search, -.tdx-icon { +.tdx-icon--search +{ filter: brightness(0) invert(var(--filter-invert)) sepia(var(--filter-sepia)) saturate(var(--filter-saturate)) hue-rotate(var(--filter-hue-rotate)) brightness(var(--filter-brightness)) contrast(var(--filter-contrast)); } @@ -3629,7 +3642,8 @@ div.select2-container.select2-allowclear .select2-choice abbr { .tdx-close-x, button.tdx-close-x, .tdx-action-menu__item--primary:after, .tdx-action-menu-dropdown:after, -.tdx-icon.tdx-icon--hover-darken, .tdx-icon--hover-darken>.tdx-icon +.tdx-icon.tdx-icon--hover-darken, .tdx-icon--hover-darken>.tdx-icon, +.tdx-dropdown__menu-icon, .tdx-dropdown--headline:after, .tdx-dropdown:after, .tdx-icon--search, .tdx-icon { filter: brightness(0) invert(var(--filter-invert)) sepia(var(--filter-sepia)) saturate(var(--filter-saturate)) hue-rotate(var(--filter-hue-rotate)) brightness(var(--filter-brightness)) contrast(var(--filter-contrast)) !important; } @@ -3638,7 +3652,8 @@ div.select2-container.select2-allowclear .select2-choice abbr { .tdx-icon__encircled:hover .tdx-icon, .tdx-close-x:hover, button.tdx-close-x:hover, .tdx-icon.tdx-icon--hover-darken:hover, .tdx-icon.tdx-icon--hover-darken:focus, .tdx-icon--hover-darken>.tdx-icon:hover, .tdx-icon--hover-darken>.tdx-icon:focus, -.tdx-leftnav__item-expander:hover .tdx-icon, .tdx-leftnav__item-expander:focus .tdx-icon +.tdx-leftnav__item-expander:hover .tdx-icon, .tdx-leftnav__item-expander:focus .tdx-icon, +.tdx-action-menu-dropdown--no-arrow:hover .tdx-icon, .tdx-action-menu-dropdown--no-arrow.active .tdx-icon { filter: brightness(0) invert(var(--filter-invert)) sepia(var(--filter-sepia)) saturate(var(--filter-saturate)) hue-rotate(var(--filter-hue-rotate)) brightness(var(--filter-brightness)) contrast(var(--filter-contrast)) brightness(125%) !important; } From 3e440ef64df3899cba166653778bf7446b9cf846 Mon Sep 17 00:00:00 2001 From: "Martin, Alexander Scott" Date: Fri, 30 May 2025 16:37:07 -0400 Subject: [PATCH 07/13] colors for dialogs and x on input pills --- tdx-enhanced.js | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index 1302d7a..0e1521b 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -1,7 +1,7 @@ // ==UserScript== // @name tdx-enhanced // @namespace purdue-it -// @version 2025-05-29-610 +// @version 2025-05-29-630 // @description enhanced tdx coloring & formatting. follows system color scheme. // @author Purdue STEM IT - it@purdue.edu // @match https://service.purdue.edu/TDWorkManagement* @@ -1982,6 +1982,10 @@ body { background-color: var(--col-400) !important; } +.tdx-list__section { + color: var(--txt-2); +} + /* Script-Specific Additions */ #settingsMenu { right: 50px; @@ -2526,6 +2530,14 @@ div.select2-container-multi .select2-choices .select2-search-choice { color: var(--col-600); } +div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close { + color: var(--col-600) !important; +} + +div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:hover, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:focus-visible, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:active, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:active:hover, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:focus:active, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:focus:hover { + color: var(--col-400) !important; +} + div.select2-container-multi .select2-choices .select2-search-choice:hover, div.select2-container-multi .select2-choices .select2-search-choice:active { background-color: var(--col-300); color: var(--col-500); @@ -2536,6 +2548,19 @@ select.form-control { border-color: var(--border-0); } +.k-chip-solid-base { + background-color: var(--col-100) !important; + color: var(--col-600) !important; +} + +.k-chip-action { + color: var(--col-600) !important; +} + +.k-chip-action:hover, .k-chip-action:focus-visible, .k-chip-action:active, .k-chip-action:active:hover, .k-chip-action:focus:active, .k-chip-action:focus:hover { + color: var(--col-400) !important; +} + .tooltip-inner { background-color: var(--bg-0); color: var(--txt-1); @@ -3029,6 +3054,15 @@ thead, tbody, tfoot, tr, td, th { color: var(--txt-1) !important; } +.tdx-confirmation-dialog { + background-color: var(--bg-0); + color: var(--col-600); +} + +.tdx-confirmation-dialog__text-area { + color: var(--col-600); +} + .k-grid, .k-pager, .k-table { background-color: var(--bg-0) !important; color: var(--txt-1) !important; @@ -3350,6 +3384,12 @@ div.btn-group.open>.dropdown-toggle.btn-primary, .open>.dropdown-toggle.btn-prim color: var(--col-green) !important; } +.tdx-error-text, span.tdx-error-text, +.tdx-error-text:hover, span.tdx-error-text:hover { + /* color: var(--col-red) !important; */ + color: var(--col-600) !important; +} + .red-bg, .status.red, .status-danger, .pri-hi { background-color: var(--col-red) !important; @@ -3648,7 +3688,8 @@ div.select2-container.select2-allowclear .select2-choice abbr { .tdx-action-menu__item--primary:after, .tdx-action-menu-dropdown:after, .tdx-icon.tdx-icon--hover-darken, .tdx-icon--hover-darken>.tdx-icon, -.tdx-dropdown__menu-icon, .tdx-dropdown--headline:after, .tdx-dropdown:after, .tdx-icon--search, .tdx-icon +.tdx-dropdown__menu-icon, .tdx-dropdown--headline:after, .tdx-dropdown:after, .tdx-icon--search, .tdx-icon, +div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:hover, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:focus-visible, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:active, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:active:hover, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:focus:active, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:focus:hover { filter: brightness(0) invert(var(--filter-invert)) sepia(var(--filter-sepia)) saturate(var(--filter-saturate)) hue-rotate(var(--filter-hue-rotate)) brightness(var(--filter-brightness)) contrast(var(--filter-contrast)) !important; } @@ -3658,7 +3699,8 @@ div.select2-container.select2-allowclear .select2-choice abbr { .tdx-close-x:hover, button.tdx-close-x:hover, .tdx-icon.tdx-icon--hover-darken:hover, .tdx-icon.tdx-icon--hover-darken:focus, .tdx-icon--hover-darken>.tdx-icon:hover, .tdx-icon--hover-darken>.tdx-icon:focus, .tdx-leftnav__item-expander:hover .tdx-icon, .tdx-leftnav__item-expander:focus .tdx-icon, -.tdx-action-menu-dropdown--no-arrow:hover .tdx-icon, .tdx-action-menu-dropdown--no-arrow.active .tdx-icon +.tdx-action-menu-dropdown--no-arrow:hover .tdx-icon, .tdx-action-menu-dropdown--no-arrow.active .tdx-icon, +div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close { filter: brightness(0) invert(var(--filter-invert)) sepia(var(--filter-sepia)) saturate(var(--filter-saturate)) hue-rotate(var(--filter-hue-rotate)) brightness(var(--filter-brightness)) contrast(var(--filter-contrast)) brightness(125%) !important; } From 75922db6db252831d71b4e649aa451f1c3b8f27b Mon Sep 17 00:00:00 2001 From: "Martin, Alexander Scott" Date: Fri, 30 May 2025 16:44:55 -0400 Subject: [PATCH 08/13] fixes for new ticket form --- tdx-enhanced.js | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index 0e1521b..26b7183 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -1,7 +1,7 @@ // ==UserScript== // @name tdx-enhanced // @namespace purdue-it -// @version 2025-05-29-630 +// @version 2025-05-29-615 // @description enhanced tdx coloring & formatting. follows system color scheme. // @author Purdue STEM IT - it@purdue.edu // @match https://service.purdue.edu/TDWorkManagement* @@ -2349,6 +2349,10 @@ button.ms-choice:focus { background-color: var(--bg-1); } +.tdx-lookup-group div.select2-container.form-control a.select2-choices, .input-group div.select2-container.form-control a.select2-choice { + border-color: var(--border-0) !important; +} + .input-group:not(:has(.input-group-section)):not(.input-group--no-border) { border-color: var(--border-0); } @@ -2357,6 +2361,10 @@ button.ms-choice:focus { border-color: var(--col-400) !important; } +div.input-group .input-group-btn .btn-file:last-child { + color: var(--txt-3); +} + .tdx-lookup-group { background-color: var(--bg-0); border-color: var(--border-0); @@ -2681,7 +2689,16 @@ a.disabledLink { } span.input-group-btn .btn-default { - color: var(--border-1); + color: var(--txt-3); +} + +span.input-group-btn .btn-default:hover, span.input-group-btn .btn-default:focus-visible, span.input-group-btn .btn-default:active, span.input-group-btn .btn-default:active:hover, span.input-group-btn .btn-default:focus:active, span.input-group-btn .btn-default:focus:hover { + color: var(--txt-2); +} + +div.input-group .input-group-btn .btn-file:last-child:hover, div.input-group .input-group-btn .btn-file:last-child:hover:focus, div.input-group .input-group-btn .btn-file:last-child:focus-visible { + background-color: var(--col-100); + color: var(--txt-2); } .btn.active, .btn.active:hover, .btn.active:focus, .btn:active, .btn:active:hover, .btn:active:focus { From c9c166421a848049e271cb97bb9a46d9b2d32601 Mon Sep 17 00:00:00 2001 From: "Martin, Alexander Scott" Date: Fri, 30 May 2025 21:28:09 -0400 Subject: [PATCH 09/13] color buttons + popups --- tdx-enhanced.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index 26b7183..5dd41e0 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -2811,6 +2811,18 @@ div.input-group .input-group-btn .btn-file:last-child:hover, div.input-group .in color: var(--txt-2) !important; } +.btn-secondary { + background-color: var(--col-200); + color: var(--col-400); + border-color: var(--col-200); +} + +.btn-secondary:hover, .btn-secondary:hover:focus, .btn-secondary:focus-visible { + background-color: var(--col-300) !important; + color: var(--col-500) !important; + border-color: var(--col-300) !important; +} + .btn-danger { background-color: var(--col-200); color: var(--col-400); @@ -3455,6 +3467,11 @@ div.feed-body>div.feed-child-box { color: var(--txt-1) !important; } +.tdx-modal__iframe-header, +.tdx-modal__iframe-footer { + background-color: var(--bg-0) !important; +} + .modal-content { background-color: var(--bg-0) !important; } From 9a234b2f361a0153731404d658368f0b1574ef62 Mon Sep 17 00:00:00 2001 From: "Martin, Alexander Scott" Date: Fri, 30 May 2025 21:31:57 -0400 Subject: [PATCH 10/13] various changes --- tdx-enhanced.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index 5dd41e0..e8fd600 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -1163,7 +1163,7 @@ } //search whole document, frames may reset when reopened - let frames = document.querySelectorAll("iframe") + let frames = document.querySelectorAll("iframe:not(.customEmbed)") if (frames) { [...frames].forEach(frame=>{ injectOtherStyles(frame) @@ -2107,10 +2107,14 @@ body { color: var(--txt-3); } +p.row { + gap: 8px; +} + /* Headers */ h1, h2, h3, h4, h5 { - color: var(--txt-1) + color: var(--txt-1) !important; } .tdx-header-container { @@ -2873,6 +2877,18 @@ div.input-group .input-group-btn .btn-file:last-child:hover, div.input-group .in color: var(--col-100) !important; } +a.btn.btn-primary { + background-color: var(--col-600) !important; + color: var(--txt-5) !important; + border-color: var(--col-600) !important; +} + +a.btn.btn-primary:hover { + background-color: var(--col-400) !important; + color: var(--txt-5) !important; + border-color: var(--col-400) !important; +} + .btn-primary { background-color: var(--col-600); color: var(--txt-5); @@ -3675,9 +3691,10 @@ div.select2-container.select2-allowclear .select2-choice abbr { background-color: var(--col-200) !important; } -.tdx-user-icon, .tdx-multiuser-icon { - background-color: var(--col-0) !important; - color: var(--txt-5) !important; +.tdx-user-icon, .tdx-multiuser-icon, +div.profile-image.red-bg, div.profile-image.green-bg, div.profile-image.red-bg, div.profile-image.blue-bg, div.profile-image.yellow-bg, div.profile-image.gray-bg, div.profile-image.initials.red-bg, div.profile-image.initials.green-bg, div.profile-image.initials.red-bg, div.profile-image.initials.blue-bg, div.profile-image.initials.yellow-bg, div.profile-image.initials.gray-bg { + background-color: var(--col-400) !important; + color: var(--col-100) !important; } .tdx-widget-indicator-icon { From ad8ff4dab6ee3d95f5108cef3f2353a6cb73a188 Mon Sep 17 00:00:00 2001 From: "Martin, Alexander Scott" Date: Fri, 30 May 2025 23:11:22 -0400 Subject: [PATCH 11/13] calendar styling + other small changes --- tdx-enhanced.js | 163 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 153 insertions(+), 10 deletions(-) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index e8fd600..c8f42e0 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -1,7 +1,7 @@ // ==UserScript== // @name tdx-enhanced // @namespace purdue-it -// @version 2025-05-29-615 +// @version 2025-05-29-645 // @description enhanced tdx coloring & formatting. follows system color scheme. // @author Purdue STEM IT - it@purdue.edu // @match https://service.purdue.edu/TDWorkManagement* @@ -1157,6 +1157,11 @@ parseOtherElements() } + //parse side panels + if (t.classList.contains("tdx-right-side-panel")) { + parseOtherElements() + } + let module = t.querySelector("div > .tdx-dashboard__widget-container") if (module) { updateHeading(t) @@ -1241,8 +1246,8 @@ const result = solver.solve(); let filters = result.filter - console.log("STYLES:",priCol) - console.log("FILTERS:",priCol,rgb,filters) + //console.log("STYLES:",priCol) + //console.log("FILTERS:",priCol,rgb,filters) style.setProperty("--filter-brightness",filters.brightness) style.setProperty("--filter-contrast",filters.contrast) @@ -2579,6 +2584,38 @@ select.form-control { box-shadow: 0 .5px 1px 1px var(--shadow-1),0 2px 4px var(--shadow-2),0 4px 6px var(--shadow-2); } +div#ui-datepicker-div .ui-datepicker-title select, div#ui-datepicker-div .ui-timepicker-div.ui-timepicker-oneLine select, div.ui-datepicker .ui-datepicker-title select, div.ui-datepicker .ui-timepicker-div.ui-timepicker-oneLine select { + color: var(--txt-1); + border-color: var(--bg-0); + background-color: var(--bg-0); +} + +div#ui-datepicker-div .ui-datepicker-title select:hover, div#ui-datepicker-div .ui-timepicker-div.ui-timepicker-oneLine select:hover, div.ui-datepicker .ui-datepicker-title select:hover, div.ui-datepicker .ui-timepicker-div.ui-timepicker-oneLine select:hover { + border-color: var(--border-0); +} + +div#ui-datepicker-div .ui-state-default, div#ui-datepicker-div .ui-state-default:hover, div.ui-datepicker .ui-state-default, div.ui-datepicker .ui-state-default:hover { + border-color: var(--bg-0) !important; +} + +div#ui-datepicker-div .ui-datepicker-header, div.ui-datepicker .ui-datepicker-header { + background: var(--col-100) !important; +} + +div#ui-datepicker-div th, div#ui-datepicker-div td, div.ui-datepicker th, div.ui-datepicker td { + color: var(--txt-1); +} + +div#ui-datepicker-div .ui-state-highlight, div#ui-datepicker-div .ui-widget-content .ui-state-highlight, div#ui-datepicker-div .ui-widget-header .ui-state-highlight, div.ui-datepicker .ui-state-highlight, div.ui-datepicker .ui-widget-content .ui-state-highlight, div.ui-datepicker .ui-widget-header .ui-state-highlight { + background: var(--col-100) !important; + color: var(--col-400) !important; +} + +button:has(>.ui-icon-circle-triangle-e), span:has(>.ui-icon-circle-triangle-e), a:has(>.ui-icon-circle-triangle-e), button:has(>.fa-chevron-circle-right), span:has(>.fa-chevron-circle-right), a:has(>.fa-chevron-circle-right), +button:has(>.ui-icon-circle-triangle-w), span:has(>.ui-icon-circle-triangle-w), a:has(>.ui-icon-circle-triangle-w), button:has(>.fa-chevron-circle-left), span:has(>.fa-chevron-circle-left), a:has(>.fa-chevron-circle-left) { + color: var(--col-400); +} + /* Links */ .tdx-dashboard__widget-container a:not(.btn):not(.k-icon) { @@ -2782,6 +2819,17 @@ div.input-group .input-group-btn .btn-file:last-child:hover, div.input-group .in color: var(--txt-1); } +.modal-footer .btn-default { + background-color: var(--col-200) !important; + color: var(--col-400) !important; + border: none !important; +} + +.modal-footer .btn-default:hover, .modal-footer .btn-default:hover:focus, .modal-footer .btn-default:focus-visible { + background-color: var(--col-300) !important; + color: var(--col-600) !important; +} + /* .btn.btn-primary:not(.btn-sm) { color: var(--txt-1); background-color: var(--bg-5); @@ -2919,8 +2967,91 @@ td > a.btn.btn-primary:hover { border-color: var(--col-100) !important; } +a.btn.btn-link.tdx-primary-button-override { + color: var(--txt-5) !important; +} + .btn-link, .btn.btn-link, .sidebar-btn.btn-link { - color: var(--col-400); + color: var(--col-400) !important; +} + +.btn-link:hover, .btn.btn-link:hover, .sidebar-btn.btn-link:hover { + color: var(--col-400) !important; +} + +.btn-link[role=button]:hover, .btn.btn-link[role=button]:hover, .sidebar-btn.btn-link[role=button]:hover, +a.btn.btn-link.tdx-tertiary-button-override:hover { + background-color: var(--col-200) !important; +} + +.tdx-calendar .cal-views { + border-color: var(--col-400) !important; +} + +.tdx-calendar .cal-view { + color: var(--txt-2) !important; +} + +.tdx-calendar .cal-view.light-blue-bg { + background-color: var(--col-400) !important; + color: var(--txt-2) !important; +} + +.tdx-calendar .cal-view:not(.cal-view.light-blue-bg):hover, .tdx-calendar .cal-view:hover:focus, .tdx-calendar .cal-view:focus-visible { + background-color: var(--col-200) !important; +} + +.tdx-calendar #btnDatePicker { + background-color: var(--bg-0) !important; + color: var(--col-400) !important; +} + +.tdx-calendar #btnDatePicker:hover, .tdx-calendar #btnDatePicker:focus-visible, .tdx-calendar #btnDatePicker:active, .tdx-calendar #btnDatePicker:active:hover, .tdx-calendar #btnDatePicker:focus:active, .tdx-calendar #btnDatePicker:focus:hover { + color: var(--col-600) !important; +} + +button:has(.ui-icon-circle-triangle-w), span:has(.ui-icon-circle-triangle-w), +button:has(.ui-icon-circle-triangle-e), span:has(.ui-icon-circle-triangle-e) { + color: var(--col-400) !important; +} + +button:has(.ui-icon-circle-triangle-e):hover, button:has(.ui-icon-circle-triangle-e):focus-visible, button:has(.ui-icon-circle-triangle-e):active, button:has(.ui-icon-circle-triangle-e):active:hover, button:has(.ui-icon-circle-triangle-e):focus:active, button:has(.ui-icon-circle-triangle-e):focus:hover, span:has(.ui-icon-circle-triangle-e):hover, span:has(.ui-icon-circle-triangle-e):focus-visible, span:has(.ui-icon-circle-triangle-e):active, span:has(.ui-icon-circle-triangle-e):active:hover, span:has(.ui-icon-circle-triangle-e):focus:active, span:has(.ui-icon-circle-triangle-e):focus:hover, +button:has(.ui-icon-circle-triangle-w):hover, button:has(.ui-icon-circle-triangle-w):focus-visible, button:has(.ui-icon-circle-triangle-w):active, button:has(.ui-icon-circle-triangle-w):active:hover, button:has(.ui-icon-circle-triangle-w):focus:active, button:has(.ui-icon-circle-triangle-w):focus:hover, span:has(.ui-icon-circle-triangle-w):hover, span:has(.ui-icon-circle-triangle-w):focus-visible, span:has(.ui-icon-circle-triangle-w):active, span:has(.ui-icon-circle-triangle-w):active:hover, span:has(.ui-icon-circle-triangle-w):focus:active, span:has(.ui-icon-circle-triangle-w):focus:hover { + color: var(--col-600) !important; +} + +.ui-widget-header { + background: var(--bg-0) !important; +} + +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, +.ui-widget-content, .ui-widget.ui-widget-content { + background: var(--bg-0) !important; + border-color: var(--border-0) !important; +} + +.tdx-calendar .fc-day-header { + color: var(--col-400) !important; +} + +.tdx-calendar .fc-day-number.fc-other-month a:first-child { + color: var(--col-200) !important; +} + +.tdx-calendar .fc-day-number a { + color: var(--col-600) !important; +} + +.tdx-calendar .ui-state-highlight a, .tdx-calendar .ui-widget-content .ui-state-highlight a, .tdx-calendar .ui-widget-header .ui-state-highlight a { + color: var(--col-400) !important; +} + +.tdx-calendar .ui-state-highlight { + background: var(--col-100) !important; +} + +.td-day-off { + background: var(--bg-2) !important; } .label-primary, .tdworkmgmt.table .hilite .label.label-primary { @@ -3350,20 +3481,28 @@ nav#divTabHeader, } .nav-tabs>li.active>a, .nav-tabs>li.active>button, .nav-pills>li.active>a, .nav-pills>li.active>button { - color: var(--col-600); + color: var(--col-600) !important; background-color: var(--bg-0) !important; border-color: var(--border-0); box-shadow: 0 .5px 1px 1px var(--shadow-1),0 2px 4px var(--shadow-2),0 4px 6px var(--shadow-2) !important; } .nav-tabs>li>a, .nav-tabs>li>a:hover, .nav-tabs>li>button, .nav-tabs>li>button:hover, .nav-pills>li>a, .nav-pills>li>a:hover { - background-color: var(--bg-0) !important; - color: var(--col-0); + color: var(--txt-3); } -.nav-tabs>li>a:hover, .nav-tabs>li>a:focus, .nav-tabs>li>a:hover:hover, .nav-tabs>li>a:hover:focus, .nav-tabs>li>button:hover, .nav-tabs>li>button:focus, .nav-tabs>li>button:hover:hover, .nav-tabs>li>button:hover:focus, .nav-pills>li>a:hover, .nav-pills>li>a:focus, .nav-pills>li>a:hover:hover, .nav-pills>li>a:hover:focus { +.nav-tabs>li>a:hover, .nav-tabs>li>a:hover:hover { + color: var(--txt-2); border-color: var(--border-0); - color: var(--col-1); +} + +.nav-tabs>li>a:hover { + color: var(--col-600); +} + +a.btn.btn-link.tdx-tertiary-button-override { + background-color: var(--col-100) !important; + color: var(--txt-1) !important; } .gray, .gray-hover:hover { @@ -3721,6 +3860,10 @@ div.profile-image.red-bg, div.profile-image.green-bg, div.profile-image.red-bg, color: var(--col-500) !important; } +.tdx-calendar .fa-plus { + color: var(--col-300) !important; +} + /* Icons + Filters */ .tdx-dropdown__menu-icon, .tdx-dropdown--headline:after, @@ -3739,7 +3882,7 @@ div.profile-image.red-bg, div.profile-image.green-bg, div.profile-image.red-bg, .tdx-action-menu__item--primary:after, .tdx-action-menu-dropdown:after, .tdx-icon.tdx-icon--hover-darken, .tdx-icon--hover-darken>.tdx-icon, -.tdx-dropdown__menu-icon, .tdx-dropdown--headline:after, .tdx-dropdown:after, .tdx-icon--search, .tdx-icon, +.tdx-dropdown__menu-icon, .tdx-dropdown--headline:after, .tdx-dropdown:after, .tdx-icon--search, .tdx-icon:not(.label), div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:hover, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:focus-visible, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:active, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:active:hover, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:focus:active, div.select2-container-multi .select2-choices .select2-search-choice>.select2-search-choice-close:focus:hover { filter: brightness(0) invert(var(--filter-invert)) sepia(var(--filter-sepia)) saturate(var(--filter-saturate)) hue-rotate(var(--filter-hue-rotate)) brightness(var(--filter-brightness)) contrast(var(--filter-contrast)) !important; From 5704d12352fcb6474a61ff238ef3ea43d82a90cd Mon Sep 17 00:00:00 2001 From: "Martin, Alexander Scott" Date: Fri, 30 May 2025 23:18:11 -0400 Subject: [PATCH 12/13] fix white line in text editor --- tdx-enhanced.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index c8f42e0..3a35e9c 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -3686,6 +3686,10 @@ body .tdworkmgmt.table>tbody>tr:not(.tdx-grid__group-header):not(.TDGridHeader): background-color: var(--bg-4); } +.cke_wysiwyg_div, .cke_wysiwyg_frame { + background: var(--bg-0) !important; +} + .cke_combo_button, .cke_toolgroup { background: var(--bg-0) !important; } From 471868c0128b5f299cd9463e50622531dfe40b81 Mon Sep 17 00:00:00 2001 From: "Martin, Alexander Scott" Date: Sat, 31 May 2025 11:06:04 -0400 Subject: [PATCH 13/13] fix table colors, ready for merge --- tdx-enhanced.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tdx-enhanced.js b/tdx-enhanced.js index 3a35e9c..ca97a2a 100644 --- a/tdx-enhanced.js +++ b/tdx-enhanced.js @@ -1,16 +1,19 @@ // ==UserScript== // @name tdx-enhanced // @namespace purdue-it -// @version 2025-05-29-645 +// @version 2025-05-31-01 // @description enhanced tdx coloring & formatting. follows system color scheme. // @author Purdue STEM IT - it@purdue.edu // @match https://service.purdue.edu/TDWorkManagement* +// @match https://service.purdue.edu/tdworkmanagement* // @match https://service.purdue.edu/TDNext* // @match https://service.purdue.edu/TDWebApi* // @match https://purdue.teamdynamixpreview.com/TDWorkManagement* // @match https://purdue.teamdynamixpreview.com/TDNext* // @require https://momentjs.com/downloads/moment.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.6.0/tinycolor.min.js +// @downloadURL https://raw.github.itap.purdue.edu/ECN/tdx-userscript/main/tdx-enhanced.js +// @updateURL https://raw.github.itap.purdue.edu/ECN/tdx-userscript/main/tdx-enhanced.js // @grant GM_getResourceText // @grant GM_addStyle // @run-at document-end @@ -3263,7 +3266,7 @@ thead, tbody, tfoot, tr, td, th { } td.k-table-td { - background-color: var(--bg-1); + /* background-color: var(--bg-1); */ } tr.k-alt td.k-table-td { @@ -3282,7 +3285,8 @@ tr.k-alt td.k-table-td { background-color: unset; } -.k-table-th, .k-table-td { +.k-table-th, .k-table-td, +td.k-table-td { background-color: unset; }