feat: init new modal

This commit is contained in:
swve 2023-04-08 15:11:24 +02:00
parent f4c239d848
commit ca5110e4f7
7 changed files with 283 additions and 26 deletions

View file

@ -14,6 +14,7 @@ import NewChapterModal from "@components/Modals/CourseEdit/NewChapter";
import NewActivityModal from "@components/Modals/CourseEdit/NewActivity"; import NewActivityModal from "@components/Modals/CourseEdit/NewActivity";
import { createActivity, createFileActivity } from "@services/courses/activities"; import { createActivity, createFileActivity } from "@services/courses/activities";
import { getOrganizationContextInfo } from "@services/organizations/orgs"; import { getOrganizationContextInfo } from "@services/organizations/orgs";
import Modal from "@components/UI/Modal/Modal";
function CourseEdit(params: any) { function CourseEdit(params: any) {
const router = useRouter(); const router = useRouter();
@ -32,7 +33,7 @@ function CourseEdit(params: any) {
const courseid = params.params.courseid; const courseid = params.params.courseid;
const orgslug = params.params.orgslug; const orgslug = params.params.orgslug;
async function getCourseChapters() { async function getCourseChapters() {
const courseChapters = await getCourseChaptersMetadata(courseid); const courseChapters = await getCourseChaptersMetadata(courseid);
@ -123,6 +124,8 @@ function CourseEdit(params: any) {
}; };
const closeNewActivityModal = () => { const closeNewActivityModal = () => {
console.log("closeNewActivityModal");
setNewActivityModal(false); setNewActivityModal(false);
}; };
@ -233,13 +236,22 @@ function CourseEdit(params: any) {
<Page> <Page>
<Title> <Title>
Edit Course {" "} Edit Course {" "}
<button <Modal
onClick={() => { isDialogOpen={newChapterModal}
setNewChapterModal(true); onOpenChange={setNewChapterModal}
}} minHeight="sm"
> dialogContent={<NewChapterModal
Add chapter + closeModal={closeNewChapterModal}
</button> submitChapter={submitChapter}
></NewChapterModal>}
dialogTitle="Create chapter"
dialogDescription="Add a new chapter to the course"
dialogTrigger={
<button> Add chapter +
</button>
}
/>
<button <button
onClick={() => { onClick={() => {
updateChapters(); updateChapters();
@ -247,16 +259,22 @@ function CourseEdit(params: any) {
> >
Save Save
</button> </button>
</Title> </Title>-
{newChapterModal && <NewChapterModal closeModal={closeNewChapterModal} submitChapter={submitChapter}></NewChapterModal>}
{newActivityModal && ( <Modal
<NewActivityModal isDialogOpen={newActivityModal}
onOpenChange={setNewActivityModal}
minHeight="md"
dialogContent={<NewActivityModal
closeModal={closeNewActivityModal} closeModal={closeNewActivityModal}
submitFileActivity={submitFileActivity} submitFileActivity={submitFileActivity}
submitActivity={submitActivity} submitActivity={submitActivity}
chapterId={newActivityModalData} chapterId={newActivityModalData}
></NewActivityModal> ></NewActivityModal>}
)} dialogTitle="Create Activity"
dialogDescription="Choose between types of activities to add to the course"
/>
<br /> <br />
{winReady && ( {winReady && (
@ -287,7 +305,7 @@ function CourseEdit(params: any) {
</DragDropContext> </DragDropContext>
</ChapterlistWrapper> </ChapterlistWrapper>
)} )}
</Page> </Page >
</> </>
); );
} }

View file

@ -21,8 +21,11 @@ function Chapter(props: any) {
props.openNewActivityModal(props.info.list.chapter.id); props.openNewActivityModal(props.info.list.chapter.id);
}} }}
> >
Create Activity Create Activity
</button> </button>
<button <button
onClick={() => { onClick={() => {
props.deleteChapter(props.info.list.chapter.id); props.deleteChapter(props.info.list.chapter.id);

View file

@ -9,20 +9,18 @@ function NewActivityModal({ closeModal, submitActivity, submitFileActivity, chap
const [selectedView, setSelectedView] = useState("home"); const [selectedView, setSelectedView] = useState("home");
return ( return (
<Modal> <div>
<button onClick={ () => {setSelectedView("home")}}> <button onClick={() => { setSelectedView("home") }}>
<ArrowLeftIcon /> <ArrowLeftIcon />
</button> </button>
<button onClick={closeModal}> <button onClick={closeModal}>
<Cross1Icon /> <Cross1Icon />
</button> </button>
<h1>Add New Activity</h1>
<br />
{selectedView === "home" && ( {selectedView === "home" && (
<ActivityChooserWrapper> <ActivityChooserWrapper>
<ActivityButton onClick={() => {setSelectedView("dynamic")}}>📄</ActivityButton> <ActivityButton onClick={() => { setSelectedView("dynamic") }}>📄</ActivityButton>
<ActivityButton onClick={() => {setSelectedView("video")}}>📹</ActivityButton> <ActivityButton onClick={() => { setSelectedView("video") }}>📹</ActivityButton>
</ActivityChooserWrapper> </ActivityChooserWrapper>
)} )}
@ -33,8 +31,8 @@ function NewActivityModal({ closeModal, submitActivity, submitFileActivity, chap
{selectedView === "video" && ( {selectedView === "video" && (
<VideoModal submitFileActivity={submitFileActivity} chapterId={chapterId} /> <VideoModal submitFileActivity={submitFileActivity} chapterId={chapterId} />
)} )}
</Modal> </div>
); );
} }

View file

@ -20,13 +20,13 @@ function NewChapterModal({ submitChapter , closeModal }: any) {
}; };
return ( return (
<Modal> <div>
<h1>Add New Chapter <button onClick={closeModal}>X</button></h1> <button onClick={closeModal}>X</button>
<input type="text" onChange={handleChapterNameChange} placeholder="Chapter Name" /> <br /> <input type="text" onChange={handleChapterNameChange} placeholder="Chapter Name" /> <br />
<input type="text" onChange={handleChapterDescriptionChange} placeholder="Chapter Description" /> <input type="text" onChange={handleChapterDescriptionChange} placeholder="Chapter Description" />
<br /> <br />
<button onClick={handleSubmit}>Add Chapter</button> <button onClick={handleSubmit}>Add Chapter</button>
</Modal> </div>
); );
} }

View file

@ -0,0 +1,226 @@
import React from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import { styled, keyframes } from '@stitches/react';
import { violet, blackA, mauve, green } from '@radix-ui/colors';
import { Cross2Icon } from '@radix-ui/react-icons';
type ModalParams = {
dialogTitle: string;
dialogDescription: string;
dialogContent: React.ReactNode;
dialogClose?: React.ReactNode | null;
dialogTrigger?: React.ReactNode;
onOpenChange: any;
isDialogOpen?: boolean;
minHeight?: "sm" | "md" | "lg" | "xl"
};
const Modal = (params: ModalParams) => (
<Dialog.Root open={params.isDialogOpen} onOpenChange={params.onOpenChange}>
{params.dialogTrigger ? (
<Dialog.Trigger asChild>
{params.dialogTrigger}
</Dialog.Trigger>
) : null}
<Dialog.Portal>
<DialogOverlay />
<DialogContent minHeight={params.minHeight}>
<DialogTopBar>
<DialogTitle>{params.dialogTitle}</DialogTitle>
<DialogDescription>
{params.dialogDescription}
</DialogDescription>
</DialogTopBar>
{params.dialogContent}
<Dialog.Close asChild>
{params.dialogClose}
</Dialog.Close>
</DialogContent>
</Dialog.Portal>
</Dialog.Root>
);
const overlayShow = keyframes({
'0%': { opacity: 0 },
'100%': { opacity: 1 },
});
const overlayClose = keyframes({
'0%': { opacity: 1 },
'100%': { opacity: 0 },
});
const contentShow = keyframes({
'0%': { opacity: 0, transform: 'translate(-50%, -50%) scale(.96)' },
'100%': { opacity: 1, transform: 'translate(-50%, -50%) scale(1)' },
});
const contentClose = keyframes({
'0%': { opacity: 1, transform: 'translate(-50%, -50%) scale(1)' },
'100%': { opacity: 0, transform: 'translate(-50%, -52%) scale(.96)' },
});
const DialogOverlay = styled(Dialog.Overlay, {
backgroundColor: blackA.blackA9,
position: 'fixed',
inset: 0,
animation: `${overlayShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
'&[data-state="closed"]': {
animation: `${overlayClose} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
},
});
const DialogContent = styled(Dialog.Content, {
variants: {
minHeight: {
'sm': {
minHeight: '300px',
},
'md': {
minHeight: '500px',
},
'lg': {
minHeight: '700px',
},
'xl': {
minHeight: '900px',
},
},
},
backgroundColor: 'white',
borderRadius: 18,
boxShadow: 'hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px',
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '90vw',
overflow: 'hidden',
maxHeight: '85vh',
minHeight: '300px',
maxWidth: '600px',
padding: 11,
animation: `${contentShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
'&:focus': { outline: 'none' },
'&[data-state="closed"]': {
animation: `${contentClose} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
},
transition: "max-height 0.3s ease-out",
});
const DialogTopBar = styled('div', {
background: "#F7F7F7",
padding: "8px 14px ",
borderRadius: 14,
});
const DialogTitle = styled(Dialog.Title, {
margin: 0,
fontWeight: 700,
letterSpacing: "-0.05em",
padding: 0,
color: mauve.mauve12,
fontSize: 21,
});
const DialogDescription = styled(Dialog.Description, {
color: mauve.mauve11,
letterSpacing: "-0.03em",
fontSize: 15,
padding: 0,
margin: 0,
});
const Flex = styled('div', { display: 'flex' });
const Button = styled('button', {
all: 'unset',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 4,
padding: '0 15px',
fontSize: 15,
lineHeight: 1,
fontWeight: 500,
height: 35,
variants: {
variant: {
violet: {
backgroundColor: 'white',
color: violet.violet11,
boxShadow: `0 2px 10px ${blackA.blackA7}`,
'&:hover': { backgroundColor: mauve.mauve3 },
'&:focus': { boxShadow: `0 0 0 2px black` },
},
green: {
backgroundColor: green.green4,
color: green.green11,
'&:hover': { backgroundColor: green.green5 },
'&:focus': { boxShadow: `0 0 0 2px ${green.green7}` },
},
},
},
defaultVariants: {
variant: 'violet',
},
});
const IconButton = styled('button', {
all: 'unset',
fontFamily: 'inherit',
borderRadius: '100%',
height: 25,
width: 25,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
color: violet.violet11,
position: 'absolute',
top: 10,
right: 10,
'&:hover': { backgroundColor: violet.violet4 },
'&:focus': { boxShadow: `0 0 0 2px ${violet.violet7}` },
});
const Fieldset = styled('fieldset', {
all: 'unset',
display: 'flex',
gap: 20,
alignItems: 'center',
marginBottom: 15,
});
const Label = styled('label', {
fontSize: 15,
color: violet.violet11,
width: 90,
textAlign: 'right',
});
const Input = styled('input', {
all: 'unset',
width: '100%',
flex: '1',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 4,
padding: '0 10px',
fontSize: 15,
lineHeight: 1,
color: violet.violet11,
boxShadow: `0 0 0 1px ${violet.violet7}`,
height: 35,
'&:focus': { boxShadow: `0 0 0 2px ${violet.violet8}` },
});
export default Modal;

View file

@ -8,6 +8,7 @@
"name": "learnhouse", "name": "learnhouse",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@radix-ui/colors": "^0.1.8",
"@radix-ui/react-dialog": "^1.0.2", "@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-icons": "^1.1.1", "@radix-ui/react-icons": "^1.1.1",
"@stitches/react": "^1.2.8", "@stitches/react": "^1.2.8",
@ -2352,6 +2353,11 @@
"url": "https://opencollective.com/popperjs" "url": "https://opencollective.com/popperjs"
} }
}, },
"node_modules/@radix-ui/colors": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-0.1.8.tgz",
"integrity": "sha512-jwRMXYwC0hUo0mv6wGpuw254Pd9p/R6Td5xsRpOmaWkUHlooNWqVcadgyzlRumMq3xfOTXwJReU0Jv+EIy4Jbw=="
},
"node_modules/@radix-ui/primitive": { "node_modules/@radix-ui/primitive": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz",
@ -8906,6 +8912,11 @@
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
}, },
"@radix-ui/colors": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-0.1.8.tgz",
"integrity": "sha512-jwRMXYwC0hUo0mv6wGpuw254Pd9p/R6Td5xsRpOmaWkUHlooNWqVcadgyzlRumMq3xfOTXwJReU0Jv+EIy4Jbw=="
},
"@radix-ui/primitive": { "@radix-ui/primitive": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz",

View file

@ -9,6 +9,7 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@radix-ui/colors": "^0.1.8",
"@radix-ui/react-dialog": "^1.0.2", "@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-icons": "^1.1.1", "@radix-ui/react-icons": "^1.1.1",
"@stitches/react": "^1.2.8", "@stitches/react": "^1.2.8",