Merge pull request #36 from learnhouse/feat/ui-refresh

Feat/UI refresh
This commit is contained in:
Badr B 2023-01-15 17:39:03 +01:00 committed by GitHub
commit d7f1e6f94a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 3839 additions and 461 deletions

1
.gitignore vendored
View file

@ -21,7 +21,6 @@ dist/
downloads/ downloads/
eggs/ eggs/
.eggs/ .eggs/
lib/
lib64/ lib64/
parts/ parts/
sdist/ sdist/

View file

@ -57,7 +57,7 @@ function NewCollection(params : any) {
}, [params.params.orgslug]); }, [params.params.orgslug]);
return ( return (
<Layout> <>
<Title>Add new</Title> <Title>Add new</Title>
<br /> <br />
<input type="text" placeholder="Name" value={name} onChange={handleNameChange} /> <input type="text" placeholder="Name" value={name} onChange={handleNameChange} />
@ -90,7 +90,7 @@ function NewCollection(params : any) {
<input type="text" placeholder="Description" value={description} onChange={handleDescriptionChange} /> <input type="text" placeholder="Description" value={description} onChange={handleDescriptionChange} />
<br /> <br />
<button onClick={handleSubmit}>Submit</button> <button onClick={handleSubmit}>Submit</button>
</Layout> </>
); );
} }

View file

@ -35,7 +35,7 @@ function Collections(params:any) {
}, []); }, []);
return ( return (
<Layout> <>
<Title> <Title>
{orgslug} Collections :{" "} {orgslug} Collections :{" "}
<Link href={"/collections/new"}> <Link href={"/collections/new"}>
@ -61,7 +61,7 @@ function Collections(params:any) {
))} ))}
</div> </div>
)} )}
</Layout> </>
); );
} }

View file

@ -225,7 +225,7 @@ function CourseEdit(params: any) {
}; };
return ( return (
<Layout> <>
<Header></Header> <Header></Header>
<Title> <Title>
Edit Course Chapters{" "} Edit Course Chapters{" "}
@ -283,7 +283,7 @@ function CourseEdit(params: any) {
</DragDropContext> </DragDropContext>
</ChapterlistWrapper> </ChapterlistWrapper>
)} )}
</Layout> </>
); );
} }

View file

@ -1,19 +1,14 @@
"use client"; "use client";
import { default as React, useEffect, useRef } from "react"; import { default as React, useEffect, useRef } from "react";
import Layout from "../../../../../../../../components/UI/Layout";
import { Title } from "../../../../../../../../components/UI/Elements/Styles/Title";
import dynamic from "next/dynamic";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { getElement } from "../../../../../../../../services/courses/elements"; import { getElement } from "../../../../../../../../services/courses/elements";
import AuthProvider from "../../../../../../../../components/Security/AuthProvider"; import AuthProvider from "../../../../../../../../components/Security/AuthProvider";
import EditorWrapper from "../../../../../../../../components/Editor/EditorWrapper"; import EditorWrapper from "../../../../../../../../components/Editor/EditorWrapper";
import { getCourseMetadata } from "../../../../../../../../services/courses/courses"; import { getCourseMetadata } from "../../../../../../../../services/courses/courses";
// Workaround (Next.js SSR doesn't support tip tap editor)
const Editor: any = dynamic(() => import("../../../../../../../../components/Editor/EditorWrapper") as any, {
ssr: false,
});
function EditElement(params: any) { function EditElement(params: any) {
const router = useRouter(); const router = useRouter();

View file

@ -1,50 +1,157 @@
"use client"; "use client";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import Link from "next/link";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import Layout from "../../../../../../../components/UI/Layout"; import Layout from "../../../../../../../components/UI/Layout";
import { getElement } from "../../../../../../../services/courses/elements"; import { getElement } from "../../../../../../../services/courses/elements";
import { getBackendUrl } from "../../../../../../../services/config"; import { getBackendUrl } from "../../../../../../../services/config";
import Canva from "../../../../../../../components/Canva/Canva"; import Canva from "../../../../../../../components/LectureViews/DynamicCanva/DynamicCanva";
import styled from "styled-components";
import { getCourse, getCourseMetadata } from "../../../../../../../services/courses/courses";
import VideoLecture from "@components/LectureViews/Video/Video";
function ElementPage(params: any) { function ElementPage(params: any) {
const router = useRouter(); const router = useRouter();
const elementid = params.params.elementid; const elementid = params.params.elementid;
const courseid = params.params.courseid;
const orgslug = params.params.orgslug;
const [element, setElement] = React.useState<any>({}); const [element, setElement] = React.useState<any>({});
const [course, setCourse] = React.useState<any>({});
const [isLoading, setIsLoading] = React.useState(true); const [isLoading, setIsLoading] = React.useState(true);
async function fetchElementData() { async function fetchElementData() {
setIsLoading(true);
const element = await getElement("element_" + elementid); const element = await getElement("element_" + elementid);
setElement(element); setElement(element);
}
async function fetchCourseData() {
const course = await getCourseMetadata("course_" + courseid);
setCourse(course);
setIsLoading(false); setIsLoading(false);
} }
React.useEffect(() => { React.useEffect(() => {
if (elementid) { if (elementid) {
fetchElementData(); fetchElementData();
fetchCourseData();
} }
return () => {}; return () => {};
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [elementid]); }, [elementid]);
return ( return (
<Layout> <>
{isLoading ? ( {isLoading ? (
<div>Loading...</div> <div>Loading...</div>
) : ( ) : (
<div> <LectureLayout>
<p>element</p> <LectureTopWrapper>
<h1>{element.name} </h1> <LectureThumbnail>
<hr /> <Link href={`/org/${orgslug}/course/${courseid}`}>
<img src={`${getBackendUrl()}content/uploads/img/${course.course.thumbnail}`} alt="" />
</Link>
</LectureThumbnail>
<LectureInfo>
<p>Course</p>
<h1>{course.course.name}</h1>
</LectureInfo>
</LectureTopWrapper>
<ChaptersWrapper>
{course.chapters.map((chapter: any) => {
return (
<>
<div style={{ display: "flex", flexDirection: "row" }} key={chapter.chapter_id}>
{chapter.elements.map((element: any) => {
return (
<>
<Link href={`/org/${orgslug}/course/${courseid}/element/${element.id.replace("element_", "")}`}>
<ChapterIndicator key={element.id} />
</Link>{" "}
</>
);
})}
</div>
&nbsp;&nbsp;&nbsp;&nbsp;
</>
);
})}
</ChaptersWrapper>
<CourseContent>
{element.type == "dynamic" && <Canva content={element.content} element={element} />} {element.type == "dynamic" && <Canva content={element.content} element={element} />}
{/* todo : use apis & streams instead of this */} {/* todo : use apis & streams instead of this */}
{element.type == "video" && ( {element.type == "video" && <VideoLecture course={course} element={element} />}
<video controls src={`${getBackendUrl()}content/uploads/video/${element.content.video.element_id}/${element.content.video.filename}`}></video> </CourseContent>
</LectureLayout>
)} )}
</div> </>
)}
</Layout>
); );
} }
const LectureLayout = styled.div``;
const LectureThumbnail = styled.div`
padding-right: 30px;
justify-self: center;
img {
box-shadow: 0px 13px 33px -13px rgba(0, 0, 0, 0.42);
border-radius: 7px;
width: 100px;
height: 57px;
}
`;
const LectureInfo = styled.div`
h1 {
margin-top: 0px;
}
p {
margin-top: 0;
margin-bottom: 0;
font-weight: 700;
}
`;
const ChaptersWrapper = styled.div`
display: flex;
// row
flex-direction: row;
justify-content: space-around;
width: 100%;
width: 1300px;
margin: 0 auto;
`;
const ChapterIndicator = styled.div`
border-radius: 20px;
height: 5px;
background: #151515;
border-radius: 3px;
width: 35px;
background-color: black;
margin: 10px;
margin-bottom: 0px;
margin-left: 0px;
transition: all 0.2s ease;
&:hover {
width: 50px;
cursor: pointer;
}
`;
const LectureTopWrapper = styled.div`
width: 1300px;
padding-top: 50px;
margin: 0 auto;
display: flex;
`;
const CourseContent = styled.div`
display: flex;
background-color: white;
min-height: 600px;
`;
export default ElementPage; export default ElementPage;

View file

@ -21,7 +21,6 @@ const CourseIdPage = (params : any) => {
setCourseInfo(course); setCourseInfo(course);
setIsLoading(false); setIsLoading(false);
} }
@ -34,7 +33,7 @@ const CourseIdPage = (params : any) => {
}, [courseid && orgslug]); }, [courseid && orgslug]);
return ( return (
<Layout> <>
{isLoading ? ( {isLoading ? (
<div>Loading...</div> <div>Loading...</div>
) : ( ) : (
@ -43,30 +42,26 @@ const CourseIdPage = (params : any) => {
<p>Course</p> <p>Course</p>
<h1> <h1>
{courseInfo.course.name}{" "} {courseInfo.course.name}{" "}
<Link <Link href={`/org/${orgslug}/course/${courseid}/edit`} rel="noopener noreferrer">
href={`/org/${orgslug}/course/${courseid}/edit`}
rel="noopener noreferrer">
<Pencil2Icon /> <Pencil2Icon />
</Link>{" "} </Link>{" "}
</h1> </h1>
<br />
<ChaptersWrapper> <ChaptersWrapper>
{courseInfo.chapters.map((chapter: any) => { {courseInfo.chapters.map((chapter: any) => {
return <> return (
<>
{chapter.elements.map((element: any) => { {chapter.elements.map((element: any) => {
return <> return (
<>
<Link href={`/org/${orgslug}/course/${courseid}/element/${element.id.replace("element_", "")}`}> <Link href={`/org/${orgslug}/course/${courseid}/element/${element.id.replace("element_", "")}`}>
<ChapterIndicator /> <ChapterIndicator />
</Link>{" "} </Link>{" "}
</>; </>
);
})} })}
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
</>; </>
);
})} })}
</ChaptersWrapper> </ChaptersWrapper>
@ -75,48 +70,54 @@ const CourseIdPage = (params : any) => {
</CourseThumbnailWrapper> </CourseThumbnailWrapper>
<h2>Description</h2> <h2>Description</h2>
<BoxWrapper>
<p>{courseInfo.course.description}</p> <p>{courseInfo.course.description}</p>
</BoxWrapper>
<h2>What you will learn</h2> <h2>What you will learn</h2>
<BoxWrapper>
<p>{courseInfo.course.learnings == ![] ? "no data" : courseInfo.course.learnings}</p> <p>{courseInfo.course.learnings == ![] ? "no data" : courseInfo.course.learnings}</p>
</BoxWrapper>
<h2>Course Lessons</h2> <h2>Course Lessons</h2>
<BoxWrapper>
{courseInfo.chapters.map((chapter: any) => { {courseInfo.chapters.map((chapter: any) => {
return <> return (
<>
<h3>Chapter : {chapter.name}</h3> <h3>Chapter : {chapter.name}</h3>
{chapter.elements.map((element: any) => { {chapter.elements.map((element: any) => {
return <> return (
<>
<p> <p>
Element {element.name} Element {element.name}
<Link <Link href={`/org/${orgslug}/course/${courseid}/element/${element.id.replace("element_", "")}`} rel="noopener noreferrer">
href={`/org/${orgslug}/course/${courseid}/element/${element.id.replace("element_", "")}`}
rel="noopener noreferrer">
<EyeOpenIcon /> <EyeOpenIcon />
</Link>{" "} </Link>{" "}
</p> </p>
</>; </>
);
})} })}
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
</>; </>
);
})} })}
</BoxWrapper>
</CoursePageLayout> </CoursePageLayout>
)} )}
</Layout> </>
); );
}; };
const CourseThumbnailWrapper = styled.div` const CourseThumbnailWrapper = styled.div`
display: flex; display: flex;
padding-bottom: 20px;
img { img {
width: 794px; width: 100%;
height: 224.28px; height: 300px;
object-fit: cover; object-fit: cover;
object-position: top; object-position: center;
background: url(), #d9d9d9; background: url(), #d9d9d9;
border: 1px solid rgba(255, 255, 255, 0.19); border: 1px solid rgba(255, 255, 255, 0.19);
box-shadow: 0px 13px 33px -13px rgba(0, 0, 0, 0.42); box-shadow: 0px 13px 33px -13px rgba(0, 0, 0, 0.42);
@ -124,21 +125,39 @@ const CourseThumbnailWrapper = styled.div`
} }
`; `;
const CoursePageLayout = styled.div` const CoursePageLayout = styled.div`
margin-left: 40px; width: 1300px;
margin-right: 40px; margin: 0 auto;
p {
margin-bottom: 0px;
letter-spacing: -0.05em;
color: #727272;
font-weight: 700;
}
h1 {
margin-top: 5px;
letter-spacing: -0.05em;
margin-bottom: 10px;
}
`; `;
const ChaptersWrapper = styled.div` const ChaptersWrapper = styled.div`
display: flex; display: flex;
justify-content: space-around;
width: 100%;
`; `;
const ChapterIndicator = styled.div` const ChapterIndicator = styled.div`
border-radius: 20px; border-radius: 20px;
height: 5px; height: 5px;
background: #151515; background: #151515;
border-radius: 3px; border-radius: 3px;
width: 40px;
width: 35px;
background-color: black; background-color: black;
margin: 10px; margin: 10px;
margin-bottom: 20px;
margin-left: 0px; margin-left: 0px;
transition: all 0.2s ease; transition: all 0.2s ease;
@ -148,4 +167,24 @@ const ChapterIndicator = styled.div`
} }
`; `;
const BoxWrapper = styled.div`
background: #ffffff;
box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.03);
border-radius: 7px;
padding: 20px;
padding-top: 7px;
padding-left: 30px;
p {
font-family: "DM Sans";
font-style: normal;
font-weight: 500;
line-height: 16px;
letter-spacing: -0.02em;
color: #9d9d9d;
}
`;
export default CourseIdPage; export default CourseIdPage;

View file

@ -1,3 +1,4 @@
"use client";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import React from "react"; import React from "react";
import { Header } from "../../../../../components/UI/Header"; import { Header } from "../../../../../components/UI/Header";
@ -55,8 +56,7 @@ const NewCoursePage = (params: any) => {
return ( return (
<Layout title="New course"> <>
<Header></Header>
<Title>New Course </Title> <Title>New Course </Title>
<hr /> <hr />
Name : <input onChange={handleNameChange} type="text" /> <br /> Name : <input onChange={handleNameChange} type="text" /> <br />
@ -64,7 +64,7 @@ const NewCoursePage = (params: any) => {
Cover Photo : <input onChange={handleThumbnailChange} type="file" /> <br /> Cover Photo : <input onChange={handleThumbnailChange} type="file" /> <br />
Learnings (empty for now) (separated by ; ) : <textarea id="story" name="story" rows={5} cols={33} /> <br /> Learnings (empty for now) (separated by ; ) : <textarea id="story" name="story" rows={5} cols={33} /> <br />
<button onClick={handleSubmit}>Create</button> <button onClick={handleSubmit}>Create</button>
</Layout> </>
); );
}; };

View file

@ -46,14 +46,11 @@ const CoursesIndexPage = (params : any) => {
}, [isLoading, orgslug]); }, [isLoading, orgslug]);
return ( return (
<Layout title="Courses"> <>
<Header></Header>
<Title> <Title>
{orgslug} Courses :{" "} {orgslug} Courses :{" "}
<Link href={"/courses/new"}> <Link href={"/courses/new"}>
<button>+</button> <button>+</button>
</Link>{" "} </Link>{" "}
</Title> </Title>
@ -65,26 +62,22 @@ const CoursesIndexPage = (params : any) => {
{courses.map((course: any) => ( {courses.map((course: any) => (
<div key={course.course_id}> <div key={course.course_id}>
<Link href={"/org/" + orgslug + "/course/" + removeCoursePrefix(course.course_id)}> <Link href={"/org/" + orgslug + "/course/" + removeCoursePrefix(course.course_id)}>
<h2>{course.name}</h2> <h2>{course.name}</h2>
<CourseWrapper> <CourseWrapper>
<img src={`${getBackendUrl()}content/uploads/img/${course.thumbnail}`} alt="" /> <img src={`${getBackendUrl()}content/uploads/img/${course.thumbnail}`} alt="" />
</CourseWrapper> </CourseWrapper>
</Link> </Link>
<button style={{ backgroundColor: "red", border: "none" }} onClick={() => deleteCourses(course.course_id)}> <button style={{ backgroundColor: "red", border: "none" }} onClick={() => deleteCourses(course.course_id)}>
Delete Delete
</button> </button>
<Link href={"/org/" + orgslug + "/course/" + removeCoursePrefix(course.course_id) + "/edit"}> <Link href={"/org/" + orgslug + "/course/" + removeCoursePrefix(course.course_id) + "/edit"}>
<button>Edit Chapters</button> <button>Edit Chapters</button>
</Link> </Link>
</div> </div>
))} ))}
</div> </div>
)} )}
</Layout> </>
); );
}; };

View file

@ -0,0 +1,14 @@
import "../../../styles/globals.css";
import { Menu } from "../../../components/UI/Elements/Menu";
import AuthProvider from "../../../components/Security/AuthProvider";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AuthProvider>
<Menu></Menu>
{children}
</AuthProvider>
</>
);
}

View file

@ -1,10 +1,7 @@
"use client"; "use client";
import { useRouter, useSearchParams, useSelectedLayoutSegment } from "next/navigation"; import { Title } from "@components/UI/Elements/Styles/Title";
import Layout from "../../../components/UI/Layout";
import { Title } from "../../../components/UI/Elements/Styles/Title";
import { Header } from "../../../components/UI/Header";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from 'next/navigation'; import { usePathname } from "next/navigation";
const OrgHomePage = (params: any) => { const OrgHomePage = (params: any) => {
const orgslug = params.params.orgslug; const orgslug = params.params.orgslug;
@ -12,13 +9,10 @@ const OrgHomePage = (params: any) => {
return ( return (
<div> <div>
<Layout orgslug={orgslug} title={"Org " + orgslug}>
<Header></Header>
<Title>Welcome {orgslug} 👋🏻</Title> <Title>Welcome {orgslug} 👋🏻</Title>
<Link href={pathname + "/courses"}> <Link href={pathname + "/courses"}>
<button>See Courses </button> <button>See Courses </button>
</Link> </Link>
</Layout>
</div> </div>
); );
}; };

View file

@ -0,0 +1,25 @@
"use client";
import { motion } from "framer-motion";
export default function Template({ children }: { children: React.ReactNode }) {
const variants = {
hidden: { opacity: 0, x: 0, y: 0 },
enter: { opacity: 1, x: 0, y: 0 },
exit: { opacity: 0, x: 0, y: 0 },
};
return (
<div>
<motion.main
variants={variants} // Pass the variant object into Framer Motion
initial="hidden" // Set the initial state to variants.hidden
animate="enter" // Animated state to variants.enter
exit="exit" // Exit state (used later) to variants.exit
transition={{ type: "linear" }} // Set the transition to linear
className=""
>
{children}
</motion.main>
</div>
);
}

View file

@ -1,15 +1,31 @@
import '../styles/globals.css' "use client";
import StyledComponentsRegistry from '../services/lib/styled-registry' import "../styles/globals.css";
import StyledComponentsRegistry from "../components/lib/styled-registry";
import { motion } from "framer-motion";
export default function RootLayout({ export default function RootLayout({ children }: { children: React.ReactNode }) {
children, const variants = {
}: { hidden: { opacity: 0, x: 0, y: 0 },
children: React.ReactNode enter: { opacity: 1, x: 0, y: 0 },
}) { exit: { opacity: 0, x: 0, y: 0 },
};
return ( return (
<html> <html className="" lang="en">
<head /> <head />
<body> <StyledComponentsRegistry>{children}</StyledComponentsRegistry></body> <body>
<StyledComponentsRegistry>
<motion.main
variants={variants} // Pass the variant object into Framer Motion
initial="hidden" // Set the initial state to variants.hidden
animate="enter" // Animated state to variants.enter
exit="exit" // Exit state (used later) to variants.exit
transition={{ type: "linear" }} // Set the transition to linear
className=""
>
{children}
</motion.main>
</StyledComponentsRegistry>
</body>
</html> </html>
) );
} }

View file

@ -34,7 +34,7 @@ const Login = () => {
return ( return (
<div> <div>
<Layout title="Login"> < >
<Header></Header> <Header></Header>
<Title>Login</Title> <Title>Login</Title>
@ -45,7 +45,7 @@ const Login = () => {
Login Login
</button> </button>
</form> </form>
</Layout> </>
</div> </div>
); );
}; };

View file

@ -6,7 +6,7 @@ import learnhouseBigIcon from "public/learnhouse_bigicon.png";
import Image from "next/legacy/image"; import Image from "next/legacy/image";
import Link from "next/link"; import Link from "next/link";
const Home: NextPage = () => { export default function Home() {
return ( return (
<HomePage> <HomePage>
<motion.div <motion.div
@ -89,4 +89,3 @@ const HomePage = styled.div`
} }
`; `;
export default Home;

View file

@ -1,3 +1,4 @@
"use client";
import React from "react"; import React from "react";
import { Header } from "../../components/UI/Header"; import { Header } from "../../components/UI/Header";
import Layout from "../../components/UI/Layout"; import Layout from "../../components/UI/Layout";

View file

@ -18,6 +18,7 @@ import WarningCallout from "./Extensions/Callout/Warning/WarningCallout";
import ImageBlock from "./Extensions/Image/ImageBlock"; import ImageBlock from "./Extensions/Image/ImageBlock";
import Youtube from "@tiptap/extension-youtube"; import Youtube from "@tiptap/extension-youtube";
import VideoBlock from "./Extensions/Video/VideoBlock"; import VideoBlock from "./Extensions/Video/VideoBlock";
import { Save } from "lucide-react";
interface Editor { interface Editor {
content: string; content: string;
@ -97,7 +98,9 @@ function Editor(props: Editor) {
{" "} {" "}
<b>{props.course.course.name}</b> <SlashIcon /> {props.element.name}{" "} <b>{props.course.course.name}</b> <SlashIcon /> {props.element.name}{" "}
</EditorInfoDocName> </EditorInfoDocName>
<EditorSaveButton onClick={() => props.setContent(editor.getJSON())}>Save</EditorSaveButton> <EditorSaveButton onClick={() => props.setContent(editor.getJSON())}>
Save <Save size={12} />
</EditorSaveButton>
</EditorInfoWrapper> </EditorInfoWrapper>
<EditorButtonsWrapper> <EditorButtonsWrapper>
<ToolbarButtons editor={editor} /> <ToolbarButtons editor={editor} />
@ -146,7 +149,7 @@ const Page = styled.div`
`; `;
const EditorTop = styled.div` const EditorTop = styled.div`
background-color: #ffffffb8; background-color: #ffffffeb;
border-radius: 15px; border-radius: 15px;
backdrop-filter: saturate(180%) blur(14px); backdrop-filter: saturate(180%) blur(14px);
margin: 40px; margin: 40px;
@ -213,24 +216,28 @@ const EditorInfoDocName = styled.div`
const EditorSaveButton = styled.div` const EditorSaveButton = styled.div`
display: flex; display: flex;
border-radius: 6px; border-radius: 8px;
padding: 5px; padding: 5px;
font-size: 12px; font-size: 12px;
margin-right: 5px; margin-right: 5px;
margin-left: 7px; margin-left: 7px;
background: rgba(176, 176, 176, 0.145); background: #ffffff8d;
color: #5252528d;
border: solid 1px #52525257;
align-items: center;
justify-content: space-between;
width: 53px;
&.is-active { &.is-active {
background: rgba(176, 176, 176, 0.5); background: rgba(176, 176, 176, 0.5);
&:hover { &:hover {
background: rgba(139, 139, 139, 0.5); background: rgba(31, 31, 31, 0.5);
cursor: pointer; cursor: pointer;
} }
} }
&:hover { &:hover {
background: rgba(217, 217, 217, 0.48);
cursor: pointer; cursor: pointer;
} }
`; `;

View file

@ -2,12 +2,13 @@ import React from "react";
import { useEditor, EditorContent } from "@tiptap/react"; import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit"; import StarterKit from "@tiptap/starter-kit";
// Custom Extensions // Custom Extensions
import InfoCallout from "../Editor/Extensions/Callout/Info/InfoCallout"; import InfoCallout from "@editor/Extensions/Callout/Info/InfoCallout";
import WarningCallout from "../Editor/Extensions/Callout/Warning/WarningCallout"; import WarningCallout from "@editor/Extensions/Callout/Warning/WarningCallout";
import ImageBlock from "../Editor/Extensions/Image/ImageBlock"; import ImageBlock from "@editor/Extensions/Image/ImageBlock";
import Youtube from "@tiptap/extension-youtube"; import Youtube from "@tiptap/extension-youtube";
import { EditorContentWrapper } from "../Editor/Editor"; import { EditorContentWrapper } from "@editor/Editor";
import VideoBlock from "../Editor/Extensions/Video/VideoBlock"; import VideoBlock from "@editor/Extensions/Video/VideoBlock";
import { styled } from "styled-components";
interface Editor { interface Editor {
content: string; content: string;
@ -46,10 +47,16 @@ function Canva(props: Editor) {
}); });
return ( return (
<EditorContentWrapper> <CanvaWrapper>
<EditorContent editor={editor} /> <EditorContent editor={editor} />
</EditorContentWrapper> </CanvaWrapper>
); );
} }
const CanvaWrapper = styled.div`
padding-top: 20px;
width: 1300px;
margin: 0 auto;
`;
export default Canva; export default Canva;

View file

@ -0,0 +1,72 @@
import { getBackendUrl } from "@services/config";
import React from "react";
import styled from "styled-components";
function VideoLecture({ element, course }: { element: any; course: any }) {
function getChapterName() {
let chapterName = "";
let chapterId = element.chapter_id;
course.chapters.forEach((chapter: any) => {
if (chapter.chapter_id === chapterId) {
chapterName = chapter.name;
}
});
return chapterName;
}
return (
<VideoLectureLayout>
<VideoTitle>
<p>Chapter : {getChapterName()}</p>
{element.name}
</VideoTitle>
<VideoPlayerWrapper>
<video controls src={`${getBackendUrl()}content/uploads/video/${element.content.video.element_id}/${element.content.video.filename}`}></video>
</VideoPlayerWrapper>
</VideoLectureLayout>
);
}
export default VideoLecture;
const VideoLectureLayout = styled.div`
display: flex;
flex-direction: column;
margin-top: 10px;
background: #141414;
min-width: 100%;
min-height: 1200px;
`;
const VideoTitle = styled.div`
display: flex;
width: 1300px;
margin: 0 auto;
padding-top: 20px;
font-size: 24px;
font-weight: 700;
color: #fff;
flex-direction: column;
p {
font-size: 14px;
padding: 0;
margin: 0;
color: #ffffffaa;
}
`;
const VideoPlayerWrapper = styled.div`
display: flex;
width: 1300px;
margin: 0 auto;
justify-content: center;
padding-top: 20px;
video {
width: 1300px;
height: 500px;
border-radius: 7px;
background-color: black;
}
`;

View file

@ -2,7 +2,6 @@ import React, { useState } from "react";
import { ArrowLeftIcon, Cross1Icon } from "@radix-ui/react-icons"; import { ArrowLeftIcon, Cross1Icon } from "@radix-ui/react-icons";
import Modal from "../Modal"; import Modal from "../Modal";
import styled from "styled-components"; import styled from "styled-components";
import dynamic from "next/dynamic";
import DynamicCanvaModal from "./NewElementModal/DynamicCanva"; import DynamicCanvaModal from "./NewElementModal/DynamicCanva";
import VideoModal from "./NewElementModal/Video"; import VideoModal from "./NewElementModal/Video";

View file

@ -34,10 +34,7 @@ const AuthProvider = ({ children }: any) => {
userInfo = await getUserInfo(access_token); userInfo = await getUserInfo(access_token);
setAuth({ access_token, isAuthenticated: true, userInfo, isLoading }); setAuth({ access_token, isAuthenticated: true, userInfo, isLoading });
// if user is authenticated and tries to access login or signup page, redirect to home
if (NON_AUTHENTICATED_ROUTES.includes(router.pathname)) {
router.push("/");
}
} else { } else {
setAuth({ access_token, isAuthenticated: false, userInfo, isLoading }); setAuth({ access_token, isAuthenticated: false, userInfo, isLoading });
//router.push("/login"); //router.push("/login");

View file

@ -1,4 +1,4 @@
"use client";
import React from "react"; import React from "react";
import Head from "next/head"; import Head from "next/head";
import styled from "styled-components"; import styled from "styled-components";
@ -14,8 +14,6 @@ const Layout = (props: any) => {
}; };
return ( return (
<html>
<body>
<AuthProvider> <AuthProvider>
<ProjectPhaseLabel>🚧 Dev Phase</ProjectPhaseLabel> <ProjectPhaseLabel>🚧 Dev Phase</ProjectPhaseLabel>
<Menu orgslug={props.orgslug}></Menu> <Menu orgslug={props.orgslug}></Menu>
@ -33,8 +31,6 @@ const Layout = (props: any) => {
<p>LearnHouse © 2021 - {new Date().getFullYear()} - All rights reserved</p> <p>LearnHouse © 2021 - {new Date().getFullYear()} - All rights reserved</p>
</Footer> </Footer>
</AuthProvider> </AuthProvider>
</body>
</html>
); );
}; };

View file

@ -0,0 +1,30 @@
'use client';
import React, { useState } from 'react';
import { useServerInsertedHTML } from 'next/navigation';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
export default function StyledComponentsRegistry({
children,
}: {
children: React.ReactNode;
}) {
// Only create stylesheet once with lazy initial state
// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());
useServerInsertedHTML(() => {
const styles = styledComponentsStyleSheet.getStyleElement();
styledComponentsStyleSheet.instance.clearTag();
return <>{styles}</>;
});
if (typeof window !== 'undefined') return <>{children}</>;
return (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
{children as React.ReactChild}
</StyleSheetManager>
);
}

3673
front/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -24,7 +24,7 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"styled-components": "^5.3.5", "styled-components": "^6.0.0-beta.9",
"y-indexeddb": "^9.0.9", "y-indexeddb": "^9.0.9",
"y-webrtc": "^10.2.3", "y-webrtc": "^10.2.3",
"yjs": "^13.5.42" "yjs": "^13.5.42"

View file

@ -76,3 +76,5 @@ export async function signup(body: NewAccountBody): Promise<any> {
.then((result) => result.json()) .then((result) => result.json())
.catch((error) => console.log("error", error)); .catch((error) => console.log("error", error));
} }

View file

@ -1,11 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es5",
"lib": [ "lib": ["dom", "dom.iterable", "esnext"],
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true, "allowJs": true,
"skipLibCheck": true, "skipLibCheck": true,
"strict": true, "strict": true,
@ -22,32 +18,17 @@
{ {
"name": "next" "name": "next"
} }
]
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
], ],
"baseUrl": ".",
"paths": { "paths": {
"@components/*": [ "@components/*": ["components/*"],
"components/*" "@public/*": ["public/*"],
], "@images/*": ["public/img/*"],
"@public/*": [ "@services/*": ["services/*"],
"public/*" "@editor/*": ["components/Editor/*"]
], }
"@images/*": [ },
"public/img/*" "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
],
"@services/*": [ "exclude": ["node_modules"]
"services/*"
],
"@editor/*": [
"components/Editor/*"
]
},
"exclude": [
"node_modules"
]
} }