Repository: Same-Page/front-and-back Branch: master Commit: 967be22b5f1a Files: 231 Total size: 1.9 MB Directory structure: gitextract_332hnacs/ ├── .gitignore ├── .prettierrc ├── README.md ├── README_EN.md ├── chatbox/ │ ├── .gitignore │ ├── .prettierrc │ ├── .storybook/ │ │ ├── addons.js │ │ └── config.js │ ├── README.md │ ├── package.json │ ├── public/ │ │ ├── index.html │ │ └── manifest.json │ └── src/ │ ├── .eslintrc.json │ ├── App.js │ ├── components/ │ │ ├── Emoji/ │ │ │ ├── Emoji.css │ │ │ ├── Emoji.js │ │ │ └── index.js │ │ ├── Iframe/ │ │ │ ├── Iframe.css │ │ │ ├── Iframe.js │ │ │ └── index.js │ │ ├── InputWithPicker/ │ │ │ ├── InputWithPicker.css │ │ │ ├── InputWithPicker.js │ │ │ └── index.js │ │ ├── MusicPlayer/ │ │ │ ├── MusicPlayer.css │ │ │ ├── MusicPlayer.js │ │ │ └── index.js │ │ └── OutsideClickDetector.js │ ├── config/ │ │ ├── index.js │ │ ├── logger.js │ │ └── urls.js │ ├── containers/ │ │ ├── Account/ │ │ │ ├── Account.js │ │ │ ├── AvatarUploader/ │ │ │ │ ├── AvatarUploader.css │ │ │ │ ├── AvatarUploader.js │ │ │ │ └── index.js │ │ │ ├── Blacklist.js │ │ │ ├── EditProfile.js │ │ │ ├── Follow/ │ │ │ │ ├── Follow.css │ │ │ │ ├── Follow.js │ │ │ │ ├── event.js │ │ │ │ └── index.js │ │ │ ├── Login.js │ │ │ ├── Profile/ │ │ │ │ ├── Profile.css │ │ │ │ ├── Profile.js │ │ │ │ └── index.js │ │ │ ├── ResetPassword.js │ │ │ └── index.js │ │ ├── Chat/ │ │ │ ├── Body.css │ │ │ ├── Body.js │ │ │ ├── Chat.js │ │ │ ├── Footer/ │ │ │ │ ├── Footer.css │ │ │ │ ├── Footer.js │ │ │ │ └── index.js │ │ │ ├── Header/ │ │ │ │ ├── Header.css │ │ │ │ ├── Header.js │ │ │ │ ├── Invite.js │ │ │ │ ├── RoomHeader.js │ │ │ │ ├── RoomInfo.js │ │ │ │ ├── Users.js │ │ │ │ └── index.js │ │ │ ├── Message/ │ │ │ │ ├── Body.css │ │ │ │ ├── Body.js │ │ │ │ ├── Message.css │ │ │ │ ├── Message.js │ │ │ │ └── index.js │ │ │ ├── ResizableMedia.js │ │ │ ├── View.js │ │ │ └── index.js │ │ ├── Comment/ │ │ │ ├── Body.js │ │ │ ├── Comment.css │ │ │ ├── Comment.js │ │ │ ├── Header.js │ │ │ ├── Message/ │ │ │ │ ├── Message.css │ │ │ │ ├── Message.js │ │ │ │ └── index.js │ │ │ └── index.js │ │ ├── Home/ │ │ │ ├── Comments/ │ │ │ │ ├── Comment.css │ │ │ │ ├── Comments.js │ │ │ │ └── index.js │ │ │ ├── CreateRoom.js │ │ │ ├── Danmus/ │ │ │ │ ├── Danmus.js │ │ │ │ └── index.js │ │ │ ├── Discover.js │ │ │ ├── Home.css │ │ │ ├── Home.js │ │ │ ├── Rooms/ │ │ │ │ ├── Room.css │ │ │ │ ├── Rooms.js │ │ │ │ └── index.js │ │ │ ├── RoomsWrapper.js │ │ │ ├── Users/ │ │ │ │ ├── Users.css │ │ │ │ ├── Users.js │ │ │ │ └── index.js │ │ │ ├── VideoRoom/ │ │ │ │ ├── VideoRoom.js │ │ │ │ └── index.js │ │ │ └── index.js │ │ ├── Inbox/ │ │ │ ├── Conversation/ │ │ │ │ ├── Conversation.css │ │ │ │ ├── Conversation.js │ │ │ │ └── index.js │ │ │ ├── Inbox.css │ │ │ ├── Inbox.js │ │ │ └── index.js │ │ ├── Music/ │ │ │ ├── MusicTab.js │ │ │ ├── Playlist/ │ │ │ │ ├── Playlist.css │ │ │ │ ├── Playlist.js │ │ │ │ └── index.js │ │ │ └── index.js │ │ ├── OtherProfile/ │ │ │ ├── AvatarWithHoverCard.js │ │ │ ├── OtherProfile.js │ │ │ ├── ProfileBody/ │ │ │ │ ├── ProfileBody.js │ │ │ │ └── index.js │ │ │ ├── ProfileCard.css │ │ │ ├── ProfileCard.js │ │ │ ├── ProfileMeta/ │ │ │ │ ├── ProfileMeta.js │ │ │ │ └── index.js │ │ │ └── index.js │ │ └── Tab/ │ │ ├── Tab.css │ │ ├── Tab.js │ │ └── index.js │ ├── context/ │ │ └── preference-context.js │ ├── i18n/ │ │ ├── en.json │ │ └── zh.json │ ├── index.css │ ├── index.js │ ├── redux/ │ │ ├── actions/ │ │ │ ├── chat/ │ │ │ │ └── index.js │ │ │ └── index.js │ │ ├── reducers/ │ │ │ └── index.js │ │ └── store/ │ │ └── index.js │ ├── serviceWorker.js │ ├── services/ │ │ ├── account.js │ │ ├── comment.js │ │ ├── danmu.js │ │ ├── follow.js │ │ ├── index.js │ │ ├── message.js │ │ ├── room.js │ │ └── user.js │ ├── socket/ │ │ ├── index.js │ │ └── socket.js │ ├── stories/ │ │ ├── IframeWithSrcInput.js │ │ ├── data/ │ │ │ ├── chats.js │ │ │ └── comments.js │ │ ├── iframe.css │ │ └── index.js │ └── utils/ │ ├── pageTitle.js │ ├── storage.js │ └── url.js ├── extension/ │ ├── build/ │ │ ├── _locales/ │ │ │ ├── en/ │ │ │ │ └── messages.json │ │ │ └── zh_CN/ │ │ │ └── messages.json │ │ ├── background.js │ │ ├── content-static/ │ │ │ ├── css/ │ │ │ │ └── main.css │ │ │ └── js/ │ │ │ └── main.js │ │ ├── manifest.json │ │ ├── popup.css │ │ ├── popup.html │ │ ├── popup_menu/ │ │ │ ├── css/ │ │ │ │ └── main.css │ │ │ └── js/ │ │ │ └── main.js │ │ └── popup_old.js │ └── popup/ │ ├── .gitignore │ ├── README.md │ ├── config/ │ │ ├── env.js │ │ ├── jest/ │ │ │ ├── cssTransform.js │ │ │ └── fileTransform.js │ │ ├── paths.js │ │ ├── webpack.config.js │ │ └── webpackDevServer.config.js │ ├── package.json │ ├── public/ │ │ ├── index.html │ │ └── manifest.json │ ├── scripts/ │ │ ├── build.js │ │ ├── start.js │ │ └── test.js │ └── src/ │ ├── App.js │ ├── App.test.js │ ├── index.css │ ├── index.js │ └── serviceWorker.js └── inject-script/ ├── .gitignore ├── .storybook/ │ ├── addons.js │ ├── config.js │ └── webpack_empty.config.js ├── README.md ├── config/ │ ├── env.js │ ├── jest/ │ │ ├── cssTransform.js │ │ └── fileTransform.js │ ├── paths.js │ ├── webpack.config.js │ └── webpackDevServer.config.js ├── package.json ├── public/ │ ├── index.html │ └── manifest.json ├── scripts/ │ ├── build.js │ ├── start.js │ └── test.js ├── src/ │ ├── config/ │ │ ├── iframe.js │ │ ├── index.js │ │ ├── logger.js │ │ └── urls.js │ ├── containers/ │ │ ├── App/ │ │ │ ├── App.js │ │ │ ├── App.test.js │ │ │ └── index.js │ │ ├── ChatDanmu/ │ │ │ ├── AnimationDanmu.css │ │ │ ├── AnimationDanmu.js │ │ │ └── Danmu.js │ │ ├── ChatIcon/ │ │ │ ├── ChatIcon.js │ │ │ └── index.js │ │ ├── ChatboxIframe/ │ │ │ ├── ChatboxIframe.css │ │ │ ├── ChatboxIframe.js │ │ │ └── index.js │ │ ├── ImageModal/ │ │ │ ├── ImageModal.css │ │ │ ├── ImageModal.js │ │ │ └── index.js │ │ ├── Room/ │ │ │ ├── Room.css │ │ │ ├── Room.js │ │ │ └── index.js │ │ └── User/ │ │ ├── User.css │ │ ├── User.js │ │ └── index.js │ ├── index.css │ ├── index.js │ ├── serviceWorker.js │ ├── services/ │ │ ├── account/ │ │ │ ├── account.js │ │ │ └── index.js │ │ ├── room/ │ │ │ ├── index.js │ │ │ └── room.js │ │ ├── socket/ │ │ │ ├── index.js │ │ │ └── socket.js │ │ └── user/ │ │ ├── index.js │ │ └── user.js │ ├── storage.js │ └── utils/ │ ├── iframe.js │ └── url.js └── stories/ └── index.stories.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store client/extension/build/content-static/* client/extension/build.zip client/.vscode/launch.json *.zip ================================================ FILE: .prettierrc ================================================ { "trailingComma": "none", "arrowParens": "avoid", "semi": false, "useTabs": true, "printWidth": 80 } ================================================ FILE: README.md ================================================ #### [Read English Version](https://github.com/Same-Page/client/blob/master/README_EN.md) # 一叶 《一叶》是一款[浏览器插件](https://chrome.google.com/webstore/detail/same-page/bldcellajihanglphncgjmceklbibjkk),它让你可以在任意网页上实时聊天。 你也可以将一叶聊天盒部署在你自己的网站上,一叶的前后端代码都是开源的。 主要功能包括有: - 同网页聊天 - 同网站聊天 - 创建个性化房间 - 用户之间可以关注,发私信等 ## 截图 ## 项目结构 一叶的前端代码在本项目里。 Client 文件夹主要有 chatbox 和 inject-script 两部分,都是用 create-react-app 创建的。工作方法是首先在网页里引入 inject-script,然后 inject-script 运行时会生成一个包含了聊天盒的 iframe。 这种分离的设计有两个优点: 1. 聊天盒因为功能很多所以文件较大,所以不用在每次加载页面的时候就加载它,而是当用户想要使用的时候才打开。 2. Iframe 可以起到很好的隔离作用,你的网站和一叶之间不会互相影响,不论是 javascript 还是 css 样式。 Inject script 部分的文件比较小,它的功能有: 1. 在网页上增加一个按钮,点击按钮可以打开含有聊天盒的 iframe。 2. 自动连接聊天服务器,显示多少人在当前网页或网站,显示实时聊天弹幕。 ## 如何开发与本地运行 ### 本地运行客户端 前面提到了客户端分有 inject-script 和 chatbox 两部分,两者都要启动聊天盒才能正常使用。 首先运行 chatbox 部分 ``` cd client/chatbox npm install . npm start ``` 第一次运行需要先 `npm install .`安装依赖的库,之后则不用。项目会运行于 localhost:3000,但聊天盒并不能独立工作,接下来我们运行 injection-script 的部分。 ``` cd client/inject-script npm install . npm start ``` 现在如果你去 localhost:3210,就可以看到客户端正常运行了,点击右下角的圆圈打开聊天盒。 客户端默认会和官方的服务器通讯,而不是你的本地后端,你可以更改默认的设定,让客户端和你的本地后端通讯。如何运行后端代码请见后端的代码库 [聊天系统后端](https://github.com/Same-Page/chat-backend) [基本系统后端](https://github.com/Same-Page/web-backend) ## 如何部署前端 ### 生成客户端文件 Inject-script 和 chatbox 两部分要分别生成。 生成聊天盒的客户端文件。 ``` cd client/chatbox npm run build ``` 生成 inject-script 的客户端文件。 ``` cd client/inject-scirpt npm run build ``` 生成的文件在对应的 build 文件夹里,更多细节可以参考 Facebook 官方的 create-react-app 教程。 ### 部署到你的网站上 将 inject-script 的`client/inject-scirpt/build/content-static`文件夹上传到你的服务器,确保可以以`your-website.com/build/content-static`的形式访问里面的文件. 接下来在你的网站里引入下面两行即可 ``` ``` 如果聊天盒的部分也要使用你自己生成的版本,相似的,上传你的`client/chatbox/build/`文件夹到你的服务器,确保可以访问`your-website.com/build/static`里面的文件。同时要记得修改 injection script 中设置的 chatbox iframe 的地址指向你自己上传的这个版本,`your-website.com/build/index.html`,也可以在你的网站定义下面的设置。 ``` window.spConfig = { chatboxUrl: 'your-website.com/build/index.html' } ``` ================================================ FILE: README_EN.md ================================================ # Same Page Same Page (previously called Chat Anywhere) is a [Chrome extension](https://chrome.google.com/webstore/detail/same-page/bldcellajihanglphncgjmceklbibjkk) that adds a chat box to any website. You can also customize the source code and use it on your own website. ## Project structure This repository contains frontend code only. The client folder includes the chat box and an injection script, both of them are built with create-react-app. The way it works is that once you include the injection script to your website, the script can create an iframe with chat box. This design has two major benefits: 1. The chat box's file size is quite big because it includes so many features, therefore you probably don't want to load it on every page load. It makes a lot more sense to load the chat box iframe only when user wants to use it. 2. Iframe provides great isolation of the chat box and your website, no need to worry about CSS or Javascript pollution. The injection script itself is rather small, it's able to 1. Add a button that creates the iframe with chat box. 2. Connect to chat socket server and show how many users are on the same page or site. 3. Show Danmu (scrolling text) for live messages. We include the 2nd and the 3rd functionality to the injection script rather than the chat box because they are very useful for the Chrome extension. ## How to develop and run locally ### Run the client locally Remeber that the client contains two pieces, so there are two steps to run client locally. First, run the chat box app ``` cd client/chatbox npm install . npm start ``` The first time you run this will be slower, because it needs to install all the packages needed. The chat box will be running on localhost:3000, but the chat box is not designed to be used by itself, instead, it must be used in an iframe. So the next thing you need to do is to run the injection script app. ``` cd client/injection-script npm install . npm start ``` Now you should see the client running on localhost:3210, the chatbox should also show up there. The client is talking to the official backend by default. If you want the client to talk to your local backend, it's very easy. Instead of `npm start`, type `npm start:dev`. Then it will be talking to your localhost:8080 for websocket connections for live chat feature and localhost:8081 for ajax calls for all other purposes. So you need to have those running. Please read the next section to learn how to run backend locally. ### Run websocket server locally for live chat ``` cd server/chat-socket npm install . node index.js ``` ### Run API backend locally ``` cd server/api (Highly recommend that you create a Python virtual env first) pip install -r requirements.txt python run.py ``` ## How to deploy frontend ### Build Like mentioned before, the client has two parts - chat box and injection script. They need to be built separately. To build the chat box. ``` cd client/chatbox npm run build ``` To build the injection script. ``` cd client/injection-scirpt npm run build ``` The final build is placed in the `/build` folder. ### Deploy To use your own version of injection script, upload your `client/injection-scirpt/build/content-static` folder to your server so it's reachable as `your-website.com/build/content-static`. Then include the scripts by adding following lines to your website. ``` ``` To use your own version of chat box, upload your `client/chatbox/build/content-static` folder to your server so it's reachable as `your-website.com/build/static`. You'll need to modify the injection script, specifically the iframe src to point to your own chat box, otherwise it will use the offical build of the chat box. This doc needs update... ================================================ FILE: chatbox/.gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: chatbox/.prettierrc ================================================ { "tabWidth": 2, "semi": false } ================================================ FILE: chatbox/.storybook/addons.js ================================================ import '@storybook/addon-actions/register'; import '@storybook/addon-links/register'; ================================================ FILE: chatbox/.storybook/config.js ================================================ import { configure } from '@storybook/react'; function loadStories() { require('../src/stories'); } configure(loadStories, module); ================================================ FILE: chatbox/README.md ================================================ This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). ## Available Scripts In the project directory, you can run: ### `npm start` Runs the app in the development mode.
Open [http://localhost:3000](http://localhost:3000) to view it in the browser. The page will reload if you make edits.
You will also see any lint errors in the console. ### `npm test` Launches the test runner in the interactive watch mode.
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. ### `npm run build` Builds the app for production to the `build` folder.
It correctly bundles React in production mode and optimizes the build for the best performance. The build is minified and the filenames include the hashes.
Your app is ready to be deployed! See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. ### `npm run eject` **Note: this is a one-way operation. Once you `eject`, you can’t go back!** If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. ## Learn More You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). To learn React, check out the [React documentation](https://reactjs.org/). ### Code Splitting This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting ### Analyzing the Bundle Size This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size ### Making a Progressive Web App This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app ### Advanced Configuration This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration ### Deployment This section has moved here: https://facebook.github.io/create-react-app/docs/deployment ### `npm run build` fails to minify This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify ================================================ FILE: chatbox/package.json ================================================ { "name": "same-page", "homepage": "./", "version": "0.1.0", "private": true, "dependencies": { "@material-ui/core": "^3.9.3", "antd": "^3.16.1", "axios": "^0.18.0", "emoji-mart": "^2.11.0", "fsevents": "^1.2.9", "material-ui": "^0.20.2", "moment": "^2.24.0", "re-resizable": "^6.2.0", "react": "^16.8.6", "react-dom": "^16.8.6", "react-images-upload": "^1.2.6", "react-intl": "^3.6.0", "react-redux": "^6.0.1", "react-scripts": "2.1.8", "redux": "^4.0.1", "rsuite": "^3.8.2", "video.js": "^7.5.4", "videojs-flash": "^2.2.0", "videojs-playlist": "^4.3.1", "videojs-youtube": "^2.6.0" }, "scripts": { "start:no_ssl": "react-scripts start", "start": "export HTTPS=true; react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject-nonono": "react-scripts eject", "storybook": "start-storybook -p 9009 -s public", "build-storybook": "build-storybook -s public" }, "eslintConfig": { "extends": "react-app", "plugins": [ "react-hooks" ], "rules": { "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn" } }, "browserslist": [ ">0.2%", "not dead", "not ie <= 11", "not op_mini all" ], "devDependencies": { "@babel/core": "^7.4.3", "@storybook/addon-actions": "^5.0.6", "@storybook/addon-links": "^5.0.6", "@storybook/addons": "^5.0.6", "@storybook/react": "^5.0.6", "babel-loader": "^8.0.5", "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.17.3", "eslint-plugin-jsx-a11y": "^6.2.1", "eslint-plugin-react": "^7.13.0", "eslint-plugin-react-hooks": "^1.6.0" } } ================================================ FILE: chatbox/public/index.html ================================================ React App
================================================ FILE: chatbox/public/manifest.json ================================================ { "short_name": "React App", "name": "Create React App Sample", "icons": [ { "src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon" } ], "start_url": ".", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff" } ================================================ FILE: chatbox/src/.eslintrc.json ================================================ { "extends": "react-app", "plugins": ["react-hooks"], "rules": { "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn" } } ================================================ FILE: chatbox/src/App.js ================================================ import axios from "axios" import moment from "moment" import { IntlProvider, createIntl } from "react-intl" import msg_zh from "i18n/zh.json" import msg_en from "i18n/en.json" import React from "react" import { Icon, message } from "antd" import { connect } from "react-redux" import Tab from "containers/Tab" // import socketManager from "socket/socket" import storageManager from "utils/storage" import urls from "config/urls" import { changeChatView, setChatModes, joinManMadeRoom } from "redux/actions/chat" import { changeTab, setAccount, setBlacklist } from "redux/actions" import store from "redux/store" import { setPageTitle } from "utils/pageTitle" import { setUrl } from "utils/url" require("moment/locale/zh-cn") //moment.js bug, has to manually include const i18nMsg = { zh: msg_zh, en: msg_en } const locale = window.navigator.userLanguage || window.navigator.language const msg = i18nMsg[locale.substring(0, 2)] const intl = createIntl({ locale: locale, messages: msg }) class App extends React.Component { constructor(props) { super(props) this.state = { // account: null, // A few steps before mounting the app // 1. Check local/chrome storage to see if there's account data // , if so, mount the app. // 2. If no account in storage, check if there's credential data // in storage, if so, mount the app and auto login // 3. If neither account nor credential data is in storage, // mount the app and auto register // TODO: remove 1 and 2? // In short, do not mount until done loading account/credential // from storage // above comment needs update loadingAccountFromStorage: true, waitingForConfigFromParent: true, // Only if there is no account data in storage on page load // autoLogin only once per page load autoLogin: false // mode: null, // room: null, // realRoom: DEFAULT_REAL_ROOM } // if (locale.indexOf("zh") > -1) { // moment.locale("zh-cn") // } moment.locale(locale) // window.spDebug(locale) message.config({ top: 80, duration: 2, maxCount: 3 }) } componentDidMount() { // TODO: this componentDidMount is registering a // couple different things, maybe move them to dedicated module // General settings for ajax calls axios.interceptors.response.use( response => { // Do something with response data return response }, error => { let errorMessage = "出错了" // set account to null when we receive 401 if (error.response && error.response.status === 401) { storageManager.set("account", null) errorMessage = intl.formatMessage({ id: "not.login" }) } if ( error.response && error.response.data && error.response.data.error ) { errorMessage = error.response.data.error } if (error.response && error.response.status === 403) { errorMessage = "禁止通行" } if (error.response && error.response.status === 409) { errorMessage = "权限不足" } if (error.response && error.response.status === 413) { errorMessage = "文件太大" } if (error.response && error.response.status === 429) { errorMessage = "操作频繁,请稍后再试" } if (error.response && error.response.status === 402) { errorMessage = "积分不足" } message.error(errorMessage) console.error(error) return Promise.reject(error) } ) // storageManager.get("mode", mode => { // if (mode) { // this.setState({ mode: mode }) // } // }) if (window.parent && window.parent !== window) { window.parent.postMessage({ action: "sp-parent-data" }, "*") // storageManager.pushToParentWindow() // shouldn't need to push to parent on chatbox load // should pull from parent instead } else { window.spConfig = {} this.setState({ waitingForConfigFromParent: false }) console.error("no parent window, this won't work without config!") } // storageManager.get("realRoom", realRoom => { // if (realRoom) { // this.setState({ realRoom: realRoom }) // } // }) // console.log("get account from storage, register account change listener") storageManager.get("room", room => { if (room) { this.props.joinManMadeRoom(room) } }) storageManager.get("account", account => { if (account) { window.spDebug("found account in storage") // window.spDebug(account) this.props.setAccount(account) } else { this.setState({ autoLogin: true }) window.spDebug("no account found in storage") } this.setState({ loadingAccountFromStorage: false }) }) storageManager.addEventListener("account", account => { this.props.setAccount(account) }) storageManager.get("blacklist", blacklist => { // simple implementation for blacklist, it's per browser device // not per account... blacklist = blacklist || [] this.props.setBlacklist(blacklist) }) storageManager.addEventListener("blacklist", blacklist => { this.props.setBlacklist(blacklist) }) window.addEventListener( "message", e => { if (!(e && e.data)) return const data = e.data.data const type = e.data.type if (type === "sp-parent-data") { const spConfig = data.spConfig window.spConfig = spConfig urls.dbAPI = spConfig.apiUrl || urls.dbAPI urls.socketAPI = spConfig.socketUrl || urls.socketAPI store.dispatch(setChatModes(spConfig.chatModes)) spConfig.defaultChatView = spConfig.defaultChatView || spConfig.chatModes[0] store.dispatch(changeChatView(spConfig.defaultChatView)) store.dispatch(changeTab(spConfig.defaultTab)) if (data.account) { storageManager.set("account", data.account) } if (data.blacklist) { storageManager.set("blacklist", data.blacklist) } this.setState({ waitingForConfigFromParent: false }) } if (type === "sp-blacklist") { storageManager.set("blacklist", data) } if (type === "sp-url-changed") { setUrl(data.url) console.log("url changed to " + data.url) setPageTitle(data.title) } }, false ) } componentDidUpdate(prevProps, prevState, snapshot) { // Need to differentiate login/logout with profile info update // maybe shouldn't have grouped them in one object? // const login = !prevState.account && this.state.account // const logout = prevState.account && !this.state.account // if (login) { // window.spDebug("logged in") // axios.defaults.headers.common["token"] = this.state.account.token // } // if (logout) { // window.spDebug("logged out") // axios.defaults.headers.common["token"] = null // // clear storage // storageManager.set("unread", false) // storageManager.set("inbox", null) // storageManager.set("inbox-offset", 0) // // TODO: change tab? // } } // setAccount = account => { // // window.spDebug("set account") // storageManager.set("account", account) // } stopAutoLogin = () => { this.setState({ autoLogin: false }) } render() { if ( this.state.loadingAccountFromStorage || this.state.waitingForConfigFromParent ) { return (
) } // if (!this.props.account) { // tab = "account" // } return ( ) } } // export default App const stateToProps = state => { return { account: state.account } } export default connect(stateToProps, { setAccount, joinManMadeRoom, setBlacklist })(App) ================================================ FILE: chatbox/src/components/Emoji/Emoji.css ================================================ .emoji-mart-preview { display: none; } .emoji-mart { max-width: 100%; position: fixed; bottom: 39px; left: 0px; border-bottom: none !important; z-index: 10; } .emoji-mart .emoji-mart-scroll { height: 200px; } .emoji-mart-category-label span { margin-bottom: 5px; } .emoji-mart-emoji-custom span { width: 72px !important; height: 72px !important; } .emoji-mart-category .emoji-mart-emoji span { cursor: pointer; } .emoji-mart-anchor { cursor: pointer; } ================================================ FILE: chatbox/src/components/Emoji/Emoji.js ================================================ import "./Emoji.css" import "emoji-mart/css/emoji-mart.css" import React from "react" import { createIntl } from "react-intl" import { Picker } from "emoji-mart" import ClickWrapper from "../OutsideClickDetector" import msg_zh from "i18n/zh.json" import msg_en from "i18n/en.json" const i18nMsg = { zh: msg_zh, en: msg_en } // const { intl } = new IntlProvider( // { locale: language, messages: messages }, // {} // ).getChildContext() const intl = createIntl({ locale: navigator.language, messages: i18nMsg[navigator.language.substring(0, 2)] }) const i18n = { search: intl.formatMessage({ id: "search" }), // clear: "清除", // Accessible label on "clear" button notfound: intl.formatMessage({ id: "not.found" }), // skintext: "Choose your default skin tone", categories: { search: intl.formatMessage({ id: "search.result" }), recent: intl.formatMessage({ id: "recently.used" }), people: intl.formatMessage({ id: "people" }), nature: intl.formatMessage({ id: "nature" }), foods: intl.formatMessage({ id: "food" }), activity: intl.formatMessage({ id: "activity" }), places: intl.formatMessage({ id: "places" }), objects: intl.formatMessage({ id: "objects" }), symbols: intl.formatMessage({ id: "symbols" }), flags: intl.formatMessage({ id: "flags" }) // custom: // " 欢乐兔" }, categorieslabel: "Emoji categories", // Accessible title for the list of categories skintones: { 1: "Default Skin Tone", 2: "Light Skin Tone", 3: "Medium-Light Skin Tone", 4: "Medium Skin Tone", 5: "Medium-Dark Skin Tone", 6: "Dark Skin Tone" } } // const customEmojis = [] // for (let i = 1; i <= 90; i++) { // const imageUrl = `stickers/happy_bun/${i}.gif` // customEmojis.push({ // name: "happy bun " + i, // short_names: [`happy_bun_` + i], // imageUrl: imageUrl // }) // } function Emoji(props) { return ( ) } export default Emoji ================================================ FILE: chatbox/src/components/Emoji/index.js ================================================ export { default } from "./Emoji" ================================================ FILE: chatbox/src/components/Iframe/Iframe.css ================================================ .sp-iframe-modal .ant-modal-content { height: 80%; position: fixed; /* width: 80%; */ top: 7% !important; left: 7%; right: 7%; } ================================================ FILE: chatbox/src/components/Iframe/Iframe.js ================================================ import "./Iframe.css" import React from "react" import { Modal } from "antd" function Iframe({ title, url, show, setShow }) { return ( { setShow(false) }} footer={null} >