feat: multi language support (#254)
* feat: multitranslational support * - completion of settings page - completion of sidebar * sidebar rerendering bug fix * completion of the lesson navigation & materials page * completion of the course navigation * completion of requested languages * - Implementation of Language Picker - Rename Bug Fixes * checkpoint save * - addition of the language picker to the onboarding. - addition of the language switcher for the lesson notes. * merge completion * initialization of the new branch * add transition.svelte file * lesson note bug fix * feat: add translation migration * completion of translation * fix height issue of dropdown * refactoring * fix: improve code with LOCALE from db * finally get it fully functional * connect with AI * backward compatibility for lesson note * preserve old content, when generating AI content * undo translations in upgrade modal * fix duplicate key issue from codacy trigger --------- Co-authored-by: Rotimi Best <best@classroomio.com>
This commit is contained in:
co-authored by
Rotimi Best
parent
ff7d2cee35
commit
d75e2f258e
+15
-5
@@ -4,6 +4,7 @@
|
||||
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
import { handleOpenWidget } from '../../store';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
|
||||
export let course = {};
|
||||
|
||||
@@ -12,10 +13,15 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<TextField className="mt-5" labelClassName="font-bold" label="Title" bind:value={course.title} />
|
||||
<TextField
|
||||
className="mt-5"
|
||||
labelClassName="font-bold"
|
||||
label={$t('course.navItem.landing_page.editor.header_form.title')}
|
||||
bind:value={course.title}
|
||||
/>
|
||||
|
||||
<TextArea
|
||||
label="Description"
|
||||
label={$t('course.navItem.landing_page.editor.header_form.description')}
|
||||
bind:value={course.description}
|
||||
rows="6"
|
||||
className="mt-5"
|
||||
@@ -25,13 +31,17 @@
|
||||
<TextField
|
||||
className="mt-5"
|
||||
labelClassName="font-bold"
|
||||
label="Short Video"
|
||||
label={$t('course.navItem.landing_page.editor.header_form.short_video')}
|
||||
placeholder="www.youtube.com/watch?v=uYRq60G5XTk"
|
||||
helperMessage="Enter a link to a youtube video"
|
||||
type="text"
|
||||
bind:value={course.metadata.videoUrl}
|
||||
/>
|
||||
<div class="mt-7">
|
||||
<p class="font-bold mb-3">Replace cover image</p>
|
||||
<PrimaryButton label="Replace" variant={VARIANTS.OUTLINED} onClick={widgetControl} />
|
||||
<p class="font-bold mb-3">{$t('course.navItem.landing_page.editor.header_form.replace_cover')}</p>
|
||||
<PrimaryButton
|
||||
label={$t('course.navItem.landing_page.editor.header_form.replace')}
|
||||
variant={VARIANTS.OUTLINED}
|
||||
onClick={widgetControl}
|
||||
/>
|
||||
</div>
|
||||
|
||||
+10
-7
@@ -8,6 +8,7 @@
|
||||
import UploadImage from '$lib/components/UploadImage/index.svelte';
|
||||
import { uploadAvatar } from '$lib/utils/services/courses';
|
||||
import type { Course } from '$lib/utils/types';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
|
||||
export let course: Course;
|
||||
let name: string | undefined;
|
||||
@@ -60,29 +61,31 @@
|
||||
</script>
|
||||
|
||||
<div class="mt-5">
|
||||
<label for="upload" class="font-bold">Instructor Logo</label>
|
||||
<label for="upload" class="font-bold"
|
||||
>{$t('course.navItem.landing_page.editor.instructure_form.upload')}</label
|
||||
>
|
||||
<UploadImage bind:avatar src={imgUrl} />
|
||||
</div>
|
||||
|
||||
<TextField
|
||||
className="mt-5"
|
||||
labelClassName="font-bold"
|
||||
label="Instructor name"
|
||||
placeholder="Your company name"
|
||||
label={$t('course.navItem.landing_page.editor.instructure_form.name')}
|
||||
placeholder={$t('course.navItem.landing_page.editor.instructure_form.name_placeholder')}
|
||||
bind:value={name}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
className="mt-5"
|
||||
labelClassName="font-bold"
|
||||
label="Instructor Role"
|
||||
label={$t('course.navItem.landing_page.editor.instructure_form.role')}
|
||||
placeholder="e.g Software developer"
|
||||
bind:value={role}
|
||||
/>
|
||||
|
||||
<TextArea
|
||||
label="About instructor"
|
||||
placeholder="A short background about the instructor"
|
||||
label={$t('course.navItem.landing_page.editor.instructure_form.about')}
|
||||
placeholder={$t('course.navItem.landing_page.editor.instructure_form.about_placeholder')}
|
||||
rows={6}
|
||||
className="mt-5"
|
||||
labelClassName="font-bold"
|
||||
@@ -92,7 +95,7 @@
|
||||
<TextField
|
||||
className="mt-5"
|
||||
labelClassName="font-bold"
|
||||
label="Total number of courses"
|
||||
label={$t('course.navItem.landing_page.editor.instructure_form.total')}
|
||||
type="number"
|
||||
bind:value={courseNo}
|
||||
/>
|
||||
|
||||
+19
-10
@@ -9,6 +9,7 @@
|
||||
import TextEditor from '$lib/components/TextEditor/index.svelte';
|
||||
import { isCourseFree } from '$lib/utils/functions/course';
|
||||
import type { Course } from '$lib/utils/types';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
|
||||
export let course: Course;
|
||||
|
||||
@@ -53,7 +54,10 @@
|
||||
</script>
|
||||
|
||||
{#if typeof course !== 'undefined'}
|
||||
<Select labelText="Currency" bind:selected={course.currency}>
|
||||
<Select
|
||||
labelText={$t('course.navItem.landing_page.editor.pricing_form.currency')}
|
||||
bind:selected={course.currency}
|
||||
>
|
||||
<SelectItem value="NGN" />
|
||||
<SelectItem value="USD" />
|
||||
</Select>
|
||||
@@ -61,7 +65,7 @@
|
||||
<TextField
|
||||
className="mt-5"
|
||||
labelClassName="font-bold"
|
||||
label="Cost"
|
||||
label={$t('course.navItem.landing_page.editor.pricing_form.cost')}
|
||||
type="number"
|
||||
bind:value={course.cost}
|
||||
/>
|
||||
@@ -70,7 +74,7 @@
|
||||
<TextField
|
||||
className="mt-5"
|
||||
labelClassName="font-bold"
|
||||
label="Payment Link"
|
||||
label={$t('course.navItem.landing_page.editor.pricing_form.payment')}
|
||||
helperMessage="Stripe, Lemon Squeezy or any payment link"
|
||||
bind:value={paymentLink}
|
||||
/>
|
||||
@@ -78,9 +82,12 @@
|
||||
|
||||
<div class="mt-5">
|
||||
<!-- <label for="text-field" class="m-0 font-bold mb-2">Discount</label> -->
|
||||
<Toggle labelText="Discount" bind:toggled={showDiscount}>
|
||||
<span slot="labelA">No</span>
|
||||
<span slot="labelB">Yes</span>
|
||||
<Toggle
|
||||
labelText={$t('course.navItem.landing_page.editor.pricing_form.discount')}
|
||||
bind:toggled={showDiscount}
|
||||
>
|
||||
<span slot="labelA">{$t('course.navItem.landing_page.editor.pricing_form.no')}</span>
|
||||
<span slot="labelB">{$t('course.navItem.landing_page.editor.pricing_form.yes')}</span>
|
||||
</Toggle>
|
||||
</div>
|
||||
|
||||
@@ -88,7 +95,7 @@
|
||||
<TextField
|
||||
className="mt-5"
|
||||
labelClassName="font-bold"
|
||||
label="Discout Percent"
|
||||
label={$t('course.navItem.landing_page.editor.pricing_form.percent')}
|
||||
type="number"
|
||||
bind:value={discount}
|
||||
helperMessage="In Percentage %"
|
||||
@@ -98,13 +105,15 @@
|
||||
<div class="mt-5">
|
||||
<!-- <label for="text-field" class="m-0 font-bold mb-2">Discount</label> -->
|
||||
<Toggle labelText="Gift on Completion" bind:toggled={giftToggled}>
|
||||
<span slot="labelA">No</span>
|
||||
<span slot="labelB">Yes</span>
|
||||
<span slot="labelA">{$t('course.navItem.landing_page.editor.pricing_form.no')}</span>
|
||||
<span slot="labelB">{$t('course.navItem.landing_page.editor.pricing_form.yes')}</span>
|
||||
</Toggle>
|
||||
</div>
|
||||
|
||||
{#if giftToggled}
|
||||
<p class="dark:text-white font-bold mt-5">About Gift</p>
|
||||
<p class="dark:text-white font-bold mt-5">
|
||||
{$t('course.navItem.landing_page.editor.pricing_form.gift')}
|
||||
</p>
|
||||
|
||||
<div class="h-2/5">
|
||||
<TextEditor value={get(course, 'metadata.reward.description', '')} onChange={handleChange} />
|
||||
|
||||
+9
-4
@@ -7,6 +7,7 @@
|
||||
import TextArea from '$lib/components/Form/TextArea.svelte';
|
||||
import TextField from '$lib/components/Form/TextField.svelte';
|
||||
import { uploadAvatar } from '$lib/utils/services/courses';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
|
||||
export let courseId;
|
||||
export let reviews = [];
|
||||
@@ -42,7 +43,7 @@
|
||||
<TextField
|
||||
className="mt-2 w-full"
|
||||
labelClassName="font-normal"
|
||||
label="Full Name"
|
||||
label={$t('course.navItem.landing_page.editor.reviews_form.fullname')}
|
||||
placeholder=""
|
||||
type="text"
|
||||
bind:value={review.name}
|
||||
@@ -51,7 +52,7 @@
|
||||
|
||||
<!-- Description -->
|
||||
<TextArea
|
||||
label="Description"
|
||||
label={$t('course.navItem.landing_page.editor.reviews_form.description')}
|
||||
rows="4"
|
||||
className="mt-2 w-full"
|
||||
labelClassName="font-normal"
|
||||
@@ -68,7 +69,7 @@
|
||||
<TextField
|
||||
className="mt-2 w-20"
|
||||
labelClassName="font-normal"
|
||||
label="Rating"
|
||||
label={$t('course.navItem.landing_page.editor.reviews_form.rating')}
|
||||
type="number"
|
||||
min={1}
|
||||
max={5}
|
||||
@@ -78,7 +79,11 @@
|
||||
|
||||
<!-- Toggle -->
|
||||
<div class="w-24">
|
||||
<Toggle labelText="Hide Review" size="sm" bind:toggled={review.hide} />
|
||||
<Toggle
|
||||
labelText={$t('course.navItem.landing_page.editor.reviews_form.hide')}
|
||||
size="sm"
|
||||
bind:toggled={review.hide}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+14
-10
@@ -25,6 +25,7 @@
|
||||
import { isMobile } from '$lib/utils/store/useMobile';
|
||||
import CustomPromptBtn from '$lib/components/AI/AIButton/CustomPromptBtn.svelte';
|
||||
import type { Course } from '$lib/utils/types';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
|
||||
export let course: Course;
|
||||
export let courseId: string;
|
||||
@@ -46,43 +47,43 @@
|
||||
{
|
||||
key: 1,
|
||||
path: '',
|
||||
title: 'Header'
|
||||
title: $t('course.navItem.landing_page.editor.title.1')
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
path: 'metadata.requirements',
|
||||
title: 'Requirement',
|
||||
title: $t('course.navItem.landing_page.editor.title.2'),
|
||||
enableAIWriter: true,
|
||||
initPrompt: 'Please write few requirements needed to take this course:'
|
||||
},
|
||||
{
|
||||
key: 3,
|
||||
path: 'metadata.description',
|
||||
title: 'Description',
|
||||
title: $t('course.navItem.landing_page.editor.title.3'),
|
||||
enableAIWriter: true,
|
||||
initPrompt: 'Please write a detailed course description for this course:'
|
||||
},
|
||||
{
|
||||
key: 4,
|
||||
path: 'metadata.goals',
|
||||
title: 'Goals',
|
||||
title: $t('course.navItem.landing_page.editor.title.4'),
|
||||
enableAIWriter: true,
|
||||
initPrompt: 'What should a student expect to learn from this course:'
|
||||
},
|
||||
{
|
||||
key: 5,
|
||||
path: '',
|
||||
title: 'Reviews'
|
||||
title: $t('course.navItem.landing_page.editor.title.5')
|
||||
},
|
||||
{
|
||||
key: 6,
|
||||
path: '',
|
||||
title: 'Instructor'
|
||||
title: $t('course.navItem.landing_page.editor.title.6')
|
||||
},
|
||||
{
|
||||
key: 7,
|
||||
path: '',
|
||||
title: 'Pricing'
|
||||
title: $t('course.navItem.landing_page.editor.title.7')
|
||||
}
|
||||
];
|
||||
let selectedSection: Section | null = null;
|
||||
@@ -168,7 +169,7 @@
|
||||
<CloseButton onClick={handleClose} />
|
||||
<div class="flex items-center">
|
||||
<PrimaryButton
|
||||
label="Save"
|
||||
label={$t('course.navItem.landing_page.editor.save')}
|
||||
type="button"
|
||||
className="mr-1"
|
||||
variant={VARIANTS.OUTLINED}
|
||||
@@ -181,7 +182,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between items-center px-2 w-full mb-2">
|
||||
<h3 class="dark:text-white">Page Builder</h3>
|
||||
<h3 class="dark:text-white">{$t('course.navItem.landing_page.editor.page_builder')}</h3>
|
||||
</div>
|
||||
{#each sections as section, index}
|
||||
<button
|
||||
@@ -189,7 +190,10 @@
|
||||
sections.length && 'border-b-0'} border-gray-300"
|
||||
on:click={handleSectionSelect(section.key)}
|
||||
>
|
||||
<p class="dark:text-white mr-2">{section.title} section</p>
|
||||
<p class="dark:text-white mr-2">
|
||||
{section.title}
|
||||
{$t('course.navItem.landing_page.editor.section')}
|
||||
</p>
|
||||
<ChevronRightIcon size={24} class="carbon-class" />
|
||||
</button>
|
||||
{/each}
|
||||
|
||||
+17
-9
@@ -10,6 +10,7 @@
|
||||
import type { Course } from '$lib/utils/types';
|
||||
import { ROLE } from '$lib/utils/constants/roles';
|
||||
import { capturePosthogEvent } from '$lib/utils/services/posthog';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
|
||||
export let className = '';
|
||||
export let editMode = false;
|
||||
@@ -92,12 +93,14 @@
|
||||
<p class="dark:text-white font-medium text-sm flex items-center gap-1">
|
||||
{formatter?.format(calculatedCost) || calculatedCost}
|
||||
{#if isFree}
|
||||
<span class="text-xs">(Free)</span>
|
||||
<span class="text-xs"
|
||||
>({$t('course.navItem.landing_page.pricing_section.free')})</span
|
||||
>
|
||||
{/if}
|
||||
</p>
|
||||
{#if courseData?.metadata?.showDiscount}
|
||||
<p class="dark:text-white font-light text-sm text-gray-500">
|
||||
{discount}% Discount.
|
||||
{discount}% {$t('course.navItem.landing_page.pricing_section.discount')}.
|
||||
<span class="line-through"
|
||||
>{formatter?.format(courseData?.cost || 0) || courseData.cost}</span
|
||||
>
|
||||
@@ -105,7 +108,7 @@
|
||||
{/if}
|
||||
{:else}
|
||||
<p class="dark:text-white text-lg">
|
||||
This course is currently not accepting new students.
|
||||
{$t('course.navItem.landing_page.pricing_section.not_accepting')}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -113,7 +116,9 @@
|
||||
<!-- Call To Action Buttons -->
|
||||
<div class="flex flex-col w-full h-full items-center">
|
||||
<PrimaryButton
|
||||
label={isFree ? 'Enroll Now' : 'Buy Now'}
|
||||
label={isFree
|
||||
? $t('course.navItem.landing_page.pricing_section.enroll')
|
||||
: $t('course.navItem.landing_page.pricing_section.buy')}
|
||||
className="w-full sm:w-full h-[40px]"
|
||||
onClick={handleJoinCourse}
|
||||
isDisabled={!courseData.metadata.allowNewStudent}
|
||||
@@ -135,12 +140,13 @@
|
||||
<p class="dark:text-white font-medium text-lg">
|
||||
{formatter?.format(calculatedCost) || calculatedCost}
|
||||
{#if isFree}
|
||||
<span class="text-sm">(Free)</span>
|
||||
<span class="text-sm">({$t('course.navItem.landing_page.pricing_section.free')})</span
|
||||
>
|
||||
{/if}
|
||||
</p>
|
||||
{#if courseData?.metadata?.showDiscount}
|
||||
<p class="dark:text-white font-light text-sm text-gray-500">
|
||||
{discount}% Discount.
|
||||
{discount}% {$t('course.navItem.landing_page.pricing_section.discount')}.
|
||||
<span class="line-through"
|
||||
>{formatter?.format(courseData?.cost || 0) || courseData.cost}</span
|
||||
>
|
||||
@@ -148,7 +154,7 @@
|
||||
{/if}
|
||||
{:else}
|
||||
<p class="dark:text-white text-lg">
|
||||
This course is currently not accepting new students.
|
||||
{$t('course.navItem.landing_page.pricing_section.not_accepting')}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -156,13 +162,15 @@
|
||||
<!-- Call To Action Buttons -->
|
||||
<div class="flex flex-col w-full items-center">
|
||||
<PrimaryButton
|
||||
label={isFree ? 'Enroll Now' : 'Buy Now'}
|
||||
label={isFree
|
||||
? $t('course.navItem.landing_page.pricing_section.enroll')
|
||||
: $t('course.navItem.landing_page.pricing_section.buy')}
|
||||
className="w-full sm:w-full py-3 mb-3"
|
||||
onClick={handleJoinCourse}
|
||||
isDisabled={!courseData.metadata.allowNewStudent}
|
||||
/>
|
||||
{#if courseData?.metadata?.showDiscount && courseData.metadata.allowNewStudent}
|
||||
<p class="dark:text-white font-light text-sm text-gray-500">Early bird offer. Buy ASAP</p>
|
||||
<p class="dark:text-white font-light text-sm text-gray-500">{$t('course.navItem.landing_page.pricing_section.bird')}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// import { t } from '$lib/utils/functions/translations';
|
||||
|
||||
export const SECTION_KEYS = {
|
||||
HEADER: 'header',
|
||||
REQUIREMENT: '#requirement',
|
||||
@@ -11,26 +13,26 @@ export const SECTION_KEYS = {
|
||||
export const NAV_ITEMS = [
|
||||
{
|
||||
key: SECTION_KEYS.REQUIREMENT,
|
||||
label: 'Requirement'
|
||||
label: 'course.navItem.landing_page.editor.title.2'
|
||||
},
|
||||
{
|
||||
key: SECTION_KEYS.DESCRIPTION,
|
||||
label: 'Description'
|
||||
label: 'course.navItem.landing_page.editor.title.3'
|
||||
},
|
||||
{
|
||||
key: SECTION_KEYS.GOALS,
|
||||
label: 'Goals'
|
||||
label: 'course.navItem.landing_page.editor.title.4'
|
||||
},
|
||||
{
|
||||
key: SECTION_KEYS.LESSONS,
|
||||
label: 'Lessons'
|
||||
label: 'course.navItems.2'
|
||||
},
|
||||
{
|
||||
key: SECTION_KEYS.REVIEWS,
|
||||
label: 'Reviews'
|
||||
label: 'course.navItem.landing_page.editor.title.5'
|
||||
},
|
||||
{
|
||||
key: SECTION_KEYS.INSTRUCTOR,
|
||||
label: 'Instructor'
|
||||
label: 'course.navItem.landing_page.editor.title.6'
|
||||
}
|
||||
];
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
import { currentOrg } from '$lib/utils/store/org';
|
||||
import UploadWidget from '$lib/components/UploadWidget/index.svelte';
|
||||
import { course } from '$lib/components/Course/store';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
|
||||
export let editMode = false;
|
||||
export let courseData: Course;
|
||||
@@ -124,7 +125,7 @@
|
||||
{get(courseData, 'metadata.instructor.name', '')}
|
||||
</p>
|
||||
<PrimaryButton
|
||||
label="Start Course"
|
||||
label={$t('course.navItem.landing_page.start_course')}
|
||||
className="px-6 py-5 mt-6 sm:w-fit hidden md:block"
|
||||
onClick={() => {
|
||||
if (editMode) return;
|
||||
@@ -207,14 +208,17 @@
|
||||
class="{navItem.key === activeNav &&
|
||||
'active text-primary-700'} z-0 mr-6 rounded-lg px-2 font-normal text-slate-700 hover:bg-gray-200 dark:text-white dark:hover:text-slate-900"
|
||||
>
|
||||
{navItem.label}
|
||||
{$t(navItem.label)}
|
||||
</a>
|
||||
{/each}
|
||||
</nav>
|
||||
|
||||
<!-- Sections - Requirement -->
|
||||
<section id="requirement" class="mt-8 border-b border-gray-300 pb-10">
|
||||
<h3 class="mb-3 mt-0 text-2xl font-bold">Requirement</h3>
|
||||
<h3 class="mb-3 mt-0 text-2xl font-bold">
|
||||
{$t('course.navItem.landing_page.requirement')}
|
||||
</h3>
|
||||
|
||||
<ul class="list font-light">
|
||||
<HtmlRender content={get(courseData, 'metadata.requirements', '')} />
|
||||
</ul>
|
||||
@@ -222,7 +226,10 @@
|
||||
|
||||
<!-- Sections - Course Description -->
|
||||
<section id="description" class="mt-8 border-b border-gray-300 pb-10">
|
||||
<h3 class="mb-3 mt-0 text-2xl font-bold">Course Description</h3>
|
||||
<h3 class="mb-3 mt-0 text-2xl font-bold">
|
||||
{$t('course.navItem.landing_page.description')}
|
||||
</h3>
|
||||
|
||||
<HtmlRender
|
||||
className="dark:text-white text-sm font-light"
|
||||
content={get(courseData, 'metadata.description', '')}
|
||||
@@ -231,27 +238,28 @@
|
||||
|
||||
<!-- Sections - Goal -->
|
||||
<section id="goals" class="mt-8 pb-10">
|
||||
<h3 class="mb-3 mt-0 text-2xl font-bold">What you'll learn</h3>
|
||||
<h3 class="text-2xl font-bold mt-0 mb-3">{$t('course.navItem.landing_page.learn')}</h3>
|
||||
<ul class="list font-light">
|
||||
<HtmlRender content={get(courseData, 'metadata.goals', '')} />
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- Sections - Certificate -->
|
||||
<section class="mt-8 border-b border-gray-300 pb-10">
|
||||
<h3 class="mt-0 text-2xl font-bold">Certificate</h3>
|
||||
<p class="mb-3 text-sm font-light dark:text-white">
|
||||
When you complete all of the courses in the program, you'll earn a Certificate to share
|
||||
with your professional network.
|
||||
<section class="border-b border-gray-300 mt-8 pb-10">
|
||||
<h3 class="text-2xl font-bold mt-0">{$t('course.navItem.landing_page.certificate')}</h3>
|
||||
<p class="dark:text-white text-sm font-light mb-3">
|
||||
{$t('course.navItem.landing_page.certificate_text')}
|
||||
</p>
|
||||
<img src="/images/certificate-template.svg" alt="certificate template" />
|
||||
</section>
|
||||
|
||||
<!-- Sections - Lessons -->
|
||||
<section id="lessons" class="mt-8 border-b border-gray-300 pb-10">
|
||||
<div class="mb-3 flex w-full items-center justify-between">
|
||||
<h3 class="mb-3 mt-0 text-2xl font-bold">Course Content</h3>
|
||||
<p class="text-sm font-light dark:text-white">
|
||||
<section id="lessons" class="border-b border-gray-300 mt-8 pb-10">
|
||||
<div class="flex items-center justify-between w-full mb-3">
|
||||
<h3 class="text-2xl font-bold mt-0 mb-3">
|
||||
{$t('course.navItem.landing_page.content')}
|
||||
</h3>
|
||||
<p class="dark:text-white text-sm font-light">
|
||||
<!-- {lessons.length} lessons -->
|
||||
{pluralize('lesson', lessons.length, true)}
|
||||
</p>
|
||||
@@ -271,23 +279,25 @@
|
||||
<div class="w-2/4">
|
||||
<div class="flex items-center">
|
||||
{#if lesson.slide_url}
|
||||
<span class="flex w-2/4 text-sm font-light"
|
||||
><PresentationFile size={16} class="mr-1" />1 slide</span
|
||||
<span class="text-sm font-light flex w-2/4"
|
||||
><PresentationFile size={16} class="mr-1" />{$t(
|
||||
'course.navItem.landing_page.slide'
|
||||
)}</span
|
||||
>
|
||||
{/if}
|
||||
{#if lesson.note}
|
||||
<span class="flex w-2/4 text-sm font-light"
|
||||
><Notebook size={16} class="mr-1" />note</span
|
||||
<span class="text-sm font-light flex w-2/4"
|
||||
><Notebook size={16} class="mr-1" />{$t(
|
||||
'course.navItem.landing_page.note'
|
||||
)}</span
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
{#if lesson.videos}
|
||||
<span class="flex w-2/4 text-sm font-light"
|
||||
><Video size={16} class="mr-1" />{lesson.videos.length} video{lesson.videos
|
||||
.length > 1
|
||||
? 's'
|
||||
: ''}
|
||||
<span class="text-sm font-light flex w-2/4"
|
||||
><Video size={16} class="mr-1" />{lesson.videos.length}
|
||||
{$t('course.navItem.landing_page.video')}{lesson.videos.length > 1 ? 's' : ''}
|
||||
</span>
|
||||
{/if}
|
||||
{#if get(lesson, 'totalExercises[0].count')}
|
||||
@@ -308,7 +318,9 @@
|
||||
<!-- Sections - Reviews -->
|
||||
{#if reviews && reviews.length > 0}
|
||||
<section id="reviews">
|
||||
<h2 class="my-16 mb-6 ml-0 mr-0 font-semibold">Reviews</h2>
|
||||
<h2 class="my-16 mr-0 mb-6 ml-0 font-semibold">
|
||||
{$t('course.navItem.landing_page.reviews')}
|
||||
</h2>
|
||||
<div class="flex flex-wrap">
|
||||
{#each reviews.slice(0, 4) as review, id}
|
||||
{#if !review.hide}
|
||||
@@ -355,7 +367,7 @@
|
||||
</div>
|
||||
{#if reviews.length > 4}
|
||||
<PrimaryButton
|
||||
label="See All"
|
||||
label={$t('course.navItem.landing_page.see_all')}
|
||||
className="w-3/12 p-4 mt-2"
|
||||
variant={VARIANTS.OUTLINED}
|
||||
onClick={() => ($reviewsModalStore.open = true)}
|
||||
@@ -367,16 +379,18 @@
|
||||
onClose={() => ($reviewsModalStore.open = false)}
|
||||
bind:open={$reviewsModalStore.open}
|
||||
width="w-9/12"
|
||||
modalHeading="Reviews"
|
||||
modalHeading={$t('course.navItem.landing_page.reviews_modal.title')}
|
||||
>
|
||||
<div class="flex">
|
||||
<!-- ratings -->
|
||||
<div class="w-1/3">
|
||||
<h2 class="text-xl font-bold">
|
||||
{averageRating} Rating
|
||||
{averageRating}
|
||||
{$t('course.navItem.landing_page.reviews_modal.rating')}
|
||||
</h2>
|
||||
<h2 class="mt-2 text-lg font-semibold">
|
||||
{reviews.length} Ratings
|
||||
<h2 class="text-lg font-semibold mt-2">
|
||||
{reviews.length}
|
||||
{$t('course.navItem.landing_page.reviews_modal.ratings')}
|
||||
</h2>
|
||||
</div>
|
||||
<!-- reviews -->
|
||||
@@ -418,8 +432,10 @@
|
||||
|
||||
<!-- Sections - Instructor -->
|
||||
<section id="instructor" class="mt-8 pb-10">
|
||||
<h3 class="mb-3 mt-0 text-2xl font-bold">Instructor</h3>
|
||||
<div class="mb-4 flex items-center">
|
||||
<h3 class="text-2xl font-bold mt-0 mb-3">
|
||||
{$t('course.navItem.landing_page.instructor')}
|
||||
</h3>
|
||||
<div class="flex items-center mb-4">
|
||||
<img
|
||||
alt="Author Avatar"
|
||||
class="mr-3 block h-20 w-20 rounded-full"
|
||||
@@ -434,7 +450,10 @@
|
||||
</p>
|
||||
<p class="text-md flex items-center font-light dark:text-white">
|
||||
<PlayFilled size={16} class="text-primary-700" />
|
||||
<span class="ml-1">{get(instructor, 'courseNo', 10)} courses</span>
|
||||
<span class="ml-1"
|
||||
>{get(instructor, 'courseNo', '')}
|
||||
{$t('course.navItem.landing_page.courses')}</span
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user