Sync lesson/id w/ server + edit & view mode
This commit is contained in:
@@ -5,21 +5,11 @@
|
||||
import TextField from '../../../../Form/TextField.svelte';
|
||||
import Exercise from '../Exercise/index.svelte';
|
||||
|
||||
import { lesson } from '../store/lessons';
|
||||
|
||||
export let path;
|
||||
export let exerciseId;
|
||||
|
||||
let exercises = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Practice Exercise',
|
||||
link: `${path}/1`,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Home task',
|
||||
link: `${path}/2`,
|
||||
},
|
||||
];
|
||||
let open = false;
|
||||
let newExercise = {
|
||||
id: 1,
|
||||
@@ -28,13 +18,16 @@
|
||||
};
|
||||
|
||||
function handleAddExercise() {
|
||||
exercises = [
|
||||
...exercises,
|
||||
{
|
||||
...newExercise,
|
||||
link: `${path}/${exercises.length + 1}`,
|
||||
},
|
||||
];
|
||||
lesson.update((_lesson) => ({
|
||||
..._lesson,
|
||||
exercises: [
|
||||
..._lesson.exercises,
|
||||
{
|
||||
...newExercise,
|
||||
link: `${path}/${_lesson.exercises.length + 1}`,
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
handleCancelAddExercise();
|
||||
}
|
||||
@@ -42,7 +35,7 @@
|
||||
function handleCancelAddExercise() {
|
||||
open = false;
|
||||
newExercise = {
|
||||
id: exercises.length + 1,
|
||||
id: $lesson.exercises.length + 1,
|
||||
title: '',
|
||||
link: '',
|
||||
};
|
||||
@@ -81,7 +74,7 @@
|
||||
</slot:fragment>
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
{#each exercises as exercise, index}
|
||||
{#each $lesson.exercises as exercise}
|
||||
<a class="w-52 bg-gray-100 px-4 py-7 mr-4 mb-4" href={exercise.link}>
|
||||
<h3 class="text-xl">{exercise.title}</h3>
|
||||
<p class="mt-4 text-sm">Created Jul 3, 2021</p>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<script>
|
||||
import { Tabs, Tab, TabContent } from 'carbon-components-svelte';
|
||||
import EditContent from '../../../../EditContent/index.svelte';
|
||||
import TextField from '../../../../Form/TextField.svelte';
|
||||
import { lesson } from '../store/lessons';
|
||||
</script>
|
||||
|
||||
<Tabs class="flex justify-center" type="container">
|
||||
<Tab label="Note" />
|
||||
<Tab label="Slide" />
|
||||
<Tab label="Video" />
|
||||
|
||||
<div slot="content">
|
||||
<TabContent>
|
||||
<EditContent
|
||||
writeLabel="Note"
|
||||
bind:value={$lesson.materials.note}
|
||||
placeholder="Start typing your lesson"
|
||||
/>
|
||||
</TabContent>
|
||||
<TabContent>
|
||||
<TextField label="Slide link" bind:value={$lesson.materials.slide} />
|
||||
</TabContent>
|
||||
<TabContent>
|
||||
<TextField label="Youtube link" bind:value={$lesson.materials.video} />
|
||||
</TabContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
@@ -0,0 +1,96 @@
|
||||
<script>
|
||||
import { Tabs, Tab, TabContent } from 'carbon-components-svelte';
|
||||
import MarkdownRender from '../../../../MarkdownRender/index.svelte';
|
||||
import { lesson } from '../store/lessons';
|
||||
</script>
|
||||
|
||||
<Tabs class="flex justify-center" type="container">
|
||||
<Tab label="Note" />
|
||||
<Tab label="Slide" />
|
||||
<Tab label="Video" />
|
||||
|
||||
<div slot="content">
|
||||
<TabContent>
|
||||
<MarkdownRender content={$lesson.materials.note} />
|
||||
</TabContent>
|
||||
<TabContent>
|
||||
<iframe
|
||||
title="Embeded Slides"
|
||||
src={$lesson.materials.slide}
|
||||
frameborder="0"
|
||||
width="100%"
|
||||
height="569"
|
||||
allowfullscreen="true"
|
||||
mozallowfullscreen="true"
|
||||
webkitallowfullscreen="true"
|
||||
/>
|
||||
</TabContent>
|
||||
<TabContent>
|
||||
<iframe
|
||||
width="100%"
|
||||
height="569"
|
||||
src={$lesson.materials.video}
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
/>
|
||||
</TabContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
|
||||
<!-- <div class="flex mb-2">
|
||||
<button
|
||||
on:click={handleTabClick(0)}
|
||||
class="focus:outline-none text-lg font-bold border-b-2 border-transparent {currentTab ===
|
||||
0 && `${activeClassName}`}"
|
||||
>
|
||||
Note
|
||||
</button>
|
||||
<button
|
||||
on:click={handleTabClick(1)}
|
||||
class="focus:outline-none text-lg font-bold border-b-2 border-transparent {currentTab ===
|
||||
1 && `${activeClassName}`}"
|
||||
>
|
||||
|
||||
</button>
|
||||
<button
|
||||
on:click={handleTabClick(2)}
|
||||
class="focus:outline-none text-lg font-bold border-b-2 border-transparent {currentTab ===
|
||||
2 && `${activeClassName}`}"
|
||||
>
|
||||
Video
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="m-2 mb-0 p-0">
|
||||
{#if currentTab === 0}
|
||||
<MarkdownRender content={$lesson.materials.note} />
|
||||
{:else if currentTab === 1}
|
||||
<iframe
|
||||
title="Embeded Slides"
|
||||
src={$lesson.materials.slide}
|
||||
frameborder="0"
|
||||
width="100%"
|
||||
height="569"
|
||||
allowfullscreen="true"
|
||||
mozallowfullscreen="true"
|
||||
webkitallowfullscreen="true"
|
||||
/>
|
||||
{:else if currentTab === 2}
|
||||
<iframe
|
||||
width="100%"
|
||||
height="569"
|
||||
src={$lesson.materials.video}
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
/>
|
||||
{/if}
|
||||
</div> -->
|
||||
<style>
|
||||
button {
|
||||
padding: 12px 12px 8px 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,16 +0,0 @@
|
||||
<script>
|
||||
// import EditContent from "../../../../EditContent/index.svelte";
|
||||
import TextField from "../../../../Form/TextField.svelte";
|
||||
// import readme from "../../readme.js";
|
||||
|
||||
// let value = readme;
|
||||
</script>
|
||||
|
||||
|
||||
<TextField label="Slide link" />
|
||||
<TextField label="Youtube link" />
|
||||
<!-- <EditContent
|
||||
writeLabel="Lecture Note"
|
||||
{value}
|
||||
placeholder="Start typing your lesson"
|
||||
/> -->
|
||||
@@ -1,62 +0,0 @@
|
||||
<!--
|
||||
import marked from "marked";
|
||||
{@html marked(readme, { breaks: true, gfm: true })}
|
||||
-->
|
||||
<script>
|
||||
const activeClassName = "border-blue-700";
|
||||
let slideLink = 'https://docs.google.com/presentation/d/e/2PACX-1vS7mulzY5v1X_D0Gz68M2sggq2zjHCuoyY5JI07hcsOA4svDV5rxhLD9V3ckO_Rz7TK1YniQJtu0CXM/embed?start=false&loop=false&delayms=3000';
|
||||
let currentTab = 1;
|
||||
|
||||
function handleTabClick(tab) {
|
||||
return () => {
|
||||
currentTab = tab;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex mb-2">
|
||||
<button
|
||||
on:click={handleTabClick(1)}
|
||||
class="focus:outline-none text-lg font-bold border-b-2 border-transparent {currentTab === 1 && `${activeClassName}`}"
|
||||
>
|
||||
Slide
|
||||
</button>
|
||||
<button
|
||||
on:click={handleTabClick(2)}
|
||||
class="focus:outline-none text-lg font-bold border-b-2 border-transparent {currentTab === 2 && `${activeClassName}`}"
|
||||
>
|
||||
Video
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="m-2 mb-0 p-0">
|
||||
{#if currentTab === 1}
|
||||
<iframe
|
||||
title="Embeded Slides"
|
||||
src={slideLink}
|
||||
frameborder="0"
|
||||
width="100%"
|
||||
height="569"
|
||||
allowfullscreen="true"
|
||||
mozallowfullscreen="true"
|
||||
webkitallowfullscreen="true"
|
||||
>
|
||||
</iframe>
|
||||
{:else if currentTab === 2}
|
||||
<iframe
|
||||
width="100%"
|
||||
height="569"
|
||||
src="https://www.youtube.com/embed/luM5uobewhA"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen>
|
||||
</iframe>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
button {
|
||||
padding: 12px 12px 8px 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,40 +0,0 @@
|
||||
<script>
|
||||
import PageNav from '../../../PageNav/index.svelte';
|
||||
import Exercises from './Exercises/index.svelte';
|
||||
import Readme from './Readme/index.svelte';
|
||||
|
||||
export let path;
|
||||
export let tab;
|
||||
export let exerciseId;
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<PageNav
|
||||
navItems={[
|
||||
{
|
||||
label: 'README.md',
|
||||
isActive: tab === 'lessons',
|
||||
href: `${path}?tab=lessons`,
|
||||
},
|
||||
{
|
||||
label: 'Exercises',
|
||||
isActive: tab === 'exercises',
|
||||
href: `${path}?tab=exercises`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<div class="course relative">
|
||||
{#if tab === 'lessons'}
|
||||
<Readme />
|
||||
{:else if tab === 'exercises'}
|
||||
<Exercises {exerciseId} path={`${path}?tab=exercises`} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.course {
|
||||
padding: 0 40px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,42 +1,51 @@
|
||||
import { writable } from "svelte/store";
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const lessons = writable([]);
|
||||
export const lesson = writable({
|
||||
lesson_id: null,
|
||||
materials: {
|
||||
note: '',
|
||||
slide: '',
|
||||
video: '',
|
||||
},
|
||||
exercises: [],
|
||||
});
|
||||
|
||||
export const tutors = writable([
|
||||
{
|
||||
id: 1,
|
||||
text: "Sergey Semko",
|
||||
text: 'Sergey Semko',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
text: "Jonathan Nelson",
|
||||
text: 'Jonathan Nelson',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
text: "Sasha Pokidin",
|
||||
text: 'Sasha Pokidin',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
text: "Natasha Rudenko",
|
||||
text: 'Natasha Rudenko',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
text: "Yulia Marushko",
|
||||
text: 'Yulia Marushko',
|
||||
},
|
||||
]);
|
||||
|
||||
export function handleAddLesson() {
|
||||
const resources = [
|
||||
{
|
||||
label: "lesson",
|
||||
label: 'lesson',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: "quiz",
|
||||
label: 'quiz',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: "home task",
|
||||
label: 'home task',
|
||||
value: 0,
|
||||
},
|
||||
];
|
||||
@@ -45,13 +54,13 @@ export function handleAddLesson() {
|
||||
return [
|
||||
..._lessons,
|
||||
{
|
||||
title: "Untitled lesson",
|
||||
to: "/courses/1/lessons/" + (_lessons.length + 1),
|
||||
title: 'Untitled lesson',
|
||||
to: '/courses/1/lessons/' + (_lessons.length + 1),
|
||||
resources,
|
||||
tutor: {
|
||||
userId: 1,
|
||||
avatar: "https://picsum.photos/32/32/?random",
|
||||
name: "",
|
||||
avatar: 'https://picsum.photos/32/32/?random',
|
||||
name: '',
|
||||
},
|
||||
date: new Date(),
|
||||
},
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import CheckmarkFilled20 from "carbon-icons-svelte/lib/CheckmarkFilled20";
|
||||
import hotkeys from "hotkeys-js";
|
||||
import ChevronLeft32 from "carbon-icons-svelte/lib/ChevronLeft32";
|
||||
import ChevronRight32 from "carbon-icons-svelte/lib/ChevronRight32";
|
||||
import { stores, goto } from "@sapper/app";
|
||||
import Expandable from "../../../Expandable/index.svelte";
|
||||
import PageNav from "../../../PageNav/index.svelte";
|
||||
import IconButton from "../../../IconButton/index.svelte";
|
||||
import { onMount } from 'svelte';
|
||||
import CheckmarkFilled20 from 'carbon-icons-svelte/lib/CheckmarkFilled20';
|
||||
import hotkeys from 'hotkeys-js';
|
||||
import ChevronLeft32 from 'carbon-icons-svelte/lib/ChevronLeft32';
|
||||
import ChevronRight32 from 'carbon-icons-svelte/lib/ChevronRight32';
|
||||
import { stores, goto } from '@sapper/app';
|
||||
import Expandable from '../../../Expandable/index.svelte';
|
||||
import PageNav from '../../../PageNav/index.svelte';
|
||||
import IconButton from '../../../IconButton/index.svelte';
|
||||
import {
|
||||
getNavItemRoute,
|
||||
getLessonsRoute,
|
||||
getLectureNo,
|
||||
} from "../../function";
|
||||
} from '../../function';
|
||||
|
||||
import { lessons } from "../Lesson/store/lessons";
|
||||
import { lessons } from '../Lesson/store/lessons';
|
||||
|
||||
// export let lessonId;
|
||||
export let courseId;
|
||||
@@ -32,43 +32,48 @@
|
||||
|
||||
const navItems = [
|
||||
{
|
||||
label: "Overview",
|
||||
label: 'Overview',
|
||||
to: getNavItemRoute(courseId),
|
||||
hideSortIcon: true,
|
||||
},
|
||||
{
|
||||
label: "Lessons",
|
||||
label: 'Lessons',
|
||||
to: getLessonsRoute(courseId),
|
||||
hideSortIcon: false,
|
||||
isLecture: true,
|
||||
},
|
||||
{
|
||||
label: "All Exercises",
|
||||
to: getNavItemRoute(courseId, "allexercises"),
|
||||
label: 'All Exercises',
|
||||
to: getNavItemRoute(courseId, 'allexercises'),
|
||||
hideSortIcon: true,
|
||||
},
|
||||
{
|
||||
label: "Scoreboard",
|
||||
to: getNavItemRoute(courseId, "scoreboard"),
|
||||
label: 'Scoreboard',
|
||||
to: getNavItemRoute(courseId, 'scoreboard'),
|
||||
hideSortIcon: true,
|
||||
},
|
||||
{
|
||||
label: "People",
|
||||
to: getNavItemRoute(courseId, "people"),
|
||||
label: 'People',
|
||||
to: getNavItemRoute(courseId, 'people'),
|
||||
hideSortIcon: true,
|
||||
},
|
||||
{
|
||||
label: "Timetable",
|
||||
to: getNavItemRoute(courseId, "timetable"),
|
||||
label: 'Timetable',
|
||||
to: getNavItemRoute(courseId, 'timetable'),
|
||||
hideSortIcon: true,
|
||||
},
|
||||
];
|
||||
|
||||
function getHref(item) {
|
||||
return item.to;
|
||||
// return item.isComplete ? item.to : path || $page.path
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
hotkeys("b", function (event, handler) {
|
||||
hotkeys('b', function (event, handler) {
|
||||
event.preventDefault();
|
||||
switch (handler.key) {
|
||||
case "b":
|
||||
case 'b':
|
||||
show = !show;
|
||||
break;
|
||||
}
|
||||
@@ -95,7 +100,7 @@
|
||||
!(path || $page.path).length > 3) &&
|
||||
'active'} pl-7 py-2 {!item.isComplete &&
|
||||
'cursor-not-allowed'}"
|
||||
href={item.isComplete ? item.to : path || $page.path}
|
||||
href={getHref(item)}
|
||||
>
|
||||
<span class="course-counter"> {getLectureNo(index + 1)} </span>
|
||||
<span>{item.title}</span>
|
||||
@@ -118,9 +123,9 @@
|
||||
value="toggle"
|
||||
onClick={() => (show = !show)}
|
||||
toolTipProps={{
|
||||
title: "Toggle sidebar",
|
||||
hotkeys: ["B"],
|
||||
direction: "right",
|
||||
title: 'Toggle sidebar',
|
||||
hotkeys: ['B'],
|
||||
direction: 'right',
|
||||
}}
|
||||
>
|
||||
{#if show}
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { onMount, afterUpdate } from 'svelte';
|
||||
|
||||
import Navigation from "../Course/components/Navigation/index.svelte";
|
||||
import { lessons } from "../Course/components/Lesson/store/lessons";
|
||||
import Navigation from '../Course/components/Navigation/index.svelte';
|
||||
import { lessons, lesson } from '../Course/components/Lesson/store/lessons';
|
||||
|
||||
export let courseData = {};
|
||||
export let path;
|
||||
|
||||
onMount(() => {
|
||||
if (!$lessons.length) {
|
||||
lessons.set(courseData.lessons);
|
||||
lessons.set(courseData.lessons);
|
||||
if (courseData.lesson) {
|
||||
lesson.set(courseData.lesson);
|
||||
}
|
||||
});
|
||||
|
||||
afterUpdate(() => {
|
||||
lessons.set(courseData.lessons);
|
||||
|
||||
if (courseData.lesson) {
|
||||
lesson.set(courseData.lesson);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import marked from 'marked';
|
||||
|
||||
export let content;
|
||||
</script>
|
||||
|
||||
<article class="prose prose-sm sm:prose p-2">
|
||||
{@html marked(content, { breaks: true, gfm: true })}
|
||||
</article>
|
||||
Reference in New Issue
Block a user