Commit 1e949ba5 authored by Takuya Noguchi's avatar Takuya Noguchi

Extract CSS from user calendar JS

Changelog: other
Co-authored-by: default avatarPaul Slaughter <pslaughter@gitlab.com>
Signed-off-by: default avatarTakuya Noguchi <takninnovationresearch@gmail.com>
parent 744edfc9
import { scaleLinear, scaleThreshold } from 'd3-scale';
import { select } from 'd3-selection';
import dateFormat from 'dateformat';
import $ from 'jquery';
......@@ -8,7 +7,7 @@ import axios from '~/lib/utils/axios_utils';
import { getDayName, getDayDifference } from '~/lib/utils/datetime_utility';
import { n__, s__, __ } from '~/locale';
const d3 = { select, scaleLinear, scaleThreshold };
const d3 = { select };
const firstDayOfWeekChoices = Object.freeze({
sunday: 0,
......@@ -16,6 +15,14 @@ const firstDayOfWeekChoices = Object.freeze({
saturday: 6,
});
const CONTRIB_LEGENDS = [
{ title: __('No contributions'), min: 0 },
{ title: __('1-9 contributions'), min: 1 },
{ title: __('10-19 contributions'), min: 10 },
{ title: __('20-29 contributions'), min: 20 },
{ title: __('30+ contributions'), min: 30 },
];
const LOADING_HTML = `
<div class="text-center">
<div class="spinner spinner-md"></div>
......@@ -42,7 +49,17 @@ function formatTooltipText({ date, count }) {
return `${contribText}<br /><span class="gl-text-gray-300">${dateDayName} ${dateText}</span>`;
}
const initColorKey = () => d3.scaleLinear().range(['#acd5f2', '#254e77']).domain([0, 3]);
// Return the contribution level from the number of contributions
export const getLevelFromContributions = (count) => {
if (count <= 0) {
return 0;
}
const nextLevel = CONTRIB_LEGENDS.findIndex(({ min }) => count < min);
// If there is no higher level, we are at the end
return nextLevel >= 0 ? nextLevel - 1 : CONTRIB_LEGENDS.length - 1;
};
export default class ActivityCalendar {
constructor(
......@@ -111,10 +128,6 @@ export default class ActivityCalendar {
innerArray.push({ count, date, day });
}
// Init color functions
this.colorKey = initColorKey();
this.color = this.initColor();
// Init the svg element
this.svg = this.renderSvg(container, group);
this.renderDays();
......@@ -180,9 +193,7 @@ export default class ActivityCalendar {
.attr('y', (stamp) => this.dayYPos(stamp.day))
.attr('width', this.daySize)
.attr('height', this.daySize)
.attr('fill', (stamp) =>
stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed',
)
.attr('data-level', (stamp) => getLevelFromContributions(stamp.count))
.attr('title', (stamp) => formatTooltipText(stamp))
.attr('class', 'user-contrib-cell has-tooltip')
.attr('data-html', true)
......@@ -246,50 +257,24 @@ export default class ActivityCalendar {
}
renderKey() {
const keyValues = [
__('No contributions'),
__('1-9 contributions'),
__('10-19 contributions'),
__('20-29 contributions'),
__('30+ contributions'),
];
const keyColors = [
'#ededed',
this.colorKey(0),
this.colorKey(1),
this.colorKey(2),
this.colorKey(3),
];
this.svg
.append('g')
.attr('transform', `translate(18, ${this.daySizeWithSpace * 8 + 16})`)
.selectAll('rect')
.data(keyColors)
.data(CONTRIB_LEGENDS)
.enter()
.append('rect')
.attr('width', this.daySize)
.attr('height', this.daySize)
.attr('x', (color, i) => this.daySizeWithSpace * i)
.attr('x', (_, i) => this.daySizeWithSpace * i)
.attr('y', 0)
.attr('fill', (color) => color)
.attr('class', 'has-tooltip')
.attr('title', (color, i) => keyValues[i])
.attr('data-level', (_, i) => i)
.attr('class', 'user-contrib-cell has-tooltip contrib-legend')
.attr('title', (x) => x.title)
.attr('data-container', 'body')
.attr('data-html', true);
}
initColor() {
const colorRange = [
'#ededed',
this.colorKey(0),
this.colorKey(1),
this.colorKey(2),
this.colorKey(3),
];
return d3.scaleThreshold().domain([0, 10, 20, 30]).range(colorRange);
}
clickDay(stamp) {
if (this.currentSelectedDate !== stamp.date) {
this.currentSelectedDate = stamp.date;
......
......@@ -30,6 +30,16 @@
cursor: pointer;
stroke: $black;
}
// `app/assets/javascripts/pages/users/activity_calendar.js` sets this attribute
@for $i from 1 through length($calendar-activity-colors) {
$color: nth($calendar-activity-colors, $i);
$level: $i - 1;
&[data-level='#{$level}'] {
fill: $color;
}
}
}
.user-contrib-text {
......
......@@ -716,6 +716,18 @@ $job-line-number-width: 50px;
$job-line-number-margin: 43px;
$job-arrow-margin: 55px;
/*
* Calendar
*/
// See https://gitlab.com/gitlab-org/gitlab/-/issues/332150 to align with Pajamas Design System
$calendar-activity-colors: (
#ededed,
#acd5f2,
#7fa8c9,
#527ba0,
#254e77,
);
/*
* Commit Page
*/
......
......@@ -15,10 +15,9 @@ RSpec.describe 'Contributions Calendar', :js do
issue_title = 'Bug in old browser'
issue_params = { title: issue_title }
def get_cell_color_selector(contributions)
activity_colors = ["#ededed", "rgb(172, 213, 242)", "rgb(127, 168, 201)", "rgb(82, 123, 160)", "rgb(37, 78, 119)"]
def get_cell_level_selector(contributions)
# We currently don't actually test the cases with contributions >= 20
activity_colors_index =
activity_level_index =
if contributions > 0 && contributions < 10
1
elsif contributions >= 10 && contributions < 20
......@@ -31,7 +30,7 @@ RSpec.describe 'Contributions Calendar', :js do
0
end
".user-contrib-cell[fill='#{activity_colors[activity_colors_index]}']"
".user-contrib-cell:not(.contrib-legend)[data-level='#{activity_level_index}']"
end
def get_cell_date_selector(contributions, date)
......@@ -42,7 +41,7 @@ RSpec.describe 'Contributions Calendar', :js do
"#{contributions} #{'contribution'.pluralize(contributions)}"
end
"#{get_cell_color_selector(contributions)}[title='#{contribution_text}<br /><span class=\"gl-text-gray-300\">#{date}</span>']"
"#{get_cell_level_selector(contributions)}[title='#{contribution_text}<br /><span class=\"gl-text-gray-300\">#{date}</span>']"
end
def push_code_contribution
......@@ -137,7 +136,7 @@ RSpec.describe 'Contributions Calendar', :js do
include_context 'visit user page'
it 'displays calendar activity square for 1 contribution', :sidekiq_might_not_need_inline do
expect(find('#js-overview')).to have_selector(get_cell_color_selector(contribution_count), count: 1)
expect(find('#js-overview')).to have_selector(get_cell_level_selector(contribution_count), count: 1)
today = Date.today.strftime(date_format)
expect(find('#js-overview')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
......@@ -187,7 +186,7 @@ RSpec.describe 'Contributions Calendar', :js do
include_context 'visit user page'
it 'displays calendar activity squares for both days', :sidekiq_might_not_need_inline do
expect(find('#js-overview')).to have_selector(get_cell_color_selector(1), count: 2)
expect(find('#js-overview')).to have_selector(get_cell_level_selector(1), count: 2)
end
it 'displays calendar activity square for yesterday', :sidekiq_might_not_need_inline do
......
import { getLevelFromContributions } from '~/pages/users/activity_calendar';
describe('getLevelFromContributions', () => {
it.each([
[0, 0],
[1, 1],
[9, 1],
[10, 2],
[19, 2],
[20, 3],
[30, 4],
[99, 4],
])('.getLevelFromContributions(%i, %i)', (count, expected) => {
expect(getLevelFromContributions(count)).toBe(expected);
});
});
......@@ -4019,7 +4019,7 @@ d3-scale-chromatic@1:
d3-color "1"
d3-interpolate "1"
d3-scale@2, d3-scale@^2.2.2:
d3-scale@2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f"
integrity sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment