Skip to content

Instantly share code, notes, and snippets.

@ChiriVulpes
Last active October 30, 2023 20:10
Show Gist options
  • Save ChiriVulpes/973db8c359b8e21e3362320ec8cea54d to your computer and use it in GitHub Desktop.
Save ChiriVulpes/973db8c359b8e21e3362320ec8cea54d to your computer and use it in GitHub Desktop.
Chiri's Trello UI/UX improvements
.u-fancy-scrollbar::-webkit-scrollbar-thumb {
background: #444 !important;
}
.u-fancy-scrollbar::-webkit-scrollbar-thumb:hover {
background: #666 !important;
}
.u-fancy-scrollbar::-webkit-scrollbar-thumb:active {
background: #555 !important;
}
:is(.markeddown, .markdown) code {
color: #ec624f;
}
/* resizable lists */
.list-wrapper {
resize: horizontal;
overflow: hidden;
height: fit-content !important;
max-height: 100%;
display: inline-grid !important;
grid-template-rows: 100%;
width: 272px;
}
.list {
width: initial;
}
.list-cards {
flex-direction: row !important;
flex-wrap: wrap;
column-gap: 8px;
}
.list-card {
width: 248px;
height: fit-content;
}
.list-card-composer-textarea {
width: 248px;
}
/* compression */
.board-wrapper:not(.is-show-menu) .board-header {
margin-right: 339px;
}
[data-testid="compact-card-label"] {
margin: 0 !important;
margin-top: -6px !important;
height: 5px !important;
}
.trello-card [data-testid='card-front-member'],
.trello-card [data-testid='card-front-member'] > [role='img'] {
height: 16px !important;
width: 16px !important;
}
.trello-card [data-testid='card-front-member'] {
margin: 4px 0 0 2px !important;
}
.list {
border-radius: 8px;
padding-bottom: 0 !important;
}
.list-wrapper {
padding-right: 0 !important;
}
.list-footer {
padding-top: 0 !important;
}
.badge {
margin: 0 !important;
margin-right: 2px !important;
}
[data-desktop-id="header"] {
z-index: 1;
pointer-events: none;
}
#header {
background: none;
backdrop-filter: none;
border: none;
}
#header > :not(:last-child) {
opacity: 0;
}
#header > :last-child {
pointer-events: all;
margin-top: 4px;
}
main {
position: absolute !important;
inset: 0;
z-index: 0;
}
.board-menu {
top: 58px !important;
}
[data-testid="badge-card-subscribed"] {
display: none !important;
}
.list-wrapper-with-margins {
margin: 0 3px !important;
}
[data-testid='trello-card'] > div {
padding: 6px 8px 0 !important;
}
.trello-card, .list-card-composer-textarea {
border-radius: 4px !important;
}
.list-header {
padding: 2px 2px 0 !important;
margin-bottom: -6px;
}
.list-header-extras-menu {
margin-top: -4px;
}
[aria-label="Open information menu"] {
display: none !important;
}
.logged-in-public-board-banner {
display: none !important;
}
.trello-attachment-canonical-card a {
padding-top: 0;
margin: 0 !important;
width: 100% !important;
}
.trello-attachment-canonical-card [data-test-class="card-label"] {
margin-top: -8px !important;
color: transparent;
max-width: 40px;
min-width: 40px;
}
.trello-attachment-canonical-card a > :nth-child(n+3) {
display: none !important;
}
.trello-attachment-canonical-card a > :nth-child(n+2) {
padding-top: 0;
}
.trello-attachment-canonical-card a + * {
display: none !important;
}
.trello-card-attachment:not(:hover) > a {
display: none;
}
.trello-card-attachment-container {
margin-bottom: 4px !important;
}
.js-trello-attachments-list {
column-count: 2;
}
/* list hiding */
.chiri-list-hidden {
resize: none;
width: 44px !important;
overflow: visible;
padding: 0 !important;
}
.chiri-list-hidden :where(.list-cards, .list-footer) {
display: none !important;
}
.chiri-list-hidden .list {
transform: rotate(90deg) translateY(-100%);
transform-origin: left top;
padding-bottom: 0 !important;
right: -4px !important;
}
.chiri-list-hidden :where(.list, .list-header) {
width: fit-content !important;
}
.chiri-list-hidden .list-header {
flex-flow: initial;
align-items: center;
padding: 4px 14px 4px 0 !important;
margin: 0;
}
.chiri-list-hidden .list-header-extras {
position: relative;
top: 0 !important;
margin: -4px 0 !important;
margin-left: 10px !important;
}
.chiri-list-hidden .list-header-extras-menu {
margin-top: 0;
}
.chiri-list-hidden .list-name {
display: block;
white-space: nowrap;
color: var(--list-title-color);
font-weight: 600;
font-size: 14px;
padding: 4px 8px 4px 12px;
margin: -5px 0;
position: relative;
}
.chiri-list-hidden .list-name-textarea {
display: none;
}
.chiri-list-filtered {
display: none !important;
}
let listHeaderTargets;
let lists;
const classesBySelector = {
"list-card": "[data-testid='list-card']",
"trello-card": ["[data-testid='trello-card']", "ui-droppable"],
"list-card-composer-textarea": "[data-testid='list-card-composer-textarea']",
"list-cards": "[data-testid='list-cards']",
"list-wrapper": "[data-testid='list-wrapper']",
"list": "[data-testid='list']",
"list-header": "[data-testid='list-header']",
"list-name-textarea": "[data-testid='list-name-textarea']",
"list-footer": "[data-testid='list-footer']",
"list-name": "[data-testid='list-name']",
};
const classes = {};
let lastMissing = Infinity;
let stylesheet;
let css;
function update() {
let missing = [];
let newClasses = [];
for (let [unobfuscatedClassName, selector] of Object.entries(classesBySelector)) {
if (!classes[unobfuscatedClassName]) {
let ignoredClasses = [];
if (Array.isArray(selector))
ignoredClasses = selector.slice(1), selector = selector[0];
let found = false;
for (const element of document.querySelectorAll(selector)) {
const classList = [...element.classList].filter(cls => !ignoredClasses.includes(cls));
const className = classList.length === 1 ? classList[0] : undefined;
if (className) {
classes[unobfuscatedClassName] = className;
newClasses.push([unobfuscatedClassName, className]);
console.log(unobfuscatedClassName, className);
found = true;
break;
}
}
if (!found)
missing.push(unobfuscatedClassName);
}
}
if (missing.length !== lastMissing) {
lastMissing = missing.length;
if (missing.length)
console.log("Missing classes:", missing);
else
console.log("No missing classes", classes);
stylesheet ??= document.querySelector("style[data-source='User JavaScript and CSS extension']");
if (!stylesheet)
return console.warn("Couldn't find user stylesheet to update");
css ??= stylesheet.textContent;
console.log(newClasses);
for (const [unobfuscatedClassName, className] of newClasses) {
console.log("Replacing", unobfuscatedClassName, "with", className);
css = css.replaceAll(new RegExp(`(?<=\\.)${unobfuscatedClassName}(?![\\w-])`, "g"), className);
}
// console.log(css);
stylesheet.textContent = css;
if (classes["list-wrapper"])
lists ??= document.getElementsByClassName(classes["list-wrapper"]);
if (classes["list-header"])
listHeaderTargets ??= document.getElementsByClassName(classes["list-header"]);
}
for (const target of listHeaderTargets ?? []) {
if (!target.classList.contains("chiri-listening")) {
target.addEventListener("contextmenu", onRightClickList);
}
}
updateListStates();
}
setInterval(update, 100);
function onRightClickList (event) {
toggleVisible(getListName(event.target));
event.preventDefault();
}
function toggleVisible (listName) {
const id = `chiri-list-hidden.${listName}`;
const hidden = !localStorage.getItem(id);
if (hidden)
localStorage.setItem(id, hidden);
else
localStorage.removeItem(id);
updateListStates();
}
function updateListStates() {
for (const list of lists ?? []) {
const listName = getListName(list);
const listFilterCardsCount = getListFilterCardsCount(list);
const shouldHide = listFilterCardsCount === undefined ? !!localStorage.getItem(`chiri-list-hidden.${listName}`) : !listFilterCardsCount;
list.classList.toggle("chiri-list-filtered", listFilterCardsCount === 0);
list.classList.toggle("chiri-list-hidden", shouldHide);
}
}
function getListName (element) {
const listElement = classes["list-wrapper"]
&& element?.closest?.(`.${classes["list-wrapper"]}`);
return classes["list-name-textarea"] &&
listElement?.querySelector(`.${classes["list-name-textarea"]}`)?.getAttribute("aria-label");
}
function getListFilterCardsCount (element) {
const paragraphs = classes["list-wrapper"]
&& element?.closest?.(`.${classes["list-wrapper"]}`)?.querySelectorAll("p");
if (!paragraphs)
return undefined;
for (const p of paragraphs) {
if (!p.textContent.endsWith(" filters"))
continue;
const count = parseInt(p.textContent);
return count;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment