mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: init new modal
This commit is contained in:
parent
f4c239d848
commit
ca5110e4f7
7 changed files with 283 additions and 26 deletions
|
|
@ -14,6 +14,7 @@ import NewChapterModal from "@components/Modals/CourseEdit/NewChapter";
|
|||
import NewActivityModal from "@components/Modals/CourseEdit/NewActivity";
|
||||
import { createActivity, createFileActivity } from "@services/courses/activities";
|
||||
import { getOrganizationContextInfo } from "@services/organizations/orgs";
|
||||
import Modal from "@components/UI/Modal/Modal";
|
||||
|
||||
function CourseEdit(params: any) {
|
||||
const router = useRouter();
|
||||
|
|
@ -123,6 +124,8 @@ function CourseEdit(params: any) {
|
|||
};
|
||||
|
||||
const closeNewActivityModal = () => {
|
||||
console.log("closeNewActivityModal");
|
||||
|
||||
setNewActivityModal(false);
|
||||
};
|
||||
|
||||
|
|
@ -233,13 +236,22 @@ function CourseEdit(params: any) {
|
|||
<Page>
|
||||
<Title>
|
||||
Edit Course {" "}
|
||||
<button
|
||||
onClick={() => {
|
||||
setNewChapterModal(true);
|
||||
}}
|
||||
>
|
||||
Add chapter +
|
||||
</button>
|
||||
<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>
|
||||
}
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
updateChapters();
|
||||
|
|
@ -247,16 +259,22 @@ function CourseEdit(params: any) {
|
|||
>
|
||||
Save
|
||||
</button>
|
||||
</Title>
|
||||
{newChapterModal && <NewChapterModal closeModal={closeNewChapterModal} submitChapter={submitChapter}></NewChapterModal>}
|
||||
{newActivityModal && (
|
||||
<NewActivityModal
|
||||
</Title>-
|
||||
|
||||
<Modal
|
||||
isDialogOpen={newActivityModal}
|
||||
onOpenChange={setNewActivityModal}
|
||||
minHeight="md"
|
||||
dialogContent={<NewActivityModal
|
||||
closeModal={closeNewActivityModal}
|
||||
submitFileActivity={submitFileActivity}
|
||||
submitActivity={submitActivity}
|
||||
chapterId={newActivityModalData}
|
||||
></NewActivityModal>
|
||||
)}
|
||||
></NewActivityModal>}
|
||||
dialogTitle="Create Activity"
|
||||
dialogDescription="Choose between types of activities to add to the course"
|
||||
|
||||
/>
|
||||
|
||||
<br />
|
||||
{winReady && (
|
||||
|
|
@ -287,7 +305,7 @@ function CourseEdit(params: any) {
|
|||
</DragDropContext>
|
||||
</ChapterlistWrapper>
|
||||
)}
|
||||
</Page>
|
||||
</Page >
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,11 @@ function Chapter(props: any) {
|
|||
props.openNewActivityModal(props.info.list.chapter.id);
|
||||
}}
|
||||
>
|
||||
|
||||
Create Activity
|
||||
</button>
|
||||
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
props.deleteChapter(props.info.list.chapter.id);
|
||||
|
|
|
|||
|
|
@ -9,20 +9,18 @@ function NewActivityModal({ closeModal, submitActivity, submitFileActivity, chap
|
|||
const [selectedView, setSelectedView] = useState("home");
|
||||
|
||||
return (
|
||||
<Modal>
|
||||
<button onClick={ () => {setSelectedView("home")}}>
|
||||
<div>
|
||||
<button onClick={() => { setSelectedView("home") }}>
|
||||
<ArrowLeftIcon />
|
||||
</button>
|
||||
<button onClick={closeModal}>
|
||||
<Cross1Icon />
|
||||
</button>
|
||||
<h1>Add New Activity</h1>
|
||||
<br />
|
||||
|
||||
{selectedView === "home" && (
|
||||
<ActivityChooserWrapper>
|
||||
<ActivityButton onClick={() => {setSelectedView("dynamic")}}>✨📄</ActivityButton>
|
||||
<ActivityButton onClick={() => {setSelectedView("video")}}>📹</ActivityButton>
|
||||
<ActivityButton onClick={() => { setSelectedView("dynamic") }}>✨📄</ActivityButton>
|
||||
<ActivityButton onClick={() => { setSelectedView("video") }}>📹</ActivityButton>
|
||||
</ActivityChooserWrapper>
|
||||
)}
|
||||
|
||||
|
|
@ -34,7 +32,7 @@ function NewActivityModal({ closeModal, submitActivity, submitFileActivity, chap
|
|||
<VideoModal submitFileActivity={submitFileActivity} chapterId={chapterId} />
|
||||
)}
|
||||
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,13 +20,13 @@ function NewChapterModal({ submitChapter , closeModal }: any) {
|
|||
};
|
||||
|
||||
return (
|
||||
<Modal>
|
||||
<h1>Add New Chapter <button onClick={closeModal}>X</button></h1>
|
||||
<div>
|
||||
<button onClick={closeModal}>X</button>
|
||||
<input type="text" onChange={handleChapterNameChange} placeholder="Chapter Name" /> <br />
|
||||
<input type="text" onChange={handleChapterDescriptionChange} placeholder="Chapter Description" />
|
||||
<br />
|
||||
<button onClick={handleSubmit}>Add Chapter</button>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
226
front/components/UI/Modal/Modal.tsx
Normal file
226
front/components/UI/Modal/Modal.tsx
Normal 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;
|
||||
11
front/package-lock.json
generated
11
front/package-lock.json
generated
|
|
@ -8,6 +8,7 @@
|
|||
"name": "learnhouse",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@radix-ui/colors": "^0.1.8",
|
||||
"@radix-ui/react-dialog": "^1.0.2",
|
||||
"@radix-ui/react-icons": "^1.1.1",
|
||||
"@stitches/react": "^1.2.8",
|
||||
|
|
@ -2352,6 +2353,11 @@
|
|||
"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": {
|
||||
"version": "1.0.0",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/colors": "^0.1.8",
|
||||
"@radix-ui/react-dialog": "^1.0.2",
|
||||
"@radix-ui/react-icons": "^1.1.1",
|
||||
"@stitches/react": "^1.2.8",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue