ECOM-7386 Added a program progress circle to program details page
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
(function(define) {
|
||||
'use strict';
|
||||
|
||||
define(['backbone',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'gettext',
|
||||
'text!../../../templates/components/progress_circle_view.underscore',
|
||||
'text!../../../templates/components/progress_circle_segment.underscore'
|
||||
],
|
||||
function(
|
||||
Backbone,
|
||||
$,
|
||||
_,
|
||||
gettext,
|
||||
progressViewTpl,
|
||||
progressSegmentTpl
|
||||
) {
|
||||
return Backbone.View.extend({
|
||||
x: 22,
|
||||
y: 22,
|
||||
radius: 16,
|
||||
degrees: 180,
|
||||
strokeWidth: 1.2,
|
||||
|
||||
viewTpl: _.template(progressViewTpl),
|
||||
segmentTpl: _.template(progressSegmentTpl),
|
||||
|
||||
initialize: function() {
|
||||
var progress = this.model.get('progress');
|
||||
|
||||
this.model.set({
|
||||
totalCourses: progress.completed + progress.in_progress + progress.not_started
|
||||
});
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var data = $.extend({}, this.model.toJSON(), {
|
||||
circleSegments: this.getProgressSegments(),
|
||||
x: this.x,
|
||||
y: this.y,
|
||||
radius: this.radius,
|
||||
strokeWidth: this.strokeWidth
|
||||
});
|
||||
|
||||
this.$el.html(this.viewTpl(data));
|
||||
},
|
||||
|
||||
getDegreeIncrement: function(total) {
|
||||
return 360 / total;
|
||||
},
|
||||
|
||||
getOffset: function(total) {
|
||||
return 100 - ((1 / total) * 100);
|
||||
},
|
||||
|
||||
getProgressSegments: function() {
|
||||
var progressHTML = [],
|
||||
total = this.model.get('totalCourses'),
|
||||
segmentDash = 2 * Math.PI * this.radius,
|
||||
degreeInc = this.getDegreeIncrement(total),
|
||||
data = {
|
||||
// Remove strokeWidth to show a gap between the segments
|
||||
dashArray: segmentDash - this.strokeWidth,
|
||||
degrees: this.degrees,
|
||||
offset: this.getOffset(total),
|
||||
x: this.x,
|
||||
y: this.y,
|
||||
radius: this.radius,
|
||||
strokeWidth: this.strokeWidth
|
||||
},
|
||||
i,
|
||||
segmentData;
|
||||
|
||||
for (i = 0; i < total; i++) {
|
||||
segmentData = $.extend({}, data, {
|
||||
classList: (i >= this.model.get('progress').completed) ? 'incomplete' : 'complete',
|
||||
degrees: data.degrees + (i * degreeInc)
|
||||
});
|
||||
|
||||
// Want the incomplete segments to have no gaps
|
||||
if (segmentData.classList === 'incomplete' && (i + 1) < total) {
|
||||
segmentData.dashArray = segmentDash;
|
||||
}
|
||||
|
||||
progressHTML.push(this.segmentTpl(segmentData));
|
||||
}
|
||||
|
||||
return progressHTML.join('');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -0,0 +1,112 @@
|
||||
define([
|
||||
'backbone',
|
||||
'jquery',
|
||||
'edx-ui-toolkit/js/utils/spec-helpers/spec-helpers',
|
||||
'common/js/components/views/progress_circle_view'
|
||||
], function(Backbone, $, SpecHelpers, ProgressCircleView) {
|
||||
'use strict';
|
||||
|
||||
describe('Progress Circle View', function() {
|
||||
var view = null,
|
||||
context = {
|
||||
title: 'XSeries Progress',
|
||||
label: 'Earned Certificates',
|
||||
progress: {
|
||||
completed: 2,
|
||||
in_progress: 1,
|
||||
not_started: 3
|
||||
}
|
||||
},
|
||||
testCircle,
|
||||
testText,
|
||||
initView,
|
||||
getProgress,
|
||||
testProgress;
|
||||
|
||||
testCircle = function(progress) {
|
||||
var $circle = view.$('.progress-circle');
|
||||
|
||||
expect($circle.find('.complete').length).toEqual(progress.completed);
|
||||
expect($circle.find('.incomplete').length).toEqual(progress.in_progress + progress.not_started);
|
||||
};
|
||||
|
||||
testText = function(progress) {
|
||||
var $numbers = view.$('.numbers'),
|
||||
total = progress.completed + progress.in_progress + progress.not_started;
|
||||
|
||||
expect(view.$('.progress-heading').html()).toEqual('XSeries Progress');
|
||||
expect(parseInt($numbers.find('.complete').html(), 10)).toEqual(progress.completed);
|
||||
expect(parseInt($numbers.find('.total').html(), 10)).toEqual(total);
|
||||
};
|
||||
|
||||
getProgress = function(x, y, z) {
|
||||
return {
|
||||
completed: x,
|
||||
in_progress: y,
|
||||
not_started: z
|
||||
};
|
||||
};
|
||||
|
||||
testProgress = function(x, y, z) {
|
||||
var progress = getProgress(x, y, z);
|
||||
|
||||
view = initView(progress);
|
||||
view.render();
|
||||
|
||||
testCircle(progress);
|
||||
testText(progress);
|
||||
};
|
||||
|
||||
initView = function(progress) {
|
||||
var data = $.extend({}, context, {
|
||||
progress: progress
|
||||
});
|
||||
|
||||
return new ProgressCircleView({
|
||||
el: '.js-program-progress',
|
||||
model: new Backbone.Model(data)
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
setFixtures('<div class="js-program-progress"></div>');
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
view.remove();
|
||||
});
|
||||
|
||||
it('should exist', function() {
|
||||
var progress = getProgress(2, 1, 3);
|
||||
|
||||
view = initView(progress);
|
||||
view.render();
|
||||
expect(view).toBeDefined();
|
||||
});
|
||||
|
||||
it('should render the progress circle based on the passed in model', function() {
|
||||
var progress = getProgress(2, 1, 3);
|
||||
|
||||
view = initView(progress);
|
||||
view.render();
|
||||
testCircle(progress);
|
||||
});
|
||||
|
||||
it('should render the progress text based on the passed in model', function() {
|
||||
var progress = getProgress(2, 1, 3);
|
||||
|
||||
view = initView(progress);
|
||||
view.render();
|
||||
testText(progress);
|
||||
});
|
||||
|
||||
SpecHelpers.withData({
|
||||
'should render the progress text with only completed courses': [5, 0, 0],
|
||||
'should render the progress text with only in progress courses': [0, 4, 0],
|
||||
'should render the progress circle with only not started courses': [0, 0, 5],
|
||||
'should render the progress text with no completed courses': [0, 2, 3],
|
||||
'should render the progress text with no in progress courses': [2, 0, 7],
|
||||
'should render the progress text with no not started courses': [2, 4, 0]
|
||||
}, testProgress);
|
||||
});
|
||||
});
|
||||
@@ -164,6 +164,7 @@
|
||||
'common/js/spec/components/paginated_view_spec.js',
|
||||
'common/js/spec/components/paging_header_spec.js',
|
||||
'common/js/spec/components/paging_footer_spec.js',
|
||||
'common/js/spec/components/progress_circle_view_spec.js',
|
||||
'common/js/spec/components/search_field_spec.js',
|
||||
'common/js/spec/components/view_utils_spec.js',
|
||||
'common/js/spec/utils/edx.utils.validate_spec.js'
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<circle class="<%- classList %>"
|
||||
r="<%- radius %>" cx="<%- x %>" cy="<%- y %>"
|
||||
transform="rotate(<%- degrees %>, <%- x %>, <%- y %>)"
|
||||
stroke-width="<%- strokeWidth %>"
|
||||
fill="none"
|
||||
stroke-dasharray="<%- dashArray %>"
|
||||
stroke-dashoffset="<%- offset %>">
|
||||
</circle>
|
||||
@@ -0,0 +1,15 @@
|
||||
<% if (title) { %>
|
||||
<h2 class="progress-heading"><%- title %></h2>
|
||||
<% } %>
|
||||
<div class="progress-circle-wrapper">
|
||||
<svg class="progress-circle" viewBox="0 0 44 44" aria-hidden="true">
|
||||
<circle class="js-circle bg" r="<%- radius %>" cx="<%- x %>" cy="<%- y %>" stroke-width="<%- strokeWidth %>" fill="none"></circle>
|
||||
<%= circleSegments %>
|
||||
</svg>
|
||||
<div class="progress-label">
|
||||
<div class="numbers">
|
||||
<span class="complete"><%- progress.completed %></span>/<span class="total"><%- totalCourses %></span>
|
||||
</div>
|
||||
<div class="label"><% if (label) { %><%- label %><% } %></div>
|
||||
</div>
|
||||
</div>
|
||||
BIN
lms/static/images/programs/program-certificate-micromasters.gif
Normal file
BIN
lms/static/images/programs/program-certificate-micromasters.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
lms/static/images/programs/program-certificate-xseries.gif
Normal file
BIN
lms/static/images/programs/program-certificate-xseries.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,35 @@
|
||||
(function(define) {
|
||||
'use strict';
|
||||
define(['backbone',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'gettext',
|
||||
'text!../../../templates/learner_dashboard/certificate_list.underscore'
|
||||
],
|
||||
function(
|
||||
Backbone,
|
||||
$,
|
||||
_,
|
||||
gettext,
|
||||
certificateTpl
|
||||
) {
|
||||
return Backbone.View.extend({
|
||||
tpl: _.template(certificateTpl),
|
||||
|
||||
initialize: function(options) {
|
||||
this.title = options.title || false;
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var data = {
|
||||
title: this.title,
|
||||
certificateList: this.collection.toJSON()
|
||||
};
|
||||
|
||||
this.$el.html(this.tpl(data));
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -1,47 +1,97 @@
|
||||
(function(define) {
|
||||
'use strict';
|
||||
|
||||
define(['backbone',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'gettext',
|
||||
'js/learner_dashboard/views/explore_new_programs_view',
|
||||
'js/learner_dashboard/views/certificate_view',
|
||||
'text!../../../templates/learner_dashboard/sidebar.underscore'
|
||||
],
|
||||
function(
|
||||
Backbone,
|
||||
$,
|
||||
_,
|
||||
gettext,
|
||||
NewProgramsView,
|
||||
CertificateView,
|
||||
sidebarTpl
|
||||
) {
|
||||
return Backbone.View.extend({
|
||||
el: '.sidebar',
|
||||
define([
|
||||
'backbone',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'gettext',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'edx-ui-toolkit/js/utils/string-utils',
|
||||
'common/js/components/views/progress_circle_view',
|
||||
'js/learner_dashboard/views/certificate_list_view',
|
||||
'text!../../../templates/learner_dashboard/program_details_sidebar.underscore'
|
||||
],
|
||||
function(
|
||||
Backbone,
|
||||
$,
|
||||
_,
|
||||
gettext,
|
||||
HtmlUtils,
|
||||
StringUtils,
|
||||
ProgramProgressView,
|
||||
CertificateView,
|
||||
sidebarTpl
|
||||
) {
|
||||
return Backbone.View.extend({
|
||||
tpl: HtmlUtils.template(sidebarTpl),
|
||||
|
||||
tpl: _.template(sidebarTpl),
|
||||
initialize: function(options) {
|
||||
this.courseModel = options.courseModel || {};
|
||||
this.certificateCollection = options.certificateCollection || [];
|
||||
this.programCertificate = this.getProgramCertificate();
|
||||
this.render();
|
||||
},
|
||||
|
||||
initialize: function(data) {
|
||||
this.context = data.context;
|
||||
},
|
||||
render: function() {
|
||||
var data = $.extend({}, this.model.toJSON(), {
|
||||
programCertificate: this.programCertificate ?
|
||||
this.programCertificate.toJSON() : {}
|
||||
});
|
||||
|
||||
render: function() {
|
||||
this.$el.html(this.tpl(this.context));
|
||||
this.postRender();
|
||||
},
|
||||
HtmlUtils.setHtml(this.$el, this.tpl(data));
|
||||
this.postRender();
|
||||
},
|
||||
|
||||
postRender: function() {
|
||||
this.newProgramsView = new NewProgramsView({
|
||||
context: this.context
|
||||
});
|
||||
postRender: function() {
|
||||
if (!this.programCertificate) {
|
||||
this.progressModel = new Backbone.Model({
|
||||
title: StringUtils.interpolate(
|
||||
gettext('{type} Progress'),
|
||||
{type: this.model.get('type')}
|
||||
),
|
||||
label: gettext('Earned Certificates'),
|
||||
progress: {
|
||||
completed: this.courseModel.get('completed').length,
|
||||
in_progress: this.courseModel.get('in_progress').length,
|
||||
not_started: this.courseModel.get('not_started').length
|
||||
}
|
||||
});
|
||||
|
||||
this.newCertificateView = new CertificateView({
|
||||
context: this.context
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
this.programProgressView = new ProgramProgressView({
|
||||
el: '.js-program-progress',
|
||||
model: this.progressModel
|
||||
});
|
||||
}
|
||||
|
||||
if (this.certificateCollection.length) {
|
||||
this.certificateView = new CertificateView({
|
||||
el: '.js-course-certificates',
|
||||
collection: this.certificateCollection,
|
||||
title: gettext('Earned Certificates')
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getProgramCertificate: function() {
|
||||
var certificate = this.certificateCollection.findWhere({type: 'program'}),
|
||||
base = '/static/images/programs/program-certificate-';
|
||||
|
||||
if (certificate) {
|
||||
certificate.set({
|
||||
img: base + this.getType() + '.gif'
|
||||
});
|
||||
}
|
||||
|
||||
return certificate;
|
||||
},
|
||||
|
||||
getType: function() {
|
||||
var type = this.model.get('type').toLowerCase();
|
||||
|
||||
return type.replace(/\s+/g, '-');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
this.options = options;
|
||||
this.programModel = new Backbone.Model(this.options.programData);
|
||||
this.courseData = new Backbone.Model(this.options.courseData);
|
||||
this.certificateCollection = new Backbone.Collection(this.options.certificateData);
|
||||
this.completedCourseCollection = new CourseCardCollection(
|
||||
this.courseData.get('completed') || [],
|
||||
this.options.userPreferences
|
||||
@@ -61,7 +62,7 @@
|
||||
remainingCount: remainingCount,
|
||||
completedCount: completedCount
|
||||
};
|
||||
data = $.extend(data, this.options.programData);
|
||||
data = $.extend(data, this.programModel.toJSON());
|
||||
HtmlUtils.setHtml(this.$el, this.tpl(data));
|
||||
this.postRender();
|
||||
},
|
||||
@@ -99,10 +100,12 @@
|
||||
}).render();
|
||||
}
|
||||
|
||||
new SidebarView({
|
||||
el: '.sidebar',
|
||||
context: this.options
|
||||
}).render();
|
||||
this.sidebarView = new SidebarView({
|
||||
el: '.js-program-sidebar',
|
||||
model: this.programModel,
|
||||
courseModel: this.courseData,
|
||||
certificateCollection: this.certificateCollection
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -743,6 +743,7 @@
|
||||
'js/spec/learner_dashboard/program_card_view_spec.js',
|
||||
'js/spec/learner_dashboard/sidebar_view_spec.js',
|
||||
'js/spec/learner_dashboard/program_details_header_spec.js',
|
||||
'js/spec/learner_dashboard/program_details_sidebar_view_spec.js',
|
||||
'js/spec/learner_dashboard/course_card_view_spec.js',
|
||||
'js/spec/learner_dashboard/course_enroll_view_spec.js',
|
||||
'js/spec/learner_dashboard/course_enroll_view_spec_2017.js',
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
@import 'elements/course-card';
|
||||
@import 'elements/program-card';
|
||||
@import 'elements-v2/icons';
|
||||
@import 'elements/progress-circle';
|
||||
@import 'views/program-details';
|
||||
@import 'views/program-list';
|
||||
|
||||
66
lms/static/sass/elements/_progress-circle.scss
Normal file
66
lms/static/sass/elements/_progress-circle.scss
Normal file
@@ -0,0 +1,66 @@
|
||||
$progress-title-color: $blue-d1 !default;
|
||||
$progress-complete-color: $blue-u1 !default;
|
||||
$progress-incomplete-color: $gray-l3 !default;
|
||||
$progress-complete-number-color: $blue-d1 !default;
|
||||
$progress-incomplete-number-color: $gray !default;
|
||||
$progress-number-label-color: palette(grayscale, base) !default;
|
||||
|
||||
.program-progress {
|
||||
width: 300px;
|
||||
margin: 0 auto 30px;
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-heading {
|
||||
color: $progress-title-color;
|
||||
text-align: center;
|
||||
margin-bottom: 0;
|
||||
font: {
|
||||
size: 1.1em;
|
||||
weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-circle-wrapper {
|
||||
position: relative;
|
||||
margin-top: -20px;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
|
||||
.progress-label {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 92px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.numbers {
|
||||
font-size: 3em;
|
||||
color: $progress-incomplete-number-color;
|
||||
|
||||
.complete {
|
||||
color: $progress-complete-number-color;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font: {
|
||||
size: 1.1em;
|
||||
weight: 600;
|
||||
}
|
||||
color: $progress-number-label-color;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-circle {
|
||||
.complete {
|
||||
stroke: $progress-complete-color;
|
||||
}
|
||||
|
||||
.incomplete {
|
||||
stroke: $progress-incomplete-color;
|
||||
}
|
||||
}
|
||||
@@ -47,8 +47,8 @@
|
||||
}
|
||||
|
||||
.crumb {
|
||||
@include float(left);
|
||||
position: relative;
|
||||
float: left;
|
||||
font-size: font-size(x-small);
|
||||
line-height: line-height(x-small);
|
||||
color: palette(grayscale, dark);
|
||||
@@ -78,14 +78,18 @@
|
||||
}
|
||||
|
||||
// CSS for April 2017 version of Program Details Page
|
||||
|
||||
.program-details {
|
||||
.window-wrap {
|
||||
background-color: $white;
|
||||
}
|
||||
}
|
||||
.program-details-wrapper {
|
||||
|
||||
.wrapper-footer {
|
||||
@include clearfix();
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
.program-details-wrapper {
|
||||
.program-details-header {
|
||||
background-color: $light-gray4;
|
||||
display: flex;
|
||||
@@ -93,14 +97,20 @@
|
||||
font-family: 'Open Sans';
|
||||
font-weight: normal;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 40px;
|
||||
padding-bottom: 35px;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
padding: 40px 10px 35px;
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
margin-left: 30px;
|
||||
margin-right: 80px;
|
||||
padding: {
|
||||
left: 30px;
|
||||
right: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: $lms-max-width) {
|
||||
padding: {
|
||||
left: calc(((100% - 1180px) / 2) + 30px);
|
||||
right: calc(((100% - 1180px) / 2) + 30px);
|
||||
}
|
||||
}
|
||||
|
||||
.hd-1 {
|
||||
@@ -111,7 +121,7 @@
|
||||
}
|
||||
|
||||
.program-details-icon {
|
||||
margin-left: 3px;
|
||||
@include margin-left(3px);
|
||||
margin-top: 10px;
|
||||
height: auto;
|
||||
|
||||
@@ -177,7 +187,7 @@
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
@media(min-width: $bp-screen-md) {
|
||||
margin: 10px 0 0 0;
|
||||
@include margin-right(10px 0 0 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -187,8 +197,8 @@
|
||||
width: 30%;
|
||||
|
||||
.orgs .org-logo {
|
||||
@include margin-left(2.5%);
|
||||
width: 46.5%;
|
||||
margin-left: 2.5%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
@@ -197,26 +207,49 @@
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.program-details-content {
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
padding: 30px 10px;
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
margin-left: 30px;
|
||||
@include float(left);
|
||||
padding: {
|
||||
left: 30px;
|
||||
right: 30px;
|
||||
}
|
||||
width: calc( 100% - 330px );
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media(min-width: $bp-screen-lg) {
|
||||
width: calc( 100% - 510px );
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
@media(min-width: $lms-max-width) {
|
||||
@include margin-left(calc((100% - 1180px) / 2));
|
||||
}
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.course-list-heading {
|
||||
font-family: "Open Sans";
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
color: palette(primary, dark);
|
||||
font-size: 0.9375em;
|
||||
line-height: normal;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 3px solid $divider-color;
|
||||
margin: {
|
||||
top: 10px;
|
||||
bottom: 20px;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-right: 7px;
|
||||
@include margin-right(7px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,27 +258,9 @@
|
||||
}
|
||||
|
||||
.course-list-headings {
|
||||
width: 700px;
|
||||
|
||||
.divider {
|
||||
margin-left: 0;
|
||||
margin-bottom: 20px;
|
||||
background-color: $divider-color;
|
||||
margin-top: 5px;
|
||||
height: 3px;
|
||||
width: 315px;
|
||||
@media(min-width: $bp-screen-sm) {
|
||||
width: 550px;
|
||||
}
|
||||
@media(min-width: $bp-screen-md) {
|
||||
width: 700px;
|
||||
}
|
||||
border: none;
|
||||
}
|
||||
|
||||
.motivating-section {
|
||||
@include margin-left(15px);
|
||||
font-size: 0.9375em;
|
||||
margin-left: 15px;
|
||||
width: 310px;
|
||||
@media(min-width: $bp-screen-sm) {
|
||||
width: auto;
|
||||
@@ -264,11 +279,7 @@
|
||||
}
|
||||
|
||||
.program-heading {
|
||||
@media(min-width: $bp-screen-md) {
|
||||
width: 70%;
|
||||
}
|
||||
width: 90%;
|
||||
margin-top: 40px;
|
||||
width: 100%;
|
||||
margin-bottom: 40px;
|
||||
|
||||
.program-heading-title {
|
||||
@@ -313,17 +324,17 @@
|
||||
|
||||
/* IE11 CSS styles */
|
||||
@media(min-width: $bp-screen-md) and (-ms-high-contrast: none), (-ms-high-contrast: active) {
|
||||
float: right;
|
||||
@include float(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
.select-choice {
|
||||
@include margin-right(2px);
|
||||
font-family: "Open Sans";
|
||||
font-weight: bold;
|
||||
font-size: 0.9375em;
|
||||
color: palette(grayscale, base);
|
||||
margin-top: 6px;
|
||||
margin-right: 2px;
|
||||
display: block;
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
@@ -339,21 +350,19 @@
|
||||
}
|
||||
}
|
||||
.run-select {
|
||||
@include margin-right(10px);
|
||||
width: 95%;
|
||||
@media(min-width: $bp-screen-sm) {
|
||||
width: 300px;
|
||||
}
|
||||
height: 34px;
|
||||
padding: 0;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.program-course-card {
|
||||
@media(min-width: $bp-screen-md) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
@@ -363,12 +372,6 @@
|
||||
.section {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-right: 40px;
|
||||
margin-left: 15px;
|
||||
|
||||
@media(min-width: $bp-screen-sm) {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
flex-wrap: wrap;
|
||||
@@ -400,9 +403,12 @@
|
||||
.course-meta-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,6 +423,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.course-certificate {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.upgrade-message {
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -432,7 +442,7 @@
|
||||
|
||||
/* IE11 CSS styles */
|
||||
@media(min-width: $bp-screen-md) and (-ms-high-contrast: none), (-ms-high-contrast: active) {
|
||||
float: right;
|
||||
@include float(right);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,6 +505,109 @@
|
||||
font-size: 0.9375em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.program-sidebar {
|
||||
padding: 30px 10px;
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
@include float(right);
|
||||
width: 300px;
|
||||
padding-right: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media(min-width: $bp-screen-lg) {
|
||||
width: 450px;
|
||||
|
||||
.program-progress {
|
||||
@include margin-left(50px);
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: $lms-max-width) {
|
||||
@include margin-right(calc((100% - 1180px) / 2));
|
||||
}
|
||||
}
|
||||
|
||||
.certificate-heading {
|
||||
margin-bottom: 10px;
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
@include margin-right(30px);
|
||||
}
|
||||
|
||||
@media(min-width: $bp-screen-lg) {
|
||||
@include margin-left(10px);
|
||||
@include margin-right(0);
|
||||
}
|
||||
}
|
||||
|
||||
.program-cert-link {
|
||||
display: inline-block;
|
||||
|
||||
&:active,
|
||||
&:focus,
|
||||
&:hover {
|
||||
.program-cert {
|
||||
border-color: $blue-d1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.program-cert {
|
||||
width: 100%;
|
||||
border: 1px solid $divider-color;
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
width: calc(100% - 30px);
|
||||
}
|
||||
|
||||
@media(min-width: $bp-screen-lg) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.certificate-list {
|
||||
@include margin(0, 0, 0, 10px);
|
||||
list-style: none;
|
||||
|
||||
.certificate {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 5px 0 10px;
|
||||
}
|
||||
|
||||
.certificate-link {
|
||||
@include margin-left(20px);
|
||||
color: $black;
|
||||
font: {
|
||||
size: 1.1em;
|
||||
weight: 600;
|
||||
}
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
@media(min-width: $bp-screen-lg) {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&:focus,
|
||||
&:hover {
|
||||
.sample-cert {
|
||||
border-color: $blue-d1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sample-cert {
|
||||
width: 120px;
|
||||
border: 3px solid $gray-l3;
|
||||
border-radius: 5px;
|
||||
|
||||
.expired-notification {
|
||||
display: inline-block;
|
||||
@@ -511,7 +624,7 @@
|
||||
}
|
||||
|
||||
.expired-icon {
|
||||
float: left;
|
||||
@include float(left);
|
||||
color: palette(primary, dark);
|
||||
}
|
||||
|
||||
@@ -520,5 +633,12 @@
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
@media(min-width: $bp-screen-md) {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
@media(min-width: $bp-screen-lg) {
|
||||
width: 120px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
lms/templates/learner_dashboard/certificate_list.underscore
Normal file
13
lms/templates/learner_dashboard/certificate_list.underscore
Normal file
@@ -0,0 +1,13 @@
|
||||
<div class="certificate-container">
|
||||
<% if (title) { %>
|
||||
<h2 class="course-list-heading"><%- title %></h2>
|
||||
<% } %>
|
||||
<ul class="certificate-list">
|
||||
<% _.each(certificateList, function(certificate){ %>
|
||||
<li class="certificate">
|
||||
<a class="image-link" href="<%- certificate.url %>" aria-hidden="true" tabindex="-1"><img src="/static/images/programs/sample-cert.png" class="sample-cert" alt=""></a>
|
||||
<a class="certificate-link" href="<%- certificate.url %>"><%- certificate.title %></a>
|
||||
</li>
|
||||
<% }); %>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="course-actions col-12 md-col-4 sm-col-12"></div>
|
||||
<div class="certificate-status"></div>
|
||||
<div class="course-certificate certificate-status"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section action-msg-view"></div>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<aside class="aside js-program-progress program-progress">
|
||||
<% if (programCertificate) { %>
|
||||
<h2 class="progress-heading certificate-heading"><%- StringUtils.interpolate(gettext('Your {program} Certificate'), {program: type}, true) %></h2>
|
||||
|
||||
<a href="<%- programCertificate.url %>" class="program-cert-link">
|
||||
<img src="<%- programCertificate.img %>" class="program-cert" alt="<%- interpolate(gettext('Open the certificate you earned for the %(title)s program.'), {title: programCertificate.title}, true) %>" />
|
||||
</a>
|
||||
<% } %>
|
||||
</aside>
|
||||
<aside class="aside js-course-certificates"></aside>
|
||||
@@ -1,6 +1,5 @@
|
||||
<header class="js-program-header program-header full-width-banner"></header>
|
||||
<div class="program-details-content">
|
||||
<div class="js-program-progress-view"></div>
|
||||
<section class="program-details-content">
|
||||
<div class="program-heading">
|
||||
<% if (inProgressCount === totalCount) { %>
|
||||
<h3 class="program-heading-title"><%- gettext('Congratulations!') %></h3>
|
||||
@@ -29,7 +28,6 @@
|
||||
<span class="status"><%- gettext('COURSES IN PROGRESS') %></span>
|
||||
<span class="count"><%- inProgressCount %></span>
|
||||
</h4>
|
||||
<div class="divider"></div>
|
||||
<div class="course-list js-course-list-in-progress row"></div>
|
||||
</div>
|
||||
<% } %>
|
||||
@@ -39,7 +37,6 @@
|
||||
<span class="status"><%- gettext('REMAINING COURSES') %></span>
|
||||
<span class="count"><%- remainingCount %></span>
|
||||
</h4>
|
||||
<div class="divider"></div>
|
||||
<div class="course-list js-course-list-remaining row"></div>
|
||||
</div>
|
||||
<% } %>
|
||||
@@ -48,7 +45,6 @@
|
||||
<span class="status"><%- gettext('COMPLETED COURSES') %></span>
|
||||
<span class="count"><%- completedCount %></span>
|
||||
</h4>
|
||||
<div class="divider"></div>
|
||||
<% if (completedCount) { %>
|
||||
<div class="course-list js-course-list-completed row"></div>
|
||||
<% } else { %>
|
||||
@@ -59,6 +55,5 @@
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="js-course-sidebar"></aside>
|
||||
</div>
|
||||
</section>
|
||||
<aside class="js-program-sidebar program-sidebar"></aside>
|
||||
|
||||
Reference in New Issue
Block a user