// ==UserScript== // @name Trello coloured Scrum Kanban // @namespace https://trello.com/ // @version 3.2 // @description Colour lists & cards, show WIP and story-point insights // @match https://trello.com/* // @require http://code.jquery.com/jquery-latest.js // @author Michael Wan // @downloadURL https://update.greasyfork.icu/scripts/37171/Trello%20coloured%20Scrum%20Kanban.user.js // @updateURL https://update.greasyfork.icu/scripts/37171/Trello%20coloured%20Scrum%20Kanban.meta.js // ==/UserScript== (function($) { 'use strict'; //── configs ──────────────────────────────────────────────────────────── const COLORS = { list: { Development: '#9ec4ff', Testing: '#dbffd1', 'Ready to Deploy': '#c4c4c4', Deployed: '#898989' }, cardBorder: { '!!': '#ff8300', '!': '#ffd800', '`': '#dbf3ff' }, cardBg: { '[P]': '#fdffbf', '[Parent]': '#fdffbf', Blocked: '#fabaff', '[VIP]': '#ff6363', '[R]': '#eeffbf', '[INFO]': '#e0f8ff' }, idColor: '#ffd396', noEstimate: '#c1150f', whiteText: '#fff', wipHighlight: 'yellow' }; const WIP_LIMIT = 2; const REFRESH_MS = 2000; //── list colouring ──────────────────────────────────────────────────── function colorLists() { $('.list-wrapper').each(function() { const title = $(this) .find('.list-header-name-assist') .text() .trim(); const bg = COLORS.list[title]; if (bg) { $(this) .css('background', bg) .find('h2') .css('color', COLORS.whiteText); } }); } //── card borders & backgrounds ──────────────────────────────────────── function styleCards() { $("[data-testid='trello-card']").each(function() { const $card = $(this); const text = $card.text(); // reset $card.css({ border: '', background: '' }); // borders for (const [marker, color] of Object.entries(COLORS.cardBorder)) { if (text.includes(marker)) { $card.css('border', `5px solid ${color}`); break; // only one border } } // backgrounds for (const [marker, color] of Object.entries(COLORS.cardBg)) { if (text.includes(marker)) { $card.css('background', color); break; } } }); } //── show card IDs & highlight missing estimates ─────────────────────── function annotateCardIds() { $('.card-short-id') .append(' ') .removeClass('hide') .css('color', COLORS.idColor); $('.js-card-name').filter(function() { return !/\(\d+\)/.test($(this).text()); }) .find('.card-short-id') .css('color', COLORS.noEstimate); } //── compute & display WIP per member ────────────────────────────────── function updateWIP() { $('#actualWIP').remove(); const $header = $('.board-header'); if (!$header.length) return; $header.after( `
#Cards:${count} #StoryPt:${pts} ${miss ? `#Miss:${miss}` : ''}
`; $list.find('textarea.list-header-name').after(insight); }); } //── orchestrator ────────────────────────────────────────────────────── function refreshAll() { colorLists(); styleCards(); annotateCardIds(); updateWIP(); updateListInsights(); } //── kick off on load + every REFRESH_MS ──────────────────────────────── $(document).ready(() => { refreshAll(); setInterval(refreshAll, REFRESH_MS); }); })(jQuery);