feat: new design system for exisitng course home
This commit is contained in:
@@ -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"},
|
||||
{
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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 }}">
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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" %}
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
67
lms/www/courses/create.html
Normal file
67
lms/www/courses/create.html
Normal 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
38
lms/www/courses/create.js
Normal 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("");
|
||||
};
|
||||
5
lms/www/courses/create.py
Normal file
5
lms/www/courses/create.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user