Merge pull request #96 from learnhouse/swve/eng-73-fix-ui-imperfections

Fix UI Imperfections
This commit is contained in:
Badr B 2023-06-22 20:49:46 +02:00 committed by GitHub
commit 5eaa235a92
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
80 changed files with 691 additions and 980 deletions

View file

@ -6,7 +6,7 @@ export async function GET(request: NextRequest) {
revalidateTag(tag);
return NextResponse.json(
{ revalidated: true, now: Date.now() },
{ revalidated: true, now: Date.now(), tag },
{
status: 200,
headers: {

View file

@ -1,4 +1,4 @@
import PageLoading from "@components/Pages/PageLoading";
import PageLoading from "@components/Objects/Loaders/PageLoading";
export default function Loading() {
// Or a custom loading skeleton component

View file

@ -1,7 +1,7 @@
import { default as React, } from "react";
import { useRouter } from "next/navigation";
import AuthProvider from "@components/Security/AuthProvider";
import EditorWrapper from "@components/Editor/EditorWrapper";
import EditorWrapper from "@components/Objects/Editor/EditorWrapper";
import { getAPIUrl } from "@services/config/config";
import { swrFetcher } from "@services/utils/ts/requests";
import { getOrganizationContextInfo } from "@services/organizations/orgs";

View file

@ -1,6 +1,6 @@
"use client";
import "../styles/globals.css";
import StyledComponentsRegistry from "../components/UI/libs/styled-registry";
import StyledComponentsRegistry from "../components/Utils/libs/styled-registry";
import { motion } from "framer-motion";
export default function RootLayout({ children }: { children: React.ReactNode }) {

View file

@ -1,6 +1,5 @@
"use client";
import React from "react";
import { Title } from "../../../components/UI/Elements/Styles/Title";
import { createNewOrganization } from "../../../services/organizations/orgs";
const Organizations = () => {
@ -35,7 +34,7 @@ const Organizations = () => {
return (
<div>
<Title>New Organization</Title>
<div className="font-bold text-lg">New Organization</div>
Name: <input onChange={handleNameChange} type="text" />
<br />
Description: <input onChange={handleDescriptionChange} type="text" />

View file

@ -1,7 +1,6 @@
"use client"; //todo: use server components
import Link from "next/link";
import React from "react";
import { Title } from "../../components/UI/Elements/Styles/Title";
import { deleteOrganizationFromBackend } from "@services/organizations/orgs";
import useSWR, { mutate } from "swr";
import { swrFetcher } from "@services/utils/ts/requests";
@ -19,14 +18,14 @@ const Organizations = () => {
return (
<>
<AuthProvider />
<Title>
<div className="font-bold text-lg">
Your Organizations{" "}
<Link href="/organizations/new">
<button className="bg-blue-500 text-white px-2 py-1 rounded-md hover:bg-blue-600 focus:outline-none">
+
</button>
</Link>
</Title>
</div>
<hr />
{error && <p className="text-red-500">Failed to load</p>}

View file

@ -1,6 +1,6 @@
'use client'; // Error components must be Client Components
import ErrorUI from '@components/UI/Error/Error';
import ErrorUI from '@components/StyledElements/Error/Error';
import { useEffect } from 'react';
export default function Error({

View file

@ -1,4 +1,4 @@
import PageLoading from "@components/Pages/PageLoading";
import PageLoading from "@components/Objects/Loaders/PageLoading";
export default function Loading() {
return (

View file

@ -1,3 +1,4 @@
import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper";
import { getBackendUrl, getUriWithOrg } from "@services/config/config";
import { getCollectionByIdWithAuthHeader } from "@services/courses/collections";
import { getOrganizationContextInfo } from "@services/organizations/orgs";
@ -38,7 +39,7 @@ const CollectionPage = async (params : any) => {
}
return <div className="max-w-7xl mx-auto px-4 py-10" >
return <GeneralWrapperStyled>
<h2 className="text-sm font-bold text-gray-400">Collection</h2>
<h1 className="text-3xl font-bold">{col.name}</h1>
<br />
@ -56,7 +57,7 @@ const CollectionPage = async (params : any) => {
</div>;
</GeneralWrapperStyled>;
};
export default CollectionPage;

View file

@ -1,70 +1,34 @@
'use client';
import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement';
import { AuthContext } from '@components/Security/AuthProvider';
import { getUriWithOrg } from '@services/config/config';
import { deleteCollection } from '@services/courses/collections';
import { revalidateTags } from '@services/utils/ts/requests';
import { Link, Trash } from 'lucide-react';
import { useRouter } from 'next/navigation';
import React from 'react'
const CollectionAdminEditsArea = (props: any) => {
const org_roles_values = ["admin", "owner"];
const user_roles_values = ["role_admin"];
const auth: any = React.useContext(AuthContext);
// this is amazingly terrible code, but gotta release that MVP
// TODO: fix this
function isAuthorized() {
const org_id = props.collection.org_id;
const org_roles = auth.userInfo.user_object.orgs;
const user_roles = auth.userInfo.user_object.roles;
const org_role = org_roles.find((org: any) => org.org_id == org_id);
const user_role = user_roles.find((role: any) => role.org_id == org_id);
if (org_role && user_role) {
if (org_roles_values.includes(org_role.org_role) && user_roles_values.includes(user_role.role_id)) {
return true;
}
else {
return false;
}
} else {
return false;
}
}
const router = useRouter();
const deleteCollectionUI = async (collectionId: number) => {
await deleteCollection(collectionId);
revalidateTags(["collections"]);
// reload the page
window.location.reload();
router.refresh();
router.push(getUriWithOrg(props.orgslug, "/collections"));
}
// this is amazingly terrible code, but gotta release that MVP
// TODO: fix this
if (auth.isAuthenticated) {
if (isAuthorized()) {
return (
<div className="flex space-x-2 py-2">
<button className="rounded-md text-sm px-3 font-bold text-red-800 bg-red-200 w-16 flex justify-center items-center" onClick={() => deleteCollectionUI(props.collection_id)}>
Delete <Trash size={10}></Trash>
</button>
</div>
)
} else {
return (
<div></div>
)
}
}
else {
return (
<div></div>
)
}
return (
<AuthenticatedClientElement orgId={props.org_id} checkMethod='roles'>
<div className="flex space-x-2 py-2">
<button className="rounded-md text-sm px-3 font-bold text-red-800 bg-red-200 w-16 flex justify-center items-center" onClick={() => deleteCollectionUI(props.collection_id)}>
Delete <Trash size={10}></Trash>
</button>
</div>
</AuthenticatedClientElement>
)
}
export default CollectionAdminEditsArea;

View file

@ -1,4 +1,4 @@
import PageLoading from "@components/Pages/PageLoading";
import PageLoading from "@components/Objects/Loaders/PageLoading";
export default function Loading() {
// Or a custom loading skeleton component

View file

@ -1,7 +1,6 @@
"use client";
import { useRouter } from "next/navigation";
import React from "react";
import { Title } from "@components/UI/Elements/Styles/Title";
import { createCollection } from "@services/courses/collections";
import useSWR from "swr";
import { getAPIUrl, getUriWithOrg } from "@services/config/config";
@ -45,14 +44,16 @@ function NewCollection(params: any) {
};
await createCollection(collection);
revalidateTags(["collections"]);
router.prefetch(getUriWithOrg(orgslug, "/collections"));
router.push(getUriWithOrg(orgslug, "/collections"));
router.refresh();
};
return (
<>
<div className="w-64 m-auto py-20">
<Title className="mb-4">Add new</Title>
<div className="font-bold text-lg mb-4">Add new</div>
<input
type="text"

View file

@ -1,13 +1,12 @@
import AuthenticatedClientElement from "@components/Security/AuthenticatedClientElement";
import TypeOfContentTitle from "@components/StyledElements/Titles/TypeOfContentTitle";
import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper";
import { getBackendUrl, getUriWithOrg } from "@services/config/config";
import { deleteCollection, getOrgCollectionsWithAuthHeader } from "@services/courses/collections";
import { getCourseMetadataWithAuthHeader } from "@services/courses/courses";
import { getOrganizationContextInfo } from "@services/organizations/orgs";
import { revalidateTags } from "@services/utils/ts/requests";
import { Metadata } from "next";
import { revalidateTag } from "next/cache";
import { cookies } from "next/headers";
import Link from "next/link";
import { Title } from "../courses/courses";
import CollectionAdminEditsArea from "./admin";
type MetadataProps = {
@ -42,17 +41,19 @@ const CollectionsPage = async (params: any) => {
const collections = await getOrgCollectionsWithAuthHeader(org_id, access_token_cookie ? access_token_cookie.value : null);
return (
<div className="max-w-7xl mx-auto px-4 py-10" >
<GeneralWrapperStyled>
<div className="flex justify-between" >
<Title title="Collections" type="col" />
<TypeOfContentTitle title="Collections" type="col" />
<AuthenticatedClientElement checkMethod='authentication'>
<Link className="flex justify-center" href={getUriWithOrg(orgslug, "/collections/new")}>
<button className="rounded-md bg-black antialiased ring-offset-purple-800 p-2 px-5 my-auto font text-sm font-bold text-white drop-shadow-lg">Add Collection + </button>
</Link>
</AuthenticatedClientElement>
</div>
<div className="home_collections flex flex-wrap">
{collections.map((collection: any) => (
<div className="pr-8 flex flex-col" key={collection.collection_id}>
<CollectionAdminEditsArea collection_id={collection.collection_id} collection={collection} />
<div className="flex flex-col py-3 px-3" key={collection.collection_id}>
<CollectionAdminEditsArea org_id={org_id} collection_id={collection.collection_id} collection={collection} />
<Link href={getUriWithOrg(orgslug, "/collection/" + removeCollectionPrefix(collection.collection_id))}>
<div className="inset-0 ring-1 ring-inset ring-black/10 rounded-lg shadow-xl relative w-[249px] h-[180px] bg-cover flex flex-col items-center justify-center bg-indigo-600 font-bold text-zinc-50" >
<h1 className="font-bold text-lg py-2 justify-center mb-2">{collection.name}</h1>
@ -68,7 +69,7 @@ const CollectionsPage = async (params: any) => {
</div>
))}
</div>
</div>
</GeneralWrapperStyled>
);
}

View file

@ -1,15 +1,15 @@
"use client";
import Link from "next/link";
import React, { useMemo } from "react";
import React from "react";
import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config";
import Canva from "@components/Pages/Activities/DynamicCanva/DynamicCanva";
import styled from "styled-components";
import VideoActivity from "@components/Pages/Activities/Video/Video";
import useSWR, { mutate } from "swr";
import { Check } from "lucide-react";
import { markActivityAsComplete } from "@services/courses/activity";
import ToolTip from "@components/UI/Tooltip/Tooltip";
import DocumentPdfActivity from "@components/Pages/Activities/DocumentPdf/DocumentPdf";
import ActivityIndicators from "@components/Pages/Courses/ActivityIndicators";
import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper";
import { useRouter } from "next/navigation";
interface ActivityClientProps {
activityid: string;
@ -19,6 +19,7 @@ interface ActivityClientProps {
course: any;
}
function ActivityClient(props: ActivityClientProps) {
const activityid = props.activityid;
const courseid = props.courseid;
@ -26,195 +27,104 @@ function ActivityClient(props: ActivityClientProps) {
const activity = props.activity;
const course = props.course;
async function markActivityAsCompleteFront() {
const trail = await markActivityAsComplete(orgslug, courseid, activityid);
mutate(`${getAPIUrl()}activities/activity_${activityid}`);
mutate(`${getAPIUrl()}courses/meta/course_${courseid}`);
function getChapterName(chapterId: string) {
let chapterName = "";
course.chapters.forEach((chapter: any) => {
if (chapter.chapter_id === chapterId) {
chapterName = chapter.name;
}
});
return chapterName;
}
return (
<>
<ActivityLayout>
<pre style={{ display: "none" }}>{JSON.stringify(activity, null, 2)}</pre>
<ActivityTopWrapper>
<ActivityThumbnail>
<GeneralWrapperStyled>
<div className="space-y-4 pt-4">
<div className="flex space-x-6">
<div className="flex">
<Link href={getUriWithOrg(orgslug, "") + `/course/${courseid}`}>
<img src={`${getBackendUrl()}content/uploads/img/${course.course.thumbnail}`} alt="" />
<img className="w-[100px] h-[57px] rounded-md drop-shadow-md" src={`${getBackendUrl()}content/uploads/img/${course.course.thumbnail}`} alt="" />
</Link>
</ActivityThumbnail>
<ActivityInfo>
<p>Course</p>
<h1>{course.course.name}</h1>
</ActivityInfo>
</ActivityTopWrapper>
<ChaptersWrapper>
{course.chapters.map((chapter: any) => {
return (
<>
<div style={{ display: "flex", flexDirection: "row" }} key={chapter.chapter_id}>
{chapter.activities.map((activity: any) => {
return (
<ToolTip sideOffset={-5} slateBlack content={activity.name} key={activity.id}>
<Link href={getUriWithOrg(orgslug, "") + `/course/${courseid}/activity/${activity.id.replace("activity_", "")}`}>
<ChapterIndicator
done={course.trail.activities_marked_complete && course.trail.activities_marked_complete.includes(activity.id) && course.trail.status == "ongoing"}
active={"activity_" + activityid === activity.id ? true : false} key={activity.id}
/>
</Link>
</ToolTip>
);
})}
</div>
&nbsp;&nbsp;&nbsp;&nbsp;
</>
);
})}
</ChaptersWrapper>
</div>
<div className="flex flex-col -space-y-1">
<p className="font-bold text-gray-700 text-md">Course </p>
<h1 className="font-bold text-gray-950 text-2xl first-letter:uppercase" >{course.course.name}</h1>
</div>
</div>
<ActivityIndicators current_activity={activityid} orgslug={orgslug} course={course} />
<div className="flex justify-between items-center">
<div className="flex flex-col -space-y-1">
<p className="font-bold text-gray-700 text-md">Chapter : {getChapterName(activity.chapter_id)}</p>
<h1 className="font-bold text-gray-950 text-2xl first-letter:uppercase" >{activity.name}</h1>
</div>
<div className="flex space-x-2">
<MarkStatus activityid={activityid} course={course} orgslug={orgslug} courseid={courseid} />
</div>
</div>
{activity ? (
<CourseContent>
{activity.type == "dynamic" && <Canva content={activity.content} activity={activity} />}
{/* todo : use apis & streams instead of this */}
{activity.type == "video" && <VideoActivity course={course} activity={activity} />}
<div className={`p-7 pt-2 drop-shadow-sm rounded-lg ${activity.type == 'dynamic' ? 'bg-white' : 'bg-zinc-950'}`}>
<div>
{activity.type == "dynamic" && <Canva content={activity.content} activity={activity} />}
{/* todo : use apis & streams instead of this */}
{activity.type == "video" && <VideoActivity course={course} activity={activity} />}
{activity.type == "documentpdf" && <DocumentPdfActivity course={course} activity={activity} />}
{activity.type == "documentpdf" && <DocumentPdfActivity course={course} activity={activity} />}
<ActivityMarkerWrapper className="py-10">
<div className="py-10">
{course.trail.activities_marked_complete &&
course.trail.activities_marked_complete.includes("activity_" + activityid) &&
course.trail.status == "ongoing" ? (
<button style={{ backgroundColor: "green" }}>
<i>
<Check size={20}></Check>
</i>{" "}
Already completed
</button>
) : (
<button onClick={markActivityAsCompleteFront}>
{" "}
<i>
<Check size={20}></Check>
</i>{" "}
Mark as complete
</button>
)}
</ActivityMarkerWrapper>
</CourseContent>
</div>
</div>
</div>
) : (<div></div>)}
{<div style={{ height: "100px" }}></div>}
</ActivityLayout>
</div>
</GeneralWrapperStyled>
</>
);
}
const ActivityLayout = styled.div``;
const ActivityThumbnail = 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 ActivityInfo = styled.div`
h1 {
margin-top: 0px;
export function MarkStatus(props: { activityid: string, course: any, orgslug: string, courseid: string }) {
const router = useRouter();
async function markActivityAsCompleteFront() {
const trail = await markActivityAsComplete(props.orgslug, props.courseid, props.activityid);
router.refresh();
}
p {
margin-top: 0;
margin-bottom: 0;
font-weight: 700;
}
`;
return (
<>{props.course.trail.activities_marked_complete &&
props.course.trail.activities_marked_complete.includes("activity_" + props.activityid) &&
props.course.trail.status == "ongoing" ? (
<div className="bg-teal-600 rounded-md drop-shadow-md flex flex-col p-3 text-sm text-white hover:cursor-pointer transition delay-150 duration-300 ease-in-out" >
<i>
<Check size={15}></Check>
</i>{" "}
Already completed
</div>
) : (
<div className="bg-zinc-600 rounded-md drop-shadow-md flex flex-col p-3 text-sm text-white hover:cursor-pointer transition delay-150 duration-300 ease-in-out" onClick={markActivityAsCompleteFront}>
{" "}
<i>
<Check size={15}></Check>
</i>{" "}
Mark as complete
</div>
)}</>
)
}
const ChaptersWrapper = styled.div`
display: flex;
// row
flex-direction: row;
width: 100%;
width: 1300px;
margin: 0 auto;
`;
const ChapterIndicator = styled.div < { active?: boolean, done?: boolean } > `
border-radius: 20px;
height: 5px;
background: #151515;
border-radius: 3px;
width: 35px;
background-color: ${props => props.done ? "green" : (props.active ? "#9d9d9d" : "black")};
margin: 10px;
margin-bottom: 0px;
margin-left: 0px;
&:hover {
cursor: pointer;
background-color: #9d9d9d;
}
`;
const ActivityTopWrapper = styled.div`
width: 1300px;
padding-top: 50px;
margin: 0 auto;
display: flex;
`;
const CourseContent = styled.div`
display: flex;
flex-direction: column;
background-color: white;
min-height: 600px;
`;
const ActivityMarkerWrapper = styled.div`
display: block;
width: 1300px;
justify-content: flex-end;
margin: 0 auto;
align-items: center;
button {
background-color: #151515;
border: none;
padding: 18px;
border-radius: 15px;
margin: 15px;
margin-left: 20px;
margin-top: 20px;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
margin: auto;
color: white;
font-weight: 700;
font-family: "DM Sans";
font-size: 16px;
letter-spacing: -0.05em;
box-shadow: 0px 13px 33px -13px rgba(0, 0, 0, 0.42);
i {
margin-right: 5px;
// center the icon
display: flex;
align-items: center;
justify-content: center;
}
&:hover {
background-color: #000000;
}
}
`;
export default ActivityClient;

View file

@ -1,6 +1,6 @@
'use client'; // Error components must be Client Components
import ErrorUI from '@components/UI/Error/Error';
import ErrorUI from '@components/StyledElements/Error/Error';
import { useEffect } from 'react';
export default function Error({

View file

@ -1,4 +1,4 @@
import PageLoading from "@components/Pages/PageLoading";
import PageLoading from "@components/Objects/Loaders/PageLoading";
export default function Loading() {
// Or a custom loading skeleton component

View file

@ -2,68 +2,75 @@
import { EyeOpenIcon, Pencil2Icon } from "@radix-ui/react-icons";
import { removeCourse, startCourse } from "@services/courses/activity";
import Link from "next/link";
import React from "react";
import React, { use } from "react";
import styled from "styled-components";
import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config";
import useSWR, { mutate } from "swr";
import ToolTip from "@components/UI/Tooltip/Tooltip";
import PageLoading from "@components/Pages/PageLoading";
import ToolTip from "@components/StyledElements/Tooltip/Tooltip";
import PageLoading from "@components/Objects/Loaders/PageLoading";
import { revalidateTags } from "@services/utils/ts/requests";
import ActivityIndicators from "@components/Pages/Courses/ActivityIndicators";
import { useRouter } from "next/navigation";
import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper";
const CourseClient = (props: any) => {
const courseid = props.courseid;
const orgslug = props.orgslug;
const course = props.course;
const router = useRouter();
async function startCourseUI() {
// Create activity
await startCourse("course_" + courseid, orgslug);
revalidateTags(['courses']);
router.refresh();
}
async function quitCourse() {
// Close activity
let activity = await removeCourse("course_" + courseid, orgslug);
// Mutate course
revalidateTags(['courses']);
router.refresh();
}
console.log(course);
return (
<>
{!course ? (
<PageLoading></PageLoading>
) : (
<CoursePageLayout className="pt-6">
<p className="text-lg font-bold">Course</p>
<h1 className="text-3xl font-bold flex items-center space-x-5">
{course.course.name}{" "}
<Link href={getUriWithOrg(orgslug, "") + `/course/${courseid}/edit`} rel="noopener noreferrer">
<Pencil2Icon />
</Link>{" "}
</h1>
<GeneralWrapperStyled>
<div className="pb-3">
<p className="text-md font-bold text-gray-400 pb-2">Course</p>
<h1 className="text-3xl -mt-3 font-bold">
{course.course.name}
</h1>
</div>
<CourseThumbnailWrapper>
<img src={`${getBackendUrl()}content/uploads/img/${course.course.thumbnail}`} alt="" />
</CourseThumbnailWrapper>
<CourseMetaWrapper>
<CourseMetaLeft>
<h2 className="py-3 font-bold">Description</h2>
<div className="inset-0 ring-1 ring-inset ring-black/10 rounded-lg shadow-xl relative w-auto h-[300px] bg-cover bg-center mb-4" style={{ backgroundImage: `url(${getBackendUrl()}content/uploads/img/${course.course.thumbnail})` }}>
<BoxWrapper>
</div>
<ActivityIndicators orgslug={orgslug} course={course} />
<div className="flex flex-row pt-10 flex-wrap">
<div className="course_metadata_left grow space-y-2">
<h2 className="py-3 text-2xl font-bold">Description</h2>
<StyledBox>
<p className="py-3">{course.course.description}</p>
</BoxWrapper>
</StyledBox>
<h2 className="py-3 text-2xl font-bold">What you will learn</h2>
<StyledBox>
<h2 className="py-3 font-bold">What you will learn</h2>
<BoxWrapper>
<p className="py-3">{course.learnings == ![] ? "no data" : course.learnings}</p>
</BoxWrapper>
</StyledBox>
<h2 className="py-3 font-bold">Course Lessons</h2>
<BoxWrapper>
<h2 className="py-3 text-2xl font-bold">Course Lessons</h2>
<StyledBox>
{course.chapters.map((chapter: any) => {
return (
<div
@ -88,142 +95,32 @@ const CourseClient = (props: any) => {
</div>
);
})}
</BoxWrapper>
</CourseMetaLeft>
<CourseMetaRight>
</StyledBox>
</div>
<div className="course_metadata_right w-64 flex items-center ml-10 h-28 p-3 bg-white rounded-md justify-center drop-shadow-[0_33px_13px_rgba(0,0,0,0.042)] transition-all">
{course.trail.status == "ongoing" ? (
<button style={{ backgroundColor: "red" }} onClick={quitCourse}>
<button className="py-2 px-5 rounded-xl text-white font-bold h-12 w-[200px] drop-shadow-md bg-red-600 hover:bg-red-700 hover:cursor-pointer" onClick={quitCourse}>
Quit Course
</button>
) : (
<button onClick={startCourseUI}>Start Course</button>
<button className="py-2 px-5 rounded-xl text-white font-bold h-12 w-[200px] drop-shadow-md bg-black hover:bg-gray-900 hover:cursor-pointer" onClick={startCourseUI}>Start Course</button>
)}
</CourseMetaRight>
</CourseMetaWrapper>
</CoursePageLayout>
</div>
</div>
</GeneralWrapperStyled>
)}
</>
);
};
const CourseThumbnailWrapper = styled.div`
display: flex;
padding-bottom: 20px;
img {
width: 100%;
height: 300px;
object-fit: cover;
object-position: center;
background: url(), #d9d9d9;
border: 1px solid rgba(255, 255, 255, 0.19);
box-shadow: 0px 13px 33px -13px rgba(0, 0, 0, 0.42);
border-radius: 7px;
}
`;
const CoursePageLayout = styled.div`
width: 1300px;
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 StyledBox = (props: any) => (
<div className="p-3 pl-10 bg-white rounded-md w-[100%] h-auto drop-shadow-[0_33px_13px_rgba(0,0,0,0.042)]">
{props.children}
</div>
const ChaptersWrapper = styled.div`
display: flex;
width: 100%;
`;
const CourseIndicator = styled.div< { active?: boolean, done?: boolean } >`
border-radius: 20px;
height: 5px;
background: #151515;
border-radius: 3px;
);
background-color: ${props => props.done ? "green" : "black"};
width: 40px;
margin: 10px;
margin-bottom: 20px;
margin-left: 0px;
&:hover {
cursor: pointer;
background-color: #9d9d9d;
}
`;
const ChapterSeparator = styled.div`
display: flex;
flex-direction: row;
padding-right: 7px;
`;
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;
}
`;
const CourseMetaWrapper = styled.div`
display: flex;
justify-content: space-between;
`;
const CourseMetaLeft = styled.div`
width: 80%;
`;
const CourseMetaRight = styled.div`
background: #ffffff;
box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.03);
border-radius: 7px;
padding: 20px;
width: 30%;
display: flex;
height: 100%;
justify-content: center;
margin-left: 50px;
margin-top: 20px;
button {
width: 100%;
height: 50px;
background: #151515;
border-radius: 15px;
border: none;
color: white;
font-weight: 700;
font-family: "DM Sans";
font-size: 16px;
letter-spacing: -0.05em;
transition: all 0.2s ease;
box-shadow: 0px 13px 33px -13px rgba(0, 0, 0, 0.42);
&:hover {
cursor: pointer;
background: #000000;
}
}
`;
export default CourseClient;

View file

@ -3,18 +3,19 @@ import React from "react";
import { useState, useEffect } from "react";
import styled from "styled-components";
import { Title } from "@components/UI/Elements/Styles/Title";
import { DragDropContext, Droppable } from "react-beautiful-dnd";
import { initialData, initialData2 } from "@components/Pages/CourseEdit/Draggables/data";
import Chapter from "@components/Pages/CourseEdit/Draggables/Chapter";
import { createChapter, deleteChapter, getCourseChaptersMetadata, updateChaptersMetadata } from "@services/courses/chapters";
import { useRouter } from "next/navigation";
import NewChapterModal from "@components/Modals/Chapters/NewChapter";
import NewActivityModal from "@components/Modals/Activities/Create/NewActivity";
import NewChapterModal from "@components/Objects/Modals/Chapters/NewChapter";
import NewActivityModal from "@components/Objects/Modals/Activities/Create/NewActivity";
import { createActivity, createFileActivity, createExternalVideoActivity } from "@services/courses/activities";
import { getOrganizationContextInfo } from "@services/organizations/orgs";
import Modal from "@components/UI/Modal/Modal";
import Modal from "@components/StyledElements/Modal/Modal";
import { denyAccessToUser } from "@services/utils/react/middlewares/views";
import { Folders, Package2, SaveIcon } from "lucide-react";
import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper";
function CourseEdit(params: any) {
@ -240,120 +241,94 @@ function CourseEdit(params: any) {
return (
<>
<Page>
<Title>
Edit Course {" "}
<div
className="bg-gradient-radial bg-fixed bg-repeat bg-[0 0],[25px 25px] bg-[50px 50px] bg-[#4744446b 1px]"
>
<GeneralWrapperStyled>
<div className="font-bold text-lg flex space-x-2 items-center">
<p> Edit Course {" "}</p>
<div
className="bg-black hover:bg-gray-950 text-white font-bold p-1 px-2 text-sm rounded flex items-center cursor-pointer space-x-2"
onClick={() => {
updateChapters();
}}
>
<SaveIcon className="w-4 h-4" />
<p>Save</p>
</div>
</div>
<Modal
isDialogOpen={newChapterModal}
onOpenChange={setNewChapterModal}
minHeight="sm"
dialogContent={<NewChapterModal
closeModal={closeNewChapterModal}
submitChapter={submitChapter}
></NewChapterModal>}
dialogTitle="Create chapter"
dialogDescription="Add a new chapter to the course"
dialogTrigger={
<button> Add chapter +
</button>
}
isDialogOpen={newActivityModal}
onOpenChange={setNewActivityModal}
minHeight="no-min"
addDefCloseButton={false}
dialogContent={<NewActivityModal
closeModal={closeNewActivityModal}
submitFileActivity={submitFileActivity}
submitExternalVideo={submitExternalVideo}
submitActivity={submitActivity}
chapterId={newActivityModalData}
></NewActivityModal>}
dialogTitle="Create Activity"
dialogDescription="Choose between types of activities to add to the course"
/>
<button
onClick={() => {
updateChapters();
}}
>
Save
</button>
</Title>
<Modal
isDialogOpen={newActivityModal}
onOpenChange={setNewActivityModal}
minHeight="no-min"
addDefCloseButton={false}
dialogContent={<NewActivityModal
closeModal={closeNewActivityModal}
submitFileActivity={submitFileActivity}
submitExternalVideo={submitExternalVideo}
submitActivity={submitActivity}
chapterId={newActivityModalData}
></NewActivityModal>}
dialogTitle="Create Activity"
dialogDescription="Choose between types of activities to add to the course"
/>
<br />
{winReady && (
<ChapterlistWrapper>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable key="chapters" droppableId="chapters" type="chapter">
{(provided) => (
<>
<div key={"chapters"} {...provided.droppableProps} ref={provided.innerRef}>
{getChapters().map((info: any, index: any) => (
<>
<Chapter
orgslug={orgslug}
courseid={courseid}
openNewActivityModal={openNewActivityModal}
deleteChapter={deleteChapterUI}
key={index}
info={info}
index={index}
></Chapter>
</>
))}
{provided.placeholder}
</div>
</>
)}
</Droppable>
</DragDropContext>
</ChapterlistWrapper>
)}
</Page >
<br />
{winReady && (
<div className="flex flex-col max-w-7xl justify-center items-center mx-auto">
<DragDropContext onDragEnd={onDragEnd}>
<Droppable key="chapters" droppableId="chapters" type="chapter">
{(provided) => (
<>
<div key={"chapters"} {...provided.droppableProps} ref={provided.innerRef}>
{getChapters().map((info: any, index: any) => (
<>
<Chapter
orgslug={orgslug}
courseid={courseid}
openNewActivityModal={openNewActivityModal}
deleteChapter={deleteChapterUI}
key={index}
info={info}
index={index}
></Chapter>
</>
))}
{provided.placeholder}
</div>
</>
)}
</Droppable>
</DragDropContext>
<Modal
isDialogOpen={newChapterModal}
onOpenChange={setNewChapterModal}
minHeight="sm"
dialogContent={<NewChapterModal
closeModal={closeNewChapterModal}
submitChapter={submitChapter}
></NewChapterModal>}
dialogTitle="Create chapter"
dialogDescription="Add a new chapter to the course"
dialogTrigger={
<div className="flex max-w-7xl bg-black shadow rounded-md text-white justify-center space-x-2 p-3 w-72 hover:bg-gray-900 hover:cursor-pointer">
<Folders size={20} />
<div>Add chapter +</div>
</div>
}
/>
</div>
)}
</GeneralWrapperStyled >
</div>
</>
);
}
const Page = styled.div`
height: 100%;
width: 100%;
min-height: 100vh;
min-width: 100vw;
padding-top: 30px;
// dots background
background-image: radial-gradient(#4744446b 1px, transparent 1px), radial-gradient(#4744446b 1px, transparent 1px);
background-position: 0 0, 25px 25px;
background-size: 50px 50px;
background-attachment: fixed;
background-repeat: repeat;
button {
margin-left: 10px;
background-color: #000000;
border: none;
border-radius: 5px;
padding: 5px 10px;
color: white;
font-size: 13px;
cursor: pointer;
transition: 0.2s;
font-family: "DM Sans", sans-serif;
&:hover {
background-color: #474444;
transition: 0.2s;
}
}
`;
const ChapterlistWrapper = styled.div`
display: flex;
padding-left: 30px;
justify-content: center;
`;
export default CourseEdit;

View file

@ -1,6 +1,6 @@
'use client'; // Error components must be Client Components
import ErrorUI from '@components/UI/Error/Error';
import ErrorUI from '@components/StyledElements/Error/Error';
import { useEffect } from 'react';
export default function Error({

View file

@ -1,4 +1,4 @@
import PageLoading from "@components/Pages/PageLoading";
import PageLoading from "@components/Objects/Loaders/PageLoading";
export default function Loading() {
// Or a custom loading skeleton component

View file

@ -1,8 +1,8 @@
'use client';
import CreateCourseModal from '@components/Modals/Course/Create/CreateCourse';
import Modal from '@components/UI/Modal/Modal';
import CreateCourseModal from '@components/Objects/Modals/Course/Create/CreateCourse';
import Modal from '@components/StyledElements/Modal/Modal';
import { Edit2, Trash } from "lucide-react";
import { getAPIUrl, getBackendUrl, getUriWithOrg } from '@services/config/config';
import { getBackendUrl, getUriWithOrg } from '@services/config/config';
import CoursesLogo from "public/svg/courses.svg";
import CollectionsLogo from "public/svg/collections.svg";
import { deleteCourseFromBackend } from '@services/courses/courses';
@ -11,6 +11,10 @@ import React from 'react'
import Image from 'next/image';
import { AuthContext } from '@components/Security/AuthProvider';
import { revalidateTags } from '@services/utils/ts/requests';
import { useRouter } from 'next/navigation';
import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWrapper';
import TypeOfContentTitle from '@components/StyledElements/Titles/TypeOfContentTitle';
import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement';
interface CourseProps {
orgslug: string;
@ -26,48 +30,48 @@ function Courses(props: CourseProps) {
const orgslug = props.orgslug;
const courses = props.courses;
const [newCourseModal, setNewCourseModal] = React.useState(false);
const router = useRouter();
async function deleteCourses(course_id: any) {
await deleteCourseFromBackend(course_id);
revalidateTags(['courses']);
// terrible, nextjs right now doesn't mutate the page when the data changes
window.location.reload();
router.refresh();
}
async function closeNewCourseModal() {
setNewCourseModal(false);
}
return (
<div>
<div className='max-w-7xl mx-auto px-4'>
<GeneralWrapperStyled>
<div className='flex flex-wrap justify-between'>
<Title title="Courses" type="cou" />
<Modal
isDialogOpen={newCourseModal}
onOpenChange={setNewCourseModal}
minHeight="md"
dialogContent={<CreateCourseModal
closeModal={closeNewCourseModal}
orgslug={orgslug}
></CreateCourseModal>}
dialogTitle="Create Course"
dialogDescription="Create a new course"
dialogTrigger={
<button className="rounded-md bg-black antialiased ring-offset-purple-800 p-2 px-5 my-auto font text-sm font-bold text-white drop-shadow-lg">Add Course + </button>
}
/>
<TypeOfContentTitle title="Courses" type="cou" />
<AuthenticatedClientElement checkMethod='authentication'>
<Modal
isDialogOpen={newCourseModal}
onOpenChange={setNewCourseModal}
minHeight="md"
dialogContent={<CreateCourseModal
closeModal={closeNewCourseModal}
orgslug={orgslug}
></CreateCourseModal>}
dialogTitle="Create Course"
dialogDescription="Create a new course"
dialogTrigger={
<button className="rounded-md bg-black antialiased ring-offset-purple-800 p-2 px-5 my-auto font text-sm font-bold text-white drop-shadow-lg">Add Course + </button>
}
/>
</AuthenticatedClientElement>
</div>
<div className="flex space-x-5">
<div className="flex flex-wrap">
{courses.map((course: any) => (
<div key={course.course_id}>
<AdminEditsArea course={course} orgslug={orgslug} course_id={course.course_id} deleteCourses={deleteCourses} />
<div className="px-3" key={course.course_id}>
<AdminEditsArea course={course} orgSlug={orgslug} courseId={course.course_id} deleteCourses={deleteCourses} />
<Link href={getUriWithOrg(orgslug, "/course/" + removeCoursePrefix(course.course_id))}>
<div className="inset-0 ring-1 ring-inset ring-black/10 rounded-lg shadow-xl relative w-[249px] h-[131px] bg-cover" style={{ backgroundImage: `url(${getBackendUrl()}content/uploads/img/${course.thumbnail})` }}>
@ -78,83 +82,28 @@ function Courses(props: CourseProps) {
))}
</div>
</div>
</GeneralWrapperStyled>
</div>
)
}
export const Title = (props: any) => {
const AdminEditsArea = (props: { orgSlug: string, courseId: string, course: any, deleteCourses: any }) => {
return (
<div className="home_category_title flex my-5">
<div className="rounded-full ring-1 ring-slate-900/5 shadow-sm p-2 my-auto mr-4">
<Image className="" src={props.type == "col" ? CollectionsLogo : CoursesLogo} alt="Courses logo" />
</div>
<h1 className="font-bold text-lg">{props.title}</h1>
<AuthenticatedClientElement checkMethod='roles' orgId={props.course.org_id}><div className="flex space-x-2 py-2">
<button className="rounded-md text-sm px-3 font-bold text-red-800 bg-red-200 w-16 flex justify-center items-center" onClick={() => props.deleteCourses(props.courseId)}>
Delete <Trash size={10}></Trash>
</button>
<Link href={getUriWithOrg(props.orgSlug, "/course/" + removeCoursePrefix(props.courseId) + "/edit")}>
<button className="rounded-md text-sm px-3 font-bold text-orange-800 bg-orange-200 w-16 flex justify-center items-center">
Edit <Edit2 size={10}></Edit2>
</button>
</Link>
</div>
</AuthenticatedClientElement>
)
}
const AdminEditsArea = (props: any) => {
const org_roles_values = ["admin", "owner"];
const user_roles_values = ["role_admin"];
const auth: any = React.useContext(AuthContext);
console.log("auth: ", auth);
// this is amazingly terrible code, but gotta release that MVP
// TODO: fix this
function isAuthorized() {
const org_id = props.course.org_id;
const org_roles = auth.userInfo.user_object.orgs;
const user_roles = auth.userInfo.user_object.roles;
const org_role = org_roles.find((org: any) => org.org_id == org_id);
const user_role = user_roles.find((role: any) => role.org_id == org_id);
if (org_role && user_role) {
if (org_roles_values.includes(org_role.org_role) && user_roles_values.includes(user_role.role_id)) {
return true;
}
else {
return false;
}
} else {
return false;
}
}
// this is amazingly terrible code, but gotta release that MVP
// TODO: fix this
if (auth.isAuthenticated) {
if (isAuthorized()) {
return (
<div className="flex space-x-2 py-2">
<button className="rounded-md text-sm px-3 font-bold text-red-800 bg-red-200 w-16 flex justify-center items-center" onClick={() => props.deleteCourses(props.course_id)}>
Delete <Trash size={10}></Trash>
</button>
<Link href={getUriWithOrg(props.orgslug, "/course/" + removeCoursePrefix(props.course_id) + "/edit")}>
<button className="rounded-md text-sm px-3 font-bold text-orange-800 bg-orange-200 w-16 flex justify-center items-center">
Edit <Edit2 size={10}></Edit2>
</button>
</Link>
</div>
)
} else {
return (
<div></div>
)
}
}
else {
return (
<div></div>
)
}
}
export default Courses

View file

@ -1,6 +1,6 @@
'use client'; // Error components must be Client Components
import ErrorUI from '@components/UI/Error/Error';
import ErrorUI from '@components/StyledElements/Error/Error';
import { useEffect } from 'react';
export default function Error({

View file

@ -1,4 +1,4 @@
import PageLoading from "@components/Pages/PageLoading";
import PageLoading from "@components/Objects/Loaders/PageLoading";
export default function Loading() {
// Or a custom loading skeleton component

View file

@ -1,6 +1,6 @@
'use client'; // Error components must be Client Components
import ErrorUI from '@components/UI/Error/Error';
import ErrorUI from '@components/StyledElements/Error/Error';
import { useEffect } from 'react';
export default function Error({

View file

@ -1,5 +1,5 @@
import "@styles/globals.css";
import { Menu } from "@components/UI/Elements/Menu/Menu";
import { Menu } from "@components/Objects/Menu/Menu";
import AuthProvider from "@components/Security/AuthProvider";
export default async function RootLayout({ children, params }: { children: React.ReactNode , params:any}) {

View file

@ -1,4 +1,4 @@
import PageLoading from "@components/Pages/PageLoading";
import PageLoading from "@components/Objects/Loaders/PageLoading";
export default function Loading() {
return (

View file

@ -2,14 +2,15 @@ export const dynamic = 'force-dynamic';
import { Metadata, ResolvingMetadata } from 'next';
import { getBackendUrl, getUriWithOrg } from "@services/config/config";
import { getCourse, getOrgCourses, getOrgCoursesWithAuthHeader } from "@services/courses/courses";
import CoursesLogo from "public/svg/courses.svg";
import CollectionsLogo from "public/svg/collections.svg";
import Link from "next/link";
import Image from "next/image";
import { getOrgCollections, getOrgCollectionsWithAuthHeader } from "@services/courses/collections";
import { getOrganizationContextInfo } from '@services/organizations/orgs';
import { cookies } from 'next/headers';
import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWrapper';
import TypeOfContentTitle from '@components/StyledElements/Titles/TypeOfContentTitle';
type MetadataProps = {
params: { orgslug: string };
@ -50,12 +51,12 @@ const OrgHomePage = async (params: any) => {
return (
<div>
<div className="max-w-7xl mx-auto px-4 py-10">
<GeneralWrapperStyled>
{/* Collections */}
<Title title="Collections" type="col" />
<TypeOfContentTitle title="Collections" type="col" />
<div className="home_collections flex flex-wrap">
{collections.map((collection: any) => (
<div className="pr-8 flex flex-col" key={collection.collection_id}>
<div className="flex flex-col py-3 px-3" key={collection.collection_id}>
<Link href={getUriWithOrg(orgslug, "/collection/" + removeCollectionPrefix(collection.collection_id))}>
<div className="inset-0 ring-1 ring-inset ring-black/10 rounded-lg shadow-xl relative w-[249px] h-[180px] bg-cover flex flex-col items-center justify-center bg-indigo-600 font-bold text-zinc-50" >
<h1 className="font-bold text-lg py-2 justify-center mb-2">{collection.name}</h1>
@ -73,35 +74,24 @@ const OrgHomePage = async (params: any) => {
</div>
{/* Courses */}
<Title title="Courses" type="cou" />
<div className='h-5'></div>
<TypeOfContentTitle title="Courses" type="cou" />
<div className="home_courses flex flex-wrap">
{courses.map((course: any) => (
<div className="pr-8" key={course.course_id}>
<div className="py-3 px-3" key={course.course_id}>
<Link href={getUriWithOrg(orgslug, "/course/" + removeCoursePrefix(course.course_id))}>
<div className="inset-0 ring-1 ring-inset ring-black/10 rounded-lg shadow-xl relative w-[249px] h-[131px] bg-cover" style={{ backgroundImage: `url(${getBackendUrl()}content/uploads/img/${course.thumbnail})` }}>
<div className="inset-0 ring-1 ring-inset ring-black/10 rounded-lg shadow-xl relative w-[249px] h-[131px] bg-cover transition-all hover:scale-102" style={{ backgroundImage: `url(${getBackendUrl()}content/uploads/img/${course.thumbnail})` }}>
</div>
</Link>
<h2 className="font-bold text-lg w-[250px] py-2">{course.name}</h2>
</div>
))}
</div>
</div>
</GeneralWrapperStyled>
</div>
);
};
const Title = (props: any) => {
return (
<div className="home_category_title flex my-5">
<div className="rounded-full ring-1 ring-slate-900/5 shadow-sm p-2 my-auto mr-4">
<Image className="" src={props.type == "col" ? CollectionsLogo : CoursesLogo} alt="Courses logo" />
</div>
<h1 className="font-bold text-lg">{props.title}</h1>
</div>
)
}
export default OrgHomePage;

View file

@ -1,5 +1,7 @@
"use client";
import PageLoading from "@components/Pages/PageLoading";
import PageLoading from "@components/Objects/Loaders/PageLoading";
import TypeOfContentTitle from "@components/StyledElements/Titles/TypeOfContentTitle";
import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper";
import { getAPIUrl, getBackendUrl } from "@services/config/config";
import { swrFetcher } from "@services/utils/ts/requests";
import React from "react";
@ -12,10 +14,8 @@ function Trail(params: any) {
return (
<TrailLayout>
<h1>Trail</h1>
<br />
{error && <p>Failed to load</p>}
<GeneralWrapperStyled>
<TypeOfContentTitle title="Trail" type="tra" />
{!trail ? (
<PageLoading></PageLoading>
) : (
@ -36,19 +36,13 @@ function Trail(params: any) {
))}
</div>
)}
</TrailLayout>
</GeneralWrapperStyled>
);
}
export default Trail;
const TrailLayout = styled.div`
display: flex;
margin: 0 auto;
width: 1300px;
height: 100%;
flex-direction: column;
`;
const TrailMetadata = styled.div`
display: flex;

View file

@ -2,12 +2,11 @@
import { useRouter } from 'next/navigation';
import React, { useState } from "react";
import { styled } from '@stitches/react';
import { Title } from "../../../../components/UI/Elements/Styles/Title";
import { loginAndGetToken } from "../../../../services/auth/auth";
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, FormMessage, Input } from '@components/UI/Form/Form';
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, FormMessage, Input } from '@components/StyledElements/Form/Form';
import * as Form from '@radix-ui/react-form';
import { BarLoader } from 'react-spinners';
import Toast from '@components/UI/Toast/Toast';
import Toast from '@components/StyledElements/Toast/Toast';
import { toast } from 'react-hot-toast';
const Login = () => {

View file

@ -4,6 +4,7 @@ import { Field, Form, Formik } from 'formik';
import { updateOrganization, uploadOrganizationLogo } from '@services/settings/org';
import { UploadCloud } from 'lucide-react';
import { revalidateTags } from '@services/utils/ts/requests';
import { useRouter } from 'next/navigation';
interface OrganizationValues {
@ -17,7 +18,7 @@ interface OrganizationValues {
function OrganizationClient(props: any) {
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const router = useRouter();
// ...
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
@ -33,9 +34,8 @@ function OrganizationClient(props: any) {
await uploadOrganizationLogo(org_id, selectedFile);
setSelectedFile(null); // Reset the selected file
revalidateTags(['organizations']);
// reload the page
// terrible hack, it will fixed later
window.location.reload();
router.refresh();
}
};

View file

@ -1,6 +1,5 @@
"use client";
import React from "react";
import { Title } from "../../../../components/UI/Elements/Styles/Title";
import { signup } from "../../../../services/auth/auth";
import { useRouter } from "next/navigation";
@ -39,9 +38,8 @@ const SignUp = (params: any) => {
return (
<div>
<div title="Sign up">
<Title>Sign up </Title>
<div className="font-bold text-lg">Sign up </div>
{/* Create a login ui with tailwindcss */}
<div className="flex justify-center items-center h-screen">
<div className="w-full max-w-md">
<form onSubmit={handleSubmit}>

View file

@ -4,7 +4,7 @@ import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import Collaboration from "@tiptap/extension-collaboration";
import CollaborationCursor from "@tiptap/extension-collaboration-cursor";
import { AuthContext } from "../Security/AuthProvider";
import { AuthContext } from "../../Security/AuthProvider";
import learnhouseIcon from "public/learnhouse_icon.png";
import { ToolbarButtons } from "./Toolbar/ToolbarButtons";
import { motion, AnimatePresence } from "framer-motion";
@ -23,7 +23,7 @@ import { Eye, Save } from "lucide-react";
import MathEquationBlock from "./Extensions/MathEquation/MathEquationBlock";
import PDFBlock from "./Extensions/PDF/PDFBlock";
import QuizBlock from "./Extensions/Quiz/QuizBlock";
import ToolTip from "@components/UI/Tooltip/Tooltip";
import ToolTip from "@components/StyledElements/Tooltip/Tooltip";
import Link from "next/link";
interface Editor {

View file

@ -5,7 +5,7 @@ import { WebrtcProvider } from "y-webrtc";
import Editor from "./Editor";
import { updateActivity } from "@services/courses/activities";
import { toast } from "react-hot-toast";
import Toast from "@components/UI/Toast/Toast";
import Toast from "@components/StyledElements/Toast/Toast";
interface EditorWrapperProps {
content: string;

View file

@ -7,7 +7,7 @@ function InfoCalloutComponent(props: any) {
return (
<NodeViewWrapper>
<InfoCalloutWrapper contentEditable={props.extension.options.editable}>
<AlertCircle /> <NodeViewContent contentEditable={props.extension.options.editable} className="content" />
<AlertCircle /> <NodeViewContent contentEditable={props.extension.options.editable} className="content" />
</InfoCalloutWrapper>
</NodeViewWrapper>
);
@ -17,7 +17,7 @@ const InfoCalloutWrapper = styled.div`
display: flex;
flex-direction: row;
color: #1f3a8a;
background-color: #dbe9fe;
background-color: #dbe9fe;
border: 1px solid #c1d9fb;
border-radius: 16px;
margin: 1rem 0;
@ -36,14 +36,6 @@ const InfoCalloutWrapper = styled.div`
}
`;
const DragHandle = styled.div`
position: absolute;
top: 0;
left: 0;
width: 1rem;
height: 100%;
cursor: move;
z-index: 1;
`;
export default InfoCalloutComponent;

View file

@ -5,8 +5,8 @@ import { Resizable } from 're-resizable';
import * as AspectRatio from '@radix-ui/react-aspect-ratio';
import { AlertCircle, AlertTriangle, Image, ImagePlus, Info } from "lucide-react";
import { getImageFile, uploadNewImageFile } from "../../../../services/blocks/Image/images";
import { getBackendUrl } from "../../../../services/config/config";
import { getImageFile, uploadNewImageFile } from "../../../../../services/blocks/Image/images";
import { getBackendUrl } from "../../../../../services/config/config";
function ImageBlockComponent(props: any) {
const [image, setImage] = React.useState(null);

View file

@ -2,8 +2,8 @@ import { NodeViewWrapper } from "@tiptap/react";
import React from "react";
import styled from "styled-components";
import { AlertCircle, AlertTriangle, FileText, Image, ImagePlus, Info } from "lucide-react";
import { getPDFFile, uploadNewPDFFile } from "../../../../services/blocks/Pdf/pdf";
import { getBackendUrl } from "../../../../services/config/config";
import { getPDFFile, uploadNewPDFFile } from "../../../../../services/blocks/Pdf/pdf";
import { getBackendUrl } from "../../../../../services/config/config";
function PDFBlockComponent(props: any) {
const [pdf, setPDF] = React.useState(null);

View file

@ -2,8 +2,8 @@ import { NodeViewWrapper } from "@tiptap/react";
import { AlertTriangle, Image, Video } from "lucide-react";
import React from "react";
import styled from "styled-components";
import { getBackendUrl } from "../../../../services/config/config";
import { uploadNewVideoFile } from "../../../../services/blocks/Video/video";
import { getBackendUrl } from "../../../../../services/config/config";
import { uploadNewVideoFile } from "../../../../../services/blocks/Video/video";
function VideoBlockComponents(props: any) {
const [video, setVideo] = React.useState(null);

View file

@ -1,7 +1,7 @@
import styled from "styled-components";
import { FontBoldIcon, FontItalicIcon, StrikethroughIcon, ArrowLeftIcon, ArrowRightIcon, OpacityIcon, DividerVerticalIcon } from "@radix-ui/react-icons";
import { AlertCircle, AlertTriangle, FileText, GraduationCap, ImagePlus, Info, Sigma, Video, Youtube } from "lucide-react";
import ToolTip from "@components/UI/Tooltip/Tooltip";
import ToolTip from "@components/StyledElements/Tooltip/Tooltip";
export const ToolbarButtons = ({ editor, props }: any) => {
if (!editor) {

View file

@ -1,11 +1,9 @@
import React from "react";
import learnhouseLogo from "public/learnhouse_logo.png";
import Link from "next/link";
import Image from "next/image";
import { getBackendUrl, getUriWithOrg } from "@services/config/config";
import { getOrganizationContextInfo, getOrganizationContextInfoNoAsync } from "@services/organizations/orgs";
import ClientComponentSkeleton from "@components/UI/Utils/ClientComp";
import { getOrganizationContextInfo } from "@services/organizations/orgs";
import ClientComponentSkeleton from "@components/Utils/ClientComp";
import { HeaderProfileBox } from "@components/Security/HeaderProfileBox";
export const Menu = async (props: any) => {

View file

@ -1,4 +1,4 @@
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, FormMessage, Input, Textarea } from "@components/UI/Form/Form";
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, FormMessage, Input, Textarea } from "@components/StyledElements/Form/Form";
import React, { useState } from "react";
import * as Form from '@radix-ui/react-form';
import BarLoader from "react-spinners/BarLoader";

View file

@ -1,4 +1,4 @@
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, FormMessage, Input, Textarea } from "@components/UI/Form/Form";
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, FormMessage, Input, Textarea } from "@components/StyledElements/Form/Form";
import React, { useState } from "react";
import * as Form from '@radix-ui/react-form';
import BarLoader from "react-spinners/BarLoader";

View file

@ -1,4 +1,4 @@
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, FormMessage, Input, Textarea } from "@components/UI/Form/Form";
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, FormMessage, Input, Textarea } from "@components/StyledElements/Form/Form";
import React, { useState } from "react";
import * as Form from '@radix-ui/react-form';
import BarLoader from "react-spinners/BarLoader";

View file

@ -1,4 +1,4 @@
import FormLayout, { Flex, FormField, Input, Textarea, FormLabel, ButtonBlack } from "@components/UI/Form/Form";
import FormLayout, { Flex, FormField, Input, Textarea, FormLabel, ButtonBlack } from "@components/StyledElements/Form/Form";
import { FormMessage } from "@radix-ui/react-form";
import * as Form from '@radix-ui/react-form';
import React, { useState } from "react";

View file

@ -1,4 +1,4 @@
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, Input, Textarea } from '@components/UI/Form/Form'
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, Input, Textarea } from '@components/StyledElements/Form/Form'
import * as Form from '@radix-ui/react-form'
import { getAPIUrl, getUriWithOrg } from '@services/config/config';
import { FormMessage } from "@radix-ui/react-form";
@ -8,6 +8,7 @@ import React, { useState } from 'react'
import { BarLoader } from 'react-spinners'
import { mutate } from 'swr';
import { revalidateTags } from '@services/utils/ts/requests';
import { useRouter } from 'next/navigation';
function CreateCourseModal({ closeModal, orgslug }: any) {
const [isSubmitting, setIsSubmitting] = useState(false);
@ -15,6 +16,7 @@ function CreateCourseModal({ closeModal, orgslug }: any) {
const [description, setDescription] = React.useState("");
const [isLoading, setIsLoading] = React.useState(false);
const [thumbnail, setThumbnail] = React.useState(null) as any;
const router = useRouter();
const [orgId, setOrgId] = React.useState(null) as any;
@ -46,9 +48,7 @@ function CreateCourseModal({ closeModal, orgslug }: any) {
if (status.org_id == orgId) {
closeModal();
// reload the page
// terrible, nextjs right now doesn't mutate the page when the data changes
window.location.reload();
router.refresh();
} else {
alert("Error creating course, please see console logs");
console.log(status);

View file

@ -1,75 +1,18 @@
import { getBackendUrl } from "@services/config/config";
import React from "react";
import styled from "styled-components";
function DocumentPdfActivity({ activity, course }: { activity: any; course: any }) {
function getChapterName() {
let chapterName = "";
let chapterId = activity.chapter_id;
course.chapters.forEach((chapter: any) => {
if (chapter.chapter_id === chapterId) {
chapterName = chapter.name;
}
});
return chapterName;
}
return (
<DocumentPdfActivityLayout>
<DocumentPdfTitle>
<p>Chapter : {getChapterName()}</p>
{activity.name}
</DocumentPdfTitle>
<DocumentPdfPlayerWrapper>
<iframe
src={`${getBackendUrl()}content/uploads/documents/documentpdf/${activity.content.documentpdf.activity_id}/${activity.content.documentpdf.filename}`}
/>
</DocumentPdfPlayerWrapper>
</DocumentPdfActivityLayout>
<div className="m-8 bg-zinc-900 rounded-md mt-14">
<iframe
className="rounded-lg w-full h-[900px]"
src={`${getBackendUrl()}content/uploads/documents/documentpdf/${activity.content.documentpdf.activity_id}/${activity.content.documentpdf.filename}`}
/>
</div>
);
}
export default DocumentPdfActivity;
const DocumentPdfActivityLayout = styled.div`
display: flex;
flex-direction: column;
margin-top: 10px;
background: #141414;
min-width: 100%;
min-height: 1200px;
`;
const DocumentPdfTitle = 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 DocumentPdfPlayerWrapper = styled.div`
display: flex;
width: 1300px;
margin: 0 auto;
justify-content: center;
padding-top: 20px;
iframe {
width: 1300px;
height: 500px;
border-radius: 7px;
background-color: black;
border: none;
}
`;

View file

@ -4,12 +4,12 @@ import StarterKit from "@tiptap/starter-kit";
import { styled } from "styled-components";
import Youtube from "@tiptap/extension-youtube";
// Custom Extensions
import InfoCallout from "@editor/Extensions/Callout/Info/InfoCallout";
import WarningCallout from "@editor/Extensions/Callout/Warning/WarningCallout";
import ImageBlock from "@editor/Extensions/Image/ImageBlock";
import VideoBlock from "@editor/Extensions/Video/VideoBlock";
import MathEquationBlock from "@components/Editor/Extensions/MathEquation/MathEquationBlock";
import PDFBlock from "@components/Editor/Extensions/PDF/PDFBlock";
import InfoCallout from "@components/Objects/Editor/Extensions/Callout/Info/InfoCallout";
import WarningCallout from "@components/Objects/Editor/Extensions/Callout/Warning/WarningCallout";
import ImageBlock from "@components/Objects/Editor/Extensions/Image/ImageBlock";
import VideoBlock from "@components/Objects/Editor/Extensions/Video/VideoBlock";
import MathEquationBlock from "@components/Objects/Editor/Extensions/MathEquation/MathEquationBlock";
import PDFBlock from "@components/Objects/Editor/Extensions/PDF/PDFBlock";
interface Editor {
content: string;
@ -64,7 +64,7 @@ function Canva(props: Editor) {
const CanvaWrapper = styled.div`
padding-top: 20px;
width: 1300px;
width: 100%;
margin: 0 auto;
`;

View file

@ -7,17 +7,6 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
const [videoId, setVideoId] = React.useState('');
const [videoType, setVideoType] = React.useState('');
function getChapterName() {
let chapterName = "";
let chapterId = activity.chapter_id;
course.chapters.forEach((chapter: any) => {
if (chapter.chapter_id === chapterId) {
chapterName = chapter.name;
}
});
return chapterName;
}
function getYouTubeEmbed(url: any) {
// Extract video ID from the YouTube URL
var videoId = url.match(/(?:\?v=|\/embed\/|\/\d\/|\/vi\/|\/v\/|https?:\/\/(?:www\.)?youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))([^#\&\?\/]+)/)[1];
@ -34,7 +23,6 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
React.useEffect(() => {
console.log(activity);
if (activity.content.video) {
setVideoType('video');
}
@ -45,20 +33,16 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
}, [activity]);
return (
<VideoActivityLayout>
<VideoTitle>
<p>{getChapterName()}</p>
<p>{activity.name}</p>
</VideoTitle>
<div>
{videoType === 'video' && (
<VideoPlayerWrapper>
<video controls src={`${getBackendUrl()}content/uploads/video/${activity.content.video.activity_id}/${activity.content.video.filename}`}></video>
</VideoPlayerWrapper>
<div className="m-8 bg-zinc-900 rounded-md mt-14">
<video className="rounded-lg w-full h-[500px]" controls src={`${getBackendUrl()}content/uploads/video/${activity.content.video.activity_id}/${activity.content.video.filename}`}></video>
</div>
)}
{videoType === 'external_video' && (
<VideoPlayerWrapper>
<div>
<YouTube
className="rounded-md overflow-hidden"
className="rounded-md overflow-hidden m-8 bg-zinc-900 mt-14"
opts={
{
width: '1300',
@ -70,10 +54,10 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
}
}
videoId={videoId} />
</VideoPlayerWrapper>
</div>
)}
</VideoActivityLayout>
</div>
);
}
@ -82,44 +66,4 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
export default VideoActivity;
const VideoActivityLayout = 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

@ -4,6 +4,7 @@ import { Draggable } from "react-beautiful-dnd";
import { EyeOpenIcon, Pencil2Icon } from '@radix-ui/react-icons'
import styled from "styled-components";
import { getUriWithOrg } from "@services/config/config";
import { FileText, Video, Sparkles } from "lucide-react";
function Activity(props: any) {
@ -11,17 +12,25 @@ function Activity(props: any) {
<Draggable key={props.activity.id} draggableId={props.activity.id} index={props.index}>
{(provided) => (
<div
className="flex flex-row items-center py-2 my-3 rounded-md justify-center bg-gray-50 hover:bg-gray-100 space-x-2" key={props.activity.id} {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
<p>{props.activity.name} </p>
className="flex flex-row items-center py-2 my-3 rounded-md justify-center bg-gray-50 hover:bg-gray-100 space-x-2 w-auto" key={props.activity.id} {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
<div >
{props.activity.type === "video" && <Video size={16} />}
{props.activity.type === "documentpdf" && <FileText size={16} />}
{props.activity.type === "dynamic" && <Sparkles size={16} />}
</div>
<p className="first-letter:uppercase">{props.activity.name} </p>
<Link
href={getUriWithOrg(props.orgslug, "") + `/course/${props.courseid}/activity/${props.activity.id.replace("activity_", "")}`}
rel="noopener noreferrer"> <EyeOpenIcon />
className=" hover:cursor-pointer p-1 rounded-md bg-slate-200"
rel="noopener noreferrer">
<EyeOpenIcon className="text-slate-700"/>
</Link>
<Link
href={getUriWithOrg(props.orgslug, "") + `/course/${props.courseid}/activity/${props.activity.id.replace("activity_", "")}/edit`}
className=" hover:cursor-pointer p-1 rounded-md bg-slate-200"
rel="noopener noreferrer">
<Pencil2Icon />
<Pencil2Icon className="text-slate-700" />
</Link>
</div>
)}

View file

@ -2,6 +2,7 @@ import React from "react";
import styled from "styled-components";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import Activity from "./Activity";
import { PlusSquare, Trash, Trash2 } from "lucide-react";
function Chapter(props: any) {
return (
@ -12,38 +13,44 @@ function Chapter(props: any) {
{...provided.draggableProps}
ref={provided.innerRef}
// isDragging={snapshot.isDragging}
className="backdrop-blur-md"
key={props.info.list.chapter.id}
>
<h3 className="pt-3 font-bold text-md">
{props.info.list.chapter.name}
<button
onClick={() => {
props.openNewActivityModal(props.info.list.chapter.id);
}}
>
Create Activity
</button>
<h3 className="flex space-x-2 pt-3 font-bold text-md items-center">
<p>{props.info.list.chapter.name}
</p>
<button
<div
className="hover:cursor-pointer p-1 rounded-md bg-slate-100"
onClick={() => {
props.deleteChapter(props.info.list.chapter.id);
}}
>
X
</button>
<Trash2 className="text-slate-500" size={16} />
</div>
</h3>
<Droppable key={props.info.list.chapter.id} droppableId={props.info.list.chapter.id} type="activity">
{(provided) => (
<ActivitiesList {...provided.droppableProps} ref={provided.innerRef}>
{props.info.list.activities.map((activity: any, index: any) => (
<Activity orgslug={props.orgslug} courseid={props.courseid} key={activity.id} activity={activity} index={index}></Activity>
))}
{provided.placeholder}
<div className="flex flex-col ">
{props.info.list.activities.map((activity: any, index: any) => (
<Activity orgslug={props.orgslug} courseid={props.courseid} key={activity.id} activity={activity} index={index}></Activity>
))}
{provided.placeholder}
<div onClick={() => {
props.openNewActivityModal(props.info.list.chapter.id);
}} className="flex space-x-2 items-center py-2 my-3 rounded-md justify-center text-slate-500 outline-slate-200 bg-slate-50 hover:cursor-pointer">
<PlusSquare className="" size={17} />
<div className="text-sm mx-auto my-auto items-center font-bold">Add Activity</div>
</div>
</div>
</ActivitiesList>
)}
</Droppable>
</ChapterWrapper>
)}
</Draggable>
@ -53,7 +60,7 @@ function Chapter(props: any) {
const ChapterWrapper = styled.div`
margin-bottom: 20px;
padding: 4px;
background-color: #ffffffc5;
background-color: #ffffff9d;
width: 900px;
font-size: 15px;
display: block;

View file

@ -0,0 +1,73 @@
import ToolTip from '@components/StyledElements/Tooltip/Tooltip'
import { getUriWithOrg } from '@services/config/config'
import Link from 'next/link'
import React from 'react'
interface Props {
course: any
orgslug: string
current_activity?: any
}
function ActivityIndicators(props: Props) {
const course = props.course
const orgslug = props.orgslug
const courseid = course.course.course_id.replace("course_", "")
const done_activity_style = 'bg-teal-600 hover:bg-teal-700'
const black_activity_style = 'bg-black hover:bg-gray-700'
const current_activity_style = 'bg-gray-600 animate-pulse hover:bg-gray-700'
function isActivityDone(activity: any) {
if (course.trail.activities_marked_complete && course.trail.activities_marked_complete.includes(activity.id) && course.trail.status == "ongoing") {
return true
}
return false
}
function isActivityCurrent(activity: any) {
let activityid = activity.id.replace("activity_", "")
if (props.current_activity && props.current_activity == activityid) {
return true
}
return false
}
function getActivityClass(activity: any) {
if (isActivityDone(activity)) {
return done_activity_style
}
if (isActivityCurrent(activity)) {
return current_activity_style
}
return black_activity_style
}
return (
<div className='grid grid-flow-col justify-stretch space-x-6'>
{course.chapters.map((chapter: any) => {
return (
<>
<div className='grid grid-flow-col justify-stretch space-x-2'>
{chapter.activities.map((activity: any) => {
return (
<ToolTip sideOffset={8} slateBlack content={activity.name} key={activity.id}>
<Link href={getUriWithOrg(orgslug, "") + `/course/${courseid}/activity/${activity.id.replace("activity_", "")}`}>
<div className={`h-[7px] w-auto ${getActivityClass(activity)} rounded-lg shadow-md`}></div>
</Link>
</ToolTip>
);
})}
</div>
</>
);
})}
</div>
)
}
export default ActivityIndicators

View file

@ -0,0 +1,50 @@
'use client';
import React from "react";
import { AuthContext } from "./AuthProvider";
interface AuthenticatedClientElementProps {
children: React.ReactNode;
checkMethod: 'authentication' | 'roles';
orgId?: string;
}
function AuthenticatedClientElement(props: AuthenticatedClientElementProps) {
const auth: any = React.useContext(AuthContext);
// Available roles
const org_roles_values = ["admin", "owner"];
const user_roles_values = ["role_admin"];
function checkRoles() {
const org_id = props.orgId;
const org_roles = auth.userInfo.user_object.orgs;
const user_roles = auth.userInfo.user_object.roles;
const org_role = org_roles.find((org: any) => org.org_id == org_id);
const user_role = user_roles.find((role: any) => role.org_id == org_id);
if (org_role && user_role) {
if (org_roles_values.includes(org_role.org_role) && user_roles_values.includes(user_role.role_id)) {
return true;
}
else {
return false;
}
} else {
return false;
}
}
if ((props.checkMethod == 'authentication' && auth.isAuthenticated) || (auth.isAuthenticated && props.checkMethod == 'roles' && checkRoles())) {
return <>{props.children}</>;
}
return <></>;
}
export default AuthenticatedClientElement

View file

@ -79,7 +79,7 @@ const contentClose = keyframes({
const DialogOverlay = styled(Dialog.Overlay, {
backgroundColor: blackA.blackA9,
position: 'fixed',
zIndex: 500,
inset: 0,
animation: `${overlayShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
'&[data-state="closed"]': {
@ -111,6 +111,7 @@ const DialogContent = styled(Dialog.Content, {
backgroundColor: 'white',
borderRadius: 18,
zIndex: 501,
boxShadow: 'hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px',
position: 'fixed',
top: '50%',

View file

@ -0,0 +1,32 @@
import Image from 'next/image'
import CoursesLogo from "public/svg/courses.svg";
import CollectionsLogo from "public/svg/collections.svg";
import TrailLogo from "public/svg/trail.svg";
function TypeOfContentTitle(props: { title: string, type: string }) {
function getLogo() {
if (props.type == "col") {
return CollectionsLogo;
}
else if (props.type == "cou") {
return CoursesLogo;
}
else if (props.type == "tra") {
return TrailLogo;
}
}
return (
<div className="home_category_title flex my-5 items-center">
<div className="rounded-full ring-1 ring-slate-900/5 shadow-sm p-2 my-auto mr-4">
<Image className="" src={getLogo()} alt="Courses logo" />
</div>
<h1 className="font-bold text-2xl">{props.title}</h1>
</div>
)
}
export default TypeOfContentTitle

View file

@ -2,8 +2,6 @@
import React from 'react';
import * as Tooltip from '@radix-ui/react-tooltip';
import { styled, keyframes } from '@stitches/react';
import { violet, blackA } from '@radix-ui/colors';
import { PlusIcon } from '@radix-ui/react-icons';
type TooltipProps = {
@ -24,7 +22,6 @@ const ToolTip = (props: TooltipProps) => {
<Tooltip.Portal>
<TooltipContent slateBlack={props.slateBlack} side="bottom" sideOffset={props.sideOffset}>
{props.content}
<TooltipArrow />
</TooltipContent>
</Tooltip.Portal>
</Tooltip.Root>
@ -62,7 +59,7 @@ const TooltipContent = styled(Tooltip.Content, {
variants: {
slateBlack: {
true: {
backgroundColor: " #5a5a5a",
backgroundColor: " #0d0d0d",
color: 'white',
},
},
@ -96,25 +93,6 @@ const TooltipContent = styled(Tooltip.Content, {
},
});
const TooltipArrow = styled(Tooltip.Arrow, {
fill: 'white',
});
const IconButton = styled('button', {
all: 'unset',
fontFamily: 'inherit',
borderRadius: '100%',
height: 35,
width: 35,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
color: violet.violet11,
backgroundColor: 'white',
boxShadow: `0 2px 10px ${blackA.blackA7}`,
'&:hover': { backgroundColor: violet.violet3 },
'&:focus': { boxShadow: `0 0 0 2px black` },
});
export default ToolTip;

View file

@ -0,0 +1,10 @@
function GeneralWrapperStyled({ children }: { children: React.ReactNode }) {
return (
<div
className='max-w-screen-2xl mx-auto px-16 py-5 tracking-tight'
>{children}</div>
)
}
export default GeneralWrapperStyled

View file

@ -1,7 +0,0 @@
import styled from "styled-components";
export const Title = styled.h1`
font-size: 1.5em;
padding-left: 20px;
font-weight: 500;
`;

189
front/package-lock.json generated
View file

@ -25,8 +25,8 @@
"avvvatars-react": "^0.4.2",
"formik": "^2.2.9",
"framer-motion": "^7.3.6",
"lucide-react": "^0.104.1",
"next": "^13.4.6",
"lucide-react": "^0.248.0",
"next": "^13.4.7-canary.4",
"re-resizable": "^6.9.9",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
@ -2123,9 +2123,9 @@
}
},
"node_modules/@next/env": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.6.tgz",
"integrity": "sha512-nqUxEtvDqFhmV1/awSg0K2XHNwkftNaiUqCYO9e6+MYmqNObpKVl7OgMkGaQ2SZnFx5YqF0t60ZJTlyJIDAijg=="
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.7.tgz",
"integrity": "sha512-ZlbiFulnwiFsW9UV1ku1OvX/oyIPLtMk9p/nnvDSwI0s7vSoZdRtxXNsaO+ZXrLv/pMbXVGq4lL8TbY9iuGmVw=="
},
"node_modules/@next/eslint-plugin-next": {
"version": "13.0.6",
@ -2137,9 +2137,9 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.6.tgz",
"integrity": "sha512-ahi6VP98o4HV19rkOXPSUu+ovfHfUxbJQ7VVJ7gL2FnZRr7onEFC1oGQ6NQHpm8CxpIzSSBW79kumlFMOmZVjg==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.7.tgz",
"integrity": "sha512-VZTxPv1b59KGiv/pZHTO5Gbsdeoxcj2rU2cqJu03btMhHpn3vwzEK0gUSVC/XW96aeGO67X+cMahhwHzef24/w==",
"cpu": [
"arm64"
],
@ -2152,9 +2152,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.6.tgz",
"integrity": "sha512-13cXxKFsPJIJKzUqrU5XB1mc0xbUgYsRcdH6/rB8c4NMEbWGdtD4QoK9ShN31TZdePpD4k416Ur7p+deMIxnnA==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.7.tgz",
"integrity": "sha512-gO2bw+2Ymmga+QYujjvDz9955xvYGrWofmxTq7m70b9pDPvl7aDFABJOZ2a8SRCuSNB5mXU8eTOmVVwyp/nAew==",
"cpu": [
"x64"
],
@ -2167,9 +2167,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.6.tgz",
"integrity": "sha512-Ti+NMHEjTNktCVxNjeWbYgmZvA2AqMMI2AMlzkXsU7W4pXCMhrryAmAIoo+7YdJbsx01JQWYVxGe62G6DoCLaA==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.7.tgz",
"integrity": "sha512-6cqp3vf1eHxjIDhEOc7Mh/s8z1cwc/l5B6ZNkOofmZVyu1zsbEM5Hmx64s12Rd9AYgGoiCz4OJ4M/oRnkE16/Q==",
"cpu": [
"arm64"
],
@ -2182,9 +2182,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.6.tgz",
"integrity": "sha512-OHoC6gO7XfjstgwR+z6UHKlvhqJfyMtNaJidjx3sEcfaDwS7R2lqR5AABi8PuilGgi0BO0O0sCXqLlpp3a0emQ==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.7.tgz",
"integrity": "sha512-T1kD2FWOEy5WPidOn1si0rYmWORNch4a/NR52Ghyp4q7KyxOCuiOfZzyhVC5tsLIBDH3+cNdB5DkD9afpNDaOw==",
"cpu": [
"arm64"
],
@ -2197,9 +2197,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.6.tgz",
"integrity": "sha512-zHZxPGkUlpfNJCboUrFqwlwEX5vI9LSN70b8XEb0DYzzlrZyCyOi7hwDp/+3Urm9AB7YCAJkgR5Sp1XBVjHdfQ==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.7.tgz",
"integrity": "sha512-zaEC+iEiAHNdhl6fuwl0H0shnTzQoAoJiDYBUze8QTntE/GNPfTYpYboxF5LRYIjBwETUatvE0T64W6SKDipvg==",
"cpu": [
"x64"
],
@ -2212,9 +2212,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.6.tgz",
"integrity": "sha512-K/Y8lYGTwTpv5ME8PSJxwxLolaDRdVy+lOd9yMRMiQE0BLUhtxtCWC9ypV42uh9WpLjoaD0joOsB9Q6mbrSGJg==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.7.tgz",
"integrity": "sha512-X6r12F8d8SKAtYJqLZBBMIwEqcTRvUdVm+xIq+l6pJqlgT2tNsLLf2i5Cl88xSsIytBICGsCNNHd+siD2fbWBA==",
"cpu": [
"x64"
],
@ -2227,9 +2227,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.6.tgz",
"integrity": "sha512-U6LtxEUrjBL2tpW+Kr1nHCSJWNeIed7U7l5o7FiKGGwGgIlFi4UHDiLI6TQ2lxi20fAU33CsruV3U0GuzMlXIw==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.7.tgz",
"integrity": "sha512-NPnmnV+vEIxnu6SUvjnuaWRglZzw4ox5n/MQTxeUhb5iwVWFedolPFebMNwgrWu4AELwvTdGtWjqof53AiWHcw==",
"cpu": [
"arm64"
],
@ -2242,9 +2242,9 @@
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.6.tgz",
"integrity": "sha512-eEBeAqpCfhdPSlCZCayjCiyIllVqy4tcqvm1xmg3BgJG0G5ITiMM4Cw2WVeRSgWDJqQGRyyb+q8Y2ltzhXOWsQ==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.7.tgz",
"integrity": "sha512-6Hxijm6/a8XqLQpOOf/XuwWRhcuc/g4rBB2oxjgCMuV9Xlr2bLs5+lXyh8w9YbAUMYR3iC9mgOlXbHa79elmXw==",
"cpu": [
"ia32"
],
@ -2257,9 +2257,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.6.tgz",
"integrity": "sha512-OrZs94AuO3ZS5tnqlyPRNgfWvboXaDQCi5aXGve3o3C+Sj0ctMUV9+Do+0zMvvLRumR8E0PTWKvtz9n5vzIsWw==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.7.tgz",
"integrity": "sha512-sW9Yt36Db1nXJL+mTr2Wo0y+VkPWeYhygvcHj1FF0srVtV+VoDjxleKtny21QHaG05zdeZnw2fCtf2+dEqgwqA==",
"cpu": [
"x64"
],
@ -6239,11 +6239,10 @@
}
},
"node_modules/lucide-react": {
"version": "0.104.1",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.104.1.tgz",
"integrity": "sha512-BKvhulnLKmBj+6pqUN5ViYk4a5fabMgc4B0a4ZLUnbRqkDDWH3h7Iet6U4WbesJzjWauQrXUlEvQCe5XpFuRnw==",
"version": "0.248.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.248.0.tgz",
"integrity": "sha512-zMqVvwsvhLV6ooekfM8HEngR/lLGkIgOwZ4X140K+CDdAPwfp9LARnmJhMF32wlDganAIVEgN7saIv3pcCLUVw==",
"peerDependencies": {
"prop-types": "^15.7.2",
"react": "^16.5.1 || ^17.0.0 || ^18.0.0"
}
},
@ -6375,11 +6374,11 @@
"dev": true
},
"node_modules/next": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.6.tgz",
"integrity": "sha512-sjVqjxU+U2aXZnYt4Ud6CTLNNwWjdSfMgemGpIQJcN3Z7Jni9xRWbR0ie5fQzCg87aLqQVhKA2ud2gPoqJ9lGw==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.7.tgz",
"integrity": "sha512-M8z3k9VmG51SRT6v5uDKdJXcAqLzP3C+vaKfLIAM0Mhx1um1G7MDnO63+m52qPdZfrTFzMZNzfsgvm3ghuVHIQ==",
"dependencies": {
"@next/env": "13.4.6",
"@next/env": "13.4.7",
"@swc/helpers": "0.5.1",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001406",
@ -6395,15 +6394,15 @@
"node": ">=16.8.0"
},
"optionalDependencies": {
"@next/swc-darwin-arm64": "13.4.6",
"@next/swc-darwin-x64": "13.4.6",
"@next/swc-linux-arm64-gnu": "13.4.6",
"@next/swc-linux-arm64-musl": "13.4.6",
"@next/swc-linux-x64-gnu": "13.4.6",
"@next/swc-linux-x64-musl": "13.4.6",
"@next/swc-win32-arm64-msvc": "13.4.6",
"@next/swc-win32-ia32-msvc": "13.4.6",
"@next/swc-win32-x64-msvc": "13.4.6"
"@next/swc-darwin-arm64": "13.4.7",
"@next/swc-darwin-x64": "13.4.7",
"@next/swc-linux-arm64-gnu": "13.4.7",
"@next/swc-linux-arm64-musl": "13.4.7",
"@next/swc-linux-x64-gnu": "13.4.7",
"@next/swc-linux-x64-musl": "13.4.7",
"@next/swc-win32-arm64-msvc": "13.4.7",
"@next/swc-win32-ia32-msvc": "13.4.7",
"@next/swc-win32-x64-msvc": "13.4.7"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
@ -10056,9 +10055,9 @@
}
},
"@next/env": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.6.tgz",
"integrity": "sha512-nqUxEtvDqFhmV1/awSg0K2XHNwkftNaiUqCYO9e6+MYmqNObpKVl7OgMkGaQ2SZnFx5YqF0t60ZJTlyJIDAijg=="
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.7.tgz",
"integrity": "sha512-ZlbiFulnwiFsW9UV1ku1OvX/oyIPLtMk9p/nnvDSwI0s7vSoZdRtxXNsaO+ZXrLv/pMbXVGq4lL8TbY9iuGmVw=="
},
"@next/eslint-plugin-next": {
"version": "13.0.6",
@ -10070,57 +10069,57 @@
}
},
"@next/swc-darwin-arm64": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.6.tgz",
"integrity": "sha512-ahi6VP98o4HV19rkOXPSUu+ovfHfUxbJQ7VVJ7gL2FnZRr7onEFC1oGQ6NQHpm8CxpIzSSBW79kumlFMOmZVjg==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.7.tgz",
"integrity": "sha512-VZTxPv1b59KGiv/pZHTO5Gbsdeoxcj2rU2cqJu03btMhHpn3vwzEK0gUSVC/XW96aeGO67X+cMahhwHzef24/w==",
"optional": true
},
"@next/swc-darwin-x64": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.6.tgz",
"integrity": "sha512-13cXxKFsPJIJKzUqrU5XB1mc0xbUgYsRcdH6/rB8c4NMEbWGdtD4QoK9ShN31TZdePpD4k416Ur7p+deMIxnnA==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.7.tgz",
"integrity": "sha512-gO2bw+2Ymmga+QYujjvDz9955xvYGrWofmxTq7m70b9pDPvl7aDFABJOZ2a8SRCuSNB5mXU8eTOmVVwyp/nAew==",
"optional": true
},
"@next/swc-linux-arm64-gnu": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.6.tgz",
"integrity": "sha512-Ti+NMHEjTNktCVxNjeWbYgmZvA2AqMMI2AMlzkXsU7W4pXCMhrryAmAIoo+7YdJbsx01JQWYVxGe62G6DoCLaA==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.7.tgz",
"integrity": "sha512-6cqp3vf1eHxjIDhEOc7Mh/s8z1cwc/l5B6ZNkOofmZVyu1zsbEM5Hmx64s12Rd9AYgGoiCz4OJ4M/oRnkE16/Q==",
"optional": true
},
"@next/swc-linux-arm64-musl": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.6.tgz",
"integrity": "sha512-OHoC6gO7XfjstgwR+z6UHKlvhqJfyMtNaJidjx3sEcfaDwS7R2lqR5AABi8PuilGgi0BO0O0sCXqLlpp3a0emQ==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.7.tgz",
"integrity": "sha512-T1kD2FWOEy5WPidOn1si0rYmWORNch4a/NR52Ghyp4q7KyxOCuiOfZzyhVC5tsLIBDH3+cNdB5DkD9afpNDaOw==",
"optional": true
},
"@next/swc-linux-x64-gnu": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.6.tgz",
"integrity": "sha512-zHZxPGkUlpfNJCboUrFqwlwEX5vI9LSN70b8XEb0DYzzlrZyCyOi7hwDp/+3Urm9AB7YCAJkgR5Sp1XBVjHdfQ==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.7.tgz",
"integrity": "sha512-zaEC+iEiAHNdhl6fuwl0H0shnTzQoAoJiDYBUze8QTntE/GNPfTYpYboxF5LRYIjBwETUatvE0T64W6SKDipvg==",
"optional": true
},
"@next/swc-linux-x64-musl": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.6.tgz",
"integrity": "sha512-K/Y8lYGTwTpv5ME8PSJxwxLolaDRdVy+lOd9yMRMiQE0BLUhtxtCWC9ypV42uh9WpLjoaD0joOsB9Q6mbrSGJg==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.7.tgz",
"integrity": "sha512-X6r12F8d8SKAtYJqLZBBMIwEqcTRvUdVm+xIq+l6pJqlgT2tNsLLf2i5Cl88xSsIytBICGsCNNHd+siD2fbWBA==",
"optional": true
},
"@next/swc-win32-arm64-msvc": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.6.tgz",
"integrity": "sha512-U6LtxEUrjBL2tpW+Kr1nHCSJWNeIed7U7l5o7FiKGGwGgIlFi4UHDiLI6TQ2lxi20fAU33CsruV3U0GuzMlXIw==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.7.tgz",
"integrity": "sha512-NPnmnV+vEIxnu6SUvjnuaWRglZzw4ox5n/MQTxeUhb5iwVWFedolPFebMNwgrWu4AELwvTdGtWjqof53AiWHcw==",
"optional": true
},
"@next/swc-win32-ia32-msvc": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.6.tgz",
"integrity": "sha512-eEBeAqpCfhdPSlCZCayjCiyIllVqy4tcqvm1xmg3BgJG0G5ITiMM4Cw2WVeRSgWDJqQGRyyb+q8Y2ltzhXOWsQ==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.7.tgz",
"integrity": "sha512-6Hxijm6/a8XqLQpOOf/XuwWRhcuc/g4rBB2oxjgCMuV9Xlr2bLs5+lXyh8w9YbAUMYR3iC9mgOlXbHa79elmXw==",
"optional": true
},
"@next/swc-win32-x64-msvc": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.6.tgz",
"integrity": "sha512-OrZs94AuO3ZS5tnqlyPRNgfWvboXaDQCi5aXGve3o3C+Sj0ctMUV9+Do+0zMvvLRumR8E0PTWKvtz9n5vzIsWw==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.7.tgz",
"integrity": "sha512-sW9Yt36Db1nXJL+mTr2Wo0y+VkPWeYhygvcHj1FF0srVtV+VoDjxleKtny21QHaG05zdeZnw2fCtf2+dEqgwqA==",
"optional": true
},
"@nicolo-ribaudo/chokidar-2": {
@ -12994,9 +12993,9 @@
}
},
"lucide-react": {
"version": "0.104.1",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.104.1.tgz",
"integrity": "sha512-BKvhulnLKmBj+6pqUN5ViYk4a5fabMgc4B0a4ZLUnbRqkDDWH3h7Iet6U4WbesJzjWauQrXUlEvQCe5XpFuRnw==",
"version": "0.248.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.248.0.tgz",
"integrity": "sha512-zMqVvwsvhLV6ooekfM8HEngR/lLGkIgOwZ4X140K+CDdAPwfp9LARnmJhMF32wlDganAIVEgN7saIv3pcCLUVw==",
"requires": {}
},
"magic-string": {
@ -13093,20 +13092,20 @@
"dev": true
},
"next": {
"version": "13.4.6",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.6.tgz",
"integrity": "sha512-sjVqjxU+U2aXZnYt4Ud6CTLNNwWjdSfMgemGpIQJcN3Z7Jni9xRWbR0ie5fQzCg87aLqQVhKA2ud2gPoqJ9lGw==",
"version": "13.4.7",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.7.tgz",
"integrity": "sha512-M8z3k9VmG51SRT6v5uDKdJXcAqLzP3C+vaKfLIAM0Mhx1um1G7MDnO63+m52qPdZfrTFzMZNzfsgvm3ghuVHIQ==",
"requires": {
"@next/env": "13.4.6",
"@next/swc-darwin-arm64": "13.4.6",
"@next/swc-darwin-x64": "13.4.6",
"@next/swc-linux-arm64-gnu": "13.4.6",
"@next/swc-linux-arm64-musl": "13.4.6",
"@next/swc-linux-x64-gnu": "13.4.6",
"@next/swc-linux-x64-musl": "13.4.6",
"@next/swc-win32-arm64-msvc": "13.4.6",
"@next/swc-win32-ia32-msvc": "13.4.6",
"@next/swc-win32-x64-msvc": "13.4.6",
"@next/env": "13.4.7",
"@next/swc-darwin-arm64": "13.4.7",
"@next/swc-darwin-x64": "13.4.7",
"@next/swc-linux-arm64-gnu": "13.4.7",
"@next/swc-linux-arm64-musl": "13.4.7",
"@next/swc-linux-x64-gnu": "13.4.7",
"@next/swc-linux-x64-musl": "13.4.7",
"@next/swc-win32-arm64-msvc": "13.4.7",
"@next/swc-win32-ia32-msvc": "13.4.7",
"@next/swc-win32-x64-msvc": "13.4.7",
"@swc/helpers": "0.5.1",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001406",

View file

@ -26,8 +26,8 @@
"avvvatars-react": "^0.4.2",
"formik": "^2.2.9",
"framer-motion": "^7.3.6",
"lucide-react": "^0.104.1",
"next": "^13.4.6",
"lucide-react": "^0.248.0",
"next": "^13.4.7-canary.4",
"re-resizable": "^6.9.9",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",

View file

@ -1,3 +1,3 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="20" height="20" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.4997 5.22045C14.4997 5.22045 14.4997 5.22045 14.4997 5.16378L14.4572 5.05753C14.4424 5.03499 14.4259 5.01367 14.4076 4.99379C14.3887 4.9638 14.3674 4.93537 14.3439 4.90878L14.2801 4.8592L14.1668 4.80254L8.85431 1.52295C8.74173 1.45259 8.61165 1.41528 8.47889 1.41528C8.34614 1.41528 8.21605 1.45259 8.10348 1.52295L2.83348 4.80254L2.76973 4.8592L2.70598 4.90878C2.6825 4.93537 2.66118 4.9638 2.64223 4.99379C2.62402 5.01367 2.60744 5.03499 2.59264 5.05753L2.55014 5.16378C2.55014 5.16378 2.55014 5.16378 2.55014 5.22045C2.54318 5.28164 2.54318 5.34343 2.55014 5.40462V11.5955C2.5499 11.7158 2.58034 11.8343 2.63859 11.9396C2.69684 12.045 2.78098 12.1337 2.88306 12.1975L8.19556 15.4771C8.22826 15.4973 8.26421 15.5117 8.30181 15.5196C8.30181 15.5196 8.33723 15.5196 8.35848 15.5196C8.47831 15.5576 8.60697 15.5576 8.72681 15.5196C8.72681 15.5196 8.76223 15.5196 8.78348 15.5196C8.82108 15.5117 8.85703 15.4973 8.88973 15.4771V15.4771L14.1668 12.1975C14.2689 12.1337 14.353 12.045 14.4113 11.9396C14.4695 11.8343 14.5 11.7158 14.4997 11.5955V5.40462C14.5067 5.34343 14.5067 5.28164 14.4997 5.22045V5.22045ZM7.79181 13.6071L3.89598 11.1988V6.67962L7.79181 9.08087V13.6071ZM8.50014 7.85545L4.53348 5.40462L8.50014 2.96087L12.4668 5.40462L8.50014 7.85545ZM13.1043 11.1988L9.20848 13.6071V9.08087L13.1043 6.67962V11.1988Z" fill="#0F0F0F"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

View file

@ -1,3 +1,3 @@
<svg width="13" height="15" viewBox="0 0 13 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="16" height="18" viewBox="0 0 13 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.7507 0.416626H3.66732C2.91587 0.416626 2.1952 0.715137 1.66385 1.24649C1.1325 1.77784 0.833984 2.49851 0.833984 3.24996V11.75C0.833984 12.5014 1.1325 13.2221 1.66385 13.7534C2.1952 14.2848 2.91587 14.5833 3.66732 14.5833H10.7507C11.1264 14.5833 11.4867 14.434 11.7524 14.1684C12.0181 13.9027 12.1673 13.5423 12.1673 13.1666V1.83329C12.1673 1.45757 12.0181 1.09723 11.7524 0.831558C11.4867 0.565881 11.1264 0.416626 10.7507 0.416626ZM2.25065 3.24996C2.25065 2.87424 2.39991 2.5139 2.66558 2.24822C2.93126 1.98255 3.29159 1.83329 3.66732 1.83329H10.7507V8.91663H3.66732C3.16797 8.91872 2.67848 9.05578 2.25065 9.31329V3.24996ZM3.66732 13.1666C3.29159 13.1666 2.93126 13.0174 2.66558 12.7517C2.39991 12.486 2.25065 12.1257 2.25065 11.75C2.25065 11.3742 2.39991 11.0139 2.66558 10.7482C2.93126 10.4825 3.29159 10.3333 3.66732 10.3333H10.7507V13.1666H3.66732ZM5.08398 4.66663H7.91732C8.10518 4.66663 8.28535 4.592 8.41819 4.45916C8.55102 4.32632 8.62565 4.14615 8.62565 3.95829C8.62565 3.77043 8.55102 3.59026 8.41819 3.45743C8.28535 3.32459 8.10518 3.24996 7.91732 3.24996H5.08398C4.89612 3.24996 4.71596 3.32459 4.58312 3.45743C4.45028 3.59026 4.37565 3.77043 4.37565 3.95829C4.37565 4.14615 4.45028 4.32632 4.58312 4.45916C4.71596 4.592 4.89612 4.66663 5.08398 4.66663V4.66663Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

View file

@ -0,0 +1,5 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M16.5751 7.95841C16.5059 7.82098 16.3999 7.70541 16.269 7.62451C16.1381 7.54361 15.9874 7.50054 15.8335 7.50008H11.6668V2.50008C11.6757 2.31731 11.6243 2.13669 11.5204 1.98608C11.4164 1.83547 11.2658 1.72325 11.0918 1.66674C10.9245 1.6117 10.744 1.61108 10.5763 1.66498C10.4087 1.71888 10.2624 1.82452 10.1585 1.96674L3.4918 11.1334C3.40827 11.2541 3.35811 11.3948 3.3464 11.5411C3.3347 11.6874 3.36186 11.8343 3.42513 11.9667C3.4834 12.1182 3.58462 12.2493 3.71637 12.3441C3.84812 12.4388 4.00467 12.493 4.1668 12.5001H8.33346V17.5001C8.33359 17.6758 8.38927 17.847 8.49254 17.9892C8.59581 18.1314 8.74139 18.2373 8.90846 18.2917C8.99219 18.3177 9.07915 18.3317 9.1668 18.3334C9.29828 18.3338 9.42799 18.303 9.5453 18.2436C9.66262 18.1842 9.76422 18.0979 9.8418 17.9917L16.5085 8.82508C16.5982 8.70074 16.652 8.55404 16.6637 8.40112C16.6755 8.24821 16.6448 8.09502 16.5751 7.95841ZM10.0001 14.9334V11.6667C10.0001 11.4457 9.91233 11.2338 9.75605 11.0775C9.59977 10.9212 9.38781 10.8334 9.1668 10.8334H5.83346L10.0001 5.06674V8.33341C10.0001 8.55442 10.0879 8.76638 10.2442 8.92267C10.4005 9.07895 10.6124 9.16674 10.8335 9.16674H14.1668L10.0001 14.9334Z"
fill="black" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -26,7 +26,7 @@
"@images/*": ["public/img/*"],
"@styles/*": ["styles/*"],
"@services/*": ["services/*"],
"@editor/*": ["components/Editor/*"]
"@editor/*": ["components/Objects/Editor/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx","**/**/*.tsx", ".next/types/**/*.ts"],