CLASSROOMIO-T-30:Developed the UI for the video upload
CLASSROOMIO-T-30: UI cleanup CLASSROOMIO-T-30: Improve UX Merge branch 'CLASSROOMIO-T-30' of https://gitlab.com/thenextgreat/classroomio into CLASSROOMIO-T-30 CLASSROOMIO-T-30:Made the input clear after upload and also chnged the icons CLASSROOMIO-T-30: Remove console log CLASSROOMIO-T-30: Better trim out white spaces in url CLASSROOMIO-T-30:Fixed the bug between the save and edit CLASSROOMIO-T-30:Trying to fix the bug between edit and save Merge branch 'main' of https://gitlab.com/thenextgreat/classroomio CLASSROOMIO-T-30:Stil working on the reviews CLASSROOMIO-T-30:Still working on some of the reviews and updates CLASSROOMIO-T-30: Remove unnessecary values in store CLASSROOMIO-T-30: Change button to div in modal CLASSROOMIO-T-100: Select only courses belonging to current org and current user is a member CLASSROOMIO-T-100: Update condition for fetchCourses CLASSROOMIO-T-100: Select only courses belonging to current org and current user is a member Co-authored-by: Rotimi Best <[email protected]> Merge-request: CLASSROOMIO-MR-35 Merged-by: Best Admin <[email protected]> Remove netlify app from redirect rule Add redirect to layout's load Redirect to about domain CLASSROOMIO-T-97: UX again? 😇 CLASSROOMIO-T-97: Better course UX 😍😍 CLASSROOMIO-T-97: Better button style and fix route not found CLASSROOMIO-T-97: Course UI improvement 😁😁😁 CLASSROOMIO-T-30: Add plyr CLASSROOMIO-T-30:Merged main into branch Merge branch 'main' of https://gitlab.com/thenextgreat/classroomio CLASSROOMIO-T-30:Wotking on the lms dashboard CLASSROOMIO-T-30:Made some changes based on the reviews Merge branch 'main' of https://gitlab.com/thenextgreat/classroomio CLASSROOMIO-T-30:Made some refactoring to keep the code DRY CLASSROOMIO-T-30:Developed the UI for the video upload Merge branch 'main' of https://gitlab.com/thenextgreat/classroomio Merge branch 'main' of https://gitlab.com/thenextgreat/classroomio CLASSROOMIO-T-27: Review Section for Instructors on landing page CLASSROOMIO-T-27: Remove unused variable Merge branch 'CLASSROOMIO-T-27' of https://gitlab.com/thenextgreat/classroomio into CLASSROOMIO-T-27 CLASSROOMIO-T-27: Complete reviews functionality CLASSROOMIO-T-27: Review Render Update CLASSROOMIO-T-27: - Resolved Feedbacks CLASSROOMIO-T-27: Fixed Ratings Data CLASSROOMIO-T-27: - Added Ratings Svg - Fixed avatar_url feedback CLASSROOMIO-T-27: Import Adjustment CLASSROOMIO-T-27: Code Review CLASSROOM-T-27: Added Add Review Functionality CLASSROOMIO-T-27: - Unresolved Review - Enhance Code Redability CLASSROOMIO-T-27: Completed the delete functionality CLASSROOMIO-T-27: Hide/Show functionality CLASSROOMIO-T-27: Double Quotation Update CLASSROOMIO-T-27: Testing toggle functinality CLASSROOMIO-T-27: Added the icons CLASSROOMIO-T-27: Completion of the hide/show functionality CLASSROOMIO-T-27: Display the store data on the review page for styling CLASSROOMIO-T-27: Styling of the review component & connecting it's data CLASSROOMIO-T-27: - Add ReviewsForm - Completion of the Reviews Form Structure/Styling CLASSROOMIO-T-27: Added a reviews modal CLASSROOMIO-T-27: Logic update for review section CLASSROOMIO-T-50: Logic for overlapping reviews CLASSROOMIO-T-27: - Completion of the structure & styling with mock data. - Addition of custom ratings assets CLASSROOMIO-T-27: - Review Section Code Structure - Import Profile Picture Assets Co-authored-by: Rotimi Best <[email protected]> Co-authored-by: Tunji Adeyemi <[email protected]> Co-authored-by: tunny17 <[email protected]> Merge-request: CLASSROOMIO-MR-22 Merged-by: Best Admin <[email protected]> CLASSROOMIO-T-62: Dark Mode Bug Fix CLASSROOMIO-T-62: Delete Unused class CLASSROOMIO-T-62: Dark Mode Bug Fix Co-authored-by: Tunji Adeyemi <[email protected]> Merge-request: CLASSROOMIO-MR-23 Merged-by: Best Admin <[email protected]> Co-authored-by: Ifeanyi Nwosu <[email protected]> Co-authored-by: Rotimi Best <[email protected]> Co-authored-by: Tunji Adeyemi <[email protected]> Co-authored-by: tunny17 <[email protected]> Merge-request: CLASSROOMIO-MR-33 Merged-by: Best Admin <[email protected]>
@@ -4,7 +4,7 @@
|
||||
|
||||
export let onClick;
|
||||
export let contained;
|
||||
export let color = '';
|
||||
export let color = 'text-blue-700 bg-blue-200 dark:bg-gray-500';
|
||||
export let size = 'large';
|
||||
</script>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
{#if size === 'large'}
|
||||
<CloseIcon size={24} class="carbon-icon dark:text-white" title="Delete" />
|
||||
{:else}
|
||||
<CloseIcon size={24} class="carbon-icon dark:text-white" title="Delete" />
|
||||
<CloseIcon size={20} class="carbon-icon dark:text-white" title="Delete" />
|
||||
{/if}
|
||||
</IconButton>
|
||||
<!-- color="text-blue-700 bg-blue-200 dark:bg-gray-200 dark:text-black" -->
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<script>
|
||||
import YoutubeVideo from './YoutubeVideo.svelte';
|
||||
import LocalVideo from './LocalVideo.svelte';
|
||||
import * as CONSTANTS from './constants';
|
||||
|
||||
let tabs = CONSTANTS.videoTabs;
|
||||
let currentTab = tabs[0].value;
|
||||
|
||||
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>
|
||||
{#each tabs as item (item.value)}
|
||||
<button
|
||||
on:click={onChange(item.value)}
|
||||
class={`w-full px-4 py-3 my-5 border ${
|
||||
currentTab === item.value
|
||||
? 'border border-[#0233BD] bg-[#F5F8FE] dark:text-black'
|
||||
: 'border border-gray-200'
|
||||
} rounded-md cursor-pointer flex flex-row items-center justify-start gap-2 whitespace-nowrap`}
|
||||
>
|
||||
<svelte:component
|
||||
this={item.icon}
|
||||
size={20}
|
||||
color={`${currentTab === item.value ? 'dark:invert-0' : 'dark:invert'}`}
|
||||
/>
|
||||
<p>{item.title}</p>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<main class="w-full h-full">
|
||||
{#if currentTab === 1}
|
||||
<YoutubeVideo />
|
||||
{:else}
|
||||
<LocalVideo />
|
||||
{/if}
|
||||
</main>
|
||||
</section>
|
||||
@@ -0,0 +1,88 @@
|
||||
<script>
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
import { deleteLessonVideo } from '$lib/components/Course/components/Lesson/store/lessons';
|
||||
|
||||
let isWrongFormat = false;
|
||||
let isUploaded = false;
|
||||
let isLoaded = false;
|
||||
let isBig = false;
|
||||
|
||||
const uploadVideo = () => {
|
||||
// if the file is too big or not the correct format
|
||||
isWrongFormat = true;
|
||||
|
||||
// when the upload has been sucessfully completed
|
||||
// here the you set the video_url to something and that would be displayed on the page
|
||||
isUploaded = false;
|
||||
|
||||
// closes the modal
|
||||
// $uploadCourseVideo.isModalOpen = false;
|
||||
};
|
||||
|
||||
const onUpload = () => {
|
||||
// PROBABLY GET THE SNAPSHOT OR SOMETHING
|
||||
isLoaded = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if isLoaded == false}
|
||||
<button
|
||||
on:click={onUpload}
|
||||
class="h-full w-full flex flex-col items-center justify-center border border-blue-300 border-dashed rounded-xl"
|
||||
>
|
||||
<img src="/upload-video.svg" alt="upload" />
|
||||
<span class="pt-3">
|
||||
<h3 class="text-center text-xl font-normal dark:text-white">Upload video</h3>
|
||||
<p class=" text-center text-sm font-normal">
|
||||
Select file( Mp4, MOV, AVI) to upload or drag and drop video here.<br /> Size must be less than
|
||||
20 MB.
|
||||
</p>
|
||||
</span>
|
||||
</button>
|
||||
{:else if isBig && isUploaded == false}
|
||||
<div class="h-full w-full flex flex-col items-center justify-center rounded-xl">
|
||||
<img src="/video-upload-error.svg" alt="upload error" />
|
||||
<span class="pt-3 pb-2">
|
||||
<h3 class="text-center text-base font-normal dark:text-white">
|
||||
Oops 😬, couldn’t upload video
|
||||
</h3>
|
||||
<p class="text-center text-xs font-normal text-[#ADADAD]">
|
||||
Sorry we video wasn’t uploaded. The file size is too big,<br /> maximum size is 20 MB. Try again!
|
||||
</p>
|
||||
</span>
|
||||
<PrimaryButton label="Try again" />
|
||||
</div>
|
||||
{:else if isWrongFormat && isUploaded == false}
|
||||
<div class="h-full w-full flex flex-col items-center justify-center rounded-xl">
|
||||
<img src="/video-upload-error.svg" alt="upload error" />
|
||||
<span class="pt-3 pb-2">
|
||||
<h3 class="text-center text-base font-normal dark:text-white">
|
||||
Oops 😬, couldn’t upload video
|
||||
</h3>
|
||||
<p class="text-center text-xs font-normal text-[#ADADAD]">
|
||||
Sorry we video wasn’t uploaded, the file format isn’t supported.<br /> Upload MP4, MOV and AVI
|
||||
files.
|
||||
</p>
|
||||
</span>
|
||||
<PrimaryButton label="Try again" />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-col w-full h-full items-start justify-between">
|
||||
<div class="h-auto w-full border rounded-md px-8 py-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="flex items-center gap-2">
|
||||
<div class="rounded-sm overflow-hidden">
|
||||
<img src="/course-video.png" alt="coursevideo" class="object-cover" />
|
||||
</div>
|
||||
<p>Video.png</p>
|
||||
</span>
|
||||
<button on:click={deleteLessonVideo}>
|
||||
<img src="/delete-video.svg" alt="deletevideo" class="dark:invert" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-auto">
|
||||
<PrimaryButton label="upload" onClick={uploadVideo} />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -0,0 +1,79 @@
|
||||
<script>
|
||||
import { CopyButton, Tag } from 'carbon-components-svelte';
|
||||
import TrashCanIcon from 'carbon-icons-svelte/lib/TrashCan.svelte';
|
||||
import TextField from '$lib/components/Form/TextField.svelte';
|
||||
import { lesson, isLessonDirty } from '$lib/components/Course/components/Lesson/store/lessons';
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
import Chip from '$lib/components/Chip/Text.svelte';
|
||||
import IconButton from '$lib/components/IconButton/index.svelte';
|
||||
|
||||
let youtubeLinks = '';
|
||||
let error = '';
|
||||
|
||||
function addVideo() {
|
||||
const links = youtubeLinks.split(',').map((link) => link.trim());
|
||||
const validLinks = links.filter(isValidYouTubeLink);
|
||||
|
||||
if (validLinks.length === 0) {
|
||||
error = 'Invalid YouTube link(s)';
|
||||
} else {
|
||||
const existingLinks = $lesson.materials.video_url
|
||||
.split(',')
|
||||
.map((link) => link.trim())
|
||||
.filter(Boolean);
|
||||
const updatedLinks = [
|
||||
...existingLinks,
|
||||
...validLinks.filter((link) => !existingLinks.includes(link))
|
||||
];
|
||||
$lesson.materials.video_url = updatedLinks.join(',').trim();
|
||||
youtubeLinks = '';
|
||||
error = '';
|
||||
}
|
||||
}
|
||||
|
||||
function isValidYouTubeLink(link) {
|
||||
const youtubeRegex =
|
||||
/^(https?:\/\/)?(www\.)?(youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9_-]{11})/;
|
||||
|
||||
return youtubeRegex.test(link.trim());
|
||||
}
|
||||
|
||||
function removeVideo(index) {
|
||||
const links = $lesson.materials.video_url.split(',').map((link) => link.trim());
|
||||
links.splice(index, 1);
|
||||
$lesson.materials.video_url = links.join(',').trim();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="w-full flex items-{error ? 'center' : 'end'} justify-between gap-5">
|
||||
<TextField
|
||||
label="Youtube link"
|
||||
bind:value={youtubeLinks}
|
||||
className="flex-1 text-left "
|
||||
inputClassName="text-sm"
|
||||
onChange={() => ($isLessonDirty = true)}
|
||||
placeholder="https://www.youtube.com/watch?v="
|
||||
errorMessage={error}
|
||||
/>
|
||||
<PrimaryButton label="Add Video" className="rounded-md" onClick={addVideo} />
|
||||
</div>
|
||||
<p class="mt-4 pl-2 text-sm">
|
||||
Added : <strong
|
||||
>{($lesson?.materials?.video_url && $lesson.materials.video_url.trim().split(',').length) || 0} Videos</strong
|
||||
>
|
||||
</p>
|
||||
<div class="">
|
||||
{#each $lesson?.materials?.video_url && $lesson.materials.video_url
|
||||
.trim()
|
||||
.split(',') as videoLink, index}
|
||||
<div class="flex items-center gap-1">
|
||||
<Tag type="blue">
|
||||
{videoLink}
|
||||
</Tag>
|
||||
<CopyButton text={videoLink} feedback="Copied to clipboard" />
|
||||
<IconButton value="delete-video" onClick={() => removeVideo(index)}>
|
||||
<TrashCanIcon size={16} class="carbon-icon dark:text-white" />
|
||||
</IconButton>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
import Link from 'carbon-icons-svelte/lib/Link.svelte';
|
||||
import Video from 'carbon-icons-svelte/lib/Video.svelte';
|
||||
export const videoTabs = [
|
||||
{
|
||||
value: 1,
|
||||
title: 'Youtube Link',
|
||||
icon: Link
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
title: 'Video',
|
||||
icon: Video
|
||||
}
|
||||
];
|
||||
@@ -1,11 +1,13 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import { useCompletion } from 'ai/svelte';
|
||||
import MODES from '$lib/utils/constants/mode.js';
|
||||
import { getEmbedId } from '$lib/utils/functions/formatYoutubeVideo';
|
||||
import Modal from '$lib/components/Modal/index.svelte';
|
||||
import { Popover } from 'carbon-components-svelte';
|
||||
import AlignBoxTopLeftIcon from 'carbon-icons-svelte/lib/AlignBoxTopLeft.svelte';
|
||||
import TrashCan from 'carbon-icons-svelte/lib/TrashCan.svelte';
|
||||
import ListIcon from 'carbon-icons-svelte/lib/List.svelte';
|
||||
import IbmWatsonKnowledgeStudioIcon from 'carbon-icons-svelte/lib/IbmWatsonKnowledgeStudio.svelte';
|
||||
import { formatYoutubeVideo } from '$lib/utils/functions/formatYoutubeVideo';
|
||||
import MachineLearningModel from 'carbon-icons-svelte/lib/MachineLearningModel.svelte';
|
||||
import Tabs from '$lib/components/Tabs/index.svelte';
|
||||
import TabContent from '$lib/components/TabContent/index.svelte';
|
||||
@@ -14,24 +16,50 @@
|
||||
import EditContent from '$lib/components/EditContent/index.svelte';
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
import TextField from '$lib/components/Form/TextField.svelte';
|
||||
import { lesson, lessons, handleUpdateLessonMaterials, isLessonDirty } from '../store/lessons';
|
||||
import {
|
||||
lesson,
|
||||
lessons,
|
||||
handleUpdateLessonMaterials,
|
||||
isLessonDirty,
|
||||
uploadCourseVideoStore,
|
||||
deleteLessonVideo
|
||||
} from '$lib/components/Course/components/Lesson/store/lessons';
|
||||
import VideoUploader from '$lib/components/Course/components/Lesson/Materials/Video/Index.svelte';
|
||||
import { course } from '$lib/components/Course/store';
|
||||
import * as CONSTANTS from './constants';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export let mode = MODES.view;
|
||||
export let prevMode = null;
|
||||
export let lessonId;
|
||||
export let prevMode = '';
|
||||
export let lessonId = '';
|
||||
|
||||
let tabs = CONSTANTS.tabs;
|
||||
let currentTab = tabs[0].value;
|
||||
let errors = {};
|
||||
let player = {};
|
||||
let textareaRef = {};
|
||||
let aiButtonRef = {};
|
||||
let openPopover = false;
|
||||
let videoUrls: Array<string> = [];
|
||||
let aiButtonClass =
|
||||
'flex items-center px-5 py-2 border border-gray-300 hover:bg-gray-200 rounded-md w-full mb-2';
|
||||
|
||||
const onChange = (tab) => () => (currentTab = tab);
|
||||
const onChange =
|
||||
(tab = 0) =>
|
||||
() =>
|
||||
(currentTab = tab);
|
||||
|
||||
function initPlyr(_player, videoUrl = '') {
|
||||
if (!browser) return;
|
||||
|
||||
const players = Array.from(document.querySelectorAll('.plyr-video-trigger')).map((p) => {
|
||||
// @ts-ignore
|
||||
return new Plyr(p);
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
window.players = players;
|
||||
}
|
||||
|
||||
function handleSave(prevMode) {
|
||||
if (prevMode === MODES.edit) {
|
||||
@@ -58,6 +86,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
const openAddVideoModal = () => {
|
||||
$uploadCourseVideoStore.isModalOpen = true;
|
||||
};
|
||||
|
||||
const { input, handleSubmit, completion, isLoading } = useCompletion({
|
||||
api: '/api/completion'
|
||||
});
|
||||
@@ -81,13 +113,31 @@
|
||||
}, 500);
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
handleUpdateLessonMaterials($lesson, lessonId);
|
||||
$uploadCourseVideoStore.isModalOpen = false;
|
||||
};
|
||||
|
||||
$: handleSave(prevMode);
|
||||
|
||||
$: initPlyr(player, $lesson.materials.video_url);
|
||||
|
||||
$: addBadgeValueToTab($lesson.materials);
|
||||
|
||||
$: updateNoteByCompletion($completion);
|
||||
|
||||
$: videoUrls = ($lesson?.materials?.video_url || '').split(',').filter((url) => !!url.trim());
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
{onClose}
|
||||
bind:open={$uploadCourseVideoStore.isModalOpen}
|
||||
width="w-4/5 h-[566px]"
|
||||
modalHeading="Add a Video"
|
||||
>
|
||||
<VideoUploader {onClose} />
|
||||
</Modal>
|
||||
|
||||
<Tabs {tabs} {currentTab} {onChange}>
|
||||
<slot:fragment slot="content">
|
||||
<TabContent value={tabs[0].value} index={currentTab}>
|
||||
@@ -186,37 +236,48 @@
|
||||
</TabContent>
|
||||
|
||||
<TabContent value={tabs[2].value} index={currentTab}>
|
||||
{#if mode === MODES.edit}
|
||||
<TextField
|
||||
label="Youtube link"
|
||||
bind:value={$lesson.materials.video_url}
|
||||
onChange={() => ($isLessonDirty = true)}
|
||||
/>
|
||||
{:else if !!$lesson.materials.video_url && $lesson.materials.video_url.includes('youtube')}
|
||||
{#each $lesson.materials.video_url.split(',') as url}
|
||||
<div class="mb-5">
|
||||
<iframe
|
||||
width="100%"
|
||||
height="569"
|
||||
class="iframe"
|
||||
src={formatYoutubeVideo(url, errors)}
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
{#if mode === MODES.edit && videoUrls.length}
|
||||
<PrimaryButton label="Add/Edit Video" onClick={openAddVideoModal} className="mb-2" />
|
||||
{/if}
|
||||
<!-- Line 230 would run if its in edit mode or the video is truthy but then in line 235 we are mapping for an empty string -->
|
||||
{#if videoUrls.length}
|
||||
<div class="flex flex-col items-start w-full h-full">
|
||||
{#each videoUrls as url, index}
|
||||
<div class="w-full h-full flex flex-col gap-2 overflow-hidden">
|
||||
{#if url.includes('youtube')}
|
||||
<div class="mb-5">
|
||||
<div
|
||||
bind:this={player}
|
||||
class="plyr-video-trigger"
|
||||
data-plyr-provider="youtube"
|
||||
data-plyr-embed-id={getEmbedId(url)}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<video bind:this={player} class="plyr-video-trigger" playsinline controls>
|
||||
<source
|
||||
src="https://pub-bd38ff7251aa402a93762181a947f7ea.r2.dev/generate-lesson-draft.mp4"
|
||||
type="video/mp4"
|
||||
/>
|
||||
<!-- <source src="/path/to/video.webm" type="video/webm" /> -->
|
||||
<!-- Captions are optional -->
|
||||
<track kind="captions" />
|
||||
</video>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<Box>
|
||||
<div class="flex justify-between flex-col items-center w-96">
|
||||
<img src="/images/empty-video-icon.svg" alt="No Video" class="my-2.5 mx-auto" />
|
||||
<h2 class="text-xl my-1.5 font-normal">No videos yet</h2>
|
||||
<p class="text-sm text-center text-slate-500">
|
||||
Share your knowledge with the world by creating engaging videos. Add your video link
|
||||
now.
|
||||
</p>
|
||||
</div>
|
||||
<img src="/no-video.svg" alt="Video not found" />
|
||||
<h3 class="text-xl font-normal dark:text-white py-2">
|
||||
No youtube video added for this lesson yet
|
||||
</h3>
|
||||
<p class="text-sm text-center font-normal py-2">
|
||||
Share your knowledge with the world by creating engaging lessons.<br />
|
||||
Start by clicking on New Lesson button.
|
||||
</p>
|
||||
<PrimaryButton label="Add Video" className="rounded-md" onClick={openAddVideoModal} />
|
||||
</Box>
|
||||
{/if}
|
||||
</TabContent>
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import type { Writable, Updater } from 'svelte/store';
|
||||
import { createLesson, updateLesson, deleteLesson } from '$lib/utils/services/courses';
|
||||
|
||||
import type { Lesson, Course } from '$lib/utils/types';
|
||||
|
||||
export const uploadCourseVideoStore = writable({
|
||||
isModalOpen: false
|
||||
});
|
||||
|
||||
export const lessons: Writable<Lesson[]> = writable([]);
|
||||
export const lesson = writable({
|
||||
id: null,
|
||||
totalExercises: 0,
|
||||
is_complete: false,
|
||||
materials: {
|
||||
note: null,
|
||||
slide_url: null,
|
||||
video_url: null
|
||||
note: '',
|
||||
slide_url: '',
|
||||
video_url: ''
|
||||
},
|
||||
exercises: []
|
||||
});
|
||||
@@ -92,7 +95,23 @@ export async function handleUpdateLessonMaterials(lesson: any, lessonId: Lesson[
|
||||
...lesson.materials
|
||||
};
|
||||
|
||||
delete materials.profile;
|
||||
delete materials.totalExercises;
|
||||
|
||||
return await updateLesson(materials, lessonId);
|
||||
}
|
||||
|
||||
export const deleteLessonVideo = (index: any) => {
|
||||
lesson.update((currentLesson) => {
|
||||
const links = currentLesson.materials.video_url.split(',').map((link) => link.trim());
|
||||
links.splice(index, 1);
|
||||
const updatedVideoUrl = links.join(',').trim();
|
||||
return {
|
||||
...currentLesson,
|
||||
materials: {
|
||||
...currentLesson.materials,
|
||||
video_url: updatedVideoUrl
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
</RoleBasedSecurity>
|
||||
</slot:fragment>
|
||||
</PageNav> -->
|
||||
<div class="h-full mt-2 overflow-y-auto">
|
||||
<div class="h-full py-3 overflow-y-auto">
|
||||
{#each navItems as navItem}
|
||||
{#if !navItem.show || (typeof navItem.show === 'function' && navItem.show())}
|
||||
<NavExpandable
|
||||
@@ -270,7 +270,6 @@
|
||||
max-width: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<script>
|
||||
export let color = 'currentColor';
|
||||
</script>
|
||||
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M14.2588 0.5V2C15.2534 2 16.2072 2.39509 16.9104 3.09835C17.6137 3.80161 18.0088 4.75544 18.0088 5.75C18.0088 6.74456 17.6137 7.69839 16.9104 8.40165C16.2072 9.10491 15.2534 9.5 14.2588 9.5V11C15.6512 11 16.9865 10.4469 17.9711 9.46231C18.9557 8.47774 19.5088 7.14239 19.5088 5.75C19.5088 4.35761 18.9557 3.02226 17.9711 2.03769C16.9865 1.05312 15.6512 0.5 14.2588 0.5ZM14.2588 21.5H15.7588V17.75C15.7572 16.3581 15.2035 15.0237 14.2193 14.0395C13.2351 13.0553 11.9007 12.5016 10.5088 12.5H6.00879C4.6169 12.5016 3.28249 13.0553 2.29828 14.0395C1.31406 15.0237 0.760417 16.3581 0.758789 17.75V21.5H2.25879V17.75C2.25996 16.7558 2.65542 15.8027 3.35843 15.0996C4.06144 14.3966 5.01459 14.0012 6.00879 14H10.5088C11.503 14.0012 12.4561 14.3966 13.1591 15.0996C13.8622 15.8027 14.2576 16.7558 14.2588 17.75V21.5ZM20.2588 21.5H21.7588V17.75C21.7572 16.3581 21.2036 15.0236 20.2194 14.0394C19.2352 13.0552 17.9007 12.5015 16.5088 12.5V14C17.503 14.0011 18.4562 14.3966 19.1592 15.0996C19.8622 15.8026 20.2577 16.7558 20.2588 17.75V21.5ZM10.3422 2.63199C9.7255 2.21993 9.00047 2 8.25879 2C7.26423 2 6.3104 2.39509 5.60714 3.09835C4.90388 3.80161 4.50879 4.75544 4.50879 5.75C4.50879 6.49168 4.72873 7.2167 5.14078 7.83339C5.55284 8.45007 6.13851 8.93072 6.82373 9.21455C7.50895 9.49838 8.26295 9.57264 8.99038 9.42795C9.71781 9.28325 10.386 8.9261 10.9104 8.40165C11.4349 7.8772 11.792 7.20902 11.9367 6.48159C12.0814 5.75416 12.0072 5.00016 11.7233 4.31494C11.4395 3.62971 10.9589 3.04404 10.3422 2.63199ZM5.34205 1.38478C6.20541 0.807907 7.22044 0.5 8.25879 0.5C9.65118 0.5 10.9865 1.05312 11.9711 2.03769C12.9557 3.02226 13.5088 4.35761 13.5088 5.75C13.5088 6.78835 13.2009 7.80339 12.624 8.66674C12.0471 9.5301 11.2272 10.203 10.2679 10.6004C9.30857 10.9977 8.25297 11.1017 7.23457 10.8991C6.21617 10.6966 5.28071 10.1965 4.54648 9.46231C3.81226 8.72808 3.31224 7.79262 3.10967 6.77422C2.9071 5.75582 3.01106 4.70022 3.40842 3.74091C3.80578 2.7816 4.47869 1.96166 5.34205 1.38478Z"
|
||||
fill={color}
|
||||
/>
|
||||
</svg>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
export let fill = '#7A797D';
|
||||
export let color = 'currentColor';
|
||||
</script>
|
||||
|
||||
<svg
|
||||
@@ -12,6 +12,6 @@
|
||||
>
|
||||
<path
|
||||
d="M18 22.5H6C5.60232 22.4995 5.22105 22.3414 4.93984 22.0602C4.65864 21.7789 4.50046 21.3977 4.5 21V3C4.5004 2.6023 4.65856 2.221 4.93978 1.93978C5.221 1.65856 5.6023 1.5004 6 1.5H18C18.3977 1.50046 18.779 1.65864 19.0602 1.93984C19.3414 2.22105 19.4995 2.60232 19.5 3V15.4636L15.75 13.5886L12 15.4636V3H6V21H18V18H19.5V21C19.4995 21.3977 19.3413 21.7789 19.0601 22.0601C18.7789 22.3413 18.3977 22.4995 18 22.5ZM15.75 11.9114L18 13.0364V3H13.5V13.0364L15.75 11.9114Z"
|
||||
{fill}
|
||||
fill={color}
|
||||
/>
|
||||
</svg>
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<script>
|
||||
export let color = 'currentColor';
|
||||
</script>
|
||||
|
||||
<svg
|
||||
width="25"
|
||||
height="24"
|
||||
@@ -8,35 +12,35 @@
|
||||
>
|
||||
<path
|
||||
d="M16.9999 2H8.99991C8.46948 2 7.96077 2.21071 7.58569 2.58579C7.21062 2.96086 6.99991 3.46957 6.99991 4V20C6.99991 20.5304 7.21062 21.0391 7.58569 21.4142C7.96077 21.7893 8.46948 22 8.99991 22H20.9999C21.5303 22 22.039 21.7893 22.4141 21.4142C22.7892 21.0391 22.9999 20.5304 22.9999 20V8L16.9999 2Z"
|
||||
stroke="#7A797D"
|
||||
stroke={color}
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M16.9999 2V8H22.9999"
|
||||
stroke="#7A797D"
|
||||
stroke={color}
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M18.9999 13H10.9999"
|
||||
stroke="#7A797D"
|
||||
stroke={color}
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M18.9999 17H10.9999"
|
||||
stroke="#7A797D"
|
||||
stroke={color}
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12.9999 9H11.9999H10.9999"
|
||||
stroke="#7A797D"
|
||||
stroke={color}
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -1,3 +1,7 @@
|
||||
<script>
|
||||
export let color = 'currentColor';
|
||||
</script>
|
||||
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
@@ -10,6 +14,6 @@
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M3 1.5H21C21.3977 1.50046 21.7789 1.65864 22.0602 1.93984C22.3414 2.22105 22.4995 2.60232 22.5 3V21C22.4995 21.3977 22.3413 21.7789 22.0601 22.0601C21.7789 22.3413 21.3977 22.4995 21 22.5H3C2.60232 22.4995 2.22105 22.3414 1.93984 22.0602C1.65864 21.7789 1.50046 21.3977 1.5 21V3C1.5004 2.6023 1.65856 2.221 1.93978 1.93978C2.221 1.65856 2.6023 1.5004 3 1.5ZM10.5 8.25H21V3H10.5V8.25ZM9 8.25V3H3V8.25H9ZM3 9.75V21H21.0015L21.0005 9.75H3ZM8.25 19.5C7.2558 19.4988 6.30265 19.1034 5.59964 18.4004C4.89664 17.6973 4.50117 16.7442 4.5 15.75H6C6 16.195 6.13196 16.63 6.37919 17C6.62643 17.37 6.97783 17.6584 7.38896 17.8287C7.8001 17.999 8.2525 18.0436 8.68895 17.9568C9.12541 17.87 9.52632 17.6557 9.84099 17.341C10.1557 17.0263 10.37 16.6254 10.4568 16.189C10.5436 15.7525 10.499 15.3001 10.3287 14.889C10.1584 14.4778 9.87004 14.1264 9.50003 13.8792C9.13002 13.632 8.69501 13.5 8.25 13.5V12C9.24456 12 10.1984 12.3951 10.9017 13.0983C11.6049 13.8016 12 14.7554 12 15.75C12 16.7446 11.6049 17.6984 10.9017 18.4016C10.1984 19.1049 9.24456 19.5 8.25 19.5ZM15 12H16.5V19.5H15V12ZM18 15.75H19.5V19.5H18V15.75Z"
|
||||
fill="#262626"
|
||||
fill={color}
|
||||
/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,20 @@
|
||||
<script>
|
||||
export let color = 'currentColor';
|
||||
</script>
|
||||
|
||||
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3647_18153)">
|
||||
<path
|
||||
d="M24 15C24 15.5304 23.7893 16.0391 23.4142 16.4142C23.0391 16.7893 22.5304 17 22 17H10L6 21V5C6 4.46957 6.21071 3.96086 6.58579 3.58579C6.96086 3.21071 7.46957 3 8 3H22C22.5304 3 23.0391 3.21071 23.4142 3.58579C23.7893 3.96086 24 4.46957 24 5V15Z"
|
||||
stroke={color}
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_3647_18153">
|
||||
<rect width="24" height="24" fill={color} transform="translate(0.258789)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
@@ -1,11 +1,12 @@
|
||||
<script>
|
||||
import { page } from '$app/stores';
|
||||
import HelpIcon from 'carbon-icons-svelte/lib/Help.svelte';
|
||||
|
||||
import TextChip from '$lib/components/Chip/Text.svelte';
|
||||
import OrgSelector from '$lib/components/OrgSelector/OrgSelector.svelte';
|
||||
import HomeIcon from '$lib/components/Icons/HomeIcon.svelte';
|
||||
import CourseIcon from '$lib/components/Icons/CourseIcon.svelte';
|
||||
import ReviewsIcon from '$lib/components/Icons/ReviewsIcon.svelte';
|
||||
import CommunityIcon from '$lib/components/Icons/CommunityIcon.svelte';
|
||||
import ExerciseIcon from '$lib/components/Icons/ExerciseIcon.svelte';
|
||||
import Avatar from '$lib/components/Avatar/index.svelte';
|
||||
import { currentOrg } from '$lib/utils/store/org';
|
||||
@@ -23,6 +24,33 @@
|
||||
|
||||
return pagePath.includes(itemPath);
|
||||
}
|
||||
let sideLinks = [
|
||||
{
|
||||
name: 'Home',
|
||||
icon: HomeIcon,
|
||||
link: '/lms'
|
||||
},
|
||||
{
|
||||
name: 'My Learning',
|
||||
icon: CourseIcon,
|
||||
link: '/lms/mylearning'
|
||||
},
|
||||
{
|
||||
name: 'Exercise',
|
||||
icon: ExerciseIcon,
|
||||
link: '/lms/exercises'
|
||||
},
|
||||
{
|
||||
name: 'Reviews',
|
||||
icon: ReviewsIcon,
|
||||
link: '/lms/reviews'
|
||||
},
|
||||
{
|
||||
name: 'Community',
|
||||
icon: CommunityIcon,
|
||||
link: '/lms/community'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<aside class="root bg-gray-100 dark:bg-gray-700 h-full">
|
||||
@@ -43,39 +71,22 @@
|
||||
<OrgSelector />
|
||||
|
||||
<ul class="my-5">
|
||||
<a href="/lms" class="text-black">
|
||||
<li
|
||||
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-800 {isActive(
|
||||
$page.url.pathname,
|
||||
`/lms`
|
||||
) && activeClass}"
|
||||
>
|
||||
<HomeIcon />
|
||||
<p class="dark:text-white ml-2">Home</p>
|
||||
</li>
|
||||
</a>
|
||||
<a href="/lms/mylearning" class="text-black">
|
||||
<li
|
||||
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-800 {isActive(
|
||||
$page.url.pathname,
|
||||
`/lms/mylearning`
|
||||
) && activeClass}"
|
||||
>
|
||||
<CourseIcon />
|
||||
<p class="dark:text-white ml-2">My Learning</p>
|
||||
</li>
|
||||
</a>
|
||||
<a href="/lms/exercises" class="text-black">
|
||||
<li
|
||||
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-800 {isActive(
|
||||
$page.url.pathname,
|
||||
`/lms/exercises`
|
||||
) && activeClass}"
|
||||
>
|
||||
<ExerciseIcon />
|
||||
<p class="dark:text-white ml-2">Exercises</p>
|
||||
</li>
|
||||
</a>
|
||||
{#each sideLinks as item (item.name)}
|
||||
<a href={item.link} class="text-black">
|
||||
<li
|
||||
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-500 {isActive(
|
||||
$page.url.pathname,
|
||||
`${item.link}`
|
||||
) && activeClass}"
|
||||
>
|
||||
<svelte:component
|
||||
this={item.icon}
|
||||
color={isActive($page.url.pathname, `${item.link}`) ? 'black' : 'gray'}
|
||||
/>
|
||||
<p class="dark:text-white ml-2">{item.name}</p>
|
||||
</li>
|
||||
</a>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
<span class="flex-grow" />
|
||||
|
||||
@@ -22,29 +22,33 @@
|
||||
</script>
|
||||
|
||||
{#if open}
|
||||
<button
|
||||
<div
|
||||
class="dialog fixed overflow-x-hidden overflow-y-auto inset-0 flex justify-center items-center z-50 bg-gray-100 bg-opacity-50"
|
||||
on:click={onClose}
|
||||
role="presentation"
|
||||
>
|
||||
<div aria-hidden="true" class="backdrop" />
|
||||
<button
|
||||
<div
|
||||
class="{maxWidth || 'container'} {size === 'sm'
|
||||
? 'small'
|
||||
: ''} bg-white dark:bg-gray-800 mx-auto {width} shadow-lg p-5 pt-2 rounded-md"
|
||||
on:click={(e) => e.stopPropagation()}
|
||||
role="presentation"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="dark:text-white text-xl m-0">
|
||||
{modalHeading}
|
||||
</h3>
|
||||
<CloseButton onClick={onClose} contained={true} />
|
||||
<div class="rounded-full">
|
||||
<CloseButton onClick={onClose} contained={true} size="small" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body p-1 h-4/5 overflow-y-auto {containerClass}">
|
||||
<slot />
|
||||
</div>
|
||||
</button>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { setCourse, course } from '$lib/components/Course/store';
|
||||
import { lessons } from '$lib/components/Course/components/Lesson/store/lessons';
|
||||
import { fetchCourse } from '$lib/utils/services/courses';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -13,6 +14,7 @@
|
||||
let loading = false;
|
||||
|
||||
async function triggerSetCourse(_profile) {
|
||||
if (!browser) return;
|
||||
loading = true;
|
||||
const { data: _data } = await fetchCourse(undefined, data.slug);
|
||||
setCourse(_data);
|
||||
|
||||
@@ -14,12 +14,13 @@
|
||||
// import TabContent from 'carbon-components-svelte/src/Tabs/TabContent.svelte';
|
||||
import StudentCertificate from '$lib/components/Course/components/Ceritficate/StudentCertificate/Index.svelte';
|
||||
import { fetchCourse } from '$lib/utils/services/courses';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export let courseId: string = '';
|
||||
let isStudent = false;
|
||||
|
||||
onMount(async () => {
|
||||
if ($course.id) return;
|
||||
if ($course.id || !browser) return;
|
||||
const { data } = await fetchCourse(courseId);
|
||||
setCourse(data);
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { setCourse, course } from '$lib/components/Course/store';
|
||||
import { lessons } from '$lib/components/Course/components/Lesson/store/lessons';
|
||||
import { fetchCourse } from '$lib/utils/services/courses';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export let data;
|
||||
const { courseId } = data;
|
||||
@@ -14,7 +15,7 @@
|
||||
let courseData = {};
|
||||
|
||||
async function triggerSetCourse(_profile) {
|
||||
if ($course.id) return;
|
||||
if ($course.id || !browser) return;
|
||||
const { data: _data } = await fetchCourse(courseId);
|
||||
setCourse(_data);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
import MODES from '$lib/utils/constants/mode.js';
|
||||
import { setCourse, course } from '$lib/components/Course/store';
|
||||
import { lesson, handleSaveLesson } from '$lib/components/Course/components/Lesson/store/lessons';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -62,9 +63,14 @@
|
||||
}));
|
||||
}
|
||||
|
||||
function toggleMode() {
|
||||
prevMode = mode;
|
||||
mode = mode === MODES.edit ? MODES.view : MODES.edit;
|
||||
}
|
||||
|
||||
$: path = $page.url.pathname.replace(/\/exercises[\/ 0-9 a-z -]*/, '');
|
||||
|
||||
$: if (data.courseId) {
|
||||
$: if (data.courseId && browser) {
|
||||
mode = MODES.view;
|
||||
fetchReqData(data.lessonId);
|
||||
}
|
||||
@@ -94,10 +100,7 @@
|
||||
className="mr-2"
|
||||
label={mode === MODES.edit ? 'Save' : 'Edit'}
|
||||
variant={VARIANTS.CONTAINED_INFO}
|
||||
onClick={() => {
|
||||
prevMode = mode;
|
||||
mode = mode === MODES.edit ? MODES.view : MODES.edit;
|
||||
}}
|
||||
onClick={toggleMode}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -109,7 +112,7 @@
|
||||
<Exercises lessonId={data.lessonId} exerciseId={data.exerciseId} path={`${path}/exercises`} />
|
||||
{:else if !!data.lessonId}
|
||||
<PageBody>
|
||||
<Materials lessonId={data.lessonId} {mode} {prevMode} />
|
||||
<Materials lessonId={data.lessonId} {mode} {prevMode} {toggleMode} />
|
||||
|
||||
<div class="w-full flex flex-row-reverse">
|
||||
<PrimaryButton
|
||||
|
||||
@@ -1 +1,15 @@
|
||||
<h1>Your Journey into progress begins today. Welcome !!!</h1>
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<section class="m-5 w-[calc(100vw - 250px)] h-full gap-5">
|
||||
<h1 class="text-3xl font-semibold">Dashboard</h1>
|
||||
|
||||
<main class="w-full h-full flex flex-row gap-3">
|
||||
<div class="w-full h-full border-2 border-dashed flex items-center justify-center">
|
||||
<p>Student section</p>
|
||||
</div>
|
||||
<div class="w-full h-full border-2 border-dashed flex items-center justify-center">
|
||||
<p>Currently Learning</p>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
community page
|
||||
@@ -0,0 +1 @@
|
||||
reviews page
|
||||
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M23 4H1C0.734784 4 0.48043 4.10536 0.292893 4.29289C0.105357 4.48043 0 4.73478 0 5C0 5.26522 0.105357 5.51957 0.292893 5.70711C0.48043 5.89464 0.734784 6 1 6H2V24C2 24.5304 2.21071 25.0391 2.58579 25.4142C2.96086 25.7893 3.46957 26 4 26H20C20.5304 26 21.0391 25.7893 21.4142 25.4142C21.7893 25.0391 22 24.5304 22 24V6H23C23.2652 6 23.5196 5.89464 23.7071 5.70711C23.8946 5.51957 24 5.26522 24 5C24 4.73478 23.8946 4.48043 23.7071 4.29289C23.5196 4.10536 23.2652 4 23 4ZM20 24H4V6H20V24ZM6 1C6 0.734784 6.10536 0.48043 6.29289 0.292893C6.48043 0.105357 6.73478 0 7 0H17C17.2652 0 17.5196 0.105357 17.7071 0.292893C17.8946 0.48043 18 0.734784 18 1C18 1.26522 17.8946 1.51957 17.7071 1.70711C17.5196 1.89464 17.2652 2 17 2H7C6.73478 2 6.48043 1.89464 6.29289 1.70711C6.10536 1.51957 6 1.26522 6 1Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 923 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="83" height="83" viewBox="0 0 83 83" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.2" d="M36.3125 56.9555L46.6875 51.875V70.0312L36.3125 64.5779V67.4375C36.3125 68.1254 36.0392 68.7851 35.5528 69.2716C35.0664 69.758 34.4067 70.0312 33.7188 70.0312H15.5625C14.8746 70.0312 14.2149 69.758 13.7284 69.2716C13.242 68.7851 12.9688 68.1254 12.9688 67.4375V54.4688C12.9688 53.7808 13.242 53.1211 13.7284 52.6347C14.2149 52.1483 14.8746 51.875 15.5625 51.875H33.7188C34.4067 51.875 35.0664 52.1483 35.5528 52.6347C36.0392 53.1211 36.3125 53.7808 36.3125 54.4688V56.9555ZM49.2812 10.375V28.5312H67.4375L49.2812 10.375Z" fill="#0233BD"/>
|
||||
<path d="M48.0589 49.6736C47.6853 49.441 47.2585 49.3074 46.819 49.2853C46.3794 49.2632 45.9414 49.3533 45.5462 49.5471L38.6663 52.9157C38.3358 51.8623 37.6777 50.9417 36.7879 50.2881C35.8981 49.6344 34.8229 49.2817 33.7188 49.2812H15.5625C14.1867 49.2812 12.8672 49.8278 11.8944 50.8006C10.9215 51.7735 10.375 53.0929 10.375 54.4688V67.4375C10.375 68.8133 10.9215 70.1328 11.8944 71.1056C12.8672 72.0785 14.1867 72.625 15.5625 72.625H33.7188C34.8603 72.6237 35.9696 72.2459 36.8747 71.5501C37.7798 70.8543 38.43 69.8794 38.7247 68.7765L45.4814 72.3429C45.8779 72.5512 46.3215 72.6532 46.7691 72.6392C47.2167 72.6251 47.653 72.4953 48.0356 72.2626C48.4182 72.0298 48.734 71.702 48.9523 71.311C49.1706 70.9199 49.2839 70.4791 49.2812 70.0312V51.875C49.2812 51.4345 49.169 51.0012 48.9552 50.616C48.7413 50.2308 48.4329 49.9065 48.0589 49.6736ZM33.7188 67.4375H15.5625V54.4688H33.7188V64.5195C33.7188 64.5617 33.7188 64.6006 33.7188 64.6427V67.4375ZM44.0938 65.7386L38.9062 63.0087V58.5734L44.0938 56.0347V65.7386ZM69.2726 26.6962L51.1163 8.53992C50.8753 8.29913 50.5891 8.1082 50.2743 7.97802C49.9594 7.84785 49.622 7.78098 49.2812 7.78125H18.1562C16.7804 7.78125 15.461 8.32779 14.4881 9.30063C13.5153 10.2735 12.9688 11.5929 12.9688 12.9688V41.5C12.9688 42.1879 13.242 42.8476 13.7284 43.3341C14.2149 43.8205 14.8746 44.0938 15.5625 44.0938C16.2504 44.0938 16.9101 43.8205 17.3966 43.3341C17.883 42.8476 18.1562 42.1879 18.1562 41.5V12.9688H46.6875V28.5312C46.6875 29.2192 46.9608 29.8789 47.4472 30.3653C47.9336 30.8517 48.5933 31.125 49.2812 31.125H64.8438V70.0312H57.0625C56.3746 70.0312 55.7149 70.3045 55.2284 70.7909C54.742 71.2774 54.4688 71.9371 54.4688 72.625C54.4688 73.3129 54.742 73.9726 55.2284 74.4591C55.7149 74.9455 56.3746 75.2188 57.0625 75.2188H64.8438C66.2196 75.2188 67.539 74.6722 68.5119 73.6994C69.4847 72.7265 70.0312 71.4071 70.0312 70.0312V28.5312C70.0315 28.1905 69.9647 27.8531 69.8345 27.5382C69.7043 27.2234 69.5134 26.9372 69.2726 26.6962ZM51.875 16.6357L61.1768 25.9375H51.875V16.6357Z" fill="#0233BD"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.2" d="M65 27.5H47.5V10L65 27.5Z" fill="#0233BD"/>
|
||||
<path d="M66.7688 25.7313L49.2688 8.23125C49.0364 7.99916 48.7606 7.81513 48.4571 7.68966C48.1536 7.56419 47.8284 7.49974 47.5 7.5H17.5C16.1739 7.5 14.9021 8.02678 13.9645 8.96447C13.0268 9.90215 12.5 11.1739 12.5 12.5V67.5C12.5 68.8261 13.0268 70.0979 13.9645 71.0355C14.9021 71.9732 16.1739 72.5 17.5 72.5H62.5C63.8261 72.5 65.0979 71.9732 66.0355 71.0355C66.9732 70.0979 67.5 68.8261 67.5 67.5V27.5C67.5003 27.1716 67.4358 26.8464 67.3103 26.5429C67.1849 26.2394 67.0008 25.9636 66.7688 25.7313ZM50 16.0344L58.9656 25H50V16.0344ZM62.5 67.5H17.5V12.5H45V27.5C45 28.163 45.2634 28.7989 45.7322 29.2678C46.2011 29.7366 46.837 30 47.5 30H62.5V67.5ZM49.2688 43.2312C49.501 43.4635 49.6853 43.7393 49.811 44.0428C49.9367 44.3462 50.0014 44.6715 50.0014 45C50.0014 45.3285 49.9367 45.6538 49.811 45.9572C49.6853 46.2607 49.501 46.5365 49.2688 46.7688C49.0365 47.001 48.7607 47.1853 48.4572 47.311C48.1538 47.4367 47.8285 47.5014 47.5 47.5014C47.1715 47.5014 46.8462 47.4367 46.5428 47.311C46.2393 47.1853 45.9635 47.001 45.7312 46.7688L42.5 43.5344V57.5C42.5 58.163 42.2366 58.7989 41.7678 59.2678C41.2989 59.7366 40.663 60 40 60C39.337 60 38.7011 59.7366 38.2322 59.2678C37.7634 58.7989 37.5 58.163 37.5 57.5V43.5344L34.2688 46.7688C34.0365 47.001 33.7607 47.1853 33.4572 47.311C33.1538 47.4367 32.8285 47.5014 32.5 47.5014C32.1715 47.5014 31.8462 47.4367 31.5428 47.311C31.2393 47.1853 30.9635 47.001 30.7312 46.7688C30.499 46.5365 30.3147 46.2607 30.189 45.9572C30.0633 45.6538 29.9986 45.3285 29.9986 45C29.9986 44.6715 30.0633 44.3462 30.189 44.0428C30.3147 43.7393 30.499 43.4635 30.7312 43.2312L38.2312 35.7312C38.4634 35.4988 38.7392 35.3144 39.0426 35.1886C39.3461 35.0628 39.6715 34.998 40 34.998C40.3285 34.998 40.6539 35.0628 40.9574 35.1886C41.2608 35.3144 41.5366 35.4988 41.7688 35.7312L49.2688 43.2312Z" fill="#0233BD"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,6 @@
|
||||
<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.2" d="M65 27.5H47.5V10L65 27.5Z" fill="#CF2D48"/>
|
||||
<path d="M66.7688 25.7313L49.2688 8.23125C49.0364 7.99916 48.7606 7.81513 48.4571 7.68966C48.1536 7.56419 47.8284 7.49974 47.5 7.5H17.5C16.1739 7.5 14.9021 8.02678 13.9645 8.96447C13.0268 9.90215 12.5 11.1739 12.5 12.5V67.5C12.5 68.8261 13.0268 70.0979 13.9645 71.0355C14.9021 71.9732 16.1739 72.5 17.5 72.5H62.5C63.8261 72.5 65.0979 71.9732 66.0355 71.0355C66.9732 70.0979 67.5 68.8261 67.5 67.5V27.5C67.5003 27.1716 67.4358 26.8464 67.3103 26.5429C67.1849 26.2394 67.0008 25.9636 66.7688 25.7313ZM50 16.0344L58.9656 25H50V16.0344ZM62.5 67.5H17.5V12.5H45V27.5C45 28.163 45.2634 28.7989 45.7322 29.2678C46.2011 29.7366 46.837 30 47.5 30H62.5V67.5ZM49.2688 43.2312C49.501 43.4635 49.6853 43.7393 49.811 44.0428C49.9367 44.3462 50.0014 44.6715 50.0014 45C50.0014 45.3285 49.9367 45.6538 49.811 45.9572C49.6853 46.2607 49.501 46.5365 49.2688 46.7688C49.0365 47.001 48.7607 47.1853 48.4572 47.311C48.1538 47.4367 47.8285 47.5014 47.5 47.5014C47.1715 47.5014 46.8462 47.4367 46.5428 47.311C46.2393 47.1853 45.9635 47.001 45.7312 46.7688L42.5 43.5344V57.5C42.5 58.163 42.2366 58.7989 41.7678 59.2678C41.2989 59.7366 40.663 60 40 60C39.337 60 38.7011 59.7366 38.2322 59.2678C37.7634 58.7989 37.5 58.163 37.5 57.5V43.5344L34.2688 46.7688C34.0365 47.001 33.7607 47.1853 33.4572 47.311C33.1538 47.4367 32.8285 47.5014 32.5 47.5014C32.1715 47.5014 31.8462 47.4367 31.5428 47.311C31.2393 47.1853 30.9635 47.001 30.7312 46.7688C30.499 46.5365 30.3147 46.2607 30.189 45.9572C30.0633 45.6538 29.9986 45.3285 29.9986 45C29.9986 44.6715 30.0633 44.3462 30.189 44.0428C30.3147 43.7393 30.499 43.4635 30.7312 43.2312L38.2312 35.7312C38.4634 35.4988 38.7392 35.3144 39.0426 35.1886C39.3461 35.0628 39.6715 34.998 40 34.998C40.3285 34.998 40.6539 35.0628 40.9574 35.1886C41.2608 35.3144 41.5366 35.4988 41.7688 35.7312L49.2688 43.2312Z" fill="#ADADAD"/>
|
||||
<circle cx="56" cy="21" r="17" fill="#EB4132"/>
|
||||
<path d="M64 14.4875L62.5125 13L55.5 20.0125L48.4875 13L47 14.4875L54.0125 21.5L47 28.5125L48.4875 30L55.5 22.9875L62.5125 30L64 28.5125L56.9875 21.5L64 14.4875Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |