feat: new design system for exisitng course home

This commit is contained in:
Jannat Patel
2023-04-20 17:55:03 +05:30
parent 2b6436915d
commit 6232f8703e
11 changed files with 364 additions and 240 deletions

View File

@@ -138,6 +138,7 @@ fixtures = ["Custom Field", "Function", "Industry"]
website_route_rules = [
{"from_route": "/sketches/<sketch>", "to_route": "sketches/sketch"},
{"from_route": "/courses/<course>", "to_route": "courses/course"},
{"from_route": "/courses/<course>/edit", "to_route": "courses/create"},
{"from_route": "/courses/<course>/<certificate>", "to_route": "courses/certificate"},
{"from_route": "/courses/<course>/learn", "to_route": "batch/learn"},
{

View File

@@ -93,18 +93,24 @@ def get_chapters(course):
return chapters
def get_lessons(course, chapter=None):
def get_lessons(course, chapter=None, get_details=True):
"""If chapter is passed, returns lessons of only that chapter.
Else returns lessons of all chapters of the course"""
lessons = []
lesson_count = 0
if chapter:
return get_lesson_details(chapter)
if get_details:
return get_lesson_details(chapter)
else:
return frappe.db.count("Lesson Reference", {"parent": chapter.name})
for chapter in get_chapters(course):
lesson = get_lesson_details(chapter)
lessons += lesson
if get_details:
lessons += get_lesson_details(chapter)
else:
lesson_count += frappe.db.count("Lesson Reference", {"parent": chapter.name})
return lessons
return lessons if get_details else lesson_count
def get_lesson_details(chapter):

View File

@@ -1,81 +1,64 @@
{% set chapters = get_chapters(course.name) %}
{% set is_instructor = is_instructor(course.name) %}
{% if course.edit_mode or chapters | length %}
{% if chapters | length %}
<div class="course-home-outline">
{% if course.edit_mode and course.name %}
<button class="btn btn-sm btn-secondary btn-chapter pull-right"> {{ _("New Chapter") }} </button>
{% endif %}
{% if course.name and (course.edit_mode or chapters | length) %}
<div class="course-home-headings" id="outline-heading" data-course="{{ course.name }}">
<div class="page-title mb-8" id="outline-heading" data-course="{{ course.name }}">
{{ _("Course Content") }}
</div>
{% endif %}
{% if course.edit_mode and course.name and not chapters | length %}
<div class="chapter-parent chapter-edit new-chapter">
<div contenteditable="true" data-placeholder="{{ _('Chapter Name') }}" class="chapter-title-main"></div>
<div class="chapter-description small my-2" contenteditable="true" data-placeholder="{{ _('Short Description') }}"></div>
<button class="btn btn-sm btn-secondary d-block btn-save-chapter" data-index="1"> {{ _('Save') }} </button>
<div class="mb-2">
<span>
{{ chapters | length }} chapters
</span>
<span>
. {{ get_lessons(course.name, None, False) }} lessons
</span>
</div>
{% endif %}
{% if chapters | length %}
<div class="chapter-dropzone">
<div class="common-card-style column-card p-4">
{% for chapter in chapters %}
<div class="chapter-parent {% if course.edit_mode %} chapter-edit {% endif %}" data-chapter="{{ chapter.name }}">
<div class="chapter-title" {% if not course.edit_mode %} data-toggle="collapse" aria-expanded="false"
data-target="#{{ get_slugified_chapter_title(chapter.title) }}" {% endif %} >
{% if not course.edit_mode %}
{% set lessons = get_lessons(course.name, chapter) %}
<div class="chapter-parent" data-chapter="{{ chapter.name }}">
<div class="chapter-title" data-toggle="collapse" aria-expanded="false"
data-target="#{{ get_slugified_chapter_title(chapter.title) }}">
<img class="chapter-icon" src="/assets/lms/icons/chevron-right.svg">
{% endif %}
<div class="w-100 chapter-title-main" {% if course.edit_mode %} contenteditable="true" {% endif %} >{{ chapter.title }}</div>
<div class="chapter-title-main">
{{ chapter.title }}
</div>
<div class="small ml-auto">
{{ lessons | length }} lessons
</div>
</div>
{% set lessons = get_lessons(course.name, chapter) %}
<div class="chapter-content {% if not course.edit_mode %} collapse navbar-collapse {% endif %} "
id="{{ get_slugified_chapter_title(chapter.title) }}">
<div class="chapter-content collapse navbar-collapse" id="{{ get_slugified_chapter_title(chapter.title) }}">
{% if chapter.description or course.edit_mode %}
<div {% if course.edit_mode %} contenteditable="true" {% endif %} class="chapter-description
{% if not course.edit_mode %} mx-8 mb-2 {% endif %} "
data-placeholder="{{ _('Short Description') }}">{% if chapter.description %}{{ chapter.description }}{% endif %}</div>
{% endif %}
{% if course.edit_mode %}
<div class="mt-2">
<button class="btn btn-sm btn-secondary btn-save-chapter"
data-index="{{ loop.index }}"> {{ _('Save') }} </button>
<a class="btn btn-sm btn-secondary btn-lesson ml-2"
href="/courses/{{ course.name }}/learn/{{loop.index}}.{{ lessons | length + 1 }}?edit=1"> {{ _("New Lesson") }} </a>
{% if chapter.description %}
<div class="chapter-description ml-2 mb-2">
{{ chapter.description }}
</div>
{% endif %}
{% set is_instructor = is_instructor(course.name) %}
{% if course.edit_mode %}
<div class="course-meta mt-8 font-weight-bold"> {{ _("Lessons") }}: </div>
{% endif %}
<div class="lessons {% if course.edit_mode %} lesson-dropzone {% endif %}">
<div class="lessons">
{% if lessons | length %}
{% for lesson in lessons %}
{% set active = membership.current_lesson == lesson.name %}
<div data-lesson="{{ lesson.name }}" class="lesson-info {% if active and not course.edit_mode %} active-lesson {% endif %}">
<div data-lesson="{{ lesson.name }}" class="lesson-info {% if active %} active-lesson {% endif %}">
{% if membership or lesson.include_in_preview or is_instructor or has_course_moderator_role() %}
<a class="lesson-links"
<a class="lesson-links" href="{{ get_lesson_url(course.name, lesson.number) }}{{course.query_parameter}}"
{% if is_instructor and not lesson.include_in_preview %}
title="{{ _('This lesson is not available for preview. As you are the Instructor of the course only you can see it.') }}"
{% endif %}
href="{{ get_lesson_url(course.name, lesson.number) }}{% if course.edit_mode and is_instructor %}?edit=1{% endif %}{{course.query_parameter}}">
{% endif %}>
<svg class="icon icon-sm mr-2">
<use class="" href="#{{ lesson.icon }}">

View File

@@ -21,7 +21,66 @@
border: 1px solid var(--primary-color)
}
.page-title {
font-size: 1.5rem;
font-weight: 600;
color: var(--gray-900);
line-height: 160%;
letter-spacing: 0.005em;
}
.rating .icon {
background: var(--gray-200);
border-radius: var(--border-radius-md);
padding: var(--padding-xs);
}
.rating .star-click {
--star-fill: var(--orange-500);
background: var(--gray-200);
border-radius: var(--border-radius-md);
padding: var(--padding-xs);
}
.cta-parent {
display: flex;
margin-bottom: 1rem;
}
.all-cta {
flex: 1
}
.field-label {
color: var(--gray-900);
font-weight: 600;
}
.field-input {
border: 1px solid var(--gray-300);
border-radius: var(--border-radius-sm);
padding: 0.5rem;
}
.field-description {
font-size: var(--text-sm);
}
.invisible-input {
border: none;
}
.invisible-input:focus-visible {
outline: none;
}
.image-preview {
width: 280px;
height: 178px;
border-radius: var(--border-radius-sm);
border: 1px solid var(--gray-300);
margin-top: 1rem;
}
body {
background-color: #FFFFFF;
@@ -93,7 +152,7 @@ input[type=checkbox] {
font-weight: 600;
color: var(--gray-900);
width: fit-content;
box-shadow: var(--shadow-sm);
border: 1px solid var(--gray-300);
}
.dark-pills {
@@ -106,9 +165,7 @@ input[type=checkbox] {
}
.common-page-style {
padding: 2rem 0 5rem;
padding-top: 3rem;
background-color: var(--bg-color);
padding: 1.25rem 0 5rem;
font-size: var(--text-base);
}
@@ -117,7 +174,7 @@ input[type=checkbox] {
background: #FFFFFF;
border-radius: var(--border-radius-md);
position: relative;
box-shadow: var(--shadow-base);
border: 1px solid var(--gray-300)
}
.course-card {
@@ -218,9 +275,7 @@ input[type=checkbox] {
.cards-parent {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
-moz-column-gap: 40px;
column-gap: 40px;
row-gap: 40px;
grid-gap: 2rem;
align-items: center;
}
@@ -309,21 +364,21 @@ input[type=checkbox] {
}
.course-card-wide {
width: 50%;
font-size: var(--text-base);
width: 50%;
margin-bottom: 2rem;
}
@media (max-width: 1000px) {
.course-card-wide {
width: 75%;
margin: 0 auto;
margin: 0 auto 2rem;
}
}
@media (max-width: 768px) {
.course-card-wide {
width: 100%;
margin: 0;
margin: 0 0 2rem;
}
}
@@ -361,15 +416,14 @@ input[type=checkbox] {
}
.wide-button {
padding: 0.5rem 6rem;
font-weight: 500;
width: 100%;
padding: 0.3rem 4rem;
width: 100%;
}
@media (max-width: 768px) {
.wide-button {
padding: 0.5rem 4rem;
}
.wide-button {
padding: 0.3rem 4rem;
}
}
.is-secondary {
@@ -407,7 +461,7 @@ input[type=checkbox] {
.course-home-page {
background-color: #FFFFFF;
padding-top: 4rem;
padding-top: 2.5rem;
}
.chapter-title {
@@ -417,6 +471,11 @@ input[type=checkbox] {
display: flex;
align-items: center;
padding-bottom: 0.5rem;
font-size: var(--text-lg);
}
.chapter-title:last-child {
padding-bottom: 0;
}
.chapter-description {
@@ -433,8 +492,7 @@ input[type=checkbox] {
}
.reviews-parent {
padding-bottom: 5rem;
color: var(--gray-900);
color: var(--gray-900);
}
.lesson-info {
@@ -457,10 +515,6 @@ input[type=checkbox] {
border-radius: var(--border-radius-md);
}
.lessons {
margin-left: 1.5rem;
}
.member-card {
display: flex;
flex-direction: column;
@@ -822,8 +876,8 @@ input[type=checkbox] {
}
.progress-percent {
margin: 0.5rem 0;
font-size: var(--text-base);
margin: 0.5rem 0;
font-size: var(--text-sm);
}
pre {
@@ -969,9 +1023,9 @@ pre {
.search-course {
background-position: 1rem;
text-indent: 1rem;
font-size: var(--text-base);
padding: 1.5rem;
width: 100%;
font-size: var(--text-base);
padding: 1.5rem;
width: 100%;
box-shadow: none;
}
@@ -1224,8 +1278,7 @@ pre {
}
.course-head-container {
color: var(--gray-900);
background-color: var(--gray-50);
border-bottom: 1px solid var(--gray-300);
}
.seperator {
@@ -1241,7 +1294,7 @@ pre {
position: absolute;
top: 10%;
right: 7%;
max-width: 400px;
max-width: 350px;
z-index: 4;
}
@@ -1362,20 +1415,16 @@ pre {
margin: 0 1rem;
}
.avg-rating-stars {
background: var(--gray-200);
border-radius: 100px;
padding: 0.5rem 0.75rem;
margin: 1.25rem 0 0.5rem;
.course-card-wide .avg-rating-stars {
margin-top: 2rem;
}
.reviews-parent .progress {
width: 200px;
color: var(--gray-900);
}
.reviews-parent .progress-bar {
background-color: var(--gray-600);
background-color: var(--accent-color);
}
.course-home-top-container {
@@ -1618,6 +1667,10 @@ li {
margin-bottom: 1rem;
}
.chapter-parent:last-child {
margin-bottom: 0;
}
.chapter-edit .chapter-title {
padding: 0.5rem 0;
}
@@ -1825,7 +1878,7 @@ li {
}
.course-description-section {
padding-bottom: 4rem;
padding-bottom: 2.5rem;
}
input::file-selector-button {
@@ -1968,11 +2021,11 @@ select {
.result-row {
display: block;
padding: 1rem;
border-top: 1px solid var(--gray-300);
font-weight: 500;
color: var(--gray-900);
font-size: var(--text-base);
cursor: pointer;
border-top: 1px solid var(--gray-300);
font-weight: 500;
color: var(--gray-900);
font-size: var(--text-base);
cursor: pointer;
}
.result-row:hover {
@@ -2011,10 +2064,10 @@ select {
.lms-card {
display: flex;
flex-direction: column;
border-radius: 0.75rem;
/* border: 1px solid var(--gray-200); */
border-radius: 0.75rem;
/* border: 1px solid var(--gray-200); */
box-shadow: var(--shadow-sm);
padding: 0.5rem;
padding: 0.5rem;
height: 100%;
position: relative;
}
@@ -2042,8 +2095,8 @@ select {
.lms-card-parent {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-gap: 1.5rem;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-gap: 1.5rem;
}
.answer-indicator {

View File

@@ -1,11 +1,9 @@
{% if not course.upcoming %}
<div class="reviews-parent">
{% set reviews = get_reviews(course.name) %}
<div class="course-home-headings mb-5"> {{ _("Reviews") }} </div>
<div class="page-title mb-5"> {{ _("Reviews") }} </div>
{% set avg_rating = get_average_rating(course.name) %}
{% if avg_rating %}
<div class="reviews-header">
<div class="text-center">
@@ -13,21 +11,21 @@
{{ frappe.utils.flt(avg_rating, frappe.get_system_settings("float_precision") or 3) }}
</div>
<div class="course-meta"> {{ reviews | length }} {{ _("ratings") }} </div>
<div class="avg-rating-stars">
<div class="rating">
{% for i in [1, 2, 3, 4, 5] %}
<svg class="icon icon-md {% if i <= frappe.utils.ceil(avg_rating) %} star-click {% endif %}" data-rating="{{ i }}">
<svg class="icon icon-lg {% if i <= frappe.utils.ceil(avg_rating) %} star-click {% endif %}" data-rating="{{ i }}">
<use href="#icon-star"></use>
</svg>
{% endfor %}
</div>
</div>
<div class="course-meta">
{{ frappe.utils.flt(avg_rating, frappe.get_system_settings("float_precision") or 3) }} {{ _("out of 5 ") }}
</div>
<div class="course-meta"> {{ reviews | length }} {{ _("ratings") }} </div>
<!--
-->
<div class="mt-5">
{% include "lms/templates/reviews_cta.html" %}

View File

@@ -5,7 +5,7 @@
{% block page_content %}
<div class="common-page-style pt-0 pb-0">
<div class="common-page-style">
<div class="course-home-top-container">
{{ CourseHomeHeader(course) }}
<div class="course-home-page">
@@ -20,7 +20,7 @@
{% include "lms/templates/reviews.html" %}
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
@@ -29,10 +29,10 @@
{% macro CourseHomeHeader(course) %}
<div class="course-head-container">
<div class="container pt-8 pb-10">
<div class="container">
<div class="course-card-wide">
{{ BreadCrumb(course) }}
{{ CourseCardWide(course) }}
{{ BreadCrumb(course) }}
{{ CourseCardWide(course) }}
</div>
</div>
</div>
@@ -53,72 +53,35 @@
{% macro CourseCardWide(course) %}
<div class="d-flex align-items-center mt-8">
{% for tag in get_tags(course.name) %}
<div class="course-card-pills" {% if course.edit_mode %} contenteditable="true" {% endif %}>{{ tag }}
{% if course.edit_mode %}
<span class="btn-delete-tag">
<svg class="icon icon-sm">
<use class="" href="#icon-close"></use>
</svg>
</span>
{% endif %}
<div class="course-card-pills">
{{ tag }}
</div>
{% endfor %}
{% if course.edit_mode %}
<button class="btn btn-default btn-sm btn-tag"> {{ _("Add Tag") }} </button>
</div>
<div id="title" {% if course.name %} data-course="{{ course.name | urlencode }}" {% endif %} class="page-title">
{% if course.title %} {{ course.title }} {% endif %}
</div>
<div id="intro">
{% if course.short_introduction %}
{{ course.short_introduction }}
{% endif %}
</div>
<div {% if course.edit_mode %} data-placeholder="{{ _('Title') }}" contenteditable="true" {% endif %}
id="title" {% if course.name %} data-course="{{ course.name | urlencode }}" {% endif %}
class="course-card-wide-title">{% if course.title %} {{ course.title }} {% endif %}</div>
<div {% if course.edit_mode %} contenteditable="true" data-placeholder="{{ _('Short Introduction') }}"
{% endif %} id="intro" >{% if course.short_introduction %} {{ course.short_introduction }} {% endif %}</div>
{% if course.edit_mode %}
<div class="preview-video-header">
<div class="d-block mt-1" contenteditable="true" id="video-link"
data-placeholder=" {{ _('Preview Video Link') }} ">{% if course.video_link %}{{ course.video_link }}{% endif %}</div>
<div class="preview-info">
<div class="tool-tip">
<div class="tooltiptext">
<span>
{{ _('If you have a video that provides a teaser or preview of the course, you can add it here.') }}
</span>
<span>
{{ _("Follow the steps mentioned below for the same.") }}
</span>
<ul>
<li>
{{ _("Upload the video on youtube.") }}
</li>
<li>
{{ _("When you share a youtube video, it shows an option called Embed.") }}
</li>
<li>
{{ _("On clicking it, it provides an iframe. Copy the source (src) of the iframe and paste it here.") }}
</li>
</ul>
</div>
<svg class="icon icon-md">
<use href="#icon-solid-info"></use>
</svg>
</div>
</div>
<div class="avg-rating-stars">
<div class="rating">
{% for i in [1, 2, 3, 4, 5] %}
<svg class="icon icon-lg {% if i <= frappe.utils.ceil(avg_rating) %} star-click {% endif %}" data-rating="{{ i }}">
<use href="#icon-star"></use>
</svg>
{% endfor %}
</div>
</div>
<div class="course-image-attachment {% if not course.image %} hide {% endif %} ">
<a {% if course.image %} href="{{ course.image }}" {% endif %} id="image" target="_blank">
{{ course.image }}
</a>
<button class="btn btn-sm btn-default btn-clear ml-4"> {{ _("Clear") }} </button>
</div>
<a class="btn btn-default btn-sm btn-attach mt-1 {% if course.image %} hide {% endif %}"> {{ _("Attach Image") }} </a>
{% endif %}
{% if not course.edit_mode %}
<div class="mt-8">
<div class="mt-4">
<div class="bold-heading">{{ _("Instructors") }}:</div>
{% for instructor in get_instructors(course.name) %}
<div class="mt-1">
@@ -129,9 +92,8 @@
</div>
{% endfor %}
</div>
{% endif %}
{% if membership and not course.edit_mode %}
{% if membership %}
{% set progress = frappe.utils.cint(membership.progress) %}
<div class="mt-8">
<div class="progress-percent m-0">{{ progress }}% {{ _("Completed") }}</div>
@@ -147,7 +109,6 @@
<!-- Overlay -->
{% macro CourseHeaderOverlay(course) %}
{% if not course.edit_mode %}
<div class="course-overlay-card">
{% if course.video_link %}
@@ -156,7 +117,10 @@
{% endif %}
<div class="course-overlay-content">
<div class="course-overlay-title"> {{ course.title }} </div>
<div class="cta-parent">
{{ CTASection(course, membership) }}
</div>
{{ Notes(course) }}
@@ -164,7 +128,7 @@
<svg class="icon icon-md mr-1">
<use class="" href="#icon-users">
</svg>
{{ get_students(course.name) | length }} {{ _("Enrolled") }}
{{ format_number(get_students(course.name) | length) }} {{ _("Enrolled") }}
</div>
{% if get_lessons(course.name) | length %}
@@ -172,29 +136,25 @@
<svg class="icon icon-md mr-1">
<use href="#icon-education"></use>
</svg>
{{ get_lessons(course.name) | length }} {{ _("Lessons") }}
{{ get_lessons(course.name, None, False) }} {{ _("Lessons") }}
</div>
{% endif %}
{% if course.paid_certificate %}
{% if course.enable_certification %}
<div class="vertically-center mb-3">
<svg class="icon icon-md mr-1">
<use href="#icon-badge"></use>
</svg>
<span class="certificate-price" data-price="{{ course.price_certificate }}">
{{ format_amount(course.price_certificate, course.currency) }}
</span>
<span class="indicator-pill green ml-3"> {{ _("Get Certified") }} </span>
{{ _("Get Certified") }}
</div>
{% endif %}
{{ CTASection(course, membership) }}
</div>
</div>
{{ SlotModal(course) }}
{% endif %}
{% endmacro %}
@@ -254,7 +214,7 @@
{% if course.related_courses | length %}
<div class="related-courses">
<div class="container">
<div class="course-home-headings"> {{ _("Other Courses") }} </div>
<div class="page-title"> {{ _("Other Courses") }} </div>
<div class="carousel slide" id="carouselExampleControls" data-ride="carousel" data-interval="false">
<div class="carousel-inner">
{% for crs in course.related_courses %}
@@ -291,62 +251,73 @@
{% set lesson_index = get_lesson_index(membership.current_lesson) if membership and
membership.current_lesson else "1.1" if first_lesson_exists(course.name) else None %}
{% if is_instructor(course.name) and not course.published and course.status != "Under Review" %}
<div class="btn btn-primary wide-button" id="submit-for-review" data-course="{{ course.name | urlencode }}">
{{ _("Submit for Review") }}
</div>
{% elif is_instructor(course.name) and lesson_index %}
<a class="btn btn-primary wide-button" id="continue-learning"
href="{{ get_lesson_url(course.name, lesson_index) }}{{ course.query_parameter }}">
{{ _("Checkout Course") }}
</a>
<div class="all-cta">
{% if is_instructor(course.name) and not course.published and course.status != "Under Review" %}
<div class="btn btn-primary wide-button" id="submit-for-review" data-course="{{ course.name | urlencode }}">
{{ _("Submit for Review") }}
</div>
{% elif course.upcoming and not is_user_interested and not is_instructor(course.name) %}
<div class="btn btn-secondary wide-button notify-me" data-course="{{course.name | urlencode}}">
{{ _("Notify me when available") }}
</div>
{% elif is_cohort_staff(course.name, frappe.session.user) %}
<a class="btn btn-secondary button-links wide-button" href="/courses/{{course.name}}/manage">
{{ _("Manage Cohorts") }}
</a>
{% elif membership %}
<a class="btn btn-primary wide-button" id="continue-learning"
href="{{ get_lesson_url(course.name, lesson_index) }}{{ course.query_parameter }}">
{{ _("Continue Learning") }}
</a>
{% elif show_start_learing_cta(course, membership) %}
<div class="btn btn-primary wide-button join-batch" data-course="{{ course.name | urlencode }}">
{{ _("Start Learning") }}
</div>
{% endif %}
{% set progress = frappe.utils.cint(membership.progress) %}
{% if membership and course.enable_certification %}
{% if certificate %}
<a class="btn btn-secondary wide-button mt-2" href="/courses/{{ course.name }}/{{ certificate }}">
{{ _("Get Certificate") }}
{% elif is_instructor(course.name) and lesson_index %}
<a class="btn btn-primary wide-button" id="continue-learning"
href="{{ get_lesson_url(course.name, lesson_index) }}{{ course.query_parameter }}">
{{ _("Checkout Course") }}
</a>
{% elif eligible_for_evaluation %}
<a class="btn btn-secondary wide-button mt-2" id="apply-certificate" data-course="{{ course.name }}">
{{ _("Apply for Certificate") }}
{% elif course.upcoming and not is_user_interested and not is_instructor(course.name) %}
<div class="btn btn-secondary wide-button notify-me" data-course="{{course.name | urlencode}}">
{{ _("Notify me when available") }}
</div>
{% elif is_cohort_staff(course.name, frappe.session.user) %}
<a class="btn btn-secondary button-links wide-button" href="/courses/{{course.name}}/manage">
{{ _("Manage Cohorts") }}
</a>
{% elif course.grant_certificate_after == "Completion" and progress == 100 %}
<div class="btn btn-secondary wide-button is-secondary mt-2" id="certification" data-course="{{ course.name }}">
{{ _("Get Certificate") }}
{% elif membership %}
<a class="btn btn-primary wide-button" id="continue-learning"
href="{{ get_lesson_url(course.name, lesson_index) }}{{ course.query_parameter }}">
{{ _("Continue Learning") }}
</a>
{% elif show_start_learing_cta(course, membership) %}
<div class="btn btn-primary wide-button join-batch" data-course="{{ course.name | urlencode }}">
{{ _("Start Learning") }}
</div>
{% endif %}
{% endif %}
{% if is_instructor(course.name) or has_course_moderator_role() %}
<a class="btn btn-secondary wide-button mt-2" href="/courses/{{ course.name }}?edit=1"> {{ _("Edit Course") }} </a>
{% endif %}
{% set progress = frappe.utils.cint(membership.progress) %}
{% if membership and course.enable_certification %}
{% if certificate %}
<a class="btn btn-secondary wide-button mt-2" href="/courses/{{ course.name }}/{{ certificate }}">
{{ _("Get Certificate") }}
</a>
{% elif eligible_for_evaluation %}
<a class="btn btn-secondary wide-button mt-2" id="apply-certificate" data-course="{{ course.name }}">
{{ _("Apply for Certificate") }}
</a>
{% elif course.grant_certificate_after == "Completion" and progress == 100 %}
<div class="btn btn-secondary wide-button is-secondary mt-2" id="certification" data-course="{{ course.name }}">
{{ _("Get Certificate") }}
</div>
{% endif %}
{% endif %}
</div>
<div>
{% if is_instructor(course.name) or has_course_moderator_role() %}
<a class="btn btn-default btn-sm pull-right ml-2" title="Edit Course" href="/courses/{{ course.name }}?edit=1">
<svg class="icon icon-md">
<use href="#icon-edit"></use>
</svg>
</a>
{% endif %}
</div>
{% endmacro %}

View File

@@ -9,6 +9,7 @@ from lms.lms.utils import (
is_certified,
is_instructor,
redirect_to_courses_list,
get_average_rating,
)
@@ -33,6 +34,7 @@ def get_context(context):
context.membership = None
else:
set_course_context(context, course_name)
context.avg_rating = get_average_rating(context.course.name)
def set_course_context(context, course_name):

View File

@@ -0,0 +1,67 @@
{% extends "lms/templates/lms_base.html" %}
{% block title %}
{{ course.title if course and course.title else _("New Course") }}
{% endblock %}
{% block content %}
<main class="common-page-style">
<div class="container">
<div class="page-title"> {{ _("Course Details") }} </div>
<div class="mt-10">
<div>
<div class="course-title">
<div class="field-label">
{{ _("Title") }}
</div>
<div class="field-description">
{{ _("Something Short and Concise") }}
</div>
</div>
<div class="">
<input type="text" class="field-input">
</div>
</div>
<div>
<div class="course-title">
<div class="field-label">
{{ _("Short Introduction") }}
</div>
<div class="field-description">
{{ _("A one line breif description") }}
</div>
</div>
<div class="">
<input type="text" class="field-input">
</div>
</div>
<div>
<div class="course-title">
<div class="field-label">
{{ _("Tags") }}
</div>
<div class="field-description">
{{ _("Add suitable tags") }}
</div>
</div>
<div class="tags field-input">
<input type="text" class="invisible-input" id="tags-input">
</div>
</div>
<div>
<div class="course-title">
<div class="field-label">
{{ _("Course Image") }}
</div>
<div class="field-description">
{{ _("Add an appropriate image") }}
</div>
</div>
<div class="">
<input type="file" class="field-input" id="image">
</div>
<img>
</div>
</div>
</div>
</main>
{% endblock %}

38
lms/www/courses/create.js Normal file
View File

@@ -0,0 +1,38 @@
frappe.ready(() => {
$(".tags").click((e) => {
e.preventDefault();
$("#tags-input").focus();
});
$("#tags-input").focusout((e) => {
create_tag(e);
});
$(document).on("click", ".btn-remove", (e) => {
$(e.target).parent().parent().remove();
});
$("#image").change((e) => {
$(e.target)
.parent()
.siblings("img")
.addClass("image-preview")
.attr("src", URL.createObjectURL(e.target.files[0]));
});
});
const create_tag = (e) => {
if ($(e.target).val() == "") {
return;
}
let tag = `<button class="btn btn-secondary btn-sm mr-2 text-uppercase">
${$(e.target).val()}
<span class="btn-remove">
<svg class="icon icon-sm" style="">
<use class="" href="#icon-close"></use>
</svg>
</span>
</button>`;
$(tag).insertBefore("#tags-input");
$(e.target).val("");
};

View File

@@ -0,0 +1,5 @@
import frappe
def get_context(context):
context.no_cache = 1

View File

@@ -7,7 +7,7 @@
{% block page_content %}
<div class="common-page-style">
<div class="common-page-style pt-8">
<div class="container">
{% if restriction %}
{% set profile_link = "<a href='/edit-profile'> profile </a>" %}
@@ -42,7 +42,7 @@
</a>
</div>
<div class="course-home-headings">
<div class="page-title mb-6">
{{ _("All Courses") }}
</div>