golang.org/x/build@v0.0.0-20240506185731-218518f32b70/devapp/static/gophercon/index.html (about)

     1  <!DOCTYPE html>
     2  <!--
     3   Copyright 2022 The Go Authors. All rights reserved.
     4   Use of this source code is governed by a BSD-style
     5   license that can be found in the LICENSE file.
     6  -->
     7  
     8  <meta charset="utf-8">
     9  <title>GopherCon 2017 Contribution Dashboard</title>
    10  <meta name=viewport content="width=device-width,minimum-scale=1,maximum-scale=1">
    11  <style>
    12  * {
    13    box-sizing: border-box;
    14    margin: 0;
    15    padding: 0;
    16  }
    17  a:link,
    18  a:visited {
    19    color: #fff;
    20  }
    21  .Site {
    22    background-color: #2a2a2a;
    23    color: #fff;
    24    display: flex;
    25    flex-direction: column;
    26    font: 14px 'Helvetica-Neue', Helvetica, sans-serif;
    27    height: 100vh;
    28    text-rendering: optimizeLegibility;
    29  }
    30  .Site-body {
    31    display: flex;
    32    flex: 1;
    33  }
    34  .Site-content {
    35    border-right: 1px solid #3a3939;
    36    overflow: hidden;
    37    padding: 1.5em;
    38    width: 60%;
    39  }
    40  .Site-activity {
    41    background-color: #323232;
    42    flex: 1;
    43    overflow: scroll;
    44  }
    45  .Site-logo {
    46    height: 60px;
    47    margin-right: 2em;
    48  }
    49  .Site-pointsTitle,
    50  .Site-points {
    51    text-align: center;
    52  }
    53  .Site-pointsTitle {
    54    font-size: 4vh;
    55    letter-spacing: 1px;
    56    text-transform: uppercase;
    57  }
    58  .Site-points {
    59    font-size: 30vh;
    60  }
    61  .u-avatar {
    62    border-radius: 50%;
    63  }
    64  .AvatarGroup {
    65    display: flex;
    66    flex-wrap: wrap;
    67    justify-content: center;
    68  }
    69  .AvatarGroup-avatar {
    70    height: 6vh;
    71    margin: 0 .5em .5em 0;
    72    width: 6vh;
    73  }
    74  .Activity {
    75    align-items: flex-start;
    76    background-color: #323232;
    77    border-bottom: 1px solid #2d2d2d;
    78    border-top: 1px solid #404040;
    79    display: flex;
    80    font-size: 2vw;
    81    padding: 1em;
    82  }
    83  .Activity-avatar {
    84    height: 2.5em;
    85    margin-right: .75em;
    86    width: 2.5em;
    87  }
    88  .Activity-main {
    89    flex: 1;
    90    margin-right: .15em;
    91  }
    92  .Activity-points {
    93    color: #85ebf9;
    94    font-size: .85em;
    95    margin-top: .25em;
    96  }
    97  .Activity-icon {
    98    font-size: 2em;
    99  }
   100  .Site-footer {
   101    align-items: center;
   102    background: #3a3737;
   103    display: flex;
   104    justify-content: space-between;
   105    padding: 1em 1.5em;
   106  }
   107  </style>
   108  <body class="Site">
   109    <div class="Site-body">
   110      <main class="Site-content">
   111        <div class="Site-pointsTitle">Total points</div>
   112        <div class="Site-points js-totalPoints">0</div>
   113        <div class="AvatarGroup js-avatarGroup"></div>
   114      </main>
   115      <aside class="Site-activity js-activityList"></aside>
   116    </div>
   117    <footer class="Site-footer">
   118      <img class="Site-logo" src="https://github.com/ashleymcnamara/gophers/raw/master/GoCommunity.png" alt="Go Community">
   119      <div>
   120        Gopher artwork by <a href="https://github.com/ashleymcnamara/gophers" target="_blank">Ashley McNamara</a>
   121        based on the original artwork by the amazing
   122        <a href="https://reneefrench.blogspot.com/" target="_blank">Renee French</a>.
   123        Licensed under a <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.</a>
   124      </div>
   125    </footer>
   126  </body>
   127  
   128  <template class="activityTemplate">
   129    <div class="Activity">
   130      <img class="u-avatar Activity-avatar js-avatar">
   131      <div class="Activity-main">
   132        <div class="Activity-body js-body"></div>
   133        <div class="Activity-points js-points"></div>
   134      </div>
   135      <div class="Activity-icon js-icon"></div>
   136    </div>
   137  </template>
   138  
   139  <script>
   140  (function() {
   141    'use strict';
   142  
   143    const ActivityType = {
   144      AMEND_CHANGE: 'AMEND_CHANGE',
   145      CREATE_CHANGE: 'CREATE_CHANGE',
   146      MERGE_CHANGE: 'MERGE_CHANGE',
   147      REGISTER: 'REGISTER',
   148    };
   149  
   150    const iconMap = {};
   151    iconMap.AMEND_CHANGE = '👍';
   152    iconMap.CREATE_CHANGE = '👏';
   153    iconMap.MERGE_CHANGE = '🤘';
   154    iconMap.REGISTER = '🎉';
   155  
   156    let lastUpdateMs = 0;
   157    getActivities(lastUpdateMs);
   158    startUpdateLoop();
   159  
   160    function getActivities(since) {
   161      const url = `/_/activities?since=${since}`;
   162      fetch(url).then(resp => {
   163        resp.json().then(obj => {
   164          processAll(obj.activities);
   165          updatePoints(obj.totalPoints);
   166        });
   167      }).catch(err => {
   168        console.error(err);
   169      });
   170    }
   171  
   172    function startUpdateLoop() {
   173      window.setInterval(() => {
   174        getActivities(lastUpdateMs);
   175      }, 5000);
   176    }
   177  
   178    // Username => img element.
   179    let avatarMap = {};
   180  
   181    function processAll(activities) {
   182      const activityListEl = document.querySelector('.js-activityList');
   183      const avatarGroupEl = document.querySelector('.js-avatarGroup');
   184      activities.forEach(activity => {
   185        if (!avatarMap[activity.gitHubUser]) {
   186          const el = createAvatarEl(activity.gitHubUser);
   187          el.classList.add('AvatarGroup-avatar');
   188          avatarMap[activity.gitHubUser] = el;
   189        }
   190        avatarGroupEl.insertBefore(avatarMap[activity.gitHubUser],
   191            avatarGroupEl.firstChild);
   192        const activityEl = createActivityEl(activity);
   193        activityListEl.insertBefore(activityEl, activityListEl.firstChild);
   194      });
   195      if (activities.length > 0) {
   196        lastUpdateMs = new Date(activities[activities.length - 1].created).getTime();
   197      }
   198    }
   199  
   200    function updatePoints(points) {
   201      document.querySelector('.js-totalPoints').textContent = points;
   202    }
   203  
   204    function createAvatarEl(username) {
   205      let img = document.createElement('IMG');
   206      img.classList.add('u-avatar');
   207      img.src = avatarSrc(username);
   208      img.alt = avatarAlt(username);
   209      return img;
   210    }
   211  
   212    function avatarSrc(username) {
   213      return `https://github.com/${encodeURIComponent(username)}.png?size=100`;
   214    }
   215  
   216    function avatarAlt(username) {
   217      return `Avatar for ${username}`;
   218    }
   219  
   220    function activityBody(type, username) {
   221      switch (type) {
   222        case ActivityType.AMEND_CHANGE:
   223        return `${username} just amended a change!`;
   224  
   225        case ActivityType.CREATE_CHANGE:
   226        return `${username} just created a change!`;
   227  
   228        case ActivityType.MERGE_CHANGE:
   229        return `${username} just merged a change!`;
   230  
   231        case ActivityType.REGISTER:
   232        return `${username} just registered!`;
   233      }
   234    }
   235  
   236    function pointsStr(points) {
   237      return `+${points} Point` + (points > 1 ? 's' : '');
   238    }
   239  
   240    function createActivityEl(activity) {
   241      const tmpl = document.querySelector('.activityTemplate');
   242      const imgEl = tmpl.content.querySelector('.js-avatar');
   243      imgEl.src = avatarSrc(activity.gitHubUser);
   244      imgEl.alt = avatarAlt(activity.gitHubUser);
   245      tmpl.content.querySelector('.js-icon').textContent = iconMap[activity.type];
   246      tmpl.content.querySelector('.js-body').textContent =
   247          activityBody(activity.type, activity.gitHubUser);
   248      tmpl.content.querySelector('.js-points').textContent =
   249          pointsStr(activity.points);
   250      return document.importNode(tmpl.content, true);
   251    }
   252  })();
   253  </script>