refactor: upgrade emoji lib

This commit is contained in:
Tristan Yang
2022-11-25 21:59:10 +08:00
parent 48a529e5d6
commit 858650924a
8 changed files with 516 additions and 696 deletions
+11 -11
View File
@@ -4,9 +4,9 @@
"private": true, "private": true,
"homepage": "https://voce.chat", "homepage": "https://voce.chat",
"dependencies": { "dependencies": {
"@emoji-mart/data": "^1.0.8", "@emoji-mart/react": "^1.0.1",
"@metamask/onboarding": "^1.0.1", "@metamask/onboarding": "^1.0.1",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.9", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"@react-oauth/google": "^0.5.0", "@react-oauth/google": "^0.5.0",
"@reduxjs/toolkit": "^1.9.0", "@reduxjs/toolkit": "^1.9.0",
"@svgr/webpack": "^6.5.1", "@svgr/webpack": "^6.5.1",
@@ -28,8 +28,8 @@
"dayjs": "^1.11.6", "dayjs": "^1.11.6",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"dotenv-expand": "^9.0.0", "dotenv-expand": "^9.0.0",
"emoji-mart": "3.0.1", "emoji-mart": "5.3.3",
"eslint": "^8.27.0", "eslint": "^8.28.0",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"firebase": "^9.14.0", "firebase": "^9.14.0",
"fs-extra": "^10.1.0", "fs-extra": "^10.1.0",
@@ -71,7 +71,7 @@
"style-loader": "^3.3.1", "style-loader": "^3.3.1",
"styled-components": "^5.3.6", "styled-components": "^5.3.6",
"styled-reset": "^4.4.2", "styled-reset": "^4.4.2",
"swiper": "^8.4.4", "swiper": "^8.4.5",
"terser-webpack-plugin": "^5.3.6", "terser-webpack-plugin": "^5.3.6",
"tippy.js": "^6.3.7", "tippy.js": "^6.3.7",
"typescript": "^4.9.3", "typescript": "^4.9.3",
@@ -120,16 +120,16 @@
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.2", "@babel/core": "^7.20.2",
"@babel/plugin-proposal-private-property-in-object": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.18.6",
"@commitlint/cli": "^17.2.0", "@commitlint/cli": "^17.3.0",
"@commitlint/config-conventional": "^17.2.0", "@commitlint/config-conventional": "^17.3.0",
"@types/emoji-mart": "^3.0.9", "@types/emoji-mart": "^3.0.9",
"@types/masonry-layout": "^4.2.5", "@types/masonry-layout": "^4.2.5",
"@types/react-helmet": "^6.1.5", "@types/react-helmet": "^6.1.5",
"@types/react-linkify": "^1.0.1", "@types/react-linkify": "^1.0.1",
"@types/react-syntax-highlighter": "^15.5.5", "@types/react-syntax-highlighter": "^15.5.5",
"@types/styled-components": "^5.1.26", "@types/styled-components": "^5.1.26",
"@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/eslint-plugin": "^5.44.0",
"@typescript-eslint/parser": "^5.43.0", "@typescript-eslint/parser": "^5.44.0",
"@welldone-software/why-did-you-render": "^7.0.1", "@welldone-software/why-did-you-render": "^7.0.1",
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.13",
"babel-loader": "^9.1.0", "babel-loader": "^9.1.0",
@@ -138,7 +138,7 @@
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.10", "eslint-plugin-react": "^7.31.11",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"gh-pages": "^4.0.0", "gh-pages": "^4.0.0",
"husky": "^8.0.2", "husky": "^8.0.2",
@@ -148,7 +148,7 @@
"postcss": "^8.4.19", "postcss": "^8.4.19",
"postcss-loader": "^7.0.1", "postcss-loader": "^7.0.1",
"postinstall-postinstall": "^2.1.0", "postinstall-postinstall": "^2.1.0",
"prettier": "^2.7.1", "prettier": "^2.8.0",
"tailwindcss": "^3.2.4" "tailwindcss": "^3.2.4"
} }
} }
-53
View File
@@ -1,53 +0,0 @@
import { useState, useEffect, FC } from "react";
import { EmojiData } from "emoji-mart";
import "emoji-mart/css/emoji-mart.css";
import { Picker } from "emoji-mart";
import styled from "styled-components";
interface Props {
onSelect: (emoji: EmojiData) => void;
}
const StyledWrapper = styled.div`
filter: drop-shadow(0px 25px 50px rgba(31, 41, 55, 0.25));
border-radius: 12px;
.emoji-mart {
border: none;
border-radius: 12px;
}
.emoji-mart-emoji {
cursor: pointer;
span {
cursor: inherit;
}
}
`;
const EmojiPicker: FC<Props> = ({ onSelect, ...rest }) => {
const [visible, setVisible] = useState(false);
useEffect(() => {
const inter = setTimeout(() => {
setVisible(true);
}, 500);
return () => {
clearTimeout(inter);
};
}, []);
return (
<StyledWrapper>
{visible ? (
<Picker
perLine={10}
emojiSize={24}
emojiTooltip={true}
showSkinTones={false}
onSelect={onSelect}
{...rest}
/>
) : null}
</StyledWrapper>
);
};
export default EmojiPicker;
+4 -5
View File
@@ -1,10 +1,8 @@
import { FC } from "react"; import { FC } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { getEmojiDataFromNative } from "emoji-mart";
import AppleEmojiData from "emoji-mart/data/apple.json";
import Tippy from "@tippyjs/react"; import Tippy from "@tippyjs/react";
import { hideAll } from "tippy.js"; import { hideAll } from "tippy.js";
import ReactionItem, { Emojis } from "../ReactionItem"; import ReactionItem, { Emojis, ReactionMap } from "../ReactionItem";
import ReactionPicker from "./ReactionPicker"; import ReactionPicker from "./ReactionPicker";
import Tooltip from "../Tooltip"; import Tooltip from "../Tooltip";
import { useReactMessageMutation } from "../../../app/services/message"; import { useReactMessageMutation } from "../../../app/services/message";
@@ -105,6 +103,7 @@ const StyledDetails = styled.div`
color: #1d2939; color: #1d2939;
} }
`; `;
const ReactionDetails = ({ const ReactionDetails = ({
uids = [], uids = [],
emoji, emoji,
@@ -118,7 +117,7 @@ const ReactionDetails = ({
const names = uids.map((id) => { const names = uids.map((id) => {
return usersData[id]?.name; return usersData[id]?.name;
}); });
const emojiData = getEmojiDataFromNative(emoji || "", "apple", AppleEmojiData); // const emojiData = getEmojiDataFromNative(emoji || "", "apple", AppleEmojiData);
const prefixDesc = const prefixDesc =
names.length > 3 names.length > 3
? `${names.join(", ")} and ${names.length - 3} others reacted with` ? `${names.join(", ")} and ${names.length - 3} others reacted with`
@@ -130,7 +129,7 @@ const ReactionDetails = ({
</div> </div>
<div className="desc"> <div className="desc">
<span>{prefixDesc}</span> <span>{prefixDesc}</span>
<span>{emojiData?.colons}</span> <span>{ReactionMap[emoji]}</span>
</div> </div>
</StyledDetails> </StyledDetails>
); );
+10 -1
View File
@@ -18,7 +18,16 @@ export interface Emojis {
"🙁": ReactElement; "🙁": ReactElement;
"🎉": ReactElement; "🎉": ReactElement;
} }
export const ReactionMap = {
"🎉": ":tada:",
"👍": ":+1:",
"🙁": ":slightly_frown_face:",
"❤️": ":heart:",
"👎": ":thumb_down:",
"😄": ":smile:",
"👀": ":eyes:",
"🚀": ":rocket:",
};
const emojis: Emojis = { const emojis: Emojis = {
"👍": <EmojiThumbUp className="emoji" />, "👍": <EmojiThumbUp className="emoji" />,
"👎": <EmojiThumbDown className="emoji" />, "👎": <EmojiThumbDown className="emoji" />,
+28 -10
View File
@@ -1,10 +1,9 @@
import { useState, useRef } from "react"; import { useState, useRef, useEffect } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useOutsideClick } from "rooks"; import { useOutsideClick } from "rooks";
import Tooltip from "../Tooltip"; import Tooltip from "../Tooltip";
import Picker from "../EmojiPicker"; import { Picker } from 'emoji-mart';
import SmileIcon from "../../../assets/icons/emoji.smile.svg"; import SmileIcon from "../../../assets/icons/emoji.smile.svg";
import { BaseEmoji, EmojiData } from "emoji-mart";
const Styled = styled.div` const Styled = styled.div`
position: relative; position: relative;
@@ -13,19 +12,20 @@ const Styled = styled.div`
align-items: center; align-items: center;
> .emoji { > .emoji {
cursor: pointer; cursor: pointer;
user-select: none;
} }
> svg { > svg {
width: 22px; width: 22px;
height: 22px; height: 22px;
} }
> .picker { > .picker {
visibility: hidden; display: none;
position: absolute; position: absolute;
top: -20px; top: -20px;
left: -20px; left: -20px;
transform: translateY(-100%); transform: translateY(-100%);
&.visible { &.visible {
visibility: visible; display: block;
} }
} }
`; `;
@@ -33,14 +33,32 @@ const Styled = styled.div`
export default function EmojiPicker({ selectEmoji }: { selectEmoji: (e: string) => void }) { export default function EmojiPicker({ selectEmoji }: { selectEmoji: (e: string) => void }) {
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const togglePickerVisible = () => { const togglePickerVisible = () => {
setVisible((prev) => !prev); setVisible((prev) => !prev);
}; };
useEffect(() => {
if (ref && ref.current) {
ref.current.innerHTML = "";
new Picker({
data: async () => {
const response = await fetch(
'https://cdn.jsdelivr.net/npm/@emoji-mart/data',
);
const handleSelect = (emoji: EmojiData) => { return response.json();
selectEmoji((emoji as BaseEmoji).native); },
}; parent: ref.current,
onEmojiSelect: (item) => {
console.log("eee333", item);
selectEmoji(item.native);
},
// onClickOutside: () => {
// setVisible(false);
// }
});
}
}, [selectEmoji]);
useOutsideClick( useOutsideClick(
ref, ref,
@@ -59,7 +77,7 @@ export default function EmojiPicker({ selectEmoji }: { selectEmoji: (e: string)
<Tooltip placement="top" tip="Emojis" disabled={visible}> <Tooltip placement="top" tip="Emojis" disabled={visible}>
<Styled> <Styled>
<div ref={ref} className={`picker ${visible ? "visible" : ""}`}> <div ref={ref} className={`picker ${visible ? "visible" : ""}`}>
<Picker onSelect={handleSelect} /> {/* emoji picker */}
</div> </div>
<SmileIcon data-emoji="toggler" className="emoji" onClick={togglePickerVisible} /> <SmileIcon data-emoji="toggler" className="emoji" onClick={togglePickerVisible} />
</Styled> </Styled>
+2
View File
@@ -62,6 +62,8 @@ declare module "*.module.css" {
const classes: { readonly [key: string]: string }; const classes: { readonly [key: string]: string };
export default classes; export default classes;
} }
declare module '@emoji-mart/react';
interface Window { interface Window {
ethereum: any; ethereum: any;
} }
+42 -32
View File
@@ -1,4 +1,4 @@
import { Suspense, useEffect, lazy } from "react"; import { useEffect, lazy } from "react";
import { Route, Routes, HashRouter } from "react-router-dom"; import { Route, Routes, HashRouter } from "react-router-dom";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
@@ -22,12 +22,14 @@ const SettingChannelPage = lazy(() => import("./settingChannel"));
const SettingPage = lazy(() => import("./setting")); const SettingPage = lazy(() => import("./setting"));
const ResourceManagement = lazy(() => import("./resources")); const ResourceManagement = lazy(() => import("./resources"));
const GuestLogin = lazy(() => import("./guest")); const GuestLogin = lazy(() => import("./guest"));
const ChatPage = lazy(() => import("./chat"));
const HomePage = lazy(() => import("./home"));
import RequireAuth from "../common/component/RequireAuth"; import RequireAuth from "../common/component/RequireAuth";
import RequireNoAuth from "../common/component/RequireNoAuth"; import RequireNoAuth from "../common/component/RequireNoAuth";
import Meta from "../common/component/Meta"; import Meta from "../common/component/Meta";
import HomePage from "./home"; // import HomePage from "./home";
import ChatPage from "./chat"; // import ChatPage from "./chat";
import Loading from "../common/component/Loading"; import LazyIt from './lazy';
import store, { useAppSelector } from "../app/store"; import store, { useAppSelector } from "../app/store";
let toastId: string; let toastId: string;
const PageRoutes = () => { const PageRoutes = () => {
@@ -49,96 +51,105 @@ const PageRoutes = () => {
return ( return (
<HashRouter> <HashRouter>
<Suspense fallback={<Loading fullscreen={true} />}>
<Routes> <Routes>
<Route path="/guest_login" element={<GuestLogin />} /> <Route path="/guest_login" element={<LazyIt><GuestLogin /></LazyIt>} />
<Route path="/cb/:type/:payload" element={<CallbackPage />} /> <Route path="/cb/:type/:payload" element={<LazyIt><CallbackPage /></LazyIt>} />
<Route path="/oauth/:token" element={<OAuthPage />} /> <Route path="/oauth/:token" element={<LazyIt><OAuthPage /></LazyIt>} />
<Route <Route
path="/login" path="/login"
element={ element={
<LazyIt>
<RequireNoAuth> <RequireNoAuth>
<LoginPage /> <LoginPage />
</RequireNoAuth> </RequireNoAuth>
</LazyIt>
} }
/> />
<Route <Route
path="/send_magic_link" path="/send_magic_link"
element={ element={
<LazyIt>
<RequireNoAuth> <RequireNoAuth>
<SendMagicLinkPage /> <SendMagicLinkPage />
</RequireNoAuth> </RequireNoAuth>
</LazyIt>
} }
/> />
<Route <Route
path="/register" path="/register"
element={ element={
<LazyIt>
<RequireNoAuth> <RequireNoAuth>
<RegBasePage /> <RegBasePage />
</RequireNoAuth> </RequireNoAuth>
</LazyIt>
} }
> >
<Route index element={<RegPage />} /> <Route index element={<LazyIt><RegPage /></LazyIt>} />
<Route path="set_name"> <Route path="set_name">
<Route index element={<RegWithUsernamePage />} /> <Route index element={<LazyIt><RegWithUsernamePage /></LazyIt>} />
<Route path=":from" element={<RegWithUsernamePage />} /> <Route path=":from" element={<LazyIt><RegWithUsernamePage /></LazyIt>} />
</Route> </Route>
</Route> </Route>
<Route <Route
path="/email_login" path="/email_login"
element={ element={
<LazyIt>
<RequireNoAuth> <RequireNoAuth>
<SendMagicLinkPage /> <SendMagicLinkPage />
</RequireNoAuth> </RequireNoAuth>
</LazyIt>
} }
/> />
<Route path="/invite" element={<InvitePage />} /> <Route path="/invite" element={<LazyIt><InvitePage /></LazyIt>} />
<Route path="/onboarding" element={<OnboardingPage />} /> <Route path="/onboarding" element={<LazyIt><OnboardingPage /></LazyIt>} />
<Route <Route
key={"main"} key={"main"}
path="/" path="/"
element={ element={
<LazyIt>
<RequireAuth> <RequireAuth>
<HomePage /> <HomePage />
</RequireAuth> </RequireAuth>
</LazyIt>
} }
> >
<Route path="setting"> <Route path="setting">
<Route <Route
index index
element={ element={
<Suspense fallback={<Loading />}> <LazyIt>
<SettingPage /> <SettingPage />
</Suspense> </LazyIt>
} }
/> />
<Route path="channel/:cid" element={<SettingChannelPage />} /> <Route path="channel/:cid" element={<LazyIt><SettingChannelPage /></LazyIt>} />
</Route> </Route>
<Route <Route
index index
element={ element={
// <Suspense fallback={<Loading />}> <LazyIt>
<ChatPage /> <ChatPage />
// </Suspense> </LazyIt>
} }
/> />
<Route path="chat"> <Route path="chat">
<Route index element={<ChatPage />} /> <Route index element={<LazyIt><ChatPage /></LazyIt>} />
<Route <Route
path="channel/:channel_id" path="channel/:channel_id"
element={ element={
// <Suspense fallback={<Loading />}> <LazyIt>
<ChatPage /> <ChatPage />
// </Suspense> </LazyIt>
} }
/> />
<Route <Route
path="dm/:user_id" path="dm/:user_id"
element={ element={
// <Suspense fallback={<Loading />}> <LazyIt>
<ChatPage /> <ChatPage />
// </Suspense> </LazyIt>
} }
/> />
</Route> </Route>
@@ -146,40 +157,39 @@ const PageRoutes = () => {
<Route <Route
index index
element={ element={
<Suspense fallback={<Loading />}> <LazyIt>
<UsersPage /> <UsersPage />
</Suspense> </LazyIt>
} }
/> />
<Route <Route
path=":user_id" path=":user_id"
element={ element={
<Suspense fallback={<Loading />}> <LazyIt>
<UsersPage /> <UsersPage />
</Suspense> </LazyIt>
} }
/> />
</Route> </Route>
<Route <Route
path="favs" path="favs"
element={ element={
<Suspense fallback={<Loading />}> <LazyIt>
<FavoritesPage /> <FavoritesPage />
</Suspense> </LazyIt>
} }
></Route> ></Route>
<Route <Route
path="files" path="files"
element={ element={
<Suspense fallback={<Loading />}> <LazyIt>
<ResourceManagement fileMessages={fileMessages} /> <ResourceManagement fileMessages={fileMessages} />
</Suspense> </LazyIt>
} }
></Route> ></Route>
</Route> </Route>
<Route path="*" element={<NotFoundPage />} /> <Route path="*" element={<NotFoundPage />} />
</Routes> </Routes>
</Suspense>
</HashRouter> </HashRouter>
); );
}; };
+339 -504
View File
File diff suppressed because it is too large Load Diff