feat: course card redesign

This commit is contained in:
pateljannat
2021-06-28 12:52:10 +05:30
parent f8948ac2ef
commit 9bc5408a44
37 changed files with 389 additions and 94 deletions

View File

@@ -21,12 +21,14 @@
"engine": "InnoDB",
"field_order": [
"title",
"is_published",
"disable_self_learning",
"column_break_3",
"short_code",
"video_link",
"column_break_3",
"is_published",
"disable_self_learning",
"image",
"section_break_5",
"tags",
"short_introduction",
"description"
],
@@ -80,6 +82,17 @@
"fieldname": "disable_self_learning",
"fieldtype": "Check",
"label": "Disable Self Learning"
},
{
"fieldname": "image",
"fieldtype": "Attach Image",
"label": "Preview Image",
"reqd": 1
},
{
"fieldname": "tags",
"fieldtype": "Data",
"label": "Tags"
}
],
"index_web_pages_for_search": 1,
@@ -106,7 +119,7 @@
"link_fieldname": "course"
}
],
"modified": "2021-06-21 11:34:04.552376",
"modified": "2021-06-28 12:04:21.524161",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Course",

View File

@@ -241,6 +241,9 @@ class LMSCourse(Document):
member_names = [m['member'] for m in memberships]
return find_all("User", name=["IN", member_names])
def get_tags(self):
return self.tags.split(",") if self.tags else []
def get_outline(self):
return CourseOutline(self)

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt
frappe.ui.form.on('LMS Course Review', {
// refresh: function(frm) {
// }
});

View File

@@ -0,0 +1,49 @@
{
"actions": [],
"creation": "2021-06-28 12:30:02.111289",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"review",
"rating"
],
"fields": [
{
"fieldname": "review",
"fieldtype": "Small Text",
"in_list_view": 1,
"label": "Review",
"reqd": 1
},
{
"fieldname": "rating",
"fieldtype": "Rating",
"label": "Rating"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-06-28 12:30:15.953008",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Course Review",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class LMSCourseReview(Document):
pass

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestLMSCourseReview(unittest.TestCase):
pass

View File

@@ -17,7 +17,7 @@
--h-color: var(--c2);
--text-color: #333;
--text-color: #192734;
--text-color-light: #ccc;
--cta-color: var(--c4);
@@ -25,6 +25,8 @@
--received-message: var(--c8);
--checkbox-size: 14px;
--control-bg: var(--gray-100);
--muted-text: #4C5A67;
--button-background: #EEF0F2;
}
body {
@@ -32,18 +34,6 @@ body {
margin: 0px;
}
/* .course-details {
margin: 20px 0px;
}
.course-details h2 {
color: var(--h-color);
font-size: 1.4em;
font-weight: bold;
margin: 20px 0px 10px 0px;
} */
.chapter-plan {
border-radius: 10px;
margin: 20px 0px;
@@ -57,21 +47,6 @@ body {
font-weight: bold;
}
/* .chapter-number {
background: var(--text-color);
color: white;
border-radius: 50%;
height: 24px;
min-width: 24px;
align-items: center;
padding: 2px 8px 2px 8px;
margin-right: 5px;
}
.chapter-description {
margin: 20px 0px;
} */
.lessons {
padding-left: 20px;
}
@@ -265,3 +240,195 @@ input[type=checkbox] {
border-radius: 50px;
padding: 5px;
}
.course-image {
height: 168px;
width: 352px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
background-size: 352px 168px;
}
@media (max-width: 768px) {
.course-image {
width: 336px;
}
}
@media (max-width: 375px) {
.course-image {
width: 312px;
background-size: cover;
background-repeat: no-repeat;
}
}
.course-tags {
display: flex;
position: relative;
top: 12px;
left: 12px;
height: 20px;
}
.course-card-pills {
background: #ffffff;
margin: 0px 10px;
border-radius: 4px;
padding: 4px 6px;
font-size: 10px;
line-height: 120%;
text-align: center;
letter-spacing: 0.011em;
text-transform: uppercase;
color: #2C5477;
font-weight: bold;
box-shadow: 0px 5px 10px rgb(0 0 0 / 10%);
}
.common-page-style {
background: #F4F5F6;
}
.common-card-style {
display: flex;
flex-direction: column;
align-items: flex-start;
background: #FFFFFF;
border-radius: 8px;
width: 352px;
height: 380px;
margin: 0px 16px 32px;
box-shadow: 0px 5px 10px rgb(0 0 0 / 10%);
}
@media (max-width: 768px) {
.common-card-style {
width: 336px;
}
}
@media (max-width: 375px) {
.common-card-style {
width: 312px;
}
}
.course-card-meta {
font-size: 12px;
line-height: 135%;
margin: 12px 16px 8px;
color: var(--muted-text);
height: 15px;
}
.course-card-content {
width: 100%;
}
.course-card-title {
font-weight: 600;
font-size: 18px;
line-height: 156%;
letter-spacing: -0.014em;
color: var(--text-color);
align-self: stretch;
margin: 0px 16px 16px;
height: 45px;
}
.card-divider {
border: 1px solid #E2E6E9;
margin: 0px 16px 16px;
}
.course-card-meta-2 {
margin: 0px 16px 16px;
}
.course-instructor {
margin: 0px 8px;
font-size: 12px;
line-height: 135%;
color: var(--text-color);
}
.course-student-count {
font-size: 12px;
line-height: 135%;
color: var(--muted-text);
float: right;
}
.view-course-link {
height: 32px;
margin: 0px 16px 16px;
background: var(--button-background);
border-radius: 4px;
font-size: 12px;
padding: 8px 0px 8px;
text-align: center;
line-height: 135%;
color: var(--text-color);
}
.course-cards-parent {
display: flex;
flex-wrap: wrap;
}
@media (max-width: 375px) {
.course-cards-parent {
justify-content: center;
}
}
.course-divider {
border: 1px solid #E2E6E9;
margin: 16px 0px 30px;
}
.courses-header {
padding: 50px 0px 20px;
color: var(--text-color);
font-weight: 600;
font-size: 22px;
line-height: 145%;
letter-spacing: -0.0175em
}
.course-top-section {
margin: 0px 140px 0px;
}
@media (max-width: 768px) {
.course-top-section {
margin: 0px 40px 0px;
}
}
@media (max-width: 375px) {
.course-top-section {
margin: 0px 24px 0px;
}
}
.is-primary {
background: var(--primary-color);
color: #FFFFFF;
}
.button-links:hover {
text-decoration: none;
}
.icon-background {
border-radius: 50%;
padding: 3px;
width: 24px;
height: 24px;
}
.small-margin {
margin-left: 10px;
}

View File

@@ -138,39 +138,6 @@ section.lightgray {
color: var(--tag-color);
}
.course-header {
margin-top: 20px;
}
/*
.course-header {
margin-top: 20px;
padding: 20px;
background: var(--header-bg);
color: var(--header-color);
border-radius: 9px;
}
.course-author-avatar {
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 20px;
}
.course-header h1 {
color: inherit;
}
*/
// .gray-section {
// background:#F6F6F6;
// border: 1px solid #C4C4C4;
// padding: 20px;
// margin: 20px 0px;
// }
.instructor-title {
color: black;
}

View File

@@ -0,0 +1,3 @@
<svg width="13" height="8" viewBox="0 0 13 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.9649 0.313118C8.76964 0.117856 8.45306 0.117856 8.2578 0.313118C8.06253 0.50838 8.06253 0.824963 8.2578 1.02023L10.7374 3.49985L1.16683 3.49719C0.890684 3.49712 0.666764 3.72091 0.666687 3.99705C0.66661 4.2732 0.890406 4.49712 1.16655 4.49719L10.7377 4.49985L8.2578 6.97978C8.06253 7.17505 8.06253 7.49163 8.2578 7.68689C8.45306 7.88215 8.76964 7.88215 8.9649 7.68689L12.2982 4.35356C12.4935 4.1583 12.4935 3.84171 12.2982 3.64645L8.9649 0.313118Z" fill="#4C5A67"/>
</svg>

After

Width:  |  Height:  |  Size: 619 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.8947 2.47619C15.8947 2.2132 15.6885 2 15.4342 2C15.1798 2 14.9737 2.2132 14.9737 2.47619V3.90476H8.52631V2.47619C8.52631 2.2132 8.32013 2 8.06579 2C7.81145 2 7.60526 2.2132 7.60526 2.47619V3.90476H5.30263C4.03092 3.90476 3 4.97074 3 6.28571V10.0952V19.619C3 20.934 4.03092 22 5.30263 22H18.1974C19.4691 22 20.5 20.934 20.5 19.619V10.0952V6.28571C20.5 4.97074 19.4691 3.90476 18.1974 3.90476H15.8947V2.47619ZM19.579 9.61905V6.28571C19.579 5.49673 18.9604 4.85714 18.1974 4.85714H15.8947V6.28572C15.8947 6.54871 15.6885 6.76191 15.4342 6.76191C15.1798 6.76191 14.9737 6.54871 14.9737 6.28572V4.85714H8.52631V6.28572C8.52631 6.54871 8.32013 6.76191 8.06579 6.76191C7.81145 6.76191 7.60526 6.54871 7.60526 6.28572V4.85714H5.30263C4.53961 4.85714 3.92105 5.49673 3.92105 6.28571V9.61905H19.579ZM3.92105 10.5714H19.579V19.619C19.579 20.408 18.9604 21.0476 18.1974 21.0476H5.30263C4.53961 21.0476 3.92105 20.408 3.92105 19.619V10.5714Z" fill="#4C5A67"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 11.9999C3 7.02937 7.02937 3 11.9999 3C16.9703 3 20.9997 7.02937 20.9997 11.9999C20.9997 16.9703 16.9703 20.9997 11.9999 20.9997C7.02937 20.9997 3 16.9703 3 11.9999ZM11.9999 2C6.47709 2 2 6.47709 2 11.9999C2 17.5226 6.47709 21.9997 11.9999 21.9997C17.5226 21.9997 21.9997 17.5226 21.9997 11.9999C21.9997 6.47709 17.5226 2 11.9999 2ZM12.5002 6.30027C12.5002 6.02413 12.2763 5.80027 12.0002 5.80027C11.724 5.80027 11.5002 6.02413 11.5002 6.30027V12.0002C11.5002 12.1896 11.6072 12.3627 11.7766 12.4474L15.5765 14.3474C15.8235 14.4709 16.1238 14.3708 16.2473 14.1238C16.3708 13.8768 16.2707 13.5764 16.0237 13.4529L12.5002 11.6912V6.30027Z" fill="#4C5A67"/>
</svg>

After

Width:  |  Height:  |  Size: 809 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 1.5C12.1903 1.5 12.3641 1.60804 12.4484 1.77869L15.4221 7.80323L22.0723 8.77526C22.2606 8.80278 22.4169 8.93478 22.4756 9.11578C22.5343 9.29679 22.4852 9.49541 22.3489 9.62818L17.5373 14.3147L18.6728 20.9355C18.705 21.1231 18.6279 21.3127 18.4739 21.4245C18.3199 21.5364 18.1157 21.5511 17.9473 21.4625L12 18.3349L6.05273 21.4625C5.88427 21.5511 5.68012 21.5364 5.52613 21.4245C5.37214 21.3127 5.29502 21.1231 5.3272 20.9355L6.46274 14.3147L1.65113 9.62818C1.51482 9.49541 1.46569 9.29679 1.52438 9.11578C1.58307 8.93478 1.73941 8.80278 1.92769 8.77526L8.57787 7.80323L11.5516 1.77869C11.6359 1.60804 11.8097 1.5 12 1.5Z" fill="#192734"/>
</svg>

After

Width:  |  Height:  |  Size: 795 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z" stroke="#192734" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 276 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 21V19C20 17.9391 19.5786 16.9217 18.8284 16.1716C18.0783 15.4214 17.0609 15 16 15H8C6.93913 15 5.92172 15.4214 5.17157 16.1716C4.42143 16.9217 4 17.9391 4 19V21" stroke="#192734" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 11C14.2091 11 16 9.20914 16 7C16 4.79086 14.2091 3 12 3C9.79086 3 8 4.79086 8 7C8 9.20914 9.79086 11 12 11Z" stroke="#192734" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 532 B

View File

@@ -0,0 +1,3 @@
<svg width="13" height="8" viewBox="0 0 13 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.96484 0.313118C8.76958 0.117856 8.453 0.117856 8.25773 0.313118C8.06247 0.50838 8.06247 0.824963 8.25773 1.02023L10.7374 3.49985L1.16676 3.49719C0.890623 3.49712 0.666703 3.72091 0.666626 3.99705C0.666549 4.2732 0.890345 4.49712 1.16649 4.49719L10.7377 4.49985L8.25773 6.97978C8.06247 7.17505 8.06247 7.49163 8.25773 7.68689C8.453 7.88215 8.76958 7.88215 8.96484 7.68689L12.2982 4.35356C12.4934 4.1583 12.4934 3.84171 12.2982 3.64645L8.96484 0.313118Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 621 B

View File

View File

View File

View File

@@ -9,37 +9,87 @@
{% endblock %}
{% block content %}
<section class="top-section" style="padding: 1rem 0rem;">
<div class='container'>
<h4 class="mt-5">{{ 'All Courses' }}</h4>
<div class="row mt-5">
{% for course in courses %}
{{ course_card(course) }}
{% endfor %}
<!-- {% if courses %}
{% for n in range( (3 - (courses|length)) %3) %}
{{ null_card() }}
{% endfor %}
{% endif %} -->
<div class="common-page-style">
<div class="">
<div class="course-top-section">
<div class="courses-header">
{{ 'All Courses' }}
</div>
<div class="course-divider"></div>
<div class="course-cards-parent">
{% for course in courses %}
{{ course_card(course) }}
{% endfor %}
</div>
</div>
</div>
</section>
</div>
{% endblock %}
{% macro course_card(course) %}
<div class="col-sm-4 mb-4 text-left">
<a class="anchor_style" style="color: inherit;" href="/courses/{{course.name}}">
<div class="card h-100" style="box-shadow: 0px 5px 10px rgb(0 0 0 / 10%);">
<div class='card-body'>
<h5 class='card-title'>{{ course.title }}</h5>
{% if course.description %}
<div class="mt-4">
{{ frappe.utils.md_to_html(course.description[:200]) }}
</div>
{% endif %}
</div>
<div class="common-card-style">
<div class="course-image" style="background-image: url({{ course.image }});">
<div class="course-tags">
{% for tag in course.get_tags() %}
<div class="course-card-pills">{{ tag }}</div>
{% endfor %}
</div>
</a>
</div>
<div class="course-card-content">
<div class="course-card-meta">
{% if course.get_chapters() | length %}
<span>
{{ course.get_chapters() | length }} Chapters
</span>
{% endif %}
{% if course.get_chapters() | length and course.get_upcoming_batches() | length %}
<span class="font-weight-bold ml-3 mr-3"> . </span>
{% endif %}
{% if course.get_upcoming_batches() | length %}
<span class="">
{{ course.get_upcoming_batches() | length }} Open Batches
</span>
{% endif %}
</div>
<div class="course-card-title">{{ course.title }}</div>
<div class="card-divider"></div>
<div class="course-card-meta-2">
{{ widgets.Avatar(member=course.get_instructor(), avatar_class="avatar-small") }}
<span class="course-instructor">
{{ course.get_instructor().full_name }}
</span>
{% if course.get_students() | length %}
<span class="course-student-count">
<img class="icon-background mr-1" src="/assets/community/icons/user.svg" />
{{ course.get_students() | length }}
</span>
{% endif %}
</div>
<a class="button-links" href="/courses/{{ course.name }}">
{% if course.get_membership(frappe.session.user) %}
<div class="view-course-link is-primary">
Continue Course <img class="ml-3" src="/assets/community/icons/white-arrow.svg" />
</div>
{% else %}
<div class="view-course-link">
View Course <img class="ml-3" src="/assets/community/icons/black-arrow.svg" />
</div>
{% endif %}
</a>
</div>
</div>
{% endmacro %}
{% block script %}
<script>
frappe.ready(() => {
$(".course-card-title").each((i, element) => {
var title = $(element).text();
var length = $(window).width() <= 375 ? 60 : 65;
var suffix = title.length > length ? "..." : "";
$(element).text(title.substring(0, length) + suffix);
})
})
</script>
{% endblock %}

View File

@@ -5,8 +5,8 @@ def get_context(context):
context.courses = get_courses()
def get_courses():
courses = frappe.get_all(
"LMS Course",
fields=['name', 'title', 'description']
)
course_names = frappe.get_all("LMS Course", pluck="name")
courses = []
for course in course_names:
courses.append(frappe.get_doc("LMS Course", course))
return courses

View File

View File

View File

View File

View File

View File

View File