CRUD* Lecture

This commit is contained in:
Ibitoye Rotimi Best
2021-07-08 09:44:16 +03:00
parent 44d612488b
commit 7941b0b51f
13 changed files with 391 additions and 66 deletions
@@ -1,5 +1,6 @@
<script> <script>
import { onMount } from "svelte"; import { onMount } from "svelte";
import CheckmarkFilled20 from "carbon-icons-svelte/lib/CheckmarkFilled20";
import hotkeys from "hotkeys-js"; import hotkeys from "hotkeys-js";
import ChevronLeft32 from "carbon-icons-svelte/lib/ChevronLeft32"; import ChevronLeft32 from "carbon-icons-svelte/lib/ChevronLeft32";
import ChevronRight32 from "carbon-icons-svelte/lib/ChevronRight32"; import ChevronRight32 from "carbon-icons-svelte/lib/ChevronRight32";
@@ -9,6 +10,8 @@
import IconButton from "../../IconButton/index.svelte"; import IconButton from "../../IconButton/index.svelte";
import { getNavItemRoute, getLectureRoute, getLectureNo } from "../function"; import { getNavItemRoute, getLectureRoute, getLectureNo } from "../function";
import { lessons } from "./Lecture/store/lessons";
// export let lectureId; // export let lectureId;
export let courseId; export let courseId;
@@ -32,33 +35,7 @@
label: "Lectures", label: "Lectures",
to: getLectureRoute(courseId), to: getLectureRoute(courseId),
hideSortIcon: false, hideSortIcon: false,
items: [ isLecture: true,
{
id: 1,
title: "Вводный урок. Soft skills",
to: getLectureRoute(courseId, 1),
},
{
id: 2,
title: "Введение в ReactJS",
to: getLectureRoute(courseId, 2),
},
{
id: 3,
title: "Компоненты",
to: getLectureRoute(courseId, 3),
},
{
id: 4,
title: "Состояние компонентов и пропсы",
to: getLectureRoute(courseId, 4),
},
{
id: 5,
title: "Жизненный цикл",
to: getLectureRoute(courseId, 5),
},
],
}, },
{ {
label: "People", label: "People",
@@ -92,6 +69,8 @@
} }
}); });
}); });
$: console.log("lessons", $lessons);
</script> </script>
<div class="root z-10 {!show && 'hide'}"> <div class="root z-10 {!show && 'hide'}">
@@ -105,16 +84,24 @@
isGroupActive={$page.path === navItem.to} isGroupActive={$page.path === navItem.to}
hideSortIcon={navItem.hideSortIcon} hideSortIcon={navItem.hideSortIcon}
> >
{#if Array.isArray(navItem.items)} {#if navItem.isLecture}
{#each navItem.items as item, index} {#each $lessons as item, index}
<a <a
class="item flex items-center {(item.to === $page.path || class="item flex items-center {(item.to === $page.path ||
!$page.path.length > 3) && !$page.path.length > 3) &&
'active'} pl-7 py-2" 'active'} pl-7 py-2 {!item.isComplete &&
href={item.to} 'cursor-not-allowed'}"
href={item.isComplete ? item.to : $page.path}
> >
<span class="course-counter"> {getLectureNo(index + 1)} </span> <span class="course-counter"> {getLectureNo(index + 1)} </span>
<span>{item.title}</span> <span>{item.title}</span>
{#if item.isComplete}
<span class="ml-2 success">
<CheckmarkFilled20 class="carbon-icon" />
</span>
{:else}
<span class="text-md ml-2">🔒</span>
{/if}
</a> </a>
{/each} {/each}
{/if} {/if}
@@ -146,13 +133,15 @@
height: 90vh; height: 90vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 360px; min-width: 360px;
max-width: 360px;
position: sticky; position: sticky;
top: 0; top: 0;
border-right: 1px solid var(--border-color); border-right: 1px solid var(--border-color);
&.hide { &.hide {
width: 0px; min-width: 0px;
max-width: 0px;
} }
} }
@@ -1,8 +1,149 @@
<script> <script>
import Time24 from "carbon-icons-svelte/lib/Time24";
import Edit24 from "carbon-icons-svelte/lib/Edit24";
import Save24 from "carbon-icons-svelte/lib/Save24";
import CheckmarkFilled24 from "carbon-icons-svelte/lib/CheckmarkFilled24";
import PageNav from "../../../../PageNav/index.svelte"; import PageNav from "../../../../PageNav/index.svelte";
import PageBody from "../../../../PageBody/index.svelte"; import PageBody from "../../../../PageBody/index.svelte";
import PrimaryButton from "../../../../PrimaryButton/index.svelte";
import TextField from "../../../../Form/TextField.svelte";
import IconButton from "../../../../IconButton/index.svelte";
import Select from "../../../../Form/Select.svelte";
import { lessons, lecturers, handleAddLesson } from "../store/lessons";
// export let path;
let lectureEditing;
let ref;
function formatDate(date) {
const d = new Date(date);
const ye = new Intl.DateTimeFormat("en", { year: "numeric" }).format(d);
const mo = new Intl.DateTimeFormat("en", { month: "2-digit" }).format(d);
const da = new Intl.DateTimeFormat("en", { day: "2-digit" }).format(d);
return `${ye}-${mo}-${da}`;
}
function addLesson() {
handleAddLesson();
setTimeout(() => {
lectureEditing = $lessons.length - 1;
if (ref) {
ref.scrollIntoView({ block: "end", behavior: "smooth" });
}
}, 100);
}
</script> </script>
<PageNav title="Lectures" /> <PageNav title="Lectures">
<div slot="widget">
<PrimaryButton label="Add" onClick={addLesson} />
</div>
</PageNav>
<PageBody>All lecture will be here</PageBody> <PageBody width="w-11/12 m-auto">
<div class="w-4/5 m-auto">
{#each $lessons as lecture, index}
<div
bind:this={ref}
class="group relative m-auto rounded-md border-2 border-gray-100 py-3 px-5 mr-4 mb-4 flex items-center hover:shadow-2xl shadow-md transition delay-150 duration-300 ease-in-out"
>
<!-- Complete or Not complete icon -->
<div class="absolute -left-5 -top-5 success">
<IconButton
onClick={() => (lecture.isComplete = !lecture.isComplete)}
>
{#if lecture.isComplete}
<CheckmarkFilled24 class="carbon-icon" />
{:else}
<span class="text-2xl">🔒</span>
{/if}
</IconButton>
</div>
<!-- Edit/Save -->
<div class="absolute top-2 right-0">
{#if lectureEditing === index}
<IconButton onClick={() => (lectureEditing = null)}>
<Save24 class="carbon-icon" />
</IconButton>
{:else}
<IconButton onClick={() => (lectureEditing = index)}>
<Edit24 class="carbon-icon" />
</IconButton>
{/if}
</div>
<div class="">
<h3 class="text-4xl font-bold">{index + 1}</h3>
</div>
<div class="ml-8 w-4/5">
{#if lectureEditing === index}
<TextField bind:value={lecture.title} autofocus={true} />
{:else}
<h3 class="text-3xl font-semibold m-0 flex items-center">
<a href={lecture.to} class="hover:underline text-black">
{lecture.title}
</a>
</h3>
{/if}
<div class="flex items-center mb-2">
<div class="flex items-center mr-2">
{lecture.resources.map((r) => `${r.value} ${r.label}`).join(", ")}
</div>
</div>
<div class="flex items-center justify-between mt-3 w-full">
{#if lectureEditing === index}
<Select
bind:value={lecture.lecturer.name}
options={$lecturers}
valueKey="text"
/>
{:else}
<a
href="courses/1/people"
class="flex items-center hover:underline text-black"
>
<img
alt="Placeholder"
class="block rounded-full"
width="24"
height="20"
src={lecture.lecturer.avatar}
/>
<p class="ml-2 text-sm font-bold">{lecture.lecturer.name}</p>
</a>
{/if}
<div class="flex items-center">
{#if lectureEditing === index}
<input
type="date"
name="lecture-date-picker"
class="p-2 rounded-md w-40"
value={formatDate(lecture.date)}
on:input={(e) => (lecture.date = e.target.value)}
/>
{:else}
<Time24 class="carbon-icon" />
<p class="text-md font-semibold ml-2">
{new Date(lecture.date).toDateString()}
</p>
{/if}
</div>
</div>
</div>
</div>
{/each}
</div>
</PageBody>
<style>
.group {
min-height: 170px;
}
</style>
@@ -7,11 +7,12 @@
export let path; export let path;
export let tab; export let tab;
// export let lectureId;
export let showLectureHome; export let showLectureHome;
</script> </script>
{#if showLectureHome} {#if showLectureHome}
<Home /> <Home {path} />
{:else} {:else}
<div> <div>
<PageNav <PageNav
@@ -0,0 +1,187 @@
import { writable } from "svelte/store";
export const lessons = writable([
{
title: "Вступительное слово. Софт скилы",
to: "/courses/1/lecture/1",
lecturer: {
userId: 1,
avatar: "https://picsum.photos/32/32/?random",
name: "Sergey Semko",
},
resources: [
{
label: "lesson",
value: 1,
},
{
label: "quiz",
value: 1,
},
{
label: "home task",
value: 2,
},
],
date: new Date(),
isComplete: true,
},
{
title: "Введение в ReactJS",
to: "/courses/1/lecture/2",
lecturer: {
userId: 1,
avatar: "https://picsum.photos/32/32/?random",
name: "Sergey Semko",
},
resources: [
{
label: "lesson",
value: 1,
},
{
label: "quiz",
value: 1,
},
{
label: "home task",
value: 2,
},
],
date: new Date(),
isComplete: false,
},
{
title: "Компоненты",
to: "/courses/1/lecture/3",
lecturer: {
userId: 1,
avatar: "https://picsum.photos/32/32/?random",
name: "Sergey Semko",
},
resources: [
{
label: "lesson",
value: 1,
},
{
label: "quiz",
value: 1,
},
{
label: "home task",
value: 2,
},
],
date: new Date(),
isComplete: false,
},
{
title: "Состояние компонентов и пропсы",
to: "/courses/1/lecture/4",
lecturer: {
userId: 1,
avatar: "https://picsum.photos/32/32/?random",
name: "Sergey Semko",
},
resources: [
{
label: "lesson",
value: 1,
},
{
label: "quiz",
value: 1,
},
{
label: "home task",
value: 2,
},
],
date: new Date(),
isComplete: false,
},
{
title: "Жизненный цикл",
to: "/courses/1/lecture/5",
lecturer: {
userId: 1,
avatar: "https://picsum.photos/32/32/?random",
name: "Sergey Semko",
},
resources: [
{
label: "lesson",
value: 1,
},
{
label: "quiz",
value: 1,
},
{
label: "home task",
value: 2,
},
],
date: new Date(),
isComplete: false,
},
]);
export const lecturers = writable([
{
id: 1,
text: "Sergey Semko",
},
{
id: 3,
text: "Jonathan Nelson",
},
{
id: 4,
text: "Sasha Pokidin",
},
{
id: 5,
text: "Natasha Rudenko",
},
{
id: 6,
text: "Yulia Marushko",
},
]);
export function handleAddLesson() {
const resources = [
{
label: "lesson",
value: 0,
},
{
label: "quiz",
value: 0,
},
{
label: "home task",
value: 0,
},
];
lessons.update(_lessons => {
return [
..._lessons,
{
title: 'Untitled lesson',
to: "/courses/1/lecture/" + (_lessons.length + 1),
resources,
lecturer: {
userId: 1,
avatar: "https://picsum.photos/32/32/?random",
name: "",
},
date: new Date()
}
]
})
}
@@ -54,7 +54,8 @@
avatarUrl={teacher.avatar} avatarUrl={teacher.avatar}
title={teacher.title} title={teacher.title}
telegramLink={teacher.telegramLink} telegramLink={teacher.telegramLink}
mailLink={teacher.mailLink} /> mailLink={teacher.mailLink}
/>
{/each} {/each}
</div> </div>
</div> </div>
@@ -68,7 +69,8 @@
<UserCard <UserCard
name={student.name} name={student.name}
avatarUrl={student.avatar} avatarUrl={student.avatar}
title={student.title} /> title={student.title}
/>
{/each} {/each}
</div> </div>
</div> </div>
+1 -1
View File
@@ -9,7 +9,7 @@
// export let subMenuItems = []; // export let subMenuItems = [];
function onClick() { function onClick() {
isExpanded = !isExpanded; // isExpanded = !isExpanded;
handleClick(); handleClick();
} }
</script> </script>
+2 -1
View File
@@ -2,13 +2,14 @@
export let label; export let label;
export let value; export let value;
export let options = []; export let options = [];
export let valueKey = "id";
</script> </script>
<label class="block"> <label class="block">
{#if label} <span class="text-gray-700">{label}</span> {/if} {#if label} <span class="text-gray-700">{label}</span> {/if}
<select bind:value class="form-select block w-full mt-1"> <select bind:value class="form-select block w-full mt-1">
{#each options as option} {#each options as option}
<option value={option.id}> <option value={option[valueKey]}>
{option.text} {option.text}
</option> </option>
{/each} {/each}
+2
View File
@@ -4,6 +4,7 @@
export let value; export let value;
export let onKeyDown; export let onKeyDown;
export let className = ""; export let className = "";
export let autofocus = false;
</script> </script>
<label class="block {className}"> <label class="block {className}">
@@ -14,5 +15,6 @@
on:keydown={onKeyDown} on:keydown={onKeyDown}
{placeholder} {placeholder}
bind:value bind:value
autofocus
/> />
</label> </label>
+2 -5
View File
@@ -1,9 +1,10 @@
<script> <script>
// import // import
// border border-gray-300 rounded-md p-3 bg-blue-200 bg-opacity-25 // border border-gray-300 rounded-md p-3 bg-blue-200 bg-opacity-25
export let width = "max-w-3xl";
</script> </script>
<div class="root mt-4 mx-auto max-w-3xl relative pb-5"> <div class="mt-4 mx-auto {width} relative pb-5">
{#if $$slots.header} {#if $$slots.header}
<div <div
class="head flex bg-white items-center justify-between sticky right-0 w-full py-3" class="head flex bg-white items-center justify-between sticky right-0 w-full py-3"
@@ -16,10 +17,6 @@
</div> </div>
<style> <style>
/* .root {
max-width: 700px;
} */
.head { .head {
top: 61px; top: 61px;
z-index: 1; z-index: 1;
+1
View File
@@ -6,6 +6,7 @@
export let addButtonHref; export let addButtonHref;
export let addButtonLabel; export let addButtonLabel;
export let disableSticky = false; export let disableSticky = false;
let dynamicRootClass = ""; let dynamicRootClass = "";
$: dynamicRootClass = $: dynamicRootClass =
+2 -2
View File
@@ -57,11 +57,11 @@
} }
[aria-current] :global(svg.carbon-icon), [aria-current] :global(svg.carbon-icon),
button.active :global(svg.carbon-icon) { .active :global(svg.carbon-icon) {
fill: var(--main-primary-color); fill: var(--main-primary-color);
} }
button.success :global(svg.carbon-icon) { .success :global(svg.carbon-icon) {
fill: green; fill: green;
} }
</style> </style>
+17 -18
View File
@@ -11,27 +11,14 @@
export let telegramLink; export let telegramLink;
</script> </script>
<style> <figure class="w-52 bg-gray-100 px-4 py-7 mr-4 mb-4">
.profile {
width: 200px;
}
.profile img {
width: 104px;
height: 104px;
}
.description {
min-height: 70px;
}
</style>
<figure class="profile bg-gray-100 rounded-xl px-4 py-7 mr-4 mb-4">
<img <img
class="w-32 h-32 rounded-full mx-auto" class="w-32 h-32 rounded-full mx-auto"
src={avatarUrl} src={avatarUrl}
alt="" alt=""
width="384" width="384"
height="512" /> height="512"
/>
<div class="pt-6 text-center space-y-4"> <div class="pt-6 text-center space-y-4">
<div class="description font-medium flex flex-col justify-around"> <div class="description font-medium flex flex-col justify-around">
<div class="text-cyan-600">{name}</div> <div class="text-cyan-600">{name}</div>
@@ -45,15 +32,27 @@
data={faTelegram} data={faTelegram}
scale="1" scale="1"
class="social-icon" class="social-icon"
style="color:#4dabf7;margin:0 5px;" /> style="color:#4dabf7;margin:0 5px;"
/>
</a> </a>
<a href={mailLink} target="_blank"> <a href={mailLink} target="_blank">
<Icon <Icon
data={faEnvelope} data={faEnvelope}
scale="1" scale="1"
class="social-icon" class="social-icon"
style="color:#d44c3d;margin:0 5px;" /> style="color:#d44c3d;margin:0 5px;"
/>
</a> </a>
</div> </div>
{/if} {/if}
</figure> </figure>
<style>
img {
width: 104px;
height: 104px;
}
.description {
min-height: 70px;
}
</style>
+6 -1
View File
@@ -44,7 +44,12 @@
{:else if courseNavItem === "hometasks"} {:else if courseNavItem === "hometasks"}
<HomeTask /> <HomeTask />
{:else if courseNavItem === "lecture"} {:else if courseNavItem === "lecture"}
<Lecture path={$page.path} {tab} showLectureHome={!lectureId} /> <Lecture
path={$page.path}
{tab}
{lectureId}
showLectureHome={!lectureId}
/>
{:else if courseNavItem === "people"} {:else if courseNavItem === "people"}
<People /> <People />
{/if} {/if}