| @@ -85,8 +85,6 @@ MAX_DISPLAY_FILE_SIZE = 8388608 | |||
| SHOW_USER_EMAIL = true | |||
| ; Set the default theme for the Gitea install | |||
| DEFAULT_THEME = gitea | |||
| ; Set the color range to use for heatmap (default to `['#f4f4f4', '#459928']` but can use `['#2d303b', '#80bb46']` with the theme `arc-green`) | |||
| HEATMAP_COLOR_RANGE = `['#f4f4f4', '#459928']` | |||
| [ui.admin] | |||
| ; Number of users that are displayed on one page | |||
| @@ -301,7 +301,6 @@ var ( | |||
| MaxDisplayFileSize int64 | |||
| ShowUserEmail bool | |||
| DefaultTheme string | |||
| HeatmapColorRange string | |||
| Admin struct { | |||
| UserPagingNum int | |||
| @@ -328,7 +327,6 @@ var ( | |||
| ThemeColorMetaTag: `#6cc644`, | |||
| MaxDisplayFileSize: 8388608, | |||
| DefaultTheme: `gitea`, | |||
| HeatmapColorRange: `['#f4f4f4', '#459928']`, | |||
| Admin: struct { | |||
| UserPagingNum int | |||
| RepoPagingNum int | |||
| @@ -193,9 +193,6 @@ func NewFuncMap() []template.FuncMap { | |||
| "DefaultTheme": func() string { | |||
| return setting.UI.DefaultTheme | |||
| }, | |||
| "HeatmapColorRange": func() string { | |||
| return setting.UI.HeatmapColorRange | |||
| }, | |||
| "dict": func(values ...interface{}) (map[string]interface{}, error) { | |||
| if len(values) == 0 { | |||
| return nil, errors.New("invalid dict call") | |||
| @@ -2293,6 +2293,96 @@ function cancelStopwatch() { | |||
| $("#cancel_stopwatch_form").submit(); | |||
| } | |||
| function initHeatmap(appElementId, heatmapUser, locale) { | |||
| var el = document.getElementById(appElementId); | |||
| if (!el) { | |||
| return; | |||
| } | |||
| locale = locale || {}; | |||
| locale.contributions = locale.contributions || 'contributions'; | |||
| locale.no_contributions = locale.no_contributions || 'No contributions'; | |||
| var vueDelimeters = ['${', '}']; | |||
| Vue.component('activity-heatmap', { | |||
| delimiters: vueDelimeters, | |||
| props: { | |||
| user: { | |||
| type: String, | |||
| required: true | |||
| }, | |||
| suburl: { | |||
| type: String, | |||
| required: true | |||
| }, | |||
| locale: { | |||
| type: Object, | |||
| required: true | |||
| } | |||
| }, | |||
| data: function () { | |||
| return { | |||
| isLoading: true, | |||
| colorRange: [], | |||
| endDate: null, | |||
| values: [] | |||
| }; | |||
| }, | |||
| mounted: function() { | |||
| this.colorRange = [ | |||
| this.getColor(0), | |||
| this.getColor(1), | |||
| this.getColor(2), | |||
| this.getColor(3), | |||
| this.getColor(4), | |||
| this.getColor(5) | |||
| ]; | |||
| console.log(this.colorRange); | |||
| this.endDate = new Date(); | |||
| this.loadHeatmap(this.user); | |||
| }, | |||
| methods: { | |||
| loadHeatmap: function(userName) { | |||
| var self = this; | |||
| $.get(this.suburl + '/api/v1/users/' + userName + '/heatmap', function(chartRawData) { | |||
| var chartData = []; | |||
| for (var i = 0; i < chartRawData.length; i++) { | |||
| chartData[i] = { date: new Date(chartRawData[i].timestamp * 1000), count: chartRawData[i].contributions }; | |||
| } | |||
| self.values = chartData; | |||
| self.isLoading = false; | |||
| }); | |||
| }, | |||
| getColor: function(idx) { | |||
| var el = document.createElement('div'); | |||
| el.className = 'heatmap-color-' + idx; | |||
| return getComputedStyle(el).backgroundColor; | |||
| } | |||
| }, | |||
| template: '<div><div v-show="isLoading"><slot name="loading"></slot></div><calendar-heatmap v-show="!isLoading" :locale="locale" :no-data-text="locale.no_contributions" :tooltip-unit="locale.contributions" :end-date="endDate" :values="values" :range-color="colorRange" />' | |||
| }); | |||
| new Vue({ | |||
| delimiters: vueDelimeters, | |||
| el: el, | |||
| data: { | |||
| suburl: document.querySelector('meta[name=_suburl]').content, | |||
| heatmapUser: heatmapUser, | |||
| locale: locale | |||
| }, | |||
| }); | |||
| } | |||
| function initFilterBranchTagDropdown(selector) { | |||
| $(selector).each(function() { | |||
| var $dropdown = $(this); | |||
| @@ -605,3 +605,27 @@ footer { | |||
| } | |||
| } | |||
| } | |||
| .heatmap-color-0 { | |||
| background-color: #f4f4f4; | |||
| } | |||
| .heatmap-color-1 { | |||
| background-color: #d7e5db; | |||
| } | |||
| .heatmap-color-2 { | |||
| background-color: #adc7ab; | |||
| } | |||
| .heatmap-color-3 { | |||
| background-color: #83a87b; | |||
| } | |||
| .heatmap-color-4 { | |||
| background-color: #598a4b; | |||
| } | |||
| .heatmap-color-5 { | |||
| background-color: #2f6b1b; | |||
| } | |||
| @@ -818,3 +818,7 @@ | |||
| color: #9e9e9e; | |||
| } | |||
| } | |||
| .heatmap-color-0 { | |||
| background-color: #2d303b; | |||
| } | |||
| @@ -136,14 +136,9 @@ | |||
| <td><a href="https://github.com/swagger-api/swagger-ui/archive/v3.0.4.tar.gz">swagger-ui-v3.0.4.tar.gz</a></td> | |||
| </tr> | |||
| <tr> | |||
| <td><a href="./plugins/d3/">d3</a></td> | |||
| <td><a href="https://github.com/d3/d3/blob/master/LICENSE">BSD 3-Clause</a></td> | |||
| <td><a href="https://github.com/d3/d3/releases/download/v4.13.0/d3.zip">d3.zip</a></td> | |||
| </tr> | |||
| <tr> | |||
| <td><a href="./plugins/calendar-heatmap/">calendar-heatmap</a></td> | |||
| <td><a href="https://github.com/DKirwan/calendar-heatmap/blob/master/LICENSE">MIT</a></td> | |||
| <td><a href="https://github.com/DKirwan/calendar-heatmap/archive/master.zip">337b431.zip</a></td> | |||
| <td><a href="./plugins/vue-calendar-heatmap">vue-calendar-heatmap</a></td> | |||
| <td><a href="https://github.com/WildCodeSchool/vue-calendar-heatmap/blob/master/README.md">MIT</a></td> | |||
| <td><a href="https://github.com/WildCodeSchool/vue-calendar-heatmap/archive/master.zip">7f48b20.zip</a></td> | |||
| </tr> | |||
| <tr> | |||
| <td><a href="./plugins/moment/">moment.js</a></td> | |||
| @@ -1,27 +0,0 @@ | |||
| text.month-name, | |||
| text.calendar-heatmap-legend-text, | |||
| text.day-initial { | |||
| font-size: 10px; | |||
| fill: inherit; | |||
| font-family: Helvetica, arial, 'Open Sans', sans-serif; | |||
| } | |||
| rect.day-cell:hover { | |||
| stroke: #555555; | |||
| stroke-width: 1px; | |||
| } | |||
| .day-cell-tooltip { | |||
| position: absolute; | |||
| z-index: 9999; | |||
| padding: 5px 9px; | |||
| color: #bbbbbb; | |||
| font-size: 12px; | |||
| background: rgba(0, 0, 0, 0.85); | |||
| border-radius: 3px; | |||
| text-align: center; | |||
| } | |||
| .day-cell-tooltip > span { | |||
| font-family: Helvetica, arial, 'Open Sans', sans-serif | |||
| } | |||
| .calendar-heatmap { | |||
| box-sizing: initial; | |||
| } | |||
| @@ -1,311 +0,0 @@ | |||
| // https://github.com/DKirwan/calendar-heatmap | |||
| function calendarHeatmap() { | |||
| // defaults | |||
| var width = 750; | |||
| var height = 110; | |||
| var legendWidth = 150; | |||
| var selector = 'body'; | |||
| var SQUARE_LENGTH = 11; | |||
| var SQUARE_PADDING = 2; | |||
| var MONTH_LABEL_PADDING = 6; | |||
| var now = moment().endOf('day').toDate(); | |||
| var yearAgo = moment().startOf('day').subtract(1, 'year').toDate(); | |||
| var startDate = null; | |||
| var counterMap= {}; | |||
| var data = []; | |||
| var max = null; | |||
| var colorRange = ['#D8E6E7', '#218380']; | |||
| var tooltipEnabled = true; | |||
| var tooltipUnit = 'contribution'; | |||
| var legendEnabled = true; | |||
| var onClick = null; | |||
| var weekStart = 1; //0 for Sunday, 1 for Monday | |||
| var locale = { | |||
| months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], | |||
| days: ['S', 'M', 'T', 'W', 'T', 'F', 'S'], | |||
| No: 'No', | |||
| on: 'on', | |||
| Less: 'Less', | |||
| More: 'More' | |||
| }; | |||
| var v = Number(d3.version.split('.')[0]); | |||
| // setters and getters | |||
| chart.data = function (value) { | |||
| if (!arguments.length) { return data; } | |||
| data = value; | |||
| counterMap= {}; | |||
| data.forEach(function (element, index) { | |||
| var key= moment(element.date).format( 'YYYY-MM-DD' ); | |||
| var counter= counterMap[key] || 0; | |||
| counterMap[key]= counter + element.count; | |||
| }); | |||
| return chart; | |||
| }; | |||
| chart.max = function (value) { | |||
| if (!arguments.length) { return max; } | |||
| max = value; | |||
| return chart; | |||
| }; | |||
| chart.selector = function (value) { | |||
| if (!arguments.length) { return selector; } | |||
| selector = value; | |||
| return chart; | |||
| }; | |||
| chart.startDate = function (value) { | |||
| if (!arguments.length) { return startDate; } | |||
| yearAgo = value; | |||
| now = moment(value).endOf('day').add(1, 'year').toDate(); | |||
| return chart; | |||
| }; | |||
| chart.colorRange = function (value) { | |||
| if (!arguments.length) { return colorRange; } | |||
| colorRange = value; | |||
| return chart; | |||
| }; | |||
| chart.tooltipEnabled = function (value) { | |||
| if (!arguments.length) { return tooltipEnabled; } | |||
| tooltipEnabled = value; | |||
| return chart; | |||
| }; | |||
| chart.tooltipUnit = function (value) { | |||
| if (!arguments.length) { return tooltipUnit; } | |||
| tooltipUnit = value; | |||
| return chart; | |||
| }; | |||
| chart.legendEnabled = function (value) { | |||
| if (!arguments.length) { return legendEnabled; } | |||
| legendEnabled = value; | |||
| return chart; | |||
| }; | |||
| chart.onClick = function (value) { | |||
| if (!arguments.length) { return onClick(); } | |||
| onClick = value; | |||
| return chart; | |||
| }; | |||
| chart.locale = function (value) { | |||
| if (!arguments.length) { return locale; } | |||
| locale = value; | |||
| return chart; | |||
| }; | |||
| function chart() { | |||
| d3.select(chart.selector()).selectAll('svg.calendar-heatmap').remove(); // remove the existing chart, if it exists | |||
| var dateRange = ((d3.time && d3.time.days) || d3.timeDays)(yearAgo, now); // generates an array of date objects within the specified range | |||
| var monthRange = ((d3.time && d3.time.months) || d3.timeMonths)(moment(yearAgo).startOf('month').toDate(), now); // it ignores the first month if the 1st date is after the start of the month | |||
| var firstDate = moment(dateRange[0]); | |||
| if (chart.data().length == 0) { | |||
| max = 0; | |||
| } else if (max === null) { | |||
| max = d3.max(chart.data(), function (d) { return d.count; }); // max data value | |||
| } | |||
| // color range | |||
| var color = ((d3.scale && d3.scale.linear) || d3.scaleLinear)() | |||
| .range(chart.colorRange()) | |||
| .domain([0, max]); | |||
| var tooltip; | |||
| var dayRects; | |||
| drawChart(); | |||
| function drawChart() { | |||
| var svg = d3.select(chart.selector()) | |||
| .style('position', 'relative') | |||
| .append('svg') | |||
| .attr('width', width) | |||
| .attr('class', 'calendar-heatmap') | |||
| .attr('height', height) | |||
| .style('padding', '36px'); | |||
| dayRects = svg.selectAll('.day-cell') | |||
| .data(dateRange); // array of days for the last yr | |||
| var enterSelection = dayRects.enter().append('rect') | |||
| .attr('class', 'day-cell') | |||
| .attr('width', SQUARE_LENGTH) | |||
| .attr('height', SQUARE_LENGTH) | |||
| .attr('fill', function(d) { return color(countForDate(d)); }) | |||
| .attr('x', function (d, i) { | |||
| var cellDate = moment(d); | |||
| var result = cellDate.week() - firstDate.week() + (firstDate.weeksInYear() * (cellDate.weekYear() - firstDate.weekYear())); | |||
| return result * (SQUARE_LENGTH + SQUARE_PADDING); | |||
| }) | |||
| .attr('y', function (d, i) { | |||
| return MONTH_LABEL_PADDING + formatWeekday(d.getDay()) * (SQUARE_LENGTH + SQUARE_PADDING); | |||
| }); | |||
| if (typeof onClick === 'function') { | |||
| (v === 3 ? enterSelection : enterSelection.merge(dayRects)).on('click', function(d) { | |||
| var count = countForDate(d); | |||
| onClick({ date: d, count: count}); | |||
| }); | |||
| } | |||
| if (chart.tooltipEnabled()) { | |||
| (v === 3 ? enterSelection : enterSelection.merge(dayRects)).on('mouseover', function(d, i) { | |||
| tooltip = d3.select(chart.selector()) | |||
| .append('div') | |||
| .attr('class', 'day-cell-tooltip') | |||
| .html(tooltipHTMLForDate(d)) | |||
| .style('left', function () { return Math.floor(i / 7) * SQUARE_LENGTH + 'px'; }) | |||
| .style('top', function () { | |||
| return formatWeekday(d.getDay()) * (SQUARE_LENGTH + SQUARE_PADDING) + MONTH_LABEL_PADDING * 2 + 'px'; | |||
| }); | |||
| }) | |||
| .on('mouseout', function (d, i) { | |||
| tooltip.remove(); | |||
| }); | |||
| } | |||
| if (chart.legendEnabled()) { | |||
| var colorRange = [color(0)]; | |||
| for (var i = 3; i > 0; i--) { | |||
| colorRange.push(color(max / i)); | |||
| } | |||
| var legendGroup = svg.append('g'); | |||
| legendGroup.selectAll('.calendar-heatmap-legend') | |||
| .data(colorRange) | |||
| .enter() | |||
| .append('rect') | |||
| .attr('class', 'calendar-heatmap-legend') | |||
| .attr('width', SQUARE_LENGTH) | |||
| .attr('height', SQUARE_LENGTH) | |||
| .attr('x', function (d, i) { return (width - legendWidth) + (i + 1) * 13; }) | |||
| .attr('y', height + SQUARE_PADDING) | |||
| .attr('fill', function (d) { return d; }); | |||
| legendGroup.append('text') | |||
| .attr('class', 'calendar-heatmap-legend-text calendar-heatmap-legend-text-less') | |||
| .attr('x', width - legendWidth - 13) | |||
| .attr('y', height + SQUARE_LENGTH) | |||
| .text(locale.Less); | |||
| legendGroup.append('text') | |||
| .attr('class', 'calendar-heatmap-legend-text calendar-heatmap-legend-text-more') | |||
| .attr('x', (width - legendWidth + SQUARE_PADDING) + (colorRange.length + 1) * 13) | |||
| .attr('y', height + SQUARE_LENGTH) | |||
| .text(locale.More); | |||
| } | |||
| dayRects.exit().remove(); | |||
| var monthLabels = svg.selectAll('.month') | |||
| .data(monthRange) | |||
| .enter().append('text') | |||
| .attr('class', 'month-name') | |||
| .text(function (d) { | |||
| return locale.months[d.getMonth()]; | |||
| }) | |||
| .attr('x', function (d, i) { | |||
| var matchIndex = 0; | |||
| dateRange.find(function (element, index) { | |||
| matchIndex = index; | |||
| return moment(d).isSame(element, 'month') && moment(d).isSame(element, 'year'); | |||
| }); | |||
| return Math.floor(matchIndex / 7) * (SQUARE_LENGTH + SQUARE_PADDING); | |||
| }) | |||
| .attr('y', 0); // fix these to the top | |||
| locale.days.forEach(function (day, index) { | |||
| index = formatWeekday(index); | |||
| if (index % 2) { | |||
| svg.append('text') | |||
| .attr('class', 'day-initial') | |||
| .attr('transform', 'translate(-8,' + (SQUARE_LENGTH + SQUARE_PADDING) * (index + 1) + ')') | |||
| .style('text-anchor', 'middle') | |||
| .attr('dy', '2') | |||
| .text(day); | |||
| } | |||
| }); | |||
| } | |||
| function pluralizedTooltipUnit (count) { | |||
| if ('string' === typeof tooltipUnit) { | |||
| return (tooltipUnit + (count === 1 ? '' : 's')); | |||
| } | |||
| for (var i in tooltipUnit) { | |||
| var _rule = tooltipUnit[i]; | |||
| var _min = _rule.min; | |||
| var _max = _rule.max || _rule.min; | |||
| _max = _max === 'Infinity' ? Infinity : _max; | |||
| if (count >= _min && count <= _max) { | |||
| return _rule.unit; | |||
| } | |||
| } | |||
| } | |||
| function tooltipHTMLForDate(d) { | |||
| var dateStr = moment(d).format('ddd, MMM Do YYYY'); | |||
| var count = countForDate(d); | |||
| return '<span><strong>' + (count ? count : locale.No) + ' ' + pluralizedTooltipUnit(count) + '</strong> ' + locale.on + ' ' + dateStr + '</span>'; | |||
| } | |||
| function countForDate(d) { | |||
| var key= moment(d).format( 'YYYY-MM-DD' ); | |||
| return counterMap[key] || 0; | |||
| } | |||
| function formatWeekday(weekDay) { | |||
| if (weekStart === 1) { | |||
| if (weekDay === 0) { | |||
| return 6; | |||
| } else { | |||
| return weekDay - 1; | |||
| } | |||
| } | |||
| return weekDay; | |||
| } | |||
| var daysOfChart = chart.data().map(function (day) { | |||
| return day.date.toDateString(); | |||
| }); | |||
| } | |||
| return chart; | |||
| } | |||
| // polyfill for Array.find() method | |||
| /* jshint ignore:start */ | |||
| if (!Array.prototype.find) { | |||
| Array.prototype.find = function (predicate) { | |||
| if (this === null) { | |||
| throw new TypeError('Array.prototype.find called on null or undefined'); | |||
| } | |||
| if (typeof predicate !== 'function') { | |||
| throw new TypeError('predicate must be a function'); | |||
| } | |||
| var list = Object(this); | |||
| var length = list.length >>> 0; | |||
| var thisArg = arguments[1]; | |||
| var value; | |||
| for (var i = 0; i < length; i++) { | |||
| value = list[i]; | |||
| if (predicate.call(thisArg, value, i, list)) { | |||
| return value; | |||
| } | |||
| } | |||
| return undefined; | |||
| }; | |||
| } | |||
| /* jshint ignore:end */ | |||
| @@ -0,0 +1,112 @@ | |||
| svg.vch__wrapper[data-v-a9cfea66] { | |||
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; | |||
| line-height: 10px; | |||
| } | |||
| svg.vch__wrapper .vch__months__labels__wrapper text.vch__month__label[data-v-a9cfea66] { | |||
| font-size: 10px; | |||
| } | |||
| svg.vch__wrapper .vch__days__labels__wrapper text.vch__day__label[data-v-a9cfea66], | |||
| svg.vch__wrapper .vch__legend__wrapper text[data-v-a9cfea66] { | |||
| font-size: 9px; | |||
| } | |||
| svg.vch__wrapper .vch__months__labels__wrapper text.vch__month__label[data-v-a9cfea66], | |||
| svg.vch__wrapper .vch__days__labels__wrapper text.vch__day__label[data-v-a9cfea66], | |||
| svg.vch__wrapper .vch__legend__wrapper text[data-v-a9cfea66] { | |||
| fill: #767676; | |||
| } | |||
| svg.vch__wrapper rect.vch__day__square[data-v-a9cfea66]:hover { | |||
| stroke: #555; | |||
| stroke-width: 1px; | |||
| } | |||
| svg.vch__wrapper rect.vch__day__square[data-v-a9cfea66]:focus { | |||
| outline: none; | |||
| } | |||
| .vue-tooltip-theme.tooltip { | |||
| display: block !important; | |||
| z-index: 10000; | |||
| } | |||
| .vue-tooltip-theme.tooltip .tooltip-inner { | |||
| background: rgba(0, 0, 0, .7); | |||
| border-radius: 3px; | |||
| color: #ebedf0; | |||
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; | |||
| font-size: 12px; | |||
| line-height: 16px; | |||
| padding: 14px 10px; | |||
| } | |||
| .vue-tooltip-theme.tooltip .tooltip-inner b { | |||
| color: white; | |||
| } | |||
| .vue-tooltip-theme.tooltip .tooltip-arrow { | |||
| width: 0; | |||
| height: 0; | |||
| border-style: solid; | |||
| position: absolute; | |||
| margin: 5px; | |||
| border-color: black; | |||
| z-index: 1; | |||
| } | |||
| .vue-tooltip-theme.tooltip[x-placement^="top"] { | |||
| margin-bottom: 5px; | |||
| } | |||
| .vue-tooltip-theme.tooltip[x-placement^="top"] .tooltip-arrow { | |||
| border-width: 5px 5px 0 5px; | |||
| border-left-color: transparent !important; | |||
| border-right-color: transparent !important; | |||
| border-bottom-color: transparent !important; | |||
| bottom: -5px; | |||
| left: calc(50% - 5px); | |||
| margin-top: 0; | |||
| margin-bottom: 0; | |||
| } | |||
| .vue-tooltip-theme.tooltip[x-placement^="bottom"] { | |||
| margin-top: 5px; | |||
| } | |||
| .vue-tooltip-theme.tooltip[x-placement^="bottom"] .tooltip-arrow { | |||
| border-width: 0 5px 5px 5px; | |||
| border-left-color: transparent !important; | |||
| border-right-color: transparent !important; | |||
| border-top-color: transparent !important; | |||
| top: -5px; | |||
| left: calc(50% - 5px); | |||
| margin-top: 0; | |||
| margin-bottom: 0; | |||
| } | |||
| .vue-tooltip-theme.tooltip[x-placement^="right"] { | |||
| margin-left: 5px; | |||
| } | |||
| .vue-tooltip-theme.tooltip[x-placement^="right"] .tooltip-arrow { | |||
| border-width: 5px 5px 5px 0; | |||
| border-left-color: transparent !important; | |||
| border-top-color: transparent !important; | |||
| border-bottom-color: transparent !important; | |||
| left: -5px; | |||
| top: calc(50% - 5px); | |||
| margin-left: 0; | |||
| margin-right: 0; | |||
| } | |||
| .vue-tooltip-theme.tooltip[x-placement^="left"] { | |||
| margin-right: 5px; | |||
| } | |||
| .vue-tooltip-theme.tooltip[x-placement^="left"] .tooltip-arrow { | |||
| border-width: 5px 0 5px 5px; | |||
| border-top-color: transparent !important; | |||
| border-right-color: transparent !important; | |||
| border-bottom-color: transparent !important; | |||
| right: -5px; | |||
| top: calc(50% - 5px); | |||
| margin-left: 0; | |||
| margin-right: 0; | |||
| } | |||
| .vue-tooltip-theme.tooltip[aria-hidden='true'] { | |||
| visibility: hidden; | |||
| opacity: 0; | |||
| transition: opacity .15s, visibility .15s; | |||
| } | |||
| .vue-tooltip-theme.tooltip[aria-hidden='false'] { | |||
| visibility: visible; | |||
| opacity: 1; | |||
| transition: opacity .15s; | |||
| } | |||
| @@ -49,28 +49,6 @@ | |||
| <script src="https://www.google.com/recaptcha/api.js" async></script> | |||
| {{end}} | |||
| {{end}} | |||
| {{if .EnableHeatmap}} | |||
| <script src="{{AppSubUrl}}/vendor/plugins/moment/moment.min.js" charset="utf-8"></script> | |||
| <script src="{{AppSubUrl}}/vendor/plugins/d3/d3.v4.min.js" charset="utf-8"></script> | |||
| <script src="{{AppSubUrl}}/vendor/plugins/calendar-heatmap/calendar-heatmap.js" charset="utf-8"></script> | |||
| <script type="text/javascript"> | |||
| $.get( '{{AppSubUrl}}/api/v1/users/{{.HeatmapUser}}/heatmap', function( chartRawData ) { | |||
| var chartData = []; | |||
| for (var i = 0; i < chartRawData.length; i++) { | |||
| chartData[i] = {date: new Date(chartRawData[i].timestamp * 1000), count: chartRawData[i].contributions}; | |||
| } | |||
| $('#loading-heatmap').removeClass('active'); | |||
| var heatmap = calendarHeatmap() | |||
| .data(chartData) | |||
| .selector('#user-heatmap') | |||
| .colorRange({{SafeJS HeatmapColorRange}}) | |||
| .tooltipEnabled(true); | |||
| heatmap(); | |||
| }); | |||
| </script> | |||
| {{end}} | |||
| {{if .RequireTribute}} | |||
| <script src="{{AppSubUrl}}/vendor/plugins/tribute/tribute.min.js"></script> | |||
| @@ -136,6 +114,13 @@ | |||
| <!-- JavaScript --> | |||
| <script src="{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.js"></script> | |||
| <script src="{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}"></script> | |||
| {{if .EnableHeatmap}} | |||
| <script src="{{AppSubUrl}}/vendor/plugins/moment/moment.min.js" charset="utf-8"></script> | |||
| <script src="{{AppSubUrl}}/vendor/plugins/vue-calendar-heatmap/vue-calendar-heatmap.browser.js" charset="utf-8"></script> | |||
| <script type="text/javascript"> | |||
| initHeatmap('user-heatmap', '{{.HeatmapUser}}'); | |||
| </script> | |||
| {{end}} | |||
| {{template "custom/footer" .}} | |||
| </body> | |||
| </html> | |||
| @@ -102,7 +102,7 @@ | |||
| <link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/dropzone/dropzone.css"> | |||
| {{end}} | |||
| {{if .EnableHeatmap}} | |||
| <link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/calendar-heatmap/calendar-heatmap.css"> | |||
| <link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/vue-calendar-heatmap/vue-calendar-heatmap.css"> | |||
| {{end}} | |||
| <style class="list-search-style"></style> | |||
| @@ -6,8 +6,13 @@ | |||
| <div class="ui mobile reversed stackable grid"> | |||
| <div class="ten wide column"> | |||
| {{if .EnableHeatmap}} | |||
| <div class="ui active centered inline indeterminate text loader" id="loading-heatmap">{{.i18n.Tr "user.heatmap.loading"}}</div> | |||
| <div id="user-heatmap"></div> | |||
| <div id="user-heatmap" style="padding-right: 40px"> | |||
| <activity-heatmap :locale="locale" :suburl="suburl" :user="heatmapUser"> | |||
| <div slot="loading"> | |||
| <div class="ui active centered inline indeterminate text loader" id="loading-heatmap">{{.i18n.Tr "user.heatmap.loading"}}</div> | |||
| </div> | |||
| </activity-heatmap> | |||
| </div> | |||
| <div class="ui divider"></div> | |||
| {{end}} | |||
| {{template "user/dashboard/feeds" .}} | |||
| @@ -96,8 +96,13 @@ | |||
| {{if eq .TabName "activity"}} | |||
| {{if .EnableHeatmap}} | |||
| <div class="ui active centered inline indeterminate text loader" id="loading-heatmap">{{.i18n.Tr "user.heatmap.loading"}}</div> | |||
| <div id="user-heatmap"></div> | |||
| <div id="user-heatmap" style="padding-right: 40px"> | |||
| <activity-heatmap :locale="locale" :suburl="suburl" :user="heatmapUser"> | |||
| <div slot="loading"> | |||
| <div class="ui active centered inline indeterminate text loader" id="loading-heatmap">{{.i18n.Tr "user.heatmap.loading"}}</div> | |||
| </div> | |||
| </activity-heatmap> | |||
| </div> | |||
| <div class="ui divider"></div> | |||
| {{end}} | |||
| <div class="feeds"> | |||