Commit 939a3672 by marjev Committed by Marko Jevtic

(SOL-531)(SOL-532)Course Cards update; A link to course discovery page has been…

(SOL-531)(SOL-532)Course Cards update; A link to course discovery page has been added to the OpenEdX homepage
parent 4ec713e9
...@@ -202,9 +202,9 @@ class IndexPageCourseCardsSortingTests(ModuleStoreTestCase): ...@@ -202,9 +202,9 @@ class IndexPageCourseCardsSortingTests(ModuleStoreTestCase):
((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence ((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence
self.assertEqual(template, 'index.html') self.assertEqual(template, 'index.html')
# Now the courses will be stored in their announcement dates. # by default the courses will be sorted by their creation dates, earliest first.
self.assertEqual(context['courses'][0].id, self.starting_later.id) self.assertEqual(context['courses'][0].id, self.starting_earlier.id)
self.assertEqual(context['courses'][1].id, self.starting_earlier.id) self.assertEqual(context['courses'][1].id, self.starting_later.id)
self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id) self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id)
# check the /courses view # check the /courses view
...@@ -213,23 +213,23 @@ class IndexPageCourseCardsSortingTests(ModuleStoreTestCase): ...@@ -213,23 +213,23 @@ class IndexPageCourseCardsSortingTests(ModuleStoreTestCase):
((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence ((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence
self.assertEqual(template, 'courseware/courses.html') self.assertEqual(template, 'courseware/courses.html')
# Now the courses will be stored in their announcement dates. # by default the courses will be sorted by their creation dates, earliest first.
self.assertEqual(context['courses'][0].id, self.starting_later.id) self.assertEqual(context['courses'][0].id, self.starting_earlier.id)
self.assertEqual(context['courses'][1].id, self.starting_earlier.id) self.assertEqual(context['courses'][1].id, self.starting_later.id)
self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id) self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id)
@patch('student.views.render_to_response', RENDER_MOCK) @patch('student.views.render_to_response', RENDER_MOCK)
@patch('courseware.views.render_to_response', RENDER_MOCK) @patch('courseware.views.render_to_response', RENDER_MOCK)
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_COURSE_SORTING_BY_START_DATE': True}) @patch.dict('django.conf.settings.FEATURES', {'ENABLE_COURSE_SORTING_BY_START_DATE': False})
def test_course_cards_sorted_by_start_date_show_earliest_first(self): def test_course_cards_sorted_by_start_date_disabled(self):
response = self.client.get('/') response = self.client.get('/')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence ((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence
self.assertEqual(template, 'index.html') self.assertEqual(template, 'index.html')
# now the courses will be sorted by their creation dates, earliest first. # now the courses will be sorted by their announcement dates.
self.assertEqual(context['courses'][0].id, self.starting_earlier.id) self.assertEqual(context['courses'][0].id, self.starting_later.id)
self.assertEqual(context['courses'][1].id, self.starting_later.id) self.assertEqual(context['courses'][1].id, self.starting_earlier.id)
self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id) self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id)
# check the /courses view as well # check the /courses view as well
...@@ -238,7 +238,7 @@ class IndexPageCourseCardsSortingTests(ModuleStoreTestCase): ...@@ -238,7 +238,7 @@ class IndexPageCourseCardsSortingTests(ModuleStoreTestCase):
((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence ((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence
self.assertEqual(template, 'courseware/courses.html') self.assertEqual(template, 'courseware/courses.html')
# now the courses will be sorted by their creation dates, earliest first. # now the courses will be sorted by their announcement dates.
self.assertEqual(context['courses'][0].id, self.starting_earlier.id) self.assertEqual(context['courses'][0].id, self.starting_later.id)
self.assertEqual(context['courses'][1].id, self.starting_later.id) self.assertEqual(context['courses'][1].id, self.starting_earlier.id)
self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id) self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id)
...@@ -383,7 +383,11 @@ def sort_by_start_date(courses): ...@@ -383,7 +383,11 @@ def sort_by_start_date(courses):
""" """
Returns a list of courses sorted by their start date, latest first. Returns a list of courses sorted by their start date, latest first.
""" """
courses = sorted(courses, key=lambda course: (course.start is None, course.start), reverse=False) courses = sorted(
courses,
key=lambda course: (course.has_ended(), course.start is None, course.start),
reverse=False
)
return courses return courses
......
...@@ -308,7 +308,7 @@ FEATURES = { ...@@ -308,7 +308,7 @@ FEATURES = {
# When a user goes to the homepage ('/') the user see the # When a user goes to the homepage ('/') the user see the
# courses listed in the announcement dates order - this is default Open edX behavior. # courses listed in the announcement dates order - this is default Open edX behavior.
# Set to True to change the course sorting behavior by their start dates, latest first. # Set to True to change the course sorting behavior by their start dates, latest first.
'ENABLE_COURSE_SORTING_BY_START_DATE': False, 'ENABLE_COURSE_SORTING_BY_START_DATE': True,
# Flag to enable new user account APIs. # Flag to enable new user account APIs.
'ENABLE_USER_REST_API': False, 'ENABLE_USER_REST_API': False,
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
@import 'views/verification'; @import 'views/verification';
@import 'views/shoppingcart'; @import 'views/shoppingcart';
@import 'views/login-register'; @import 'views/login-register';
@import 'views/homepage';
// applications // applications
@import "discussion/utilities/variables"; @import "discussion/utilities/variables";
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
@import 'views/verification'; @import 'views/verification';
@import 'views/decoupled-verification'; @import 'views/decoupled-verification';
@import 'views/shoppingcart'; @import 'views/shoppingcart';
@import 'views/homepage';
@import 'course/auto-cert'; @import 'course/auto-cert';
// applications // applications
......
...@@ -4,10 +4,13 @@ ...@@ -4,10 +4,13 @@
$max-width: 1200px; $max-width: 1200px;
/* Override the default global box-sizing */ /* Override the default global box-sizing */
$border-box-sizing: false; $border-box-sizing: false;
/* Grid width variables */
$large-min-width: 769px;
/* Breakpoints */ /* Breakpoints */
$mobile: new-breakpoint(max-width 320px 4); $bp-tiny: new-breakpoint(max-width 320px 4);
$tablet: new-breakpoint(min-width 321px max-width 768px, 8); $bp-small: new-breakpoint(min-width 321px max-width 540px, 4);
$desktop: new-breakpoint(min-width 769px 12); $bp-medium: new-breakpoint(min-width 541px max-width 768px, 8);
$xl-desktop: new-breakpoint(min-width 980px 12); $bp-large: new-breakpoint(min-width $large-min-width max-width 979px, 12);
$bp-huge: new-breakpoint(min-width 980px 12);
...@@ -13,23 +13,6 @@ ...@@ -13,23 +13,6 @@
} }
} }
.courses-listing {
@include clearfix();
margin: 0;
padding: 0;
list-style: none;
.courses-listing-item {
width: flex-grid(4);
@include margin-right(flex-gutter());
@include float(left);
&:nth-child(3n+3) {
@include margin-right(0);
}
}
}
.course { .course {
background: $body-bg; background: $body-bg;
border: 1px solid $border-color-1; border: 1px solid $border-color-1;
......
...@@ -446,10 +446,10 @@ $edx-footer-bg-color: rgb(252,252,252); ...@@ -446,10 +446,10 @@ $edx-footer-bg-color: rgb(252,252,252);
@include span-columns(12); @include span-columns(12);
} }
@include media( $tablet ) { @include media( $bp-medium ) {
} }
@include media( $desktop ) { @include media( $bp-large ) {
.footer-about { .footer-about {
@include span-columns(6); @include span-columns(6);
} }
......
...@@ -765,7 +765,7 @@ header.global-new { ...@@ -765,7 +765,7 @@ header.global-new {
} }
} }
@include media( $desktop ) { @include media( $bp-large ) {
.wrapper-header { .wrapper-header {
width: 100%; width: 100%;
min-width: 800px; min-width: 800px;
...@@ -828,7 +828,7 @@ header.global-new { ...@@ -828,7 +828,7 @@ header.global-new {
} }
} }
@include media( $xl-desktop ) { @include media( $bp-huge ) {
.wrapper-header { .wrapper-header {
padding: 17px 0; padding: 17px 0;
} }
......
// lms - views - homepage view
// ====================
$course-card-height: ($baseline*18);
$course-image-height: ($baseline*8);
$course-info-height: ($baseline*10);
$course-title-height: ($baseline*3.6);
$learn-more-horizontal-position: calc(50% - 100px); // calculate the left position for "LEARN MORE" content
.courses-container {
@include outer-container;
padding: ($baseline*0.9) ($baseline/2) 0 ($baseline/2);
.courses {
@include row();
.courses-listing {
@extend %ui-no-list;
.courses-listing-item {
@include fill-parent();
max-height: $course-card-height;
margin: ($baseline*0.75) 0 ($baseline*1.5) 0;
@include media($bp-medium) {
@include span-columns(4); // 4 of 8
@include omega(2n);
}
@include media($bp-large) {
@include span-columns(4); // 4 of 12
@include omega(3n);
}
@include media($bp-huge) {
@include span-columns(3); // 3 of 12
@include omega(4n);
}
}
}
.course {
@include box-sizing(border-box);
@include transition(all $tmg-f3 linear 0s);
position: relative;
border-bottom: 3px solid $action-primary-bg;
box-shadow: 0 1px 10px 0 $black-t0, inset 0 0 0 1px $white-t3;
background: $body-bg;
width: 100%;
.course-image .cover-image {
height: $course-image-height;
overflow: hidden;
// places the shadow on top of the course image while hovering over the course card
&:before {
@include left(0);
@extend %ui-depth1;
position: absolute;
top: 0;
opacity: 0;
background: $black;
width: 100%;
height: $course-image-height;
content: '';
}
img {
width: 100%;
height: auto;
}
.learn-more {
@include left($learn-more-horizontal-position);
@include box-sizing(border-box);
@include line-height(28);
@extend %ui-depth2;
position: absolute;
top: ($baseline*2.75);
opacity: 0;
border: 3px solid $white;
border-radius: 3px;
padding: 0 $baseline;
width: ($baseline*10);
height: ($baseline*2.5);
text-align: center;
color: $white;
}
}
.course-info {
height: $course-info-height;
.course-organization, .course-code, .course-date {
@extend %t-icon6;
color: $black;
}
.course-organization, .course-code, .course-title {
display: block;
}
.course-organization {
@include line-height(11);
padding: ($baseline/2) ($baseline*0.75) ($baseline/10) ($baseline*0.75);
}
.course-code {
@include line-height(16);
padding: 0 ($baseline*0.75);
}
.course-title {
@include line-height(16);
@extend %t-icon4;
margin: ($baseline*0.25) 0 ($baseline*1.75) 0;
padding: 0 ($baseline*0.75);
height: $course-title-height;
color: $link-color;
}
.course-date {
@include line-height(14);
padding: ($baseline/10) ($baseline*0.75);
}
}
// STATE: hover and focus
&:hover,
&:focus {
.cover-image {
&:before {
@include transition(opacity $tmg-f2 ease-out $tmg-f2);
opacity: 0.6;
}
.learn-more {
@include transition(opacity $tmg-f2 ease-out $tmg-f2);
opacity: 1;
}
}
}
}
}
.courses-more {
@include margin-right(0);
text-align: center;
@include media($large-min-width) {
@include margin-right($baseline*0.5);
@include text-align(right);
}
.courses-more-cta {
font-weight: $font-semibold;
&:after {
content: " ›";
}
}
}
}
...@@ -1420,7 +1420,7 @@ ...@@ -1420,7 +1420,7 @@
} }
} }
@include media( $desktop ) { @include media( $bp-large ) {
.contribution-options { .contribution-options {
.field { .field {
width: auto; width: auto;
...@@ -1443,7 +1443,7 @@ ...@@ -1443,7 +1443,7 @@
} }
} }
@include media( $xl-desktop ) { @include media( $bp-huge ) {
.register-choice { .register-choice {
.list-actions { .list-actions {
float: right; float: right;
......
...@@ -5,35 +5,28 @@ from django.core.urlresolvers import reverse ...@@ -5,35 +5,28 @@ from django.core.urlresolvers import reverse
from courseware.courses import course_image_url, get_course_about_section from courseware.courses import course_image_url, get_course_about_section
%> %>
<%page args="course" /> <%page args="course" />
<article id="${course.id | h}" class="course"> <article class="course" id="${course.id | h}" role="region" aria-label="${get_course_about_section(course, 'title')}">
%if course.is_newish:
<span class="status">${_("New")}</span>
%endif
<a href="${reverse('about_course', args=[course.id.to_deprecated_string()])}"> <a href="${reverse('about_course', args=[course.id.to_deprecated_string()])}">
<div class="inner-wrapper"> <header class="course-image">
<header class="course-preview"> <div class="cover-image">
<hgroup> <img src="${course_image_url(course)}" alt="${get_course_about_section(course, 'title')} ${course.display_number_with_default}" />
<h2><span class="course-number">${course.display_number_with_default | h}</span> ${get_course_about_section(course, 'title')}</h2> <div class="learn-more" aria-hidden=true>${_("LEARN MORE")}</div>
</hgroup> </div>
<div class="info-link">&#x2794;</div> </header>
</header> <section class="course-info" aria-hidden=true>
<section class="info"> <h2 class="course-name">
<div class="cover-image"> <span class="course-organization">${get_course_about_section(course, 'university')}</span>
<img src="${course_image_url(course)}" alt="${course.display_number_with_default | h} ${get_course_about_section(course, 'title')} Cover Image" /> <span class="course-code">${course.display_number_with_default}</span>
</div> <span class="course-title">${get_course_about_section(course, 'title')}</span>
<div class="desc"> </h2>
<p>${get_course_about_section(course, 'short_description')}</p> <div class="course-date" aria-hidden="true">${_("Starts")}: ${course.start_datetime_text()}</div>
</div> </section>
<div class="bottom"> <div class="sr">
<span class="university">${get_course_about_section(course, 'university')}</span> <ul>
% if not course.start_date_is_still_default: <li>${get_course_about_section(course, 'university')}</li>
<span class="start-date">${course.start_datetime_text()}</span> <li>${course.display_number_with_default}</li>
% endif <li>${_("Starts")}: <time itemprop="startDate" datetime="${course.start_datetime_text()}">${course.start_datetime_text()}</time></li>
</div> </ul>
</section>
</div>
<div class="meta-info">
<p class="university">${get_course_about_section(course, 'university')}</p>
</div> </div>
</a> </a>
</article> </article>
<%! <%!
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from microsite_configuration import microsite from microsite_configuration import microsite
%> %>
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
</div> </div>
</header> </header>
<section class="container"> <section class="courses-container">
<section class="courses"> <section class="courses">
<ul class="courses-listing"> <ul class="courses-listing">
%for course in courses: %for course in courses:
......
...@@ -48,19 +48,23 @@ ...@@ -48,19 +48,23 @@
% endif % endif
</div> </div>
</header> </header>
<section class="container"> <section class="courses-container">
<section class="highlighted-courses"> <section class="highlighted-courses">
% if settings.FEATURES.get('COURSES_ARE_BROWSABLE'): % if settings.FEATURES.get('COURSES_ARE_BROWSABLE'):
<section class="courses"> <section class="courses">
<ul class="courses-listing"> <ul class="courses-listing">
%for course in courses: ## cap for showing 9 or less courses
%for course in courses[:9]:
<li class="courses-listing-item"> <li class="courses-listing-item">
<%include file="course.html" args="course=course" /> <%include file="course.html" args="course=course" />
</li> </li>
%endfor %endfor
</ul> </ul>
</section> </section>
<div class="courses-more">
<a class="courses-more-cta" href="${marketing_link('COURSES')}" > ${_("View all Courses")} </a>
</div>
% endif % endif
</section> </section>
......
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