feat: emojies
This commit is contained in:
parent
b7baa00a20
commit
af59c764ed
@ -17,6 +17,7 @@
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dnd": "^3.0.2",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"emoji-mart": "^5.5.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"html-to-image": "^1.11.11",
|
||||
"jszip": "^3.10.1",
|
||||
@ -71,6 +72,8 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emoji-mart/data": "^1.1.2",
|
||||
"@emoji-mart/react": "^1.1.1",
|
||||
"@types/react-beautiful-dnd": "^13.1.4",
|
||||
"craco-alias": "^3.0.1"
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useState, useRef } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { Draggable } from "react-beautiful-dnd";
|
||||
import {
|
||||
@ -7,29 +7,30 @@ import {
|
||||
FormControl,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
Popover,
|
||||
useTheme,
|
||||
useMediaQuery,
|
||||
} from "@mui/material";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import { EmojiPicker } from "@ui_kit/EmojiPicker";
|
||||
|
||||
import { questionStore, updateQuestionsList } from "@root/questions";
|
||||
|
||||
import PointsIcon from "@icons/questionsPage/PointsIcon";
|
||||
import DeleteIcon from "@icons/questionsPage/deleteIcon";
|
||||
import MessageIcon from "@icons/messagIcon";
|
||||
import Popover from "@mui/material/Popover";
|
||||
import TextareaAutosize from "@mui/base/TextareaAutosize";
|
||||
import AddEmoji from "../../../assets/icons/questionsPage/addEmoji";
|
||||
|
||||
import type { ChangeEvent, KeyboardEvent } from "react";
|
||||
import type { Variants } from "@root/questions";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
type AnswerItemProps = {
|
||||
index: number;
|
||||
totalIndex: number;
|
||||
variants: Variants[];
|
||||
variant: Variants;
|
||||
icon?: ReactNode;
|
||||
emoji: boolean;
|
||||
};
|
||||
|
||||
export const AnswerItem = ({
|
||||
@ -37,12 +38,14 @@ export const AnswerItem = ({
|
||||
totalIndex,
|
||||
variants,
|
||||
variant,
|
||||
icon,
|
||||
emoji,
|
||||
}: AnswerItemProps) => {
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const quizId = Number(useParams().quizId);
|
||||
const { listQuestions } = questionStore();
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||
const anchorElement = useRef();
|
||||
const debounced = useDebouncedCallback((value) => {
|
||||
const answerNew = variants.slice();
|
||||
answerNew[index].answer = value;
|
||||
@ -69,7 +72,7 @@ export const AnswerItem = ({
|
||||
|
||||
const addNewAnswer = () => {
|
||||
const answerNew = variants.slice();
|
||||
answerNew.push({ answer: "", hints: "" });
|
||||
answerNew.push({ answer: "", hints: "", emoji: "" });
|
||||
|
||||
updateQuestionsList(quizId, totalIndex, {
|
||||
content: {
|
||||
@ -137,19 +140,64 @@ export const AnswerItem = ({
|
||||
>
|
||||
<PointsIcon />
|
||||
</InputAdornment>
|
||||
{icon && icon}
|
||||
{emoji && (
|
||||
<Box sx={{ cursor: "pointer", margin: "0 15px 0 5px" }}>
|
||||
<Box ref={anchorElement} onClick={() => setOpen(true)}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
gap: "5px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: "30px" }}>{variant.emoji}</Box>
|
||||
<AddEmoji />
|
||||
</Box>
|
||||
</Box>
|
||||
<Popover
|
||||
open={open}
|
||||
anchorEl={anchorElement.current}
|
||||
onClose={() => setOpen(false)}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
sx={{
|
||||
".MuiPaper-root.MuiPaper-rounded": {
|
||||
background: "transparent",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<EmojiPicker
|
||||
onEmojiSelect={({ native }) => {
|
||||
setOpen(false);
|
||||
const cloneVariants = [...variants];
|
||||
|
||||
cloneVariants[index] = {
|
||||
...cloneVariants[index],
|
||||
emoji: native,
|
||||
};
|
||||
|
||||
updateQuestionsList(quizId, totalIndex, {
|
||||
content: {
|
||||
...listQuestions[quizId][totalIndex].content,
|
||||
variants: cloneVariants,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Popover>
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton
|
||||
aria-describedby="my-popover-id"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<IconButton onClick={handleClick}>
|
||||
<MessageIcon />
|
||||
</IconButton>
|
||||
<Popover
|
||||
id="my-popover-id"
|
||||
open={isOpen}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
@ -173,7 +221,7 @@ export const AnswerItem = ({
|
||||
}}
|
||||
sx={{
|
||||
"& .MuiInputBase-root": {
|
||||
padding: icon ? "5px 13.5px" : "13.5px",
|
||||
padding: emoji ? "5px 13.5px" : "13.5px",
|
||||
borderRadius: "10px",
|
||||
background: "#ffffff",
|
||||
},
|
||||
|
||||
@ -8,20 +8,19 @@ import { updateVariants } from "@root/questions";
|
||||
|
||||
import { reorder } from "./helper";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import type { DropResult } from "react-beautiful-dnd";
|
||||
import type { Variants } from "@root/questions";
|
||||
|
||||
type AnswerDraggableListProps = {
|
||||
variants: Variants[];
|
||||
totalIndex: number;
|
||||
icon?: ReactNode;
|
||||
emoji?: boolean;
|
||||
};
|
||||
|
||||
export const AnswerDraggableList = ({
|
||||
variants,
|
||||
totalIndex,
|
||||
icon,
|
||||
emoji = false,
|
||||
}: AnswerDraggableListProps) => {
|
||||
const quizId = Number(useParams().quizId);
|
||||
|
||||
@ -45,7 +44,7 @@ export const AnswerDraggableList = ({
|
||||
totalIndex={totalIndex}
|
||||
variants={variants}
|
||||
variant={variant}
|
||||
icon={icon}
|
||||
emoji={emoji}
|
||||
/>
|
||||
))}
|
||||
{provided.placeholder}
|
||||
|
||||
@ -68,7 +68,7 @@ export default function ButtonsOptions({ SSHC, switchState, totalIndex }: Props)
|
||||
}}
|
||||
>
|
||||
{buttonSetting.map(({ icon, title, value, myFunc }) => (
|
||||
<>
|
||||
<Box key={value}>
|
||||
{value === "branching" ? (
|
||||
<Tooltip
|
||||
arrow
|
||||
@ -135,7 +135,7 @@ export default function ButtonsOptions({ SSHC, switchState, totalIndex }: Props)
|
||||
{isMobile ? null : title}
|
||||
</MiniButtonSetting>
|
||||
)}
|
||||
</>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
<Box
|
||||
|
||||
@ -27,7 +27,7 @@ export default function DropDown({ totalIndex }: Props) {
|
||||
|
||||
const addNewAnswer = () => {
|
||||
const answerNew = variants.slice();
|
||||
answerNew.push({ answer: "", hints: "" });
|
||||
answerNew.push({ answer: "", hints: "", emoji: "" });
|
||||
|
||||
updateQuestionsList(quizId, totalIndex, {
|
||||
content: {
|
||||
@ -39,7 +39,11 @@ export default function DropDown({ totalIndex }: Props) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ padding: isMobile ? "15px 20px 20px 20px" : "20px 20px 20px 20px " }}>
|
||||
<Box
|
||||
sx={{
|
||||
padding: isMobile ? "15px 20px 20px 20px" : "20px 20px 20px 20px ",
|
||||
}}
|
||||
>
|
||||
{variants.length === 0 ? (
|
||||
<Typography
|
||||
sx={{
|
||||
@ -81,7 +85,11 @@ export default function DropDown({ totalIndex }: Props) {
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<ButtonsOptions switchState={switchState} SSHC={SSHC} totalIndex={totalIndex} />
|
||||
<ButtonsOptions
|
||||
switchState={switchState}
|
||||
SSHC={SSHC}
|
||||
totalIndex={totalIndex}
|
||||
/>
|
||||
<SwitchDropDown switchState={switchState} totalIndex={totalIndex} />
|
||||
</>
|
||||
);
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import EnterIcon from "../../../assets/icons/questionsPage/enterIcon";
|
||||
import ButtonsOptions from "../ButtonsOptions";
|
||||
import SwitchEmoji from "./switchEmoji";
|
||||
import React from "react";
|
||||
import AddEmoji from "../../../assets/icons/questionsPage/addEmoji";
|
||||
import { AnswerDraggableList } from "../AnswerDraggableList";
|
||||
import { questionStore, updateQuestionsList } from "@root/questions";
|
||||
|
||||
@ -12,7 +11,7 @@ interface Props {
|
||||
totalIndex: number;
|
||||
}
|
||||
export default function Emoji({ totalIndex }: Props) {
|
||||
const [switchState, setSwitchState] = React.useState("setting");
|
||||
const [switchState, setSwitchState] = useState<string>("setting");
|
||||
const { listQuestions } = questionStore();
|
||||
const quizId = Number(useParams().quizId);
|
||||
const theme = useTheme();
|
||||
@ -28,11 +27,7 @@ export default function Emoji({ totalIndex }: Props) {
|
||||
<AnswerDraggableList
|
||||
variants={listQuestions[quizId][totalIndex].content.variants}
|
||||
totalIndex={totalIndex}
|
||||
icon={
|
||||
<Box sx={{ margin: "0 15px 0 5px" }}>
|
||||
<AddEmoji />
|
||||
</Box>
|
||||
}
|
||||
emoji
|
||||
/>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
||||
<Link
|
||||
@ -40,8 +35,9 @@ export default function Emoji({ totalIndex }: Props) {
|
||||
variant="body2"
|
||||
sx={{ color: theme.palette.brightPurple.main }}
|
||||
onClick={() => {
|
||||
const answerNew = listQuestions[quizId][totalIndex].content.variants.slice();
|
||||
answerNew.push({ answer: "", hints: "" });
|
||||
const answerNew =
|
||||
listQuestions[quizId][totalIndex].content.variants.slice();
|
||||
answerNew.push({ answer: "", hints: "", emoji: "" });
|
||||
|
||||
updateQuestionsList(quizId, totalIndex, {
|
||||
content: {
|
||||
@ -70,7 +66,11 @@ export default function Emoji({ totalIndex }: Props) {
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<ButtonsOptions switchState={switchState} SSHC={SSHC} totalIndex={totalIndex} />
|
||||
<ButtonsOptions
|
||||
switchState={switchState}
|
||||
SSHC={SSHC}
|
||||
totalIndex={totalIndex}
|
||||
/>
|
||||
<SwitchEmoji switchState={switchState} totalIndex={totalIndex} />
|
||||
</>
|
||||
);
|
||||
|
||||
@ -28,6 +28,7 @@ export default function OptionsAndPicture({ totalIndex }: Props) {
|
||||
<Box sx={{ paddingBottom: "25px" }}>
|
||||
{listQuestions[quizId][totalIndex].content.variants.map((_, index) => (
|
||||
<ButtonBase
|
||||
key={index}
|
||||
component="label"
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
@ -76,7 +77,7 @@ export default function OptionsAndPicture({ totalIndex }: Props) {
|
||||
sx={{ color: theme.palette.brightPurple.main }}
|
||||
onClick={() => {
|
||||
const clonContent = listQuestions[quizId][totalIndex].content;
|
||||
clonContent.variants.push({ answer: "", hints: "" });
|
||||
clonContent.variants.push({ answer: "", hints: "", emoji: "" });
|
||||
|
||||
updateQuestionsList(quizId, totalIndex, { content: clonContent });
|
||||
}}
|
||||
|
||||
@ -25,7 +25,7 @@ export default function AnswerOptions({ totalIndex }: Props) {
|
||||
|
||||
const addNewAnswer = () => {
|
||||
const answerNew = variants.slice();
|
||||
answerNew.push({ answer: "", hints: "" });
|
||||
answerNew.push({ answer: "", hints: "", emoji: "" });
|
||||
|
||||
updateQuestionsList(quizId, totalIndex, {
|
||||
content: {
|
||||
@ -87,7 +87,11 @@ export default function AnswerOptions({ totalIndex }: Props) {
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<ButtonsOptionsAndPict switchState={switchState} SSHC={SSHC} totalIndex={totalIndex} />
|
||||
<ButtonsOptionsAndPict
|
||||
switchState={switchState}
|
||||
SSHC={SSHC}
|
||||
totalIndex={totalIndex}
|
||||
/>
|
||||
<SwitchAnswerOptions switchState={switchState} totalIndex={totalIndex} />
|
||||
</>
|
||||
);
|
||||
|
||||
@ -4,6 +4,7 @@ import { persist } from "zustand/middleware";
|
||||
export type Variants = {
|
||||
answer: string;
|
||||
hints: string;
|
||||
emoji: string;
|
||||
};
|
||||
|
||||
type Hint = {
|
||||
@ -121,6 +122,7 @@ export const DEFAULT_QUESTION: Omit<Question, "id"> = {
|
||||
{
|
||||
answer: "",
|
||||
hints: "",
|
||||
emoji: "",
|
||||
},
|
||||
],
|
||||
hint: {
|
||||
|
||||
19
src/ui_kit/EmojiPicker.tsx
Normal file
19
src/ui_kit/EmojiPicker.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import EmojiPickerOriginal from "@emoji-mart/react";
|
||||
|
||||
type Emoji = {
|
||||
emoticons: string[];
|
||||
id: string;
|
||||
keywords: string[];
|
||||
name: string;
|
||||
native: string;
|
||||
shortcodes: string;
|
||||
unified: string;
|
||||
};
|
||||
|
||||
type EmojiPickerProps = {
|
||||
onEmojiSelect: (emoji: Emoji) => void;
|
||||
};
|
||||
|
||||
export const EmojiPicker = ({ onEmojiSelect }: EmojiPickerProps) => (
|
||||
<EmojiPickerOriginal onEmojiSelect={onEmojiSelect} />
|
||||
);
|
||||
15
yarn.lock
15
yarn.lock
@ -1218,6 +1218,16 @@
|
||||
resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz"
|
||||
integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==
|
||||
|
||||
"@emoji-mart/data@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@emoji-mart/data/-/data-1.1.2.tgz#777c976f8f143df47cbb23a7077c9ca9fe5fc513"
|
||||
integrity sha512-1HP8BxD2azjqWJvxIaWAMyTySeZY0Osr83ukYjltPVkNXeJvTz7yDrPLBtnrD5uqJ3tg4CcLuuBW09wahqL/fg==
|
||||
|
||||
"@emoji-mart/react@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@emoji-mart/react/-/react-1.1.1.tgz#ddad52f93a25baf31c5383c3e7e4c6e05554312a"
|
||||
integrity sha512-NMlFNeWgv1//uPsvLxvGQoIerPuVdXwK/EUek8OOkJ6wVOWPUizRBJU0hDqWZCOROVpfBgCemaC3m6jDOXi03g==
|
||||
|
||||
"@emotion/babel-plugin@^11.10.5":
|
||||
version "11.10.5"
|
||||
resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz"
|
||||
@ -4163,6 +4173,11 @@ emittery@^0.8.1:
|
||||
resolved "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz"
|
||||
integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==
|
||||
|
||||
emoji-mart@^5.5.2:
|
||||
version "5.5.2"
|
||||
resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-5.5.2.tgz#3ddbaf053139cf4aa217650078bc1c50ca8381af"
|
||||
integrity sha512-Sqc/nso4cjxhOwWJsp9xkVm8OF5c+mJLZJFoFfzRuKO+yWiN7K8c96xmtughYb0d/fZ8UC6cLIQ/p4BR6Pv3/A==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user