Initial commit

This commit is contained in:
2025-08-04 16:33:07 +03:30
commit f798e8e35c
9595 changed files with 1208683 additions and 0 deletions

View File

@@ -0,0 +1,315 @@
<script setup>
import { VideoPlayer } from '@videojs-player/vue'
import InstructorPoster from '@images/pages/instructor-poster.png'
import 'video.js/dist/video-js.css'
const courseDetails = ref()
const { data, error } = await useApi('/apps/academy/course-details')
if (error.value)
console.log(error.value)
else if (data.value)
courseDetails.value = data.value
const panelStatus = ref(0)
</script>
<template>
<VRow>
<VCol
cols="12"
md="8"
>
<VCard>
<VCardItem
title="UI/UX Basic Fundamentals"
class="pb-6"
>
<template #subtitle>
<div class="text-body-1">
Prof. <span class="text-h6 d-inline-block">{{ courseDetails?.instructor }}</span>
</div>
</template>
<template #append>
<div class="d-flex gap-4 align-center">
<VChip
variant="tonal"
color="error"
size="small"
>
UI/UX
</VChip>
<VIcon
size="24"
class="cursor-pointer"
icon="tabler-share"
/>
<VIcon
size="24"
class="cursor-pointer"
icon="tabler-bookmarks"
/>
</div>
</template>
</VCardItem>
<VCardText>
<VCard
flat
border
>
<div class="px-2 pt-2">
<VideoPlayer
src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4"
:poster="InstructorPoster"
controls
plays-inline
:height="$vuetify.display.mdAndUp ? 440 : 250"
class="w-100 rounded"
/>
</div>
<VCardText>
<h5 class="text-h5 mb-4">
About this course
</h5>
<p class="text-body-1">
{{ courseDetails?.about }}
</p>
<VDivider class="my-6" />
<h5 class="text-h5 mb-4">
By the numbers
</h5>
<div class="d-flex gap-x-12 gap-y-5 flex-wrap">
<div>
<VList class="card-list text-medium-emphasis">
<VListItem>
<template #prepend>
<VIcon
icon="tabler-check"
size="20"
/>
</template>
<VListItemTitle>Skill Level: {{ courseDetails?.skillLevel }}</VListItemTitle>
</VListItem>
<VListItem>
<template #prepend>
<VIcon
icon="tabler-users"
size="20"
/>
</template>
<VListItemTitle>Students: {{ courseDetails?.totalStudents }}</VListItemTitle>
</VListItem>
<VListItem>
<template #prepend>
<VIcon
icon="tabler-world"
size="20"
/>
</template>
<VListItemTitle>Languages: {{ courseDetails?.language }}</VListItemTitle>
</VListItem>
<VListItem>
<template #prepend>
<VIcon
icon="tabler-file"
size="20"
/>
</template>
<VListItemTitle>Captions: {{ courseDetails?.isCaptions }}</VListItemTitle>
</VListItem>
</VList>
</div>
<div>
<VList class="card-list text-medium-emphasis">
<VListItem>
<template #prepend>
<VIcon
icon="tabler-video"
size="20"
/>
</template>
<VListItemTitle>Lectures: {{ courseDetails?.totalLectures }}</VListItemTitle>
</VListItem>
<VListItem>
<template #prepend>
<VIcon
icon="tabler-clock"
size="20"
/>
</template>
<VListItemTitle>Video: {{ courseDetails?.length }}</VListItemTitle>
</VListItem>
</VList>
</div>
</div>
<VDivider class="my-6" />
<h5 class="text-h5 mb-4">
Description
</h5>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-html="courseDetails?.description" />
<VDivider class="my-6" />
<h5 class="text-h5 mb-4">
Instructor
</h5>
<div class="d-flex align-center gap-x-4">
<VAvatar
:image="courseDetails?.instructorAvatar"
size="38"
/>
<div>
<h6 class="text-h6 mb-1">
{{ courseDetails?.instructor }}
</h6>
<div class="text-body-2">
{{ courseDetails?.instructorPosition }}
</div>
</div>
</div>
</VCardText>
</VCard>
</VCardText>
</VCard>
</VCol>
<VCol
cols="12"
md="4"
>
<div class="course-content">
<VExpansionPanels
v-model="panelStatus"
variant="accordion"
class="expansion-panels-width-border"
>
<template
v-for="(section, index) in courseDetails?.content"
:key="index"
>
<VExpansionPanel
elevation="0"
:value="index"
expand-icon="tabler-chevron-right"
collapse-icon="tabler-chevron-down"
>
<template #title>
<div>
<h5 class="text-h5 mb-1">
{{ section.title }}
</h5>
<div class="text-medium-emphasis font-weight-normal">
{{ section.status }} | {{ section.time }}
</div>
</div>
</template>
<template #text>
<VList class="card-list">
<VListItem
v-for="(topic, id) in section.topics"
:key="id"
class="py-4"
>
<template #prepend>
<VCheckbox
:model-value="topic.isCompleted"
class="me-1"
/>
</template>
<VListItemTitle class="text-high-emphasis font-weight-medium">
{{ id + 1 }} . {{ topic.title }}
</VListItemTitle>
<VListItemSubtitle>
<div class="text-body-2">
{{ topic.time }}
</div>
</VListItemSubtitle>
</VListItem>
</VList>
</template>
</VExpansionPanel>
</template>
</VExpansionPanels>
</div>
</VCol>
</VRow>
</template>
<style lang="scss" scoped>
.course-content {
position: sticky;
inset-block: 4rem 0;
}
.card-list {
--v-card-list-gap: 16px;
}
</style>
<style lang="scss">
@use "@layouts/styles/mixins" as layoutsMixins;
body .v-layout .v-application__wrap {
.course-content {
.v-expansion-panels {
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
border-radius: 6px;
.v-expansion-panel {
&--active {
.v-expansion-panel-title--active {
border-block-end: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
.v-expansion-panel-title__overlay {
opacity: var(--v-hover-opacity) !important;
}
}
}
.v-expansion-panel-title {
.v-expansion-panel-title__overlay {
background-color: rgba(var(--v-theme-on-surface));
opacity: var(--v-hover-opacity) !important;
}
&:hover {
.v-expansion-panel-title__overlay {
opacity: var(--v-hover-opacity) !important;
}
}
&__icon {
.v-icon {
block-size: 1.5rem !important;
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
font-size: 1.5rem !important;
inline-size: 1.5rem !important;
@include layoutsMixins.rtl {
transform: scaleX(-1);
}
}
}
}
.v-expansion-panel-text {
&__wrapper {
padding-block: 1rem;
padding-inline: 0.75rem;
}
}
}
}
}
.card-list {
.v-list-item__prepend {
.v-list-item__spacer {
inline-size: 8px !important;
}
}
}
}
</style>

View File

@@ -0,0 +1,253 @@
<script setup>
import AcademyAssignmentProgress from '@/views/apps/academy/AcademyAssignmentProgress.vue'
import AcademyCardPopularInstructors from '@/views/apps/academy/AcademyCardPopularInstructors.vue'
import AcademyCardTopCourses from '@/views/apps/academy/AcademyCardTopCourses.vue'
import AcademyCourseTable from '@/views/apps/academy/AcademyCourseTable.vue'
import AcademyTopicYouAreInterested from '@/views/apps/academy/AcademyTopicYouAreInterested.vue'
import AcademyUpcomingWebinar from '@/views/apps/academy/AcademyUpcomingWebinar.vue'
import customCheck from '@images/svg/Check.svg'
import customLaptop from '@images/svg/laptop.svg'
import customLightbulb from '@images/svg/lightbulb.svg'
const donutChartColors = {
donut: {
series1: '#22A95E',
series2: '#24B364',
series3: '#56CA00',
series4: '#53D28C',
series5: '#7EDDA9',
series6: '#A9E9C5',
},
}
const timeSpendingChartConfig = {
chart: {
height: 157,
width: 130,
parentHeightOffset: 0,
type: 'donut',
},
labels: [
'36h',
'56h',
'16h',
'32h',
'56h',
'16h',
],
colors: [
donutChartColors.donut.series1,
donutChartColors.donut.series2,
donutChartColors.donut.series3,
donutChartColors.donut.series4,
donutChartColors.donut.series5,
donutChartColors.donut.series6,
],
stroke: { width: 0 },
dataLabels: {
enabled: false,
formatter(val) {
return `${ Number.parseInt(val) }%`
},
},
legend: { show: false },
tooltip: { theme: false },
grid: { padding: { top: 0 } },
plotOptions: {
pie: {
donut: {
size: '75%',
labels: {
show: true,
value: {
fontSize: '1.125rem',
color: 'rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity))',
fontWeight: 500,
offsetY: -15,
formatter(val) {
return `${ Number.parseInt(val) }%`
},
},
name: { offsetY: 20 },
total: {
show: true,
fontSize: '15px',
label: 'Total',
color: 'rgba(var(--v-theme-on-background), var(--v-disabled-opacity))',
formatter() {
return '231h'
},
},
},
},
},
},
}
const timeSpendingChartSeries = [
23,
35,
10,
20,
35,
23,
]
</script>
<template>
<div>
<VRow class="py-6">
<!-- 👉 Welcome -->
<VCol
cols="12"
md="8"
:class="$vuetify.display.mdAndUp ? 'border-e' : 'border-b'"
>
<div class="pe-3">
<h5 class="text-h5 mb-2">
Welcome back,<span class="text-h4"> Felecia 👋🏻 </span>
</h5>
<div
class="text-wrap text-body-1"
style="max-inline-size: 360px;"
>
Your progress this week is Awesome. let's keep it up
and get a lot of points reward!
</div>
<div class="d-flex justify-space-between flex-wrap gap-4 flex-column flex-md-row mt-4">
<div
v-for="{ title, value, icon, color } in [
{ title: 'Hours Spent', value: '34h', icon: customLaptop, color: 'primary' },
{ title: 'Test Results', value: '82%', icon: customLightbulb, color: 'info' },
{ title: 'Course Completed', value: '14', icon: customCheck, color: 'warning' },
]"
:key="title"
>
<div class="d-flex align-center">
<VAvatar
variant="tonal"
:color="color"
rounded
size="54"
class="text-primary me-4"
>
<VIcon
:icon="icon"
size="38"
/>
</VAvatar>
<div>
<h6 class="text-h6 text-medium-emphasis">
{{ title }}
</h6>
<h4
class="text-h4"
:class="`text-${color}`"
>
{{ value }}
</h4>
</div>
</div>
</div>
</div>
</div>
</VCol>
<!-- 👉 Time Spending -->
<VCol
cols="12"
md="4"
>
<div class="d-flex justify-space-between align-center">
<div class="d-flex flex-column ps-3">
<h5 class="text-h5 mb-1 text-no-wrap">
Time Spending
</h5>
<div class="text-body-1 mb-7">
Weekly Report
</div>
<h4 class="text-h4 mb-2">
231<span class="text-medium-emphasis">h</span> 14<span class="text-medium-emphasis">m</span>
</h4>
<div>
<VChip
color="success"
label
size="small"
>
+18.4%
</VChip>
</div>
</div>
<div>
<VueApexCharts
type="donut"
height="150"
width="150"
:options="timeSpendingChartConfig"
:series="timeSpendingChartSeries"
/>
</div>
</div>
</VCol>
</VRow>
<VRow class="match-height">
<!-- 👉 Topics you are interested in -->
<VCol
cols="12"
md="8"
>
<!-- 👉 Topic You are Interested in -->
<AcademyTopicYouAreInterested />
</VCol>
<!-- 👉 Popular Instructors -->
<VCol
cols="12"
md="4"
sm="6"
>
<AcademyCardPopularInstructors />
</VCol>
<!-- 👉 Academy Top Courses -->
<VCol
cols="12"
md="4"
sm="6"
>
<AcademyCardTopCourses />
</VCol>
<!-- 👉 Academy Upcoming Webinar -->
<VCol
cols="12"
md="4"
sm="6"
>
<AcademyUpcomingWebinar />
</VCol>
<!-- 👉 Academy Assignment Progress -->
<VCol
cols="12"
md="4"
sm="6"
>
<AcademyAssignmentProgress />
</VCol>
<!-- 👉 Academy Course Table -->
<VCol>
<AcademyCourseTable />
</VCol>
</VRow>
</div>
</template>
<style lang="scss">
@use "@core-scss/template/libs/apex-chart.scss";
</style>

View File

@@ -0,0 +1,234 @@
<script setup>
import { VideoPlayer } from '@videojs-player/vue'
import AcademyMyCourses from '@/views/apps/academy/AcademyMyCourses.vue'
import boyAppAcademy from '@images/illustrations/boy-app-academy.png'
import girlAppAcademy from '@images/illustrations/girl-app-academy.png'
import academyCourseIllustration1 from '@images/pages/academy-course-illustration1.png'
import academyCourseIllustration2Dark from '@images/pages/academy-course-illustration2-dark.png'
import academyCourseIllustration2Light from '@images/pages/academy-course-illustration2-light.png'
import guitarCoursePoster from '@images/pages/guitar-course-poster.png'
import singingCoursePoster from '@images/pages/singing-course-poster.png'
const academyCourseIllustration2 = useGenerateImageVariant(academyCourseIllustration2Light, academyCourseIllustration2Dark)
const searchQuery = ref('')
</script>
<template>
<div>
<VCard class="mb-6">
<VCardText class="py-12 position-relative">
<div
class="d-flex flex-column gap-y-4 mx-auto"
:class="$vuetify.display.mdAndUp ? 'w-50' : $vuetify.display.xs ? 'w-100' : 'w-75'"
>
<h4
class="text-h4 text-center text-wrap mx-auto"
:class="$vuetify.display.mdAndUp ? 'w-75' : 'w-100'"
>
Education, talents, and career
opportunities. <span class="text-primary text-no-wrap"> All in one place.</span>
</h4>
<p class="text-center text-wrap text-body-1 mx-auto mb-0">
Grow your skill with the most reliable online courses and certifications in marketing, information technology, programming, and data science.
</p>
<div class="d-flex justify-center align-center gap-4 flex-wrap">
<div
class="flex-grow-1"
style="max-inline-size: 350px;"
>
<AppTextField
v-model="searchQuery"
placeholder="Find your course"
/>
</div>
<VBtn
color="primary"
density="comfortable"
icon="tabler-search"
class="rounded"
/>
</div>
</div>
<img
:src="academyCourseIllustration1"
class="illustration1 d-none d-md-block flip-in-rtl"
height="180"
>
<img
:src="academyCourseIllustration2"
class="illustration2 d-none d-md-block"
height="100"
>
</VCardText>
</VCard>
<AcademyMyCourses :search-query="searchQuery" />
<div class="mb-6">
<VRow>
<VCol
v-for="{ title, btnText, color, description, image } in [
{ title: 'Earn a Certificate', description: 'Get the right professional certificate program for you.', btnText: 'View Programs', color: 'primary', image: boyAppAcademy },
{ title: 'Best Rated Courses', description: 'Enroll now in the most popular and best rated courses.', btnText: 'View Courses', color: 'error', image: girlAppAcademy },
]"
:key="title"
cols="12"
md="6"
>
<VCard
flat
:color="`rgba(var(--v-theme-${color}), var(--v-selected-opacity))`"
>
<VCardText>
<div class="d-flex justify-space-between gap-4 flex-column-reverse flex-sm-row">
<div class="text-center text-sm-start">
<h5
class="text-h5 mb-1"
:class="`text-${color}`"
>
<div class="d-flex justify-space-between gap-4 flex-column-reverse flex-sm-row">
<div class="text-center text-sm-start">
<h5
class="text-h5 mb-1"
:class="`text-${color}`"
>
{{ title }}
</h5>
</div>
</div>
</h5>
<p
class="text-body-1 mx-auto"
style="max-inline-size: 300px;"
>
{{ description }}
</p>
<VBtn :color="color">
{{ btnText }}
</VBtn>
</div>
<div class="align-self-center">
<div class="align-self-center">
<img
:src="image"
height="127"
class="flip-in-rtl"
>
</div>
</div>
</div>
</VCardText>
</VCard>
</VCol>
</VRow>
</div>
<VCard>
<VCardText>
<VRow>
<VCol
cols="12"
md="4"
>
<div class="d-flex flex-column align-center gap-y-4 h-100 justify-center">
<VAvatar
variant="tonal"
size="52"
rounded
color="primary"
>
<VIcon
icon="tabler-gift"
size="36"
/>
</VAvatar>
<h4 class="text-h4 font-weight-medium">
Today's Free Courses
</h4>
<p class="text-body-1 text-center mb-0">
We offers 284 Free Online courses from top tutors and companies to help you start or advance your career skills. Learn online for free and fast today!
</p>
<VBtn>Get Premium Courses</VBtn>
</div>
</VCol>
<VCol
cols="12"
md="4"
sm="6"
>
<VCard
flat
border
>
<div class="px-2 pt-2">
<VideoPlayer
src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4"
:poster="guitarCoursePoster"
controls
plays-inline
:height="$vuetify.display.mdAndUp ? 200 : 150"
class="w-100 rounded"
/>
</div>
<VCardText>
<h5 class="text-h5 mb-2">
Your First Singing Lesson
</h5>
<p class="text-body-1 mb-0">
In the same way as any other artistic domain, singing lends itself perfectly to self-teaching.
</p>
</VCardText>
</VCard>
</VCol>
<VCol
cols="12"
md="4"
sm="6"
>
<VCard
flat
border
>
<div class="px-2 pt-2">
<VideoPlayer
src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4"
:poster="singingCoursePoster"
controls
plays-inline
:height="$vuetify.display.mdAndUp ? 200 : 150"
class="w-100 rounded"
/>
</div>
<VCardText>
<h5 class="text-h5 mb-2">
Guitar for Beginners
</h5>
<p class="text-body-1 mb-0">
The Fender Acoustic Guitar is best choice for beginners and professionals.
</p>
</VCardText>
</VCard>
</VCol>
</VRow>
</VCardText>
</VCard>
</div>
</template>
<style lang="scss">
@import "video.js/dist/video-js.css";
.illustration1 {
position: absolute;
inset-block-end: 0;
inset-inline-end: 0;
}
.illustration2 {
position: absolute;
inset-block-start: 2rem;
inset-inline-start: 2.5rem;
}
</style>