Skip to content

Instantly share code, notes, and snippets.

@KnIfER
Last active June 6, 2024 22:20
Show Gist options
  • Save KnIfER/adfeaf418b5edac33e77958ac26215ca to your computer and use it in GitHub Desktop.
Save KnIfER/adfeaf418b5edac33e77958ac26215ca to your computer and use it in GitHub Desktop.
GitHubDesktop pin repository list

Workaround for Desktop / Allow the repository list to be expanded all the time

How to use :

  • try to alt+click the big button
  • or right/left click on the left edge of maximized window.

It will toggle the pinning state of repository list view.

When the list view is pinned, it's styles are modified to make it non-modal and always visible.

It's not perfect : when you select items in the list, the old view will be destoryed, and to bring it back, the workaround just tries to simulate a click on the big button. So if you switch fastly, the big title button will flicker and sometimes the list view will not restore scroll position correctly.

Installation Steps :

  1. locate install folder of GitHubDesktop (%AppData%\..\Local\GitHubDesktop)
  2. Open & edit app-2.9.15\resources\app\index.html, You can use vscode extension to beautify the minified html in place.
  3. Create and inject your custom script:

index.html

<head>
	<meta charset="UTF-8" />
	<script defer="defer" src="renderer.js"></script>
	<script src="custom.js"></script>

custom.js

// see below

(If it won't work just open devtool by ctrl+shift+I and modify on your own.)

Update :

  • fix other popups not showing
// workaround for [Desktop / Allow the repository list to be expanded all the time / Issue #1593 / desktop/desktop](https://github.com/desktop/desktop/issues/1593)
// how to use : alt+click the big button
// or right/left click on the left edge of maximized window.
// for GitHubDesktop 2.9.15 (x64)
var sidePinned, sideHidden;
(function(){
var debug = console.log;
debug('custom!!!');
// default state
var DEFAULT_PINNED = true;
var win = window, doc=document, d=doc;
win._st = true;
// UTIILS
function craft(t, c, p) {
var e=document.createElement(t||'DIV');
if(c)e.className=c;
if(p)p.appendChild(e);
return e;
}
function addEvent(a, b, c) {
win.addEventListener(a, b, c);
}
function gc(c, d) {
return (d||document).getElementsByClassName(c)[0];
}
function ge(id) {
return document.getElementById(id);
}
function gcs(c, d) {
return (d||document).getElementsByClassName(c);
}
function gt(c, d) {
return (d||document).getElementsByTagName(c)[0];
}
function gts(c, d) {
return (d||document).getElementsByTagName(c);
}
function gcp(c, d, max) {
var p = d||document;
if(!max) max=99999;
while(p) {
if(p.classList && p.classList.contains(c)) return p;
p = p.parentNode;
if(--max<=0) return null;
}
return p;
}
function gep(c, d, max) {
var p = d||document;
if(!max) max=99999;
while(p) {
if(p.id==c) return p;
p = p.parentNode;
if(--max<=0) return null;
}
return p;
}
function stop(e) {
try{
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
} catch(e) {debug(e)}
}
function click(el) {
try{
el.click();
} catch(e) {debug(e)}
}
win.US_addStyle = function(text, id, h){
var el = 0;
if(id) el = ge(id);
if(!el) {
el = document.createElement('STYLE');
if(id) el.id = id;
(h||document.head).append(el);
}
else if(h && h!=el.parentNode) {
h.append(el);
}
el.textContent = text;
};
var toastTimer=-1, toastView;
function fadeToast() {
clearTimeout(toastTimer);
var toast = ge("toastview");
toast.style.opacity=0;
toastTimer=setTimeout(function(){toastTimer=-1;toast.style.display='none'}, 300);
}
function toast(msg, severity, time, parent, alpha){
if(toastTimer!=-1)clearTimeout(toastTimer);
if(!parent) parent=d.body;
var toast = ge("toastview");
if(!toast) {
toast = craft(0,0,parent);
toast.id="toastview";
craft(0,0,toast).id="toasttext";
craft('STYLE', 0,d.head).textContent=`#toastview {
display:none;
position:fixed;
left:50%;
top:89%;
width:100%;
opacity:0;
position:absolute;
transform:translate(-50%,-50%);
-webkit-transform:translate(-50%,-50%);
transition:opacity 0.3s;
overflow:auto;
text-align:center;
z-index: 999999999999999;
position: fixed;
pointer-events:none;
}
#toasttext{
display:inline-block;
margin:0 0px;
padding:7px 15px;
font-size:16px;
color:#FFFFFF;
letter-spacing:0;
line-height:22px;
border-radius:30px;
-moz-border-radius:30px;
-moz-user-select:text;
-webkit-user-select:text;
-ms-user-select:text;
-khtml-user-select:text;
user-select:text;
}
#toasttext.warn{
background-image: linear-gradient(-45deg, #ff9569 0%, #e92758 100%);
}
#toasttext.info{
background-image: linear-gradient(0deg, #27bdc9 0%, #296ade 21%);
box-shadow: inset 0px 0px 4px 0px #ffffff9c;
}`;
}
var p=toast.parentNode;
if(p!=parent){
//debug("re-add toast!");
if(p) toast.remove();
parent.appendChild(toast);
}
var tt=toast.firstChild;
tt.innerHTML=msg;
tt.className=severity>=1?"warn":"info";
toastTimer=setTimeout(fadeToast, time||1500);
setTimeout(function(){toast.style.opacity=1}, 16);
toast.style.display='block'
tt.style.opacity=alpha||1;
}
// UTIILS
function pinSidebar(pin, force) {
if(sidePinned!=pin || force) {
sidePinned = pin;
sideHidden = false;
US_addStyle(pin?`
.sidebar-section #foldout-container{
width:165px!important;
}
.sidebar-section #foldout .ReactVirtualized__Grid{
width:165px!important;
}
.sidebar-section .foldout{
width: 165px!important;
min-width: 165px!important;
}
#repository{
padding-left: 165px;
}
.repository-list .list-item.selected, #changes-list .list-item.selected{
--text-color: var(--box-selected-active-text-color)!important;
--text-secondary-color: var(--box-selected-active-text-color)!important;
color: var(--text-color)!important;
background-color: var(--box-selected-active-background-color)!important;
}
#app-menu-bar .toolbar-dropdown.open{
z-index:999999999;
}
`:'', `pin_sty`)
}
}
function hideSidebar() {
sideHidden = true;
US_addStyle('', `pin_sty`);
}
if(DEFAULT_PINNED) {
pinSidebar(DEFAULT_PINNED);
}
var sideBar, sideBarP, sideBarFading, sideBarScroll;
function simulatePopup(sim) {
simulating = sim;
click(gt('button', gc('toolbar-button', gc('sidebar-section'))));
simulating = 0;
}
function findOtherPopup() {
return gc('branch-button open') || gc('toolbar-dropdown open', ge('app-menu-bar')||craft());
}
var targetNode = gc('toolbar-dropdown')
, simulating = false
, observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
// debug('Δ title button::', mutation, mutation.target);
if(sidePinned)
if(targetNode.classList.contains('open')) {
sideBar = ge('foldout-container');
if(sideBar && !sideBar._op) {
sideBar._op = 1;
sideBarP = sideBar.parentNode;
var el = gc('ReactVirtualized__Grid', targetNode);
if(el) el.scrollTop = sideBarScroll
setTimeout(()=>{
var el = gc('ReactVirtualized__Grid', targetNode);
if(el) {
if(sideBarScroll) {
el.scrollTop = sideBarScroll
}
el.onscroll = (e)=>{
var f = gep('foldout-container', e.target, 99);
if(!f._z) sideBarScroll = el.scrollTop;
}
}
if(sideBarFading) {
setTimeout(()=>sideBarFading.remove(), 10)
}
}, 50)
}
}
else if(targetNode.classList.contains('closed')) {
targetNode._z = 1;
if(sidePinned && !sideHidden) {
var f = sideBar, popup = findOtherPopup();
if(f && !f._z) {
f._z = 1;
// f.id = '';
// f.style.zIndex = '0';
f.style.pointerEvents = 'none'
if(sideBarFading) sideBarFading.remove();
sideBarFading = f;
sideBarP.appendChild(f);
var el = gc('ReactVirtualized__Grid', f);
if(sideBarScroll) {
el.scrollTop = sideBarScroll;
el.onscroll = 0;
}
if(!popup)
setTimeout(()=>{
if(f.parentNode && !findOtherPopup())
f.remove()
}, 800)
}
if(!popup)
simulatePopup(1);
else if(!popup._ob) {
popup._ob = 1;
observer1.observe(popup, { attributes: true })
}
}
}
});
})
, observer1 = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
// debug('Δ branch/menu btn::', mutation, mutation.target);
if(sidePinned && !sideHidden)
if(!mutation.target.classList.contains('open')) {
var popup = findOtherPopup();
observer1.disconnect();
mutation.target._ob = 0;
if(popup) { // pass observer to other menu
popup._ob = 1;
observer1.observe(popup, { attributes: true })
} else {
// var f = sideBarFading;
// setTimeout(()=>f.remove(), 800)
simulatePopup(1);
}
// debug('Δ branch/menu btn::', mutation, mutation.target);
}
});
})
function init() {
observer.observe(targetNode, { attributes: true })
if(DEFAULT_PINNED) {
simulatePopup(1);
}
if(1) { // add thin side button
var el = craft(0,'btnLeft',doc.body);
el.id='btnLeft';
el.style=`width:1.5px;position:fixed;background:#00ff0000;height:100%;top:0;left:0;z-index:99999999;`;
el.oncontextmenu = (e)=>{ // right-click to toggle pinning of repo list
pinSidebar(!sidePinned);
if(!ge('foldout-container'))
simulatePopup(1);
stop(e);
}
el.onclick = e=>{ // then left-click to toggle visibility of repo list
if(sideBarFading)
sideBarFading.remove();
if(!sidePinned && gc('overlay'))
click(gc('overlay'));
else
simulatePopup()
}
el.onmousedown = e=>{ // toggle sort mode
if(e.button==1) {
_st = !_st;
if(navigator.language?.startsWith('zh-'))
toast(_st?'时间排序 ⌚':'A-Z 字母排序')
else
toast(_st?'Sort local changes by date ⌚':'Sort local changes by path A-Z')
}
}
}
addEvent('click', (e)=>{
if(simulating) return;
var t = e.target;
// debug('click', e, t)
if(gcp('toolbar-button', t, 4) && gcp('sidebar-section', t, 9)) {
// debug('click!!!')
if(e.altKey) {
pinSidebar(!sidePinned);
} else if(sidePinned) {
if(sideHidden=!sideHidden) {
hideSidebar();
} else {
pinSidebar(sidePinned, true);
}
}
}
})
}
var initTm = setInterval(() => {
var p = ge('desktop-app-toolbar');
targetNode = p && gc('toolbar-dropdown', p);
debug('targetNode', targetNode)
if(targetNode) {
clearInterval(initTm)
init();
}
}, 250);
})()
@adeopura4
Copy link

Thanks for this. I think the one issue with this is that the branches list does not open when you click on the current branch (or press Cmd+B). Will try to debug, but if you have a solution, please let me know. Thank you.

@KnIfER
Copy link
Author

KnIfER commented Jun 4, 2024

Ok, I'm fixing it. the menu buttons have the same issue too.

@adeopura4
Copy link

adeopura4 commented Jun 6, 2024

Works well now. Thank you.

One minor issue that I saw - Cannot focus on the Commit Summary and Description input boxes. The focus seems to always be in the "Filter" input box on the left hand top corner.

I do not think that is a big deal for me, but wanted to point that out in case it is helpful to you or anyone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment