diff options
| -rw-r--r-- | web/cgit-extra.html | 152 | ||||
| -rw-r--r-- | web/git.css | 73 |
2 files changed, 221 insertions, 4 deletions
diff --git a/web/cgit-extra.html b/web/cgit-extra.html index 2237e26..ed62938 100644 --- a/web/cgit-extra.html +++ b/web/cgit-extra.html @@ -30,7 +30,7 @@ function branchFromForm() { async function getFile( repo, branch, file ) { try { const res = await fetch( `https://${location.host}/${repo}/plain/${file}` ); - if( !res.ok ) + if( !res.ok || !res.headers.get( "Content-Type" ).toLowerCase().startsWith( "text/plain" ) ) return null; return await res.text(); } catch( e ) { @@ -68,6 +68,7 @@ function isIndex( repo ) { let path = location.pathname; return path.replaceAll( "/", "" ) === repo; } + function parseLink( text, start ) { let isImg = 0; @@ -194,7 +195,7 @@ function replaceCodeTicks( text ) { } function runHighlight() { - if( hljs === undefined || !hljs ) + if( typeof( hljs ) === 'undefined' || !hljs ) return setTimeout( runHighlight, 200 ); hljs.highlightAll(); @@ -249,7 +250,154 @@ function isCodeView( repo ) { return location.pathname.includes( `/${repo}/tree` ); } +function isMainPage() { + return location.pathname === "/"; +} + +async function getActivityData( days ) { + const response = await fetch( "https://networkheaven.net/git-access.log" ); + const data = await response.text(); + const ret = new Array( days ).fill( 0 ); + let highest = 0; + + const now = new Date(); + let start = data.length - 1; + let line = ''; + for( let i = data.length - 1; i >= 0; --i ) { + if( i != 0 && data[i] != '\n' ) + continue; + + line = data.substring( i, start ); + start = i; + if( !line.length ) + continue; + + const date = new Date( parseInt( line ) * 1000 ); + const delta = Math.floor( ( now - date ) / 1000 / 60 / 60 / 24 ); + if( delta > days ) + break; + + ret[delta] += 1; + if( ret[delta] > highest ) + highest = ret[delta]; + } + + return { values: ret, highest }; +} + +function getActivityClass( delta, highest ) { + if( !highest ) + return ""; + + const ratio = delta / highest; + if( ratio < 0.0001 ) + return ""; + if( ratio < 0.25 ) + return "activity-low"; + else if( ratio < 0.5 ) + return "activity-medium"; + else if( ratio < 0.75 ) + return "activity-high"; + else + return "activity-very-high"; +} + +let spinnerFrame = 0; +const spinnerFrames = [ + '/', + '-', + '\\', + '|', +]; + +function doSpinner() { + if( spinnerFrame >= spinnerFrames.length ) + spinnerFrame = 0; + const frame = spinnerFrames[spinnerFrame]; + const spinners = document.querySelectorAll( ".spinner" ); + if( !spinners.length ) + return; + for( const el of spinners ) + el.innerText = frame; + spinnerFrame++; + setTimeout( doSpinner, 150 ); +} + +function createActivityContainer() { + const wrapper = document.createElement( "div" ); + wrapper.classList.add( "activity-outer" ); + + const title = document.createElement( "h2" ); + title.classList.add( "activity-title" ); + title.textContent = "Activity"; + wrapper.appendChild( title ); + + const hr = document.createElement( "hr" ); + hr.classList.add( "activity-hr" ); + wrapper.appendChild( hr ); + + const inner = document.createElement( "div" ); + inner.classList.add( "activity-inner" ); + wrapper.appendChild( inner ); + + const table = document.createElement( "table" ); + table.classList.add( "activity-table" ); + inner.appendChild( table ); + + const spinner = document.createElement( "div" ); + spinner.classList.add( "spinner" ); + spinner.innerText = "-"; + inner.appendChild( spinner ); + setTimeout( doSpinner, 150 ); + + const content = document.querySelector( ".content" ); + content.appendChild( wrapper ); +} + +async function createActivityGraph() { + const date = new Date(); + let weekday = date.getDay(); + // christ is king + if( weekday == 0 ) weekday = 6; + else weekday -= 1; + + const activity = await getActivityData( 365 + weekday ); + const table = document.querySelector( ".activity-table" ); + + let row = document.createElement( "tr" ); + table.appendChild( row ); + let rowc = 0; + let colc = 0; + for( let i = 0; i < 365 + weekday; ++i ) { + const day = 364 + weekday - i; + const commits = activity.values[day]; + const aclass = getActivityClass( commits, activity.highest ); + const cell = document.createElement( "td" ); + cell.classList.add( "activity-cell-" + day ); + if( aclass ) cell.classList.add( aclass ); + + const popup = document.createElement( "div" ); + popup.classList.add( "popup" ); + if( i > 20 ) popup.classList.add( "right" ); + const dateStr = new Date( (new Date()) - day * 24 * 60 * 60 * 1000 ).toLocaleDateString(); + popup.innerText = `${dateStr}\n${commits} commits`; + + cell.appendChild( popup ); + row.appendChild( cell ); + } + + const wrapper = document.querySelector( ".activity-outer" ); + const spinner = wrapper.querySelector( ".spinner" ); + if( spinner ) + spinner.remove(); +} + const main = async () => { + if( isMainPage() ) { + createActivityContainer(); + return setTimeout( createActivityGraph ); + } + const mainEl = document.querySelector( ".main" ); if( !mainEl ) return; diff --git a/web/git.css b/web/git.css index 84ef9ad..a8b3435 100644 --- a/web/git.css +++ b/web/git.css @@ -84,6 +84,75 @@ a:hover { color: #fff; } +.activity-wrapper { + display: flex; +} + +.activity-inner { + display: flex; +} + +.activity-table tr { + height: 11px; +} + +.activity-table td { + height: 9px; + width: 9px; + border: 1px solid #888; + background-color: #7f7f7f; +} + +.activity-title { + margin-left: 5px; + margin-bottom: 1px; + text-decoration: none; + background: var( --gradient ); + background-clip: border-box; + -webkit-text-fill-color: transparent; + -webkit-background-clip: text; + color: #c6a6ff; + font-weight: normal !important; + font-size: 17px; + font-family: JPN16; + width: fit-content; +} + +.activity-table td:hover { + border-left: 3px solid #888; + border-right: 3px solid #888; +} +td .popup { + display: none; + position: absolute; + border-top: 1px solid #fff; + border-left: 1px solid #ccc; + border-right: 1px solid #666; + border-bottom: 1px solid #000; + background: #888; + padding: 3px; + padding-right: 5px; + z-index: 1; +} + +td .popup.right { + translate: -100%; +} + +td:hover .popup { + display: inline-block; +} + +hr { + margin: 0; + color: #fff; +} + +.activity-low { background-color: #f0f !important; } +.activity-medium { background-color: #c488ff !important; } +.activity-high { background-color: #c6a6ff !important; } +.activity-very-high { background-color: #0ff !important; } + div#cgit { padding: 0em; margin: 0em; @@ -725,7 +794,7 @@ div#cgit ul.pager .current { } div#cgit span.age-mins { - color: #0f0; + color: #0ff; } div#cgit span.age-hours { @@ -733,7 +802,7 @@ div#cgit span.age-hours { } div#cgit span.age-days { - color: #040; + color: #0c0; } div#cgit span.age-weeks { |
