diff --git a/app/assets/javascripts/pages/users/activity_calendar.js b/app/assets/javascripts/pages/users/activity_calendar.js
index 13bba06d425bbf111d9417c949d613da9d0a28c9..dbb0fe585791f777f5dc827e5c1deb246730b375 100644
--- a/app/assets/javascripts/pages/users/activity_calendar.js
+++ b/app/assets/javascripts/pages/users/activity_calendar.js
@@ -72,7 +72,7 @@ export default class ActivityCalendar {
this.clickDay = this.clickDay.bind(this);
this.currentSelectedDate = '';
this.daySpace = 1;
- this.daySize = 15;
+ this.daySize = 14;
this.daySizeWithSpace = this.daySize + this.daySpace * 2;
this.monthNames = [
__('Jan'),
@@ -131,7 +131,6 @@ export default class ActivityCalendar {
this.renderDays();
this.renderMonths();
this.renderDayTitles();
- this.renderKey();
}
// Add extra padding for the last month label if it is also the last column
@@ -257,25 +256,6 @@ export default class ActivityCalendar {
.text((date) => this.monthNames[date.month]);
}
- renderKey() {
- this.svg
- .append('g')
- .attr('transform', `translate(18, ${this.daySizeWithSpace * 8 + 16})`)
- .selectAll('rect')
- .data(CONTRIB_LEGENDS)
- .enter()
- .append('rect')
- .attr('width', this.daySize)
- .attr('height', this.daySize)
- .attr('x', (_, i) => this.daySizeWithSpace * i)
- .attr('y', 0)
- .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);
- }
-
clickDay(stamp) {
if (this.currentSelectedDate !== stamp.date) {
this.currentSelectedDate = stamp.date;
diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js
index 79eb3902116f3683688d7de46c44d6a55c338201..62f49769f4d4a7e126ef8fd9540dd33c5b4aa5fb 100644
--- a/app/assets/javascripts/pages/users/user_tabs.js
+++ b/app/assets/javascripts/pages/users/user_tabs.js
@@ -1,7 +1,6 @@
// TODO: Remove this with the removal of the old navigation.
// See https://gitlab.com/groups/gitlab-org/-/epics/11875.
-import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import $ from 'jquery';
import Activities from '~/activities';
import AjaxCache from '~/lib/utils/ajax_cache';
@@ -67,17 +66,32 @@ import UserOverviewBlock from './user_overview_block';
const CALENDAR_TEMPLATE = `
-
+
+
+
+
`;
-const CALENDAR_PERIOD_6_MONTHS = 6;
const CALENDAR_PERIOD_12_MONTHS = 12;
-/* computation based on
- * width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
- * (see activity_calendar.js)
- */
-const OVERVIEW_CALENDAR_BREAKPOINT = 918;
export default class UserTabs {
constructor({ defaultAction, action, parentEl }) {
@@ -105,12 +119,6 @@ export default class UserTabs {
.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', (event) => this.tabShown(event))
.on('click', '.gl-pagination a', (event) => this.changeProjectsPage(event));
-
- window.addEventListener('resize', () => this.onResize());
- }
-
- onResize() {
- this.loadActivityCalendar();
}
changeProjectsPage(e) {
@@ -199,6 +207,7 @@ export default class UserTabs {
UserTabs.renderMostRecentBlocks('#js-overview .activities-block', {
requestParams: { limit: 15 },
});
+
UserTabs.renderMostRecentBlocks('#js-overview .projects-block', {
requestParams: { limit: 10, skip_pagination: true, skip_namespace: true, compact_mode: true },
});
@@ -218,8 +227,6 @@ export default class UserTabs {
loadActivityCalendar() {
const $calendarWrap = this.$parentEl.find('.tab-pane.active .user-calendar');
- if (!$calendarWrap.length || bp.getBreakpointSize() === 'xs') return;
-
const calendarPath = $calendarWrap.data('calendarPath');
AjaxCache.retrieve(calendarPath)
@@ -240,7 +247,6 @@ export default class UserTabs {
}
static renderActivityCalendar(data, $calendarWrap) {
- const monthsAgo = UserTabs.getVisibleCalendarPeriod($calendarWrap);
const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath');
const utcOffset = $calendarWrap.data('utcOffset');
const calendarHint = __('Issues, merge requests, pushes, and comments.');
@@ -257,8 +263,12 @@ export default class UserTabs {
calendarActivitiesPath,
utcOffset,
firstDayOfWeek: gon.first_day_of_week,
- monthsAgo,
+ CALENDAR_PERIOD_12_MONTHS,
});
+
+ // Scroll to end
+ const calendarContainer = document.querySelector('.js-contrib-calendar');
+ calendarContainer.scrollLeft = calendarContainer.scrollWidth;
}
toggleLoading(status) {
@@ -282,11 +292,4 @@ export default class UserTabs {
getCurrentAction() {
return this.$parentEl.find('.nav-links a.active').data('action');
}
-
- static getVisibleCalendarPeriod($calendarWrap) {
- const width = $calendarWrap.width();
- return width < OVERVIEW_CALENDAR_BREAKPOINT
- ? CALENDAR_PERIOD_6_MONTHS
- : CALENDAR_PERIOD_12_MONTHS;
- }
}
diff --git a/app/assets/javascripts/profile/components/activity_calendar.vue b/app/assets/javascripts/profile/components/activity_calendar.vue
index d359b478d35c0523851b6549f0c947e233a86301..07a137e7fef4a7a2eb46bbcb7de7cab83c3b2178 100644
--- a/app/assets/javascripts/profile/components/activity_calendar.vue
+++ b/app/assets/javascripts/profile/components/activity_calendar.vue
@@ -1,12 +1,8 @@
-
-
+
+
-
-
-
-
- {{ $options.i18n.calendarHint }}
-
-
+
+
+
+ {{ $options.i18n.calendarHint }}
+
diff --git a/app/assets/javascripts/profile/components/overview_tab.vue b/app/assets/javascripts/profile/components/overview_tab.vue
index 8cfa3fb3eea188ed45158038df5dacf477b274ec..ab8a2871a41c1c78214ddf418cd9b42137bd7ce9 100644
--- a/app/assets/javascripts/profile/components/overview_tab.vue
+++ b/app/assets/javascripts/profile/components/overview_tab.vue
@@ -54,19 +54,19 @@ export default {
-
-
-
+
+
{{ $options.i18n.activity }}
{{ $options.i18n.viewAll }}
+
-
+
diff --git a/app/assets/javascripts/profile/components/user_achievements.vue b/app/assets/javascripts/profile/components/user_achievements.vue
index 7ce6b61c4aca7ca73334202aeba0d051e7ead561..b148d99b8b48758f1502bfbc672b96ea60f5cf83 100644
--- a/app/assets/javascripts/profile/components/user_achievements.vue
+++ b/app/assets/javascripts/profile/components/user_achievements.vue
@@ -28,6 +28,11 @@ export default {
},
},
},
+ computed: {
+ hasUserAchievements() {
+ return this.userAchievements && this.userAchievements.length > 0;
+ },
+ },
methods: {
processNodes(nodes) {
return Object.entries(groupBy(nodes, 'achievement.id'))
@@ -67,12 +72,16 @@ export default {
i18n: {
awardedBy: s__('Achievements|Awarded %{timeAgo} by %{namespace}'),
awardedByUnknownNamespace: s__('Achievements|Awarded %{timeAgo} by a private namespace'),
+ achievementsLabel: s__('Achievements|Achievements'),
},
};
-
+
+
+ {{ $options.i18n.achievementsLabel }}
+
{{
diff --git a/app/assets/stylesheets/page_bundles/profile.scss b/app/assets/stylesheets/page_bundles/profile.scss
index e18ecfc79306209d0c3739daca9da754d1dce59c..573f9dbc69b968912042389b84dacc8db8a33782 100644
--- a/app/assets/stylesheets/page_bundles/profile.scss
+++ b/app/assets/stylesheets/page_bundles/profile.scss
@@ -29,97 +29,35 @@
}
}
-.calendar-block {
- padding-left: 0;
- padding-right: 0;
- border-top: 0;
-
- @media (min-width: map-get($grid-breakpoints, sm)) and (max-width: map-get($grid-breakpoints, sm)) {
- overflow-x: auto;
- }
-}
-
+.calendar-legend,
.calendar-hint {
- font-size: 12px;
+ position: relative;
+ z-index: 1;
direction: ltr;
- margin-top: -23px;
- float: right;
}
-.cover-block {
- text-align: center;
- background: var(--gray-50, $gray-light);
- padding-top: 44px;
- position: relative;
-
- .avatar-holder {
- .avatar,
- .identicon {
- margin: 0 auto;
- float: none;
- }
-
- .identicon {
- border-radius: 50%;
- }
- }
-
- .cover-title {
- color: var(--gl-text-color, $gl-text-color);
- font-size: 23px;
-
- h1 {
- color: var(--gl-text-color, $gl-text-color);
- margin-bottom: 6px;
- font-size: 23px;
- }
-
- .visibility-icon {
- display: inline-block;
- margin-left: 5px;
- font-size: 18px;
- color: color('gray');
- }
+.calendar-legend {
+ margin-top: -36px;
- p {
- padding: 0 $gl-padding;
- color: var(--gl-text-color, $gl-text-color);
- }
+ @include media-breakpoint-up(md) {
+ float: left;
}
+}
- .cover-controls {
- @include media-breakpoint-up(sm) {
- position: absolute;
- top: 1rem;
- right: 1.25rem;
- }
+.calendar-hint {
+ margin-bottom: $gl-padding-8;
- &.left {
- @include media-breakpoint-up(sm) {
- left: 1.25rem;
- right: auto;
- }
- }
+ @include media-breakpoint-up(md) {
+ float: right;
+ margin-top: -36px;
}
+}
- &.user-cover-block {
- padding: 24px 0 0;
-
- .nav-links {
- width: 100%;
- float: none;
-
- &.scrolling-tabs {
- float: none;
- }
- }
-
- li:first-child {
- margin-left: auto;
- }
-
- li:last-child {
- margin-right: auto;
+.user-profile-image {
+ .gl-avatar {
+ @include media-breakpoint-up(md) {
+ height: 7.5rem;
+ width: 7.5rem;
}
}
}
@@ -140,15 +78,6 @@
max-width: 600px;
}
-.user-calendar {
- text-align: center;
- min-height: 172px;
-
- .calendar {
- display: inline-block;
- }
-}
-
.user-calendar-activities {
direction: ltr;
@@ -158,16 +87,27 @@
}
.user-contrib-text {
- font-size: 12px;
+ font-size: 11px;
fill: $calendar-user-contrib-text;
}
.user-profile {
- .profile-header {
- margin: 0 $gl-padding;
+ @include media-breakpoint-up(lg) {
+ .profile-header {
+ position: sticky;
+ top: $calc-application-header-height;
+ height: $calc-application-viewport-height;
+ margin-bottom: $content-wrapper-padding;
+ }
+ }
- .avatar-holder {
- margin: 0 auto 10px;
+ .cover-controls {
+ position: absolute;
+ top: $gl-padding-24;
+ right: -$gl-padding-8;
+
+ @include media-breakpoint-up(lg) {
+ position: static;
}
}
@@ -197,17 +137,7 @@
}
}
- .projects-block {
- @include media-breakpoint-up(lg) {
- margin-left: 5px;
- }
- }
-
@include media-breakpoint-down(xs) {
- .cover-block {
- padding-top: 20px;
- }
-
.user-profile-nav {
a {
margin-right: 0;
@@ -272,6 +202,8 @@
}
.user-profile {
+ position: relative;
+
@include media-breakpoint-up(lg) {
display: grid;
grid-template-columns: minmax(240px, 1fr) 3fr;
@@ -287,3 +219,8 @@
.user-profile-content {
min-width: 1px; // grid overflow fix
}
+
+.js-contrib-calendar {
+ // make contrib calendar scrollable
+ overflow-x: auto;
+}
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e4610b44aea03112c055ba6e27d6e00d3accd96a..b964f97adb21f3bdb7444f4d7dcdbbd63e7df312 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2675,6 +2675,9 @@ msgstr ""
msgid "Achievements|%{namespace_link} awarded you the %{bold_start}%{achievement_name}%{bold_end} achievement!"
msgstr ""
+msgid "Achievements|Achievements"
+msgstr ""
+
msgid "Achievements|Awarded %{timeAgo} by %{namespace}"
msgstr ""
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index 291c40f0f6b382888302814fdec6767e5615411e..c750cd0a8448190686ebce3efb94bab62587aabc 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -224,24 +224,6 @@ def selected_day_activities(visible: true)
end
end
- describe 'on smaller screens' do
- shared_examples 'hidden activity calendar' do
- include_context 'when user page is visited'
-
- it 'hides the activity calender' do
- expect(find('#js-overview')).not_to have_css('.js-contrib-calendar')
- end
- end
-
- context 'when screen size is xs' do
- before do
- resize_screen_xs
- end
-
- it_behaves_like 'hidden activity calendar'
- end
- end
-
describe 'first_day_of_week setting' do
context 'when first day of the week is set to Monday' do
before do
@@ -356,24 +338,6 @@ def selected_day_activities(visible: true)
end
end
- describe 'on smaller screens' do
- shared_examples 'hidden activity calendar' do
- include_context 'when user page is visited'
-
- it 'hides the activity calender' do
- expect(page).not_to have_css('[data-testid="contrib-calendar"]')
- end
- end
-
- context 'when screen size is xs' do
- before do
- resize_screen_xs
- end
-
- it_behaves_like 'hidden activity calendar'
- end
- end
-
describe 'first_day_of_week setting' do
context 'when first day of the week is set to Monday' do
before do
diff --git a/spec/frontend/profile/components/activity_calendar_spec.js b/spec/frontend/profile/components/activity_calendar_spec.js
index fb9dc7b22f73a49057427b600bb1a6634d1fb2f5..043e717538c2d5859c8618e79f62535f1945af63 100644
--- a/spec/frontend/profile/components/activity_calendar_spec.js
+++ b/spec/frontend/profile/components/activity_calendar_spec.js
@@ -1,5 +1,4 @@
import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
-import * as GitLabUIUtils from '@gitlab/ui/dist/utils';
import ActivityCalendar from '~/profile/components/activity_calendar.vue';
import AjaxCache from '~/lib/utils/ajax_cache';
@@ -57,23 +56,6 @@ describe('ActivityCalendar', () => {
expect(findCalendar().exists()).toBe(true);
expect(wrapper.findByText(ActivityCalendar.i18n.calendarHint).exists()).toBe(true);
});
-
- describe('when window is resized', () => {
- it('re-renders the calendar', async () => {
- createComponent();
-
- await waitForPromises();
-
- mockSuccessfulApiRequest();
- window.innerWidth = 1200;
- window.dispatchEvent(new Event('resize'));
-
- await waitForPromises();
-
- expect(findCalendar().exists()).toBe(true);
- expect(AjaxCache.retrieve).toHaveBeenCalledTimes(2);
- });
- });
});
describe('when API request is not successful', () => {
@@ -105,16 +87,4 @@ describe('ActivityCalendar', () => {
});
});
});
-
- describe('when screen is extra small', () => {
- beforeEach(() => {
- GitLabUIUtils.GlBreakpointInstance.getBreakpointSize.mockReturnValueOnce('xs');
- });
-
- it('does not render the calendar', () => {
- createComponent();
-
- expect(findCalendar().exists()).toBe(false);
- });
- });
});