gitlytics 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ :root{--bg-color:#0a0a0a;--bg-card:#111;--bg-hover:#1a1a1a;--border-color:#2a2a2a;--text-primary:#ededed;--text-secondary:#a1a1aa;--accent-color:#2563eb;--accent-hover:#1d4ed8;--danger-color:#ef4444;--success-color:#22c55e;--radius:6px}*{box-sizing:border-box;margin:0;padding:0}body{background-color:var(--bg-color);color:var(--text-primary);-webkit-font-smoothing:antialiased;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;line-height:1.5}.fade-in{animation:.4s ease-out forwards fadeIn}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.app-container{flex-direction:column;min-height:100vh;display:flex}.topbar{background-color:var(--bg-card);border-bottom:1px solid var(--border-color);justify-content:space-between;align-items:center;padding:16px 40px;display:flex}.main-content{flex:1;width:100%;max-width:1200px;margin:0 auto;padding:40px;overflow-y:auto}h1,h2,h3,h4{color:var(--text-primary);margin-bottom:16px;font-weight:600}p{color:var(--text-secondary);margin-bottom:16px}.card{background-color:var(--bg-card);border:1px solid var(--border-color);border-radius:var(--radius);margin-bottom:24px;padding:24px}.stat-card{flex-direction:column;display:flex}.stat-card .label{color:var(--text-secondary);margin-bottom:8px;font-size:14px}.stat-card .value{font-size:28px;font-weight:600}.grid{gap:24px;display:grid}.grid-3{grid-template-columns:repeat(3,1fr)}.grid-4{grid-template-columns:repeat(4,1fr)}.grid-2{grid-template-columns:repeat(2,1fr)}.grid-2-col{grid-template-columns:2fr 1fr}@media (width<=1000px){.grid-2-col,.grid-3,.grid-4,.grid-2{grid-template-columns:1fr}}input[type=text],input[type=password],select{background-color:var(--bg-color);border:1px solid var(--border-color);border-radius:var(--radius);width:100%;color:var(--text-primary);appearance:none;outline:none;padding:12px 16px;font-size:14px;transition:border-color .2s}select{cursor:pointer;background-image:url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a1a1aa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");background-position:right 12px center;background-repeat:no-repeat;background-size:16px;padding-right:40px}input[type=text]:focus,input[type=password]:focus,select:focus{border-color:var(--accent-color)}.btn{background-color:var(--bg-card);border:1px solid var(--border-color);color:var(--text-primary);border-radius:var(--radius);cursor:pointer;justify-content:center;align-items:center;gap:8px;padding:10px 16px;font-size:14px;font-weight:500;transition:all .2s;display:inline-flex}.btn:hover{background-color:var(--bg-hover)}.btn-primary{background-color:var(--text-primary);color:var(--bg-color);border-color:var(--text-primary)}.btn-primary:hover{background-color:#d1d5db}.btn-danger{color:var(--danger-color);border-color:var(--border-color)}.btn-danger:hover{border-color:var(--danger-color);background-color:#0000}.nav-item{border-radius:var(--radius);color:var(--text-secondary);cursor:pointer;align-items:center;gap:12px;padding:8px 16px;font-weight:500;text-decoration:none;transition:all .2s;display:flex}.nav-item:hover{background-color:var(--bg-hover);color:var(--text-primary)}.nav-item.active{background-color:var(--accent-color);color:#fff}.landing-tabs{background-color:var(--bg-hover);border-radius:var(--radius);margin-bottom:24px;padding:4px;display:flex}.landing-tab{text-align:center;cursor:pointer;color:var(--text-secondary);border-radius:4px;flex:1;padding:8px 16px;font-weight:500;transition:all .2s}.landing-tab.active{background-color:var(--bg-card);color:var(--text-primary);box-shadow:0 1px 3px #00000080}.badge{text-transform:uppercase;letter-spacing:.5px;border-radius:12px;align-items:center;padding:2px 8px;font-size:11px;font-weight:600;display:inline-flex}.badge-public{color:var(--success-color);background-color:#22c55e26;border:1px solid #22c55e33}.badge-private{color:var(--danger-color);background-color:#ef444426;border:1px solid #ef444433}.data-bar-bg{background-color:#2563eb26;border-radius:4px;padding:4px 8px;display:inline-block;position:relative;overflow:hidden}table{border-collapse:collapse;width:100%}th,td{text-align:left;border-bottom:1px solid var(--border-color);padding:16px 20px;font-size:14px}th{color:var(--text-secondary);text-transform:uppercase;letter-spacing:.5px;font-size:12px;font-weight:500}td{color:var(--text-primary)}.loading-container{flex-direction:column;justify-content:center;align-items:center;max-width:400px;margin:100px auto;display:flex}.loading-bar-bg{background-color:var(--border-color);border-radius:4px;width:100%;height:6px;margin-top:24px;position:relative;overflow:hidden}.loading-bar-fill{background:linear-gradient(90deg, transparent, var(--accent-color), transparent);width:50%;height:100%;animation:1.5s ease-in-out infinite loadingSlide;position:absolute;top:0;left:0}@keyframes loadingSlide{0%{transform:translate(-100%)}to{transform:translate(200%)}}.accordion-row{cursor:pointer;transition:background-color .2s}.accordion-row:hover{background-color:var(--bg-hover)}.accordion-content{background-color:var(--bg-color);border-bottom:1px solid var(--border-color);padding:32px 24px}tr:hover td{background-color:var(--bg-hover)}.flex{display:flex}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-4{gap:16px}.mt-4{margin-top:16px}.mb-8{margin-bottom:32px}.text-center{text-align:center}.text-secondary{color:var(--text-secondary)}
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="46" fill="none" viewBox="0 0 48 46"><path fill="#863bff" d="M25.946 44.938c-.664.845-2.021.375-2.021-.698V33.937a2.26 2.26 0 0 0-2.262-2.262H10.287c-.92 0-1.456-1.04-.92-1.788l7.48-10.471c1.07-1.497 0-3.578-1.842-3.578H1.237c-.92 0-1.456-1.04-.92-1.788L10.013.474c.214-.297.556-.474.92-.474h28.894c.92 0 1.456 1.04.92 1.788l-7.48 10.471c-1.07 1.498 0 3.579 1.842 3.579h11.377c.943 0 1.473 1.088.89 1.83L25.947 44.94z" style="fill:#863bff;fill:color(display-p3 .5252 .23 1);fill-opacity:1"/><mask id="a" width="48" height="46" x="0" y="0" maskUnits="userSpaceOnUse" style="mask-type:alpha"><path fill="#000" d="M25.842 44.938c-.664.844-2.021.375-2.021-.698V33.937a2.26 2.26 0 0 0-2.262-2.262H10.183c-.92 0-1.456-1.04-.92-1.788l7.48-10.471c1.07-1.498 0-3.579-1.842-3.579H1.133c-.92 0-1.456-1.04-.92-1.787L9.91.473c.214-.297.556-.474.92-.474h28.894c.92 0 1.456 1.04.92 1.788l-7.48 10.471c-1.07 1.498 0 3.578 1.842 3.578h11.377c.943 0 1.473 1.088.89 1.832L25.843 44.94z" style="fill:#000;fill-opacity:1"/></mask><g mask="url(#a)"><g filter="url(#b)"><ellipse cx="5.508" cy="14.704" fill="#ede6ff" rx="5.508" ry="14.704" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -4.47 31.516)"/></g><g filter="url(#c)"><ellipse cx="10.399" cy="29.851" fill="#ede6ff" rx="10.399" ry="29.851" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -39.328 7.883)"/></g><g filter="url(#d)"><ellipse cx="5.508" cy="30.487" fill="#7e14ff" rx="5.508" ry="30.487" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.814 -25.913 -14.639)scale(1 -1)"/></g><g filter="url(#e)"><ellipse cx="5.508" cy="30.599" fill="#7e14ff" rx="5.508" ry="30.599" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.814 -32.644 -3.334)scale(1 -1)"/></g><g filter="url(#f)"><ellipse cx="5.508" cy="30.599" fill="#7e14ff" rx="5.508" ry="30.599" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -34.34 30.47)"/></g><g filter="url(#g)"><ellipse cx="14.072" cy="22.078" fill="#ede6ff" rx="14.072" ry="22.078" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="rotate(93.35 24.506 48.493)scale(-1 1)"/></g><g filter="url(#h)"><ellipse cx="3.47" cy="21.501" fill="#7e14ff" rx="3.47" ry="21.501" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.009 28.708 47.59)scale(-1 1)"/></g><g filter="url(#i)"><ellipse cx="3.47" cy="21.501" fill="#7e14ff" rx="3.47" ry="21.501" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.009 28.708 47.59)scale(-1 1)"/></g><g filter="url(#j)"><ellipse cx=".387" cy="8.972" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(39.51 .387 8.972)"/></g><g filter="url(#k)"><ellipse cx="47.523" cy="-6.092" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 47.523 -6.092)"/></g><g filter="url(#l)"><ellipse cx="41.412" cy="6.333" fill="#47bfff" rx="5.971" ry="9.665" style="fill:#47bfff;fill:color(display-p3 .2799 .748 1);fill-opacity:1" transform="rotate(37.892 41.412 6.333)"/></g><g filter="url(#m)"><ellipse cx="-1.879" cy="38.332" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 -1.88 38.332)"/></g><g filter="url(#n)"><ellipse cx="-1.879" cy="38.332" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 -1.88 38.332)"/></g><g filter="url(#o)"><ellipse cx="35.651" cy="29.907" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 35.651 29.907)"/></g><g filter="url(#p)"><ellipse cx="38.418" cy="32.4" fill="#47bfff" rx="5.971" ry="15.297" style="fill:#47bfff;fill:color(display-p3 .2799 .748 1);fill-opacity:1" transform="rotate(37.892 38.418 32.4)"/></g></g><defs><filter id="b" width="60.045" height="41.654" x="-19.77" y="16.149" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="c" width="90.34" height="51.437" x="-54.613" y="-7.533" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="d" width="79.355" height="29.4" x="-49.64" y="2.03" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="e" width="79.579" height="29.4" x="-45.045" y="20.029" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="f" width="79.579" height="29.4" x="-43.513" y="21.178" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="g" width="74.749" height="58.852" x="15.756" y="-17.901" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="h" width="61.377" height="25.362" x="23.548" y="2.284" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="i" width="61.377" height="25.362" x="23.548" y="2.284" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="j" width="56.045" height="63.649" x="-27.636" y="-22.853" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="k" width="54.814" height="64.646" x="20.116" y="-38.415" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="l" width="33.541" height="35.313" x="24.641" y="-11.323" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="m" width="54.814" height="64.646" x="-29.286" y="6.009" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="n" width="54.814" height="64.646" x="-29.286" y="6.009" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="o" width="54.814" height="64.646" x="8.244" y="-2.416" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="p" width="39.409" height="43.623" x="18.713" y="10.588" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter></defs></svg>
@@ -0,0 +1,24 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg">
2
+ <symbol id="bluesky-icon" viewBox="0 0 16 17">
3
+ <g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
4
+ <defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
5
+ </symbol>
6
+ <symbol id="discord-icon" viewBox="0 0 20 19">
7
+ <path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
8
+ </symbol>
9
+ <symbol id="documentation-icon" viewBox="0 0 21 20">
10
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
11
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
12
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
13
+ </symbol>
14
+ <symbol id="github-icon" viewBox="0 0 19 19">
15
+ <path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
16
+ </symbol>
17
+ <symbol id="social-icon" viewBox="0 0 20 20">
18
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
19
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
20
+ </symbol>
21
+ <symbol id="x-icon" viewBox="0 0 19 19">
22
+ <path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
23
+ </symbol>
24
+ </svg>
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>frontend</title>
8
+ <script type="module" crossorigin src="/assets/index-BJy89P_N.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-DHekp9vT.css">
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ </body>
14
+ </html>
@@ -0,0 +1,144 @@
1
+ # ISC License
2
+ #
3
+ # Copyright (c) 2018-2025, Andrea Giammarchi, @WebReflection
4
+ #
5
+ # Permission to use, copy, modify, and/or distribute this software for any
6
+ # purpose with or without fee is hereby granted, provided that the above
7
+ # copyright notice and this permission notice appear in all copies.
8
+ #
9
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14
+ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ # PERFORMANCE OF THIS SOFTWARE.
16
+
17
+ import json as _json
18
+
19
+ class _Known:
20
+ def __init__(self):
21
+ self.key = []
22
+ self.value = []
23
+
24
+ class _String:
25
+ def __init__(self, value):
26
+ self.value = value
27
+
28
+ def _array_keys(value):
29
+ for i in range(len(value)):
30
+ yield i
31
+
32
+ def _object_keys(value):
33
+ for key in value:
34
+ yield key
35
+
36
+ def _is_array(value):
37
+ return isinstance(value, (list, tuple))
38
+
39
+ def _is_object(value):
40
+ return isinstance(value, dict)
41
+
42
+ def _is_string(value):
43
+ return isinstance(value, str)
44
+
45
+ def _index(known, input, value):
46
+ input.append(value)
47
+ index = str(len(input) - 1)
48
+ known.key.append(value)
49
+ known.value.append(index)
50
+ return index
51
+
52
+ def _relate(known, input, value):
53
+ if _is_string(value) or _is_array(value) or _is_object(value):
54
+ try:
55
+ return known.value[known.key.index(value)]
56
+ except:
57
+ return _index(known, input, value)
58
+
59
+ return value
60
+
61
+ def _resolver(input, lazy, parsed):
62
+ def resolver(output):
63
+ keys = _array_keys(output) if _is_array(output) else _object_keys(output) if _is_object(output) else []
64
+ for key in keys:
65
+ value = output[key]
66
+ if isinstance(value, _String):
67
+ tmp = input[int(value.value)]
68
+ output[key] = tmp
69
+ if (_is_array(tmp) or _is_object(tmp)) and tmp not in parsed:
70
+ parsed.append(tmp)
71
+ lazy.append([output, key])
72
+
73
+ return output
74
+
75
+ return resolver
76
+
77
+ def _transform(known, input, value):
78
+ if _is_array(value):
79
+ output = []
80
+ for val in value:
81
+ output.append(_relate(known, input, val))
82
+ return output
83
+
84
+ if _is_object(value):
85
+ obj = {}
86
+ for key in value:
87
+ obj[key] = _relate(known, input, value[key])
88
+ return obj
89
+
90
+ return value
91
+
92
+ def _wrap(value):
93
+ if _is_string(value):
94
+ return _String(value)
95
+
96
+ if _is_array(value):
97
+ i = 0
98
+ for val in value:
99
+ value[i] = _wrap(val)
100
+ i += 1
101
+
102
+ elif _is_object(value):
103
+ for key in value:
104
+ value[key] = _wrap(value[key])
105
+
106
+ return value
107
+
108
+ def parse(value, *args, **kwargs):
109
+ json = _json.loads(value, *args, **kwargs)
110
+ wrapped = []
111
+ for value in json:
112
+ wrapped.append(_wrap(value))
113
+
114
+ input = []
115
+ for value in wrapped:
116
+ if isinstance(value, _String):
117
+ input.append(value.value)
118
+ else:
119
+ input.append(value)
120
+
121
+ value = input[0]
122
+ lazy = []
123
+ revive = _resolver(input, lazy, [value])
124
+
125
+ value = revive(value)
126
+
127
+ i = 0
128
+ while i < len(lazy):
129
+ o, k = lazy[i]
130
+ i += 1
131
+ o[k] = revive(o[k])
132
+
133
+ return value
134
+
135
+
136
+ def stringify(value, *args, **kwargs):
137
+ known = _Known()
138
+ input = []
139
+ output = []
140
+ i = int(_index(known, input, value))
141
+ while i < len(input):
142
+ output.append(_transform(known, input, input[i]))
143
+ i += 1
144
+ return _json.dumps(output, *args, **kwargs)
@@ -0,0 +1,43 @@
1
+ """
2
+ process.py
3
+ This file acts as a translator, magically turning your raw CSV uploads into beautiful dashboard charts!
4
+ """
5
+ import pandas as pd
6
+
7
+ def process_uploaded_csv(uploaded_file) -> pd.DataFrame:
8
+ """Process an uploaded monthly traffic CSV file into the format expected by the dashboard."""
9
+ raw_df = pd.read_csv(uploaded_file)
10
+ records = []
11
+ if "repo_name" not in raw_df.columns:
12
+ raise ValueError("Invalid CSV format: missing 'repo_name' column")
13
+
14
+ for repo, group in raw_df.groupby("repo_name"):
15
+ group = group.sort_values("date")
16
+ daily_views = []
17
+ daily_clones = []
18
+ for _, row in group.iterrows():
19
+ timestamp = f"{row['date']}T00:00:00Z"
20
+ if row.get('views', 0) > 0 or row.get('unique_visitors', 0) > 0:
21
+ daily_views.append({"timestamp": timestamp, "count": int(row.get("views", 0)), "uniques": int(row.get("unique_visitors", 0))})
22
+ if row.get('clones', 0) > 0 or row.get('unique_cloners', 0) > 0:
23
+ daily_clones.append({"timestamp": timestamp, "count": int(row.get("clones", 0)), "uniques": int(row.get("unique_cloners", 0))})
24
+
25
+ records.append({
26
+ "Repository": repo,
27
+ "Private": False,
28
+ "Stars": int(group["stars"].max()) if "stars" in group else 0,
29
+ "Forks": int(group["forks"].max()) if "forks" in group else 0,
30
+ "Total Views": int(group["views"].sum()) if "views" in group else 0,
31
+ "Unique Visitors": int(group["unique_visitors"].sum()) if "unique_visitors" in group else 0,
32
+ "Total Clones": int(group["clones"].sum()) if "clones" in group else 0,
33
+ "Unique Cloners": int(group["unique_cloners"].sum()) if "unique_cloners" in group else 0,
34
+ "Top Referrer": None,
35
+ "Top Referrer Views": 0,
36
+ "Top Path": None,
37
+ "Top Path Views": 0,
38
+ "_daily_views": daily_views,
39
+ "_daily_clones": daily_clones,
40
+ "_referrers": [],
41
+ "_paths": []
42
+ })
43
+ return pd.DataFrame(records)
@@ -0,0 +1,201 @@
1
+ Metadata-Version: 2.4
2
+ Name: gitlytics
3
+ Version: 0.1.1
4
+ Summary: Monitor and automate your GitHub repository traffic analytics.
5
+ Keywords: github,traffic,analytics,automation,cli
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: Apache Software License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: requests
13
+ Requires-Dist: pandas
14
+ Requires-Dist: python-dotenv
15
+ Provides-Extra: dashboard
16
+ Requires-Dist: fastapi; extra == "dashboard"
17
+ Requires-Dist: uvicorn; extra == "dashboard"
18
+ Requires-Dist: python-multipart; extra == "dashboard"
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
21
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ <div align="center">
25
+
26
+ # Gitlytics
27
+ ## 🚀 GitHub Traffic Monitor 📊
28
+
29
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
30
+ [![Python](https://img.shields.io/badge/Python-3.9%2B-blue)](https://www.python.org/)
31
+ [![PyPI](https://img.shields.io/pypi/v/gitlytics?color=blue)](https://pypi.org/project/gitlytics/)
32
+ [![React](https://img.shields.io/badge/UI-React-61dafb?logo=react)](https://react.dev/)
33
+ [![FastAPI](https://img.shields.io/badge/Backend-FastAPI-009688?logo=fastapi)](https://fastapi.tiangolo.com/)
34
+
35
+ **Beautiful GitHub traffic analytics for all your repositories — public and private.** 📈
36
+
37
+ Please consider giving this project a ⭐ if you find it helpful!
38
+
39
+ </div>
40
+
41
+ ---
42
+
43
+ > **⚠️ NOTE: NAME AND TECH STACK UPGRADE!**
44
+ > This library was formerly known as `github-traffic-monitor`. We have officially rebranded to **`gitlytics`**!
45
+ >
46
+ > In addition to the name change, we have migrated away from Streamlit. The dashboard is currently a base version working on a new and better **React + Vite** architecture, powered by a **FastAPI** backend!
47
+
48
+ ---
49
+
50
+ A local-only GitHub traffic analytics tool with two modes:
51
+ - **🖥️ Web UI** — Beautiful React + FastAPI dashboard (recommended)
52
+ - **⌨️ CLI** — Terminal output + CSV export
53
+
54
+ View 14-day views, clones, referrers, and popular paths for **all** your repositories. Everything runs on your machine. Your token never leaves your device.
55
+
56
+ ![GitHub Traffic Dashboard](assets/gittracker_thumnail1.png)
57
+
58
+ ---
59
+
60
+ ## 🚨 The 14-Day Catch (And How to Fix It!)
61
+
62
+ > **⚠️ Did you know?** GitHub normally **only saves your repository traffic data for 14 days**. After two weeks, your valuable views and clones data is permanently deleted.
63
+
64
+ **Don't lose your data!** We built a companion automation tool that runs silently in the background every 13 days using GitHub Actions to fetch and save your data permanently.
65
+
66
+ 👉 **[Set up GitHub Traffic Automation here](https://github.com/ameyac11/github-traffic-monitor-automation)** (It takes literally 2 minutes to set up!)
67
+
68
+ Once you have your automated data saved, you can seamlessly plug it right into this dashboard to visualize your beautiful, long-term historical charts.
69
+
70
+ ---
71
+
72
+ ## ✨ Features
73
+
74
+ | Feature | React UI | CLI |
75
+ |---|:---:|:---:|
76
+ | **Dual Mode Interface** (Live API & CSV Upload) | ✅ | ❌ |
77
+ | Token input (no hardcoding) | ✅ | ✅ |
78
+ | Upload & visualize historical CSV data | ✅ | ❌ |
79
+ | Summary metrics (views, clones, stars, forks) | ✅ | ✅ |
80
+ | Animated Area & Pie charts per repository | ✅ | ❌ |
81
+ | Per-repo daily views & clones chart | ✅ | ✅ |
82
+ | Top referrers & popular paths | ✅ | ✅ |
83
+ | Expandable repository list | ✅ | ❌ |
84
+ | Export to CSV | ✅ (download button) | ✅ (file) |
85
+ | Runs 100% locally | ✅ | ✅ |
86
+
87
+ ---
88
+
89
+ ## 🛠️ Installation
90
+
91
+ You can install the package directly from PyPI.
92
+
93
+ ```bash
94
+ # Basic CLI installation
95
+ pip install gitlytics
96
+
97
+ # Installation with Dashboard UI support
98
+ pip install "gitlytics[dashboard]"
99
+ ```
100
+
101
+ ### Generating a GitHub Personal Access Token (PAT)
102
+ To use either the CLI or Dashboard, you'll need a GitHub token.
103
+
104
+ 1. Go to **[GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)](https://github.com/settings/tokens)**
105
+ 2. Click **Generate new token (classic)**
106
+ 3. Select the **`repo`** scope — required to read traffic data for private repositories
107
+ 4. Click **Generate token** and **copy it immediately**
108
+
109
+ > **🔒 Security Note:** Your token is completely safe, used only on your machine, and never sent to any external server.
110
+
111
+ ---
112
+
113
+ ## 🖥️ Run: React Dashboard (Recommended)
114
+
115
+ If you installed with the `[dashboard]` extra, you can launch the beautiful web UI with a single command:
116
+
117
+ ```bash
118
+ gitlytics dashboard
119
+ ```
120
+
121
+ The server opens automatically in your terminal and you can view your dashboard at `http://localhost:8000`.
122
+
123
+ ---
124
+
125
+ ## ⌨️ Run: CLI (Terminal Mode)
126
+
127
+ If you just want terminal output or to export CSV files, you can use the CLI commands.
128
+
129
+ **Fetch data and print to terminal:**
130
+ ```bash
131
+ gitlytics fetch --token ghp_your_token_here
132
+ ```
133
+
134
+ **Fetch data and save to a specific CSV file:**
135
+ ```bash
136
+ gitlytics fetch --token ghp_your_token_here --output my_report.csv
137
+ ```
138
+
139
+ **Sync data (Append today's traffic to historical monthly CSVs):**
140
+ ```bash
141
+ gitlytics sync --token ghp_your_token_here --dir ./data
142
+ ```
143
+
144
+ You can also store your token in a `.env` file as `GITHUB_TOKEN=ghp_...` so you don't have to type it out every time.
145
+
146
+ ---
147
+
148
+ ## 📊 CSV Output Columns
149
+
150
+ | Column | Description |
151
+ |---|---|
152
+ | `Repository` | Full repo name (`user/repo`) |
153
+ | `Private` | `True` / `False` |
154
+ | `Stars` | Current star count |
155
+ | `Forks` | Current fork count |
156
+ | `Total Views` | Page views in last 14 days |
157
+ | `Unique Visitors` | Unique visitors in last 14 days |
158
+ | `Total Clones` | Clone count in last 14 days |
159
+ | `Unique Cloners` | Unique cloners in last 14 days |
160
+ | `Top Referrer` | Highest-traffic referral source |
161
+ | `Top Referrer Views` | View count from top referrer |
162
+ | `Top Path` | Most visited path |
163
+ | `Top Path Views` | View count for top path |
164
+ | `Fetched At` | UTC timestamp of the fetch |
165
+
166
+ ---
167
+
168
+ ## ⚠️ Requirements
169
+
170
+ - **Python 3.9+**
171
+ - A GitHub account with at least one repository
172
+ - A GitHub Personal Access Token with the `repo` scope
173
+
174
+ ---
175
+
176
+ ## 🛠️ Development Install
177
+
178
+ ```bash
179
+ git clone https://github.com/ameyac11/github-traffic-monitor
180
+ cd github-traffic-monitor
181
+ pip install -e ".[dev,dashboard]"
182
+ ```
183
+
184
+ ## 🧪 Running Tests
185
+
186
+ ```bash
187
+ pip install pytest
188
+ pytest
189
+ ```
190
+
191
+ ---
192
+
193
+ ## 🌟 Show Your Support
194
+
195
+ If you find this project useful, please consider giving it a ⭐ on [GitHub](https://github.com/ameyac11/github-traffic-monitor)! It helps more people discover the tool.
196
+
197
+ ---
198
+
199
+ ## 📄 License
200
+
201
+ This project is licensed under the [Apache License 2.0](LICENSE).
@@ -0,0 +1,19 @@
1
+ github_traffic/__init__.py,sha256=kgreBtat6L0mg1KKTczkRkZefdSADKsGKOumIlpIug8,94
2
+ github_traffic/api.py,sha256=Sgx6L7eHMKvkc-udOmSAak4JIH60sxmM56RoEpHaB8w,2584
3
+ github_traffic/automation.py,sha256=fKF59up5pWifVJoZ4umDUrPPH9MkW-kNvN8bf0lfTm8,4688
4
+ github_traffic/cli.py,sha256=AZ1CER93WCo1jUkcMXZRs_v52mPJ6ixv26uhgGJgUZs,5215
5
+ github_traffic/core.py,sha256=cxmx3aySV1Njp8ac__toJf2w_D9gxO9vc8sZVkqzWn0,5715
6
+ github_traffic/process.py,sha256=abiL3tfetXauumavmM-EXae3YR4NhvxyIWnnfalAZsU,2102
7
+ github_traffic/frontend/dist/favicon.svg,sha256=YbyaFh3lgkgojmkFQl1xgPBiTChlAHuX12P9rBIEOmY,9522
8
+ github_traffic/frontend/dist/icons.svg,sha256=tF-lBhlc_N70BrqfDHezbdwafCJAQJJuxwq8L96nuTo,5031
9
+ github_traffic/frontend/dist/index.html,sha256=rlfebm_5jlK_t_m2QNpwEbaXj6N4_CLSLbFNMHztkns,458
10
+ github_traffic/frontend/dist/assets/axios-BATw4G7Y.js,sha256=jjohykm-H6HmDTGJ5XY18qawwZaQanr-418V185Vw48,44446
11
+ github_traffic/frontend/dist/assets/index-BJy89P_N.js,sha256=S88GdAEkToLg7Rs0SDSCIh_53llbEO_YtWqUgdHqpRY,594449
12
+ github_traffic/frontend/dist/assets/index-DHekp9vT.css,sha256=Sq1lJpvSYIo65UZadjVk3vdSlUpsWFgKHBNmra6O6-0,5599
13
+ github_traffic/frontend/node_modules/flatted/python/flatted.py,sha256=94TCVN52olQ166phxylCByczrktCYZuUO_N7CfpF5kQ,3773
14
+ gitlytics-0.1.1.dist-info/licenses/LICENSE,sha256=JHzLZOs2TJfPNmptk_TON-mgNVCLPGUISt_cqityB4s,11354
15
+ gitlytics-0.1.1.dist-info/METADATA,sha256=dUdR8Z0mmpszdq07AghbNVfZbMiREgsE11hoCDdBo08,6623
16
+ gitlytics-0.1.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
17
+ gitlytics-0.1.1.dist-info/entry_points.txt,sha256=X4MpjNM57OumkaYliCopn8ScZX4JoApYqMdGO1Ex84s,54
18
+ gitlytics-0.1.1.dist-info/top_level.txt,sha256=Eq5BxYnfGnSOgUfSChuUfF9u2mL5hY0C1WBJ7R0iJzk,15
19
+ gitlytics-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ gitlytics = github_traffic.cli:main