This commit is contained in:
Rotimi Best
2023-12-04 18:49:35 +03:00
16 changed files with 93 additions and 127 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
<a href="https://classroomio.com/"> <a href="https://classroomio.com/">
<img alt="Spend less time doing the boring stuffs, instead focus on impacting the lives of your students." src="https://classroomio.com/classroomio-opengraph-image.png" /> <img alt="Spend less time doing the boring stuff, instead focus on impacting the lives of your students." src="https://classroomio.com/classroomio-opengraph-image.png" />
<h1 align="center">ClassroomIO</h1> <h1 align="center">ClassroomIO</h1>
</a> </a>
+2 -2
View File
@@ -18,7 +18,7 @@
<meta property="og:image" itemprop="image" content="https://classroomio.com/classroomio-opengraph-image.png"> <meta property="og:image" itemprop="image" content="https://classroomio.com/classroomio-opengraph-image.png">
<meta property="og:title" content="ClassroomIO –&nbsp;The Open Source Platform for Tech Bootcamps" /> <meta property="og:title" content="ClassroomIO –&nbsp;The Open Source Platform for Tech Bootcamps" />
<meta property="og:description" <meta property="og:description"
content="Spend less time doing the boring stuffs, instead focus on impacting the lives of your students." /> content="Spend less time doing the boring stuff, instead focus on impacting the lives of your students." />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
@@ -33,7 +33,7 @@
<meta property="twitter:url" content="https://www.classroomio.com/"> <meta property="twitter:url" content="https://www.classroomio.com/">
<meta name="twitter:title" content="ClassroomIO – The Open Source Platform for Tech Bootcamps"> <meta name="twitter:title" content="ClassroomIO – The Open Source Platform for Tech Bootcamps">
<meta name="twitter:description" <meta name="twitter:description"
content="Spend less time doing the boring stuffs, instead focus on impacting the lives of your students."> content="Spend less time doing the boring stuff, instead focus on impacting the lives of your students.">
<meta name="twitter:image" content="https://classroomio.com/classroomio-opengraph-image.png"> <meta name="twitter:image" content="https://classroomio.com/classroomio-opengraph-image.png">
<!-- <link rel="stylesheet" href="global.css"> --> <!-- <link rel="stylesheet" href="global.css"> -->
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" /> <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
@@ -45,7 +45,7 @@
<p <p
class="mx-auto mt-10 lg:mt-6 px-4 lg:p-0 text-md md:text-xl tracking-wide leading-6 lg:leading-10 text-slate-700 lg:w-2/4" class="mx-auto mt-10 lg:mt-6 px-4 lg:p-0 text-md md:text-xl tracking-wide leading-6 lg:leading-10 text-slate-700 lg:w-2/4"
> >
Spend less time doing the boring stuffs, instead focus on impacting the Spend less time doing the boring stuff, instead focus on impacting the
lives of your students. lives of your students.
</p> </p>
<button <button
+1 -1
View File
@@ -1,5 +1,5 @@
<a href="https://classroomio.com/"> <a href="https://classroomio.com/">
<img alt="Spend less time doing the boring stuffs, instead focus on impacting the lives of your students." src="https://classroomio.com/classroomio-opengraph-image.png" /> <img alt="Spend less time doing the boring stuff, instead focus on impacting the lives of your students." src="https://classroomio.com/classroomio-opengraph-image.png" />
<h1 align="center">ClassroomIO</h1> <h1 align="center">ClassroomIO</h1>
<p align="center"> <p align="center">
The Open Source Teaching Platform for Bootcamps The Open Source Teaching Platform for Bootcamps
+3 -3
View File
@@ -14,7 +14,7 @@
<title>ClassroomIO –&nbsp;The Open Source Platform for Tech Bootcamps</title> <title>ClassroomIO –&nbsp;The Open Source Platform for Tech Bootcamps</title>
<meta <meta
name="description" name="description"
content="Spend less time doing the boring stuffs, instead focus on impacting the lives of your students." content="Spend less time doing the boring stuff, instead focus on impacting the lives of your students."
/> />
<meta name="theme-color" content="#ffffff" /> <meta name="theme-color" content="#ffffff" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -24,7 +24,7 @@
/> />
<meta <meta
property="og:description" property="og:description"
content="Spend less time doing the boring stuffs, instead focus on impacting the lives of your students." content="Spend less time doing the boring stuff, instead focus on impacting the lives of your students."
/> />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:image:type" content="image/png" /> <meta property="og:image:type" content="image/png" />
@@ -42,7 +42,7 @@
/> />
<meta <meta
name="twitter:description" name="twitter:description"
content="Spend less time doing the boring stuffs, instead focus on impacting the lives of your students." content="Spend less time doing the boring stuff, instead focus on impacting the lives of your students."
/> />
<!-- <link rel="stylesheet" href="global.css"> --> <!-- <link rel="stylesheet" href="global.css"> -->
@@ -1,46 +0,0 @@
<script>
import Editor from 'cl-editor/src/Editor.svelte';
export let html = '';
export let editor;
let colors = [
'#000000',
'#e60000',
'#ff9900',
'#ffff00',
'#008a00',
'#0066cc',
'#9933ff',
'#ffffff',
'#facccc',
'#ffebcc',
'#ffffcc',
'#cce8cc',
'#cce0f5',
'#ebd6ff',
'#bbbbbb',
'#f06666',
'#ffc266',
'#ffff66',
'#66b966',
'#66a3e0',
'#c285ff',
'#888888',
'#a10000',
'#b26b00',
'#b2b200',
'#006100',
'#0047b2',
'#6b24b2',
'#444444',
'#5c0000',
'#663d00',
'#666600',
'#003700',
'#002966',
'#3d1466'
];
</script>
<Editor bind:this={editor} {html} {colors} on:change={(evt) => (html = evt.detail)} />
@@ -1,4 +1,4 @@
<script> <script lang="ts">
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import set from 'lodash/set'; import set from 'lodash/set';
import get from 'lodash/get'; import get from 'lodash/get';
@@ -7,32 +7,37 @@
import TextField from '$lib/components/Form/TextField.svelte'; import TextField from '$lib/components/Form/TextField.svelte';
import UploadImage from '$lib/components/UploadImage/index.svelte'; import UploadImage from '$lib/components/UploadImage/index.svelte';
import { uploadAvatar } from '$lib/utils/services/courses'; import { uploadAvatar } from '$lib/utils/services/courses';
import type { Course } from '$lib/utils/types';
export let course = {}; export let course: Course;
let name; let name: string | undefined;
let role; let role: string | undefined;
let imgUrl; let imgUrl: string | undefined;
let description; let description: string | undefined;
let courseNo; let courseNo: string | undefined;
let avatar; let avatar: string | undefined;
let hasBeenSet = false; let hasBeenSet = false;
function setter(value, setterKey) { function setter(value: any, setterKey: string) {
if (!value) return; if (!value) return;
const _course = cloneDeep(course); const _course = cloneDeep(course);
set(_course, setterKey, value); set(_course, setterKey, value);
course = _course; course = _course;
} }
async function onAvatarChange(_avatar) { async function onAvatarChange(_avatar: string | undefined) {
if (!_avatar) return; if (!_avatar || !course.id) return;
const logo = await uploadAvatar(course.id, _avatar); const logo = await uploadAvatar(course.id, _avatar);
if (!logo) return;
imgUrl = logo; imgUrl = logo;
} }
function setDefaults(course) { function setDefaults(course: Course) {
if (isEmpty(course) || hasBeenSet) return; if (isEmpty(course) || hasBeenSet) return;
hasBeenSet = true; hasBeenSet = true;
@@ -78,7 +83,7 @@
<TextArea <TextArea
label="About instructor" label="About instructor"
placeholder="A short background about the instructor" placeholder="A short background about the instructor"
rows="6" rows={6}
className="mt-5" className="mt-5"
labelClassName="font-bold" labelClassName="font-bold"
bind:value={description} bind:value={description}
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import TextEditor from '$lib/components/TextEditor/index.svelte'; import TextEditor from '$lib/components/TextEditor/index.svelte';
export let value: string; export let value: string | undefined;
</script> </script>
<div class="h-2/5"> <div class="h-2/5">
@@ -27,6 +27,7 @@
export let course: Course; export let course: Course;
export let courseId: string; export let courseId: string;
export let syncCourseStore: (course: Course) => void;
let borderBottomGrey = 'border-r-0 border-b border-l-0 border-gray-300'; let borderBottomGrey = 'border-r-0 border-b border-l-0 border-gray-300';
let loading = false; let loading = false;
@@ -123,9 +124,9 @@
polls: undefined, polls: undefined,
slug: course.slug slug: course.slug
}); });
loading = false;
return `${window.location.origin}/course/${course.slug}`; loading = false;
syncCourseStore(course);
} }
/** /**
* 1. Use all you have for editing now * 1. Use all you have for editing now
@@ -149,10 +150,11 @@
size={$isMobile ? 'large' : 'small'} size={$isMobile ? 'large' : 'small'}
color="text-black" color="text-black"
toolTipProps={$isMobile toolTipProps={$isMobile
? {} ? undefined
: { : {
title: 'Toggle editor', title: 'Toggle editor',
direction: 'right' direction: 'right',
hotkeys: []
}} }}
> >
{#if show} {#if show}
@@ -86,7 +86,7 @@
$: video = get(courseData, 'metadata.videoUrl'); $: video = get(courseData, 'metadata.videoUrl');
$: bannerImage = get(courseData, 'logo'); $: bannerImage = get(courseData, 'logo');
$: lessons = get(courseData, 'lessons', []); $: lessons = get(courseData, 'lessons', []);
$: instructor = courseData?.metadata?.instructor || {}; $: instructor = get(courseData, 'metadata.instructor') || {};
$: initPlyr(player, video); $: initPlyr(player, video);
$: { $: {
reviews = get(courseData, 'metadata.reviews') || []; reviews = get(courseData, 'metadata.reviews') || [];
@@ -276,7 +276,7 @@
{/if} {/if}
{#if lesson.note} {#if lesson.note}
<span class="text-sm font-light flex w-2/4" <span class="text-sm font-light flex w-2/4"
><Notebook size={16} class="mr-1" />1 note</span ><Notebook size={16} class="mr-1" />note</span
> >
{/if} {/if}
</div> </div>
@@ -4,7 +4,7 @@
import { appStore } from '$lib/utils/store/app'; import { appStore } from '$lib/utils/store/app';
export let id = ''; export let id = '';
export let value: string; export let value: string | undefined = '';
export let onChange = (html: string) => {}; export let onChange = (html: string) => {};
export let height = 300; export let height = 300;
export let placeholder = ''; export let placeholder = '';
@@ -14,7 +14,7 @@
const apiKey = PUBLIC_TINYMCE_API_KEY; const apiKey = PUBLIC_TINYMCE_API_KEY;
let tinmycEditor: any; let tinmycEditor: any;
let unmount = false let unmount = false;
// editor configuration // editor configuration
let conf = { let conf = {
@@ -73,6 +73,6 @@
<div> <div>
{#if !unmount} {#if !unmount}
<Editor bind:value {apiKey} bind:conf /> <Editor bind:value {apiKey} bind:conf />
{/if} {/if}
</div> </div>
@@ -1,21 +1,22 @@
<script> <script lang="ts">
import Camera from 'carbon-icons-svelte/lib/Camera.svelte'; import Camera from 'carbon-icons-svelte/lib/Camera.svelte';
export let avatar = null; export let avatar: string | undefined;
export let src = null; export let src: string | undefined;
export let widthHeight = ''; export let widthHeight = '';
export let shape = 'rounded-full'; export let shape = 'rounded-full';
export let errorMessage = null; export let errorMessage: string | null = null;
let fileinput; let fileinput: HTMLInputElement;
const onFileSelected = (e) => { const onFileSelected = (e: Event<HTMLInputElement>) => {
const image = e.target.files[0]; const image = e.target.files[0];
let reader = new FileReader(); let reader = new FileReader();
reader.readAsDataURL(image); reader.readAsDataURL(image);
reader.onload = (e) => { reader.onload = (e) => {
avatar = image; avatar = image;
src = e.target.result; // @ts-ignore
src = e.target?.result || undefined;
}; };
}; };
</script> </script>
+6 -7
View File
@@ -90,7 +90,6 @@
error, error,
status status
} = await supabase.from('profile').select(`*`).eq('id', authUser?.id).single(); } = await supabase.from('profile').select(`*`).eq('id', authUser?.id).single();
console.log('Get user', authUser);
console.log('Get profile', profileData); console.log('Get profile', profileData);
if (error && !profileData && status === 406 && authUser) { if (error && !profileData && status === 406 && authUser) {
@@ -219,10 +218,7 @@
handleResize(); handleResize();
if ( if (!isSupabaseTokenInLocalStorage() && !isPublicRoute($page.url.pathname)) {
!isSupabaseTokenInLocalStorage() &&
!isPublicRoute($page.url.pathname)
) {
console.log('No auth token and is not a public route, redirect to login', path); console.log('No auth token and is not a public route, redirect to login', path);
return goto('/login?redirect=/' + path); return goto('/login?redirect=/' + path);
} }
@@ -408,9 +404,12 @@
} }
:global(.plyr__controls) { :global(.plyr__controls) {
background: url(/logo-192.png) 99% 70% no-repeat, background:
url(/logo-192.png) 99% 70% no-repeat,
linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.5)) !important; linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.5)) !important;
background-size: 50px auto, auto !important; background-size:
50px auto,
auto !important;
} }
:global(.cards-container) { :global(.cards-container) {
@@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
import { dev } from '$app/environment';
import { fly } from 'svelte/transition'; import { fly } from 'svelte/transition';
import CourseLandingPage from '$lib/components/CourseLandingPage/index.svelte'; import CourseLandingPage from '$lib/components/CourseLandingPage/index.svelte';
import Editor from '$lib/components/CourseLandingPage/components/Editor/index.svelte'; import Editor from '$lib/components/CourseLandingPage/components/Editor/index.svelte';
@@ -10,14 +11,18 @@
const { courseId } = data; const { courseId } = data;
let courseData: Course; let courseData: Course = $course;
function setCourseData(course: Course, lessons: Lesson[]) { function setCourseData(course: Course, lessons: Lesson[]) {
courseData = { ...course, lessons }; courseData = { ...course, lessons };
} }
function syncCourseStore(_courseData: Course) {
$course = _courseData;
}
$: setCourseData($course, $lessons); $: setCourseData($course, $lessons);
$: console.log('courseData changed', courseData); $: dev && console.log('courseData changed', courseData);
</script> </script>
<div <div
@@ -25,7 +30,7 @@
in:fly={{ y: 500, duration: 500 }} in:fly={{ y: 500, duration: 500 }}
out:fly={{ y: 500, duration: 500 }} out:fly={{ y: 500, duration: 500 }}
> >
<Editor {courseId} bind:course={courseData} /> <Editor {courseId} bind:course={courseData} {syncCourseStore} />
<div class="rightBar"> <div class="rightBar">
<CourseLandingPage bind:courseData editMode={true} /> <CourseLandingPage bind:courseData editMode={true} />
</div> </div>
+32 -32
View File
File diff suppressed because one or more lines are too long
@@ -230,7 +230,7 @@ CREATE TABLE IF NOT EXISTS "public"."course" (
"is_template" boolean DEFAULT true, "is_template" boolean DEFAULT true,
"logo" "text" DEFAULT ''::"text" NOT NULL, "logo" "text" DEFAULT ''::"text" NOT NULL,
"slug" character varying, "slug" character varying,
"metadata" "jsonb" DEFAULT '{"gols": "", "description": "", "requirements": ""}'::"jsonb" NOT NULL, "metadata" "jsonb" DEFAULT '{"goals": "", "description": "", "requirements": ""}'::"jsonb" NOT NULL,
"cost" bigint DEFAULT '0'::bigint, "cost" bigint DEFAULT '0'::bigint,
"currency" character varying DEFAULT 'NGN'::character varying NOT NULL, "currency" character varying DEFAULT 'NGN'::character varying NOT NULL,
"banner_image" "text", "banner_image" "text",