feat: support embed of generic links
This commit is contained in:
+80
@@ -0,0 +1,80 @@
|
||||
<script>
|
||||
import { CopyButton, Tag } from 'carbon-components-svelte';
|
||||
import TrashCanIcon from 'carbon-icons-svelte/lib/TrashCan.svelte';
|
||||
import IconButton from '$lib/components/IconButton/index.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';
|
||||
|
||||
let genericLinks = '';
|
||||
let error = '';
|
||||
|
||||
function getVideoUrls(urls = '') {
|
||||
return (urls || '').split(',').filter((url) => !!url.trim());
|
||||
}
|
||||
|
||||
function addVideo() {
|
||||
const links = getVideoUrls(genericLinks);
|
||||
const validLinks = links.filter(isValidLink);
|
||||
|
||||
if (validLinks.length === 0) {
|
||||
error = 'Invalid link(s)';
|
||||
} else {
|
||||
const existingLinks = $lesson?.materials?.videos || [];
|
||||
|
||||
$lesson.materials.videos = [
|
||||
...existingLinks,
|
||||
...validLinks.map((link = '') => ({
|
||||
type: 'generic',
|
||||
link,
|
||||
metadata: {}
|
||||
}))
|
||||
];
|
||||
genericLinks = '';
|
||||
error = '';
|
||||
}
|
||||
}
|
||||
|
||||
function isValidLink(link = '') {
|
||||
const linkRegex = /^(https?:\/\/)?(www\.)?([a-zA-Z]+\.com\/)([a-zA-Z0-9_-]+)/;
|
||||
|
||||
return linkRegex.test(link.trim());
|
||||
}
|
||||
|
||||
function removeVideo(index = 0) {
|
||||
$lesson.materials.videos = $lesson.materials.videos.filter((v, i) => i !== index);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="w-full flex items-{error ? 'center' : 'end'} justify-between gap-5">
|
||||
<TextField
|
||||
label="Embed link"
|
||||
bind:value={genericLinks}
|
||||
className="flex-1 text-left "
|
||||
inputClassName="text-sm"
|
||||
onChange={() => ($isLessonDirty = true)}
|
||||
placeholder="https://www.videoplayer.com/"
|
||||
errorMessage={error}
|
||||
/>
|
||||
<PrimaryButton label="Add Video" className="rounded-md" onClick={addVideo} />
|
||||
</div>
|
||||
<p class="mt-4 pl-2 text-sm">
|
||||
Videos added: <strong>
|
||||
{$lesson?.materials?.videos.filter((v) => v.type === 'generic').length || 0}
|
||||
</strong>
|
||||
</p>
|
||||
<div class="">
|
||||
{#each $lesson?.materials?.videos as video, index}
|
||||
{#if video.type === 'generic'}
|
||||
<div class="flex items-center gap-1">
|
||||
<Tag type="blue">
|
||||
{video.link}
|
||||
</Tag>
|
||||
<CopyButton text={video.link} feedback="Copied to clipboard" />
|
||||
<IconButton value="delete-video" onClick={() => removeVideo(index)}>
|
||||
<TrashCanIcon size={16} class="carbon-icon dark:text-white" />
|
||||
</IconButton>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
+3
@@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import YoutubeVideo from './YoutubeVideo.svelte';
|
||||
import LocalVideo from './LocalVideo.svelte';
|
||||
import EmbedLink from './EmbedLink.svelte';
|
||||
import * as CONSTANTS from './constants';
|
||||
|
||||
export let lessonId = '';
|
||||
@@ -37,6 +38,8 @@
|
||||
<main class="w-full h-full">
|
||||
{#if currentTab === 1}
|
||||
<YoutubeVideo />
|
||||
{:else if currentTab === 2}
|
||||
<EmbedLink />
|
||||
{:else}
|
||||
<LocalVideo {lessonId} />
|
||||
{/if}
|
||||
|
||||
+8
-1
@@ -1,5 +1,7 @@
|
||||
import Link from 'carbon-icons-svelte/lib/Link.svelte';
|
||||
import Video from 'carbon-icons-svelte/lib/Video.svelte';
|
||||
import DirectLink from 'carbon-icons-svelte/lib/DirectLink.svelte';
|
||||
|
||||
export const videoTabs = [
|
||||
{
|
||||
value: 1,
|
||||
@@ -8,7 +10,12 @@ export const videoTabs = [
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
title: 'Video',
|
||||
title: 'Embed Link',
|
||||
icon: DirectLink
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
title: 'Upload',
|
||||
icon: Video
|
||||
}
|
||||
];
|
||||
|
||||
+11
@@ -35,6 +35,17 @@
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
/>
|
||||
{:else if video.type === 'generic'}
|
||||
<iframe
|
||||
width="100%"
|
||||
height="569"
|
||||
class="iframe"
|
||||
src={video.link}
|
||||
title="Embeded Video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
/>
|
||||
{:else if video.metadata?.svid}
|
||||
<div style="position:relative;padding-bottom:51.416579%">
|
||||
<iframe
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
export let prevMode = '';
|
||||
export let lessonId = '';
|
||||
export let isSaving = false;
|
||||
export let isStudent = false;
|
||||
export let toggleMode = () => {};
|
||||
|
||||
let lessonTitle = '';
|
||||
@@ -343,6 +344,17 @@
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
/>
|
||||
{:else if video.type === 'generic'}
|
||||
<iframe
|
||||
width="100%"
|
||||
height="569"
|
||||
class="iframe"
|
||||
src={video.link}
|
||||
title="Embeded Video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
/>
|
||||
{:else if video.metadata?.svid}
|
||||
<div style="position:relative;padding-bottom:51.416579%">
|
||||
<iframe
|
||||
@@ -381,10 +393,12 @@
|
||||
<h3 class="text-xl font-normal dark:text-white py-2">
|
||||
No note, video or slide added for this lesson yet
|
||||
</h3>
|
||||
<p class="text-sm text-center font-normal py-2">
|
||||
Share your knowledge with your students by creating engaging content<br />
|
||||
Start by clicking on <strong>Get started</strong> button.
|
||||
</p>
|
||||
<PrimaryButton label="Get started" className="rounded-md" onClick={toggleMode} />
|
||||
{#if !isStudent}
|
||||
<p class="text-sm text-center font-normal py-2">
|
||||
Share your knowledge with your students by creating engaging content<br />
|
||||
Start by clicking on <strong>Get started</strong> button.
|
||||
</p>
|
||||
<PrimaryButton label="Get started" className="rounded-md" onClick={toggleMode} />
|
||||
{/if}
|
||||
</Box>
|
||||
{/if}
|
||||
|
||||
@@ -298,7 +298,16 @@
|
||||
width="lg:w-full xl:w-11/12"
|
||||
className="overflow-x-hidden"
|
||||
>
|
||||
<Materials lessonId={data.lessonId} {mode} {prevMode} {toggleMode} bind:isSaving />
|
||||
<!-- Shows Lesson Note / Slides / Video -->
|
||||
<Materials
|
||||
lessonId={data.lessonId}
|
||||
{mode}
|
||||
{prevMode}
|
||||
{toggleMode}
|
||||
bind:isSaving
|
||||
{isStudent}
|
||||
/>
|
||||
|
||||
{#if isStudent}
|
||||
<div class="w-full hidden lg:flex flex-row-reverse mt-10">
|
||||
<PrimaryButton
|
||||
|
||||
Reference in New Issue
Block a user