CLASSROOMIO-T-146:Made the course page responsive

CLASSROOMIO-T-146:Made updates to the code following the reviews

CLASSROOMIO-T-146:Made updates to the Z-Index

Merge branch 'main' into CLASSROOMIO-T-146

Merge branch 'main' into CLASSROOMIO-T-146

CLASSROOMIO-T-146:Made the course page responsive

CLASSROOMIO-T-146:working on the course page responsiveness

Merge branch 'main' into CLASSROOMIO-T-145

CLASSROOMIO-T-146:Making the course page responsive

CLASSROOMIO-T-145: All done and ready

CLASSROOMIO-T-145: All done and ready

CLASSROOMIO-T-145: Fixed the Z-index issue

Merge branch 'main' into CLASSROOMIO-T-145

CLASSROOMIO-T-145: Finished implementing the responsive design for the Main dashboard and LMS dashboard

Merge branch 'main' into CLASSROOMIO-T-145

CLASSROOMIO-T-144:Updating the dashboard responsiveness ooth for LMS and the Main dashboard

CLASSROOMIO-T-144:Updated the dashboard responsiveness ooth for LMS and the Main dashboard

Merge branch 'main' into CLASSROOMIO-T-145

CLASSROOMIO-T-145:Made the LMS dashboard responsive


Co-authored-by: Ifeanyi Nwosu <ifeanyi@digdippa.com>


Merge-request: CLASSROOMIO-MR-73
Merged-by: Best Admin <best@digdippa.com>
This commit is contained in:
emmanuel
2023-09-14 20:59:51 +00:00
committed by Space Cloud
parent be619ae6bd
commit f3f8a00809
24 changed files with 520 additions and 520 deletions
+40 -3
View File
@@ -6,12 +6,15 @@
import SendAlt from 'carbon-icons-svelte/lib/SendAlt.svelte';
import ChartPie from 'carbon-icons-svelte/lib/ChartPie.svelte';
import IconButton from '$lib/components/IconButton/index.svelte';
import Settings from 'carbon-icons-svelte/lib/Settings.svelte';
import { apps } from './store';
import QandA from './components/QandA/index.svelte';
import LiveChat from './components/LiveChat/index.svelte';
import Notes from './components/Notes/index.svelte';
import Poll from './components/Poll/index.svelte';
import APPS_CONSTANTS from './constants';
import { OverflowMenu, OverflowMenuItem } from 'carbon-components-svelte';
let selectedApp;
@@ -48,8 +51,21 @@
});
</script>
<div class="root">
<div class="apps">
<div class={`root ${$apps.open ? 'open dark:bg-slate-800' : 'close dark:bg-slate-800'}`}>
<div class={`apps`}>
<div class="lg:hidden">
<IconButton
buttonClassName="lg:hidden"
toolTipProps={{ title: 'Settings', hotkeys: ['A', '0'] }}
onClick={() => {
handleAppClick;
$apps.dropdown = !$apps.dropdown;
}}
>
<Settings size={24} class="carbon-icon dark:text-white lg:hidden" />
</IconButton>
</div>
<IconButton
toolTipProps={{ title: 'Live Chat', hotkeys: ['A', '1'] }}
value={APPS_CONSTANTS.APPS.LIVE_CHAT}
@@ -104,7 +120,7 @@
<style lang="scss">
.root {
height: 93vh;
height: calc(100vh - 48px);
position: sticky;
top: 0;
border-left: 1px solid var(--border-color);
@@ -129,4 +145,25 @@
overflow: auto;
}
}
@media screen and (max-width: 1024px) {
.root {
position: absolute;
height: calc(100vh - 109px);
top: 109px;
right: 0;
z-index: 999;
}
.open {
position: absolute;
transform: translateX(0);
transition: all 0.2s ease-in-out;
}
.close {
position: absolute;
transform: translateX(100%);
display: none;
transition: all 0.2s ease-in-out;
}
}
</style>
+6
View File
@@ -0,0 +1,6 @@
import { writable } from 'svelte/store';
export const apps = writable({
open: false,
dropdown: false
});
@@ -45,8 +45,8 @@
</svelte:head>
<main class="md:-ml-4 md:-mr-4 px-2">
<div class="flex-1 flex flex-col md:flex-row justify-between gap-3 w-full mb-3 h-4/5">
<section class="w-full md:w-2/5 h-full">
<div class="flex-1 flex flex-col lg:flex-row justify-between gap-3 w-full mb-3 h-4/5">
<section class="w-full lg:w-2/5 h-full">
<strong class="my-2 text-base font-semibold text-black dark:text-gray-100"
>Certificate settings</strong
>
@@ -99,7 +99,7 @@
</div>
</section>
<section
class="bg-gray-100 dark:bg-gray-700 flex justify-center items-center rounded-md w-full md:w-3/5"
class="bg-gray-100 dark:bg-gray-700 flex justify-center items-center rounded-md w-full lg:w-3/5"
>
<div class="certificate-container flex justify-center items-center h-5/6">
{#if $course.certificate_theme === 'professional'}
@@ -55,7 +55,7 @@
<Modal
onClose={() => (openModal = false)}
bind:open={openModal}
width="w-[60%]"
width="w-[80%] md:w-[60%]"
containerClass="overflow-hidden"
modalHeading="Add New Lesson"
>
@@ -165,8 +165,8 @@
<p class="dark:text-white mt-4 text-sm">Created Jul 3, 2021</p>
</a>
{:else}
<Box className="mt-3">
<div class="flex justify-between flex-col items-center w-96">
<Box className="mt-3 text-center">
<div class="flex justify-between flex-col items-center w-[80%] md:w-96">
<img src="/images/empty-exercise-icon.svg" alt="Exercise" class="my-2.5 mx-auto" />
<h2 class="text-xl my-1.5 font-normal">No exercises added for this lesson</h2>
<p class="text-sm text-center text-slate-500">
@@ -11,13 +11,15 @@
const onChange = (tab) => () => (currentTab = tab);
</script>
<section class="w-full h-full flex flex-row items-start gap-3">
<div class="flex-1 flex-col">
<p class="text-sm font-normal text-start text-[#4F4B4B] dark:text-[#b0a9a9] mb-3">Add By</p>
<section class="w-full h-full flex flex-col md:flex-row items-start gap-3">
<div class="flex flex-row md:flex-col gap-2 items-center">
<p class="text-sm font-normal text-start text-[#4F4B4B] dark:text-[#b0a9a9] mb-3 w-full">
Add By
</p>
{#each tabs as item (item.value)}
<button
on:click={onChange(item.value)}
class={`w-full px-4 py-3 my-5 border ${
class={`w-full px-4 py-3 my-1 border ${
currentTab === item.value
? 'border border-[#0233BD] bg-[#F5F8FE] dark:text-black'
: 'border border-gray-200'
@@ -197,13 +197,13 @@
<Modal
{onClose}
bind:open={$uploadCourseVideoStore.isModalOpen}
width="w-4/5 h-[566px]"
width="w-4/5 w-[90%] h-[80%] md:h-[566px]"
modalHeading="Add a Video"
>
<VideoUploader {lessonId} />
</Modal>
<h1 class="text-4xl mt-0">
<h1 class="text-4xl mt-0 capitalize">
{lessonTitle}
</h1>
@@ -386,7 +386,7 @@
</article>
{/if}
{:else}
<Box>
<Box className="text-center">
<img src="/no-video.svg" alt="Video not found" />
<h3 class="text-xl font-normal dark:text-white py-2">
No note, video or slide added for this lesson yet
@@ -24,6 +24,7 @@
import { updateCourse } from '$lib/utils/services/courses';
import { NavClasses } from '$lib/utils/constants/reusableClass';
import { isMobile } from '$lib/utils/store/useMobile';
import { menu } from '$lib/components/Org/store';
// export let lessonId;
export let path;
@@ -32,12 +33,14 @@
let show = null;
let isLessonActive = false;
const toggleSidebar = () => {
$menu.hidden = !$menu.hidden;
};
function handleMainGroupClick(href) {
return () => {
if ($isMobile) {
setTimeout(() => (show = false), 500);
}
goto(href);
toggleSidebar();
};
}
@@ -146,145 +149,66 @@
<Settings />
<div class="root z-10 {!show && 'hide'} {$isMobile ? 'fixed shadow-xl' : 'sticky'}">
{#if show}
<div class="relative h-full dark:bg-gray-800">
<!-- <PageNav title="Back to courses" paddingClass="pl-2" titleSize="text-md">
<slot:fragment slot="image">
<Avatar src={$course.logo} />
<IconButton
value="toggle"
onClick={() => goto(`${$currentOrgPath}/courses`)}
size="small"
contained={true}
<aside
class={`${
$menu.hidden
? '-translate-x-[100%] absolute md:translate-x-0 md:relative z-[40]'
: 'translate-x-0 absolute md:relative z-[40]'
} transition w-[250px] min-w-[250px] bg-gray-100 dark:bg-gray-800 h-[calc(100vh-48px)] border border-l-0 border-t-0 border-b-0 border-r-1`}
>
<div class="h-full flex flex-col">
<ul class="my-5">
{#each navItems as navItem}
{#if !navItem.show || (typeof navItem.show === 'function' && navItem.show())}
<NavExpandable
label={navItem.label}
handleClick={handleMainGroupClick(navItem.to)}
isGroupActive={(path || $page.url.pathname) === navItem.to}
isExpanded={isLessonActive}
total={navItem.isLecture ? ($lessons || []).length : 0}
>
<ArrowLeftIcon size={20} class="carbon-icon dark:text-white" />
</IconButton>
</slot:fragment>
<slot:fragment slot="widget">
<RoleBasedSecurity allowedRoles={[1, 2]}>
<IconButton onClick={() => ($settingsDialog.open = !$settingsDialog.open)}>
<SettingsIcon size={20} class="carbon-icon dark:text-white" />
</IconButton>
</RoleBasedSecurity>
</slot:fragment>
</PageNav> -->
<div class="h-full py-3 overflow-y-auto">
{#each navItems as navItem}
{#if !navItem.show || (typeof navItem.show === 'function' && navItem.show())}
<NavExpandable
label={navItem.label}
handleClick={handleMainGroupClick(navItem.to)}
isGroupActive={(path || $page.url.pathname) === navItem.to}
isExpanded={isLessonActive}
total={navItem.isLecture ? ($lessons || []).length : 0}
>
{#if navItem.isLecture}
{#each $lessons as item, index}
<a
class="pl-7 w-[95%] text-[0.80rem] mb-1 text-black dark:text-white {isStudent &&
!item.is_unlocked
? 'cursor-not-allowed'
: ''}"
href={isStudent && !item.is_unlocked
? $page.url.pathname
: getLessonsRoute($course.id, item.id)}
on:click={() => {
if ($isMobile) {
setTimeout(() => (show = false), 500);
}
}}
aria-disabled={!item.is_unlocked}
{#if navItem.isLecture}
{#each $lessons as item, index}
<a
class="pl-7 w-[95%] text-[0.80rem] mb-1 text-black dark:text-white {isStudent &&
!item.is_unlocked
? 'cursor-not-allowed'
: ''}"
href={isStudent && !item.is_unlocked
? $page.url.pathname
: getLessonsRoute($course.id, item.id)}
on:click={toggleSidebar}
aria-disabled={!item.is_unlocked}
>
<div
class="flex items-center py-3 px-4 {NavClasses.item} {(
path || $page.url.pathname
).includes(item.id) && NavClasses.active}"
>
<div
class="flex items-center py-3 px-4 {NavClasses.item} {(
path || $page.url.pathname
).includes(item.id) && NavClasses.active}"
>
<TextChip
value={getLectureNo(index + 1)}
className="bg-primary-200 text-primary-600 text-xs mr-2"
size="sm"
shape="rounded-full"
/>
<span>{item.title}</span>
<span class="grow" />
{#if !item.is_unlocked}
<span class="text-md ml-2" title="This lesson is locked.">
<LockedIcon class="carbon-icon dark:text-white" />
</span>
{:else if item.is_complete}
<span class="ml-2" title="You have completed this lesson">
<CheckmarkFilled class="carbon-icon dark:text-white" />
</span>
{/if}
</div>
</a>
{/each}
{/if}
</NavExpandable>
{/if}
{/each}
</div>
</div>
{/if}
<div class="toggler rounded-full shadow-lg absolute bottom-0">
<IconButton
value="toggle"
onClick={() => (show = !show)}
size={$isMobile ? 'large' : 'small'}
color="text-black"
toolTipProps={$isMobile
? {}
: {
title: 'Toggle sidebar',
hotkeys: ['B'],
direction: 'right'
}}
>
{#if show}
<ChevronLeftIcon size={16} />
{:else}
<ChevronRightIcon size={16} />
{/if}
</IconButton>
<TextChip
value={getLectureNo(index + 1)}
className="bg-primary-200 text-primary-600 text-xs mr-2"
size="sm"
shape="rounded-full"
/>
<span>{item.title}</span>
<span class="grow" />
{#if !item.is_unlocked}
<span class="text-md ml-2" title="This lesson is locked.">
<LockedIcon class="carbon-icon dark:text-white" />
</span>
{:else if item.is_complete}
<span class="ml-2" title="You have completed this lesson">
<CheckmarkFilled class="carbon-icon dark:text-white" />
</span>
{/if}
</div>
</a>
{/each}
{/if}
</NavExpandable>
{/if}
{/each}
</ul>
</div>
</div>
<style lang="scss">
.root {
height: calc(100vh - 48px);
display: flex;
flex-direction: column;
min-width: 360px;
max-width: 360px;
top: 0;
border-right: 1px solid var(--border-color);
background-color: rgb(250, 251, 252);
&.hide {
min-width: 15px;
max-width: 15px;
}
}
.footer {
border-top: 1px solid var(--border-color);
}
.toggler {
right: -15px;
z-index: 10;
border: 1px solid var(--border-color);
top: 50px;
height: fit-content;
background: var(--border-color);
}
@media (max-width: 760px) {
.root {
width: 98%;
min-width: unset;
max-width: unset;
}
}
</style>
</aside>
@@ -145,7 +145,7 @@
<Modal
onClose={resetForm}
bind:open={$invitationModal.open}
width="w-2/5"
width="w-4/5 md:w-2/5"
maxWidth="max-w-lg"
modalHeading="Invite people"
>
@@ -16,9 +16,7 @@
export let isFetching = false;
$: {
const user = $group.people.find(
(person) => person.profile_id === $profile.id
);
const user = $group.people.find((person) => person.profile_id === $profile.id);
if (user) {
isStudent = user.role_id === 3;
@@ -58,6 +56,6 @@
}
.rightBar.isMobile {
margin-left: 10px;
/* margin-left: 10px; */
}
</style>
@@ -7,36 +7,12 @@
export let show = true;
</script>
<section
class="root z-10 {!show && 'hide'} {$isMobile ? 'fixed shadow-xl' : 'sticky'}"
>
<section class="root z-10">
{#if show}
<div class="relative h-full bg-white dark:bg-gray-800">
<slot />
</div>
{/if}
<div class="toggler rounded-full shadow-lg absolute bottom-0">
<IconButton
value="toggle"
onClick={() => (show = !show)}
size={$isMobile ? 'large' : 'small'}
color="text-black"
toolTipProps={$isMobile
? {}
: {
title: 'Toggle editor',
hotkeys: ['B'],
direction: 'right',
}}
>
{#if show}
<ChevronLeftIcon size={16} />
{:else}
<ChevronRightIcon size={16} />
{/if}
</IconButton>
</div>
</section>
<style lang="scss">
@@ -50,11 +26,6 @@
left: 0;
border-right: 1px solid var(--border-color);
background-color: rgb(250, 251, 252);
&.hide {
min-width: 15px;
max-width: 15px;
}
}
.toggler {
@@ -67,10 +38,5 @@
}
@media (max-width: 760px) {
.root {
width: 98%;
min-width: unset;
max-width: unset;
}
}
</style>
@@ -18,13 +18,16 @@
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import { updateCourse } from '$lib/utils/services/courses';
import generateSlug from '$lib/utils/functions/generateSlug';
import ChevronLeftIcon from 'carbon-icons-svelte/lib/ChevronLeft.svelte';
import { isMobile } from '$lib/utils/store/useMobile';
export let course;
export let courseId;
let borderBottomGrey = 'border-r-0 border-b border-l-0 border-gray-300';
let loading = false;
let show = false;
const sections = [
{
key: 1,
@@ -115,69 +118,112 @@
}
</script>
<Container show={true}>
<!-- Publish Header Section -->
{#if !selectedSection}
<div class="flex justify-between items-center px-2 w-full">
<CloseButton onClick={handleClose} />
<div class="flex items-center">
<PrimaryButton
label="Save"
type="button"
className="mr-1"
variant={VARIANTS.OUTLINED}
onClick={handleSave}
isLoading={loading}
/>
<PrimaryButton label="Publish" type="button" onClick={handlePublish} isDisabled={loading} />
<IconButton onClick={handlePreview} disabled={loading || !course.slug}>
<ArrowUpRightIcon size={24} class="carbon-icon dark:text-white" title="Preview" />
</IconButton>
</div>
</div>
<div class="flex justify-between items-center px-2 w-full mb-2">
<h3 class="dark:text-white">Page Builder</h3>
</div>
{#each sections as section}
<button
class="w-full flex items-center justify-between px-2 py-3 border border-b-0 border-gray-300"
on:click={handleSectionSelect(section.key)}
>
<p class="dark:text-white mr-2">{section.title} section</p>
<ChevronRightIcon size={24} class="carbon-class" />
</button>
{/each}
{:else}
<!-- Title -->
<div class="flex items-center {borderBottomGrey} w-full">
<IconButton onClick={handleClose}>
<ArrowLeftIcon size={24} class="carbon-icon dark:text-white" title="Go back" />
</IconButton>
<h3 class="dark:text-white">{selectedSection.title}</h3>
</div>
<div class="title-content p-2 overflow-y-auto">
{#if selectedSection.key === 1}
<HeaderForm bind:course />
{:else if selectedSection.key === 2}
<RequirementForm bind:course />
{:else if selectedSection.key === 3}
<DescriptionForm bind:course />
{:else if selectedSection.key === 4}
<GoalsForm bind:course />
{:else if selectedSection.key === 5}
<ReviewsForm bind:course />
{:else if selectedSection.key === 6}
<InstructorForm bind:course />
{:else if selectedSection.key === 7}
<PricingForm bind:course />
<aside
class={`${
show ? '-translate-x-[100%] fixed z-[9999]' : 'translate-x-0 fixed z-[9999]'
} left-0 transition w-[280px] min-w-[280px] bg-gray-100 dark:bg-gray-800 h-full border border-l-0 border-t-0 border-b-0 border-r-1`}
>
<div class="toggler rounded-full shadow-lg absolute">
<IconButton
value="toggle"
onClick={() => (show = !show)}
size={$isMobile ? 'large' : 'small'}
color="text-black"
toolTipProps={$isMobile
? {}
: {
title: 'Toggle editor',
direction: 'right'
}}
>
{#if show}
<ChevronRightIcon size={16} />
{:else}
<ChevronLeftIcon size={16} />
{/if}
</div>
{/if}
</Container>
</IconButton>
</div>
<div class="h-full flex flex-col">
{#if !selectedSection}
<div class="flex justify-between items-center px-2 w-full">
<CloseButton onClick={handleClose} />
<div class="flex items-center">
<PrimaryButton
label="Save"
type="button"
className="mr-1"
variant={VARIANTS.OUTLINED}
onClick={handleSave}
isLoading={loading}
/>
<PrimaryButton
label="Publish"
type="button"
onClick={handlePublish}
isDisabled={loading}
/>
<IconButton onClick={handlePreview} disabled={loading || !course.slug}>
<ArrowUpRightIcon size={24} class="carbon-icon dark:text-white" title="Preview" />
</IconButton>
</div>
</div>
<div class="flex justify-between items-center px-2 w-full mb-2">
<h3 class="dark:text-white">Page Builder</h3>
</div>
{#each sections as section}
<button
class="w-full flex items-center justify-between px-2 py-3 border border-b-0 border-gray-300"
on:click={handleSectionSelect(section.key)}
>
<p class="dark:text-white mr-2">{section.title} section</p>
<ChevronRightIcon size={24} class="carbon-class" />
</button>
{/each}
{:else}
<!-- Title -->
<div class="flex items-center {borderBottomGrey} w-full">
<IconButton onClick={handleClose}>
<ArrowLeftIcon size={24} class="carbon-icon dark:text-white" title="Go back" />
</IconButton>
<h3 class="dark:text-white">{selectedSection.title}</h3>
</div>
<div class="title-content p-2 overflow-y-auto">
{#if selectedSection.key === 1}
<HeaderForm bind:course />
{:else if selectedSection.key === 2}
<RequirementForm bind:course />
{:else if selectedSection.key === 3}
<DescriptionForm bind:course />
{:else if selectedSection.key === 4}
<GoalsForm bind:course />
{:else if selectedSection.key === 5}
<ReviewsForm bind:course />
{:else if selectedSection.key === 6}
<InstructorForm bind:course />
{:else if selectedSection.key === 7}
<PricingForm bind:course />
{/if}
</div>
{/if}
</div>
</aside>
<style>
.title-content {
height: 90%;
}
.toggler {
right: -15px;
z-index: 10;
border: 1px solid var(--border-color);
top: 50px;
height: fit-content;
background: var(--border-color);
}
@media screen and (max-width: 767px) {
.toggler {
right: -25px;
}
}
</style>
@@ -38,7 +38,7 @@
</script>
<!-- Pricing Details -->
<aside class="{className} price-container md:sticky md:top-0 md:shadow-2xl md:rounded-lg m-h-fit">
<aside class="{className} price-container lg:sticky lg:top-0 lg:shadow-2xl lg:rounded-lg m-h-fit">
<div class="p-10">
<!-- Pricing -->
<div class="mb-6">
@@ -120,9 +120,9 @@
height: fit-content;
}
@media (max-width: 768px) {
@media screen and (min-width: 768px) and (max-width: 1024px) {
.price-container {
width: 100%;
width: 405px;
min-width: unset;
}
}
@@ -164,12 +164,14 @@
{/if}
</div>
</header>
<PricingSection className="md:hidden" {courseData} />
<!-- <PricingSection className="md:hidden" {courseData} /> -->
<!-- Body -->
<div class="bg-white dark:bg-gray-800 w-full">
<div class="py-8 lg:w-10/12 w-full m-2 lg:m-auto flex justify-between">
<div
class="py-8 lg:w-11/12 w-full m-2 lg:m-auto flex flex-col-reverse lg:flex-row items-center lg:items-start justify-between"
>
<!-- Course Details -->
<div class="course-content w-full p-3 md:w-9/12 md:mr-14">
<div class="course-content w-full p-3 lg:w-10/12 lg:mr-14">
<!-- Navigation -->
<nav class="flex items-center border-b border-gray-300 pb-3">
{#each NAV_ITEMS as navItem}
@@ -416,7 +418,7 @@
</div>
<!-- Pricing Details -->
<PricingSection className="hidden md:block" {courseData} />
<PricingSection {courseData} />
</div>
</div>
</div>
@@ -464,7 +466,7 @@
}
.course-content {
max-width: 608px;
max-width: 800px;
}
nav {
+2 -2
View File
@@ -6,7 +6,7 @@
</script>
<div class="w-full flex flex-col">
<div class="flex items-center border-b-2 w-full">
<div class="flex items-center border-b-2 w-full overflow-x-auto">
{#each tabs as tab}
{#if !tab.icon && !tab.badgeValue}
<button
@@ -32,7 +32,7 @@
: 'dark:bg-gray-500 dark:text-white'} dark:bg-transparent font-semibold focus:outline-none w-24 text-left py-3 mr-10"
on:click={onChange(tab.value)}
>
<div class="grid grid-cols-4 gap-3 items-center">
<div class="grid grid-cols-5 md:grid-cols-4 gap-5 md:gap-3 items-center">
{#if tab.icon}
<svelte:component this={tab.icon} />
{/if}